diff --git a/CMakeLists.txt b/CMakeLists.txt index acc474da3..26e662c97 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,6 +28,7 @@ OPTION(USE_DOUBLE_PRECISION "Use double precision" OFF) OPTION(USE_GRAPHICAL_BENCHMARK "Use Graphical Benchmark" ON) OPTION(BUILD_SHARED_LIBS "Use shared libraries" OFF) OPTION(USE_SOFT_BODY_MULTI_BODY_DYNAMICS_WORLD "Use btSoftMultiBodyDynamicsWorld" OFF) +OPTION(BULLET2_USE_THREAD_LOCKS "Build Bullet 2 libraries with mutex locking around certain operations" OFF) OPTION(USE_MSVC_INCREMENTAL_LINKING "Use MSVC Incremental Linking" OFF) OPTION(USE_CUSTOM_VECTOR_MATH "Use custom vectormath library" OFF) @@ -155,6 +156,13 @@ IF(USE_GRAPHICAL_BENCHMARK) ADD_DEFINITIONS( -DUSE_GRAPHICAL_BENCHMARK) ENDIF (USE_GRAPHICAL_BENCHMARK) +IF(BULLET2_USE_THREAD_LOCKS) + ADD_DEFINITIONS( -DBT_THREADSAFE=1 ) + IF (NOT MSVC) + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") + ENDIF (NOT MSVC) +ENDIF (BULLET2_USE_THREAD_LOCKS) + IF (WIN32) OPTION(USE_GLUT "Use Glut" ON) ADD_DEFINITIONS( -D_CRT_SECURE_NO_WARNINGS ) @@ -195,8 +203,6 @@ ENDIF (OPENGL_FOUND) #FIND_PACKAGE(GLU) - - IF (APPLE) FIND_LIBRARY(COCOA_LIBRARY Cocoa) ENDIF() @@ -211,7 +217,8 @@ IF(BUILD_PYBULLET) FIND_PACKAGE(PythonLibs) OPTION(BUILD_PYBULLET_NUMPY "Set when you want to build pybullet with NumPy support" OFF) - + OPTION(BUILD_PYBULLET_ENET "Set when you want to build pybullet with enet UDP networking support" ON) + IF(BUILD_PYBULLET_NUMPY) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_LIST_DIR}/build3/cmake) #include(FindNumPy) @@ -264,6 +271,15 @@ IF(BUILD_BULLET2_DEMOS) IF(EXISTS ${BULLET_PHYSICS_SOURCE_DIR}/examples AND IS_DIRECTORY ${BULLET_PHYSICS_SOURCE_DIR}/examples) SUBDIRS(examples) ENDIF() + + IF (BULLET2_USE_THREAD_LOCKS) + OPTION(BULLET2_MULTITHREADED_OPEN_MP_DEMO "Build Bullet 2 MultithreadedDemo using OpenMP (requires a compiler with OpenMP support)" OFF) + OPTION(BULLET2_MULTITHREADED_TBB_DEMO "Build Bullet 2 MultithreadedDemo using Intel Threading Building Blocks (requires the TBB library to be already installed)" OFF) + IF (MSVC) + OPTION(BULLET2_MULTITHREADED_PPL_DEMO "Build Bullet 2 MultithreadedDemo using Microsoft Parallel Patterns Library (requires MSVC compiler)" OFF) + ENDIF (MSVC) + ENDIF (BULLET2_USE_THREAD_LOCKS) + ENDIF(BUILD_BULLET2_DEMOS) diff --git a/Extras/Serialize/BulletFileLoader/autogenerated/bullet.h b/Extras/Serialize/BulletFileLoader/autogenerated/bullet.h index 49fb0dee0..2e2e8e322 100644 --- a/Extras/Serialize/BulletFileLoader/autogenerated/bullet.h +++ b/Extras/Serialize/BulletFileLoader/autogenerated/bullet.h @@ -553,6 +553,8 @@ typedef struct bInvalidHandle { double m_deactivationTime; double m_friction; double m_rollingFriction; + double m_contactDamping; + double m_contactStiffness; double m_restitution; double m_hitFraction; double m_ccdSweptSphereRadius; @@ -585,6 +587,8 @@ typedef struct bInvalidHandle { float m_deactivationTime; float m_friction; float m_rollingFriction; + float m_contactDamping; + float m_contactStiffness; float m_restitution; float m_hitFraction; float m_ccdSweptSphereRadius; diff --git a/README.md b/README.md index 19d90086b..5c654bd04 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ # Bullet Physics SDK -This is the official C++ source code repository of the Bullet Physics SDK: real-time collision detection and multi-physics simulation for games, visual effects, robotics etc. +This is the official C++ source code repository of the Bullet Physics SDK: real-time collision detection and multi-physics simulation for VR, games, visual effects, robotics, machine learning etc. New in Bullet 2.85: pybullet Python bindings, improved support for robotics and VR diff --git a/build3/premake4.lua b/build3/premake4.lua index f0de611fd..525996461 100644 --- a/build3/premake4.lua +++ b/build3/premake4.lua @@ -57,7 +57,7 @@ description = "Use Midi controller to control parameters" } --- --_OPTIONS["midi"] = "1"; +-- _OPTIONS["midi"] = "1"; newoption { @@ -73,8 +73,8 @@ newoption { - trigger = "enet", - description = "Enable enet NAT punchthrough test" + trigger = "no-enet", + description = "Disable enet and enet tests" } newoption @@ -237,6 +237,7 @@ end language "C++" + if not _OPTIONS["no-demos"] then include "../examples/ExampleBrowser" include "../examples/OpenGLWindow" @@ -261,14 +262,23 @@ end if not _OPTIONS["no-test"] then include "../test/SharedMemory" - if _OPTIONS["enet"] then - include "../examples/ThirdPartyLibs/enet" - include "../test/enet/client" - include "../test/enet/server" - end + end end + if _OPTIONS["midi"] then + include "../examples/ThirdPartyLibs/midi" + end + + if not _OPTIONS["no-enet"] then + include "../examples/ThirdPartyLibs/enet" + include "../test/enet/nat_punchthrough/client" + include "../test/enet/nat_punchthrough/server" + include "../test/enet/chat/client" + include "../test/enet/chat/server" + defines {"BT_ENABLE_ENET"} + end + if _OPTIONS["no-bullet3"] then print "--no-bullet3 implies --no-demos" _OPTIONS["no-demos"] = "1" diff --git a/build3/premake5.exe b/build3/premake5.exe new file mode 100644 index 000000000..28bccbcb8 Binary files /dev/null and b/build3/premake5.exe differ diff --git a/build_cmake_pybullet_win32.bat b/build_cmake_pybullet_win32.bat new file mode 100644 index 000000000..f3e672899 --- /dev/null +++ b/build_cmake_pybullet_win32.bat @@ -0,0 +1,4 @@ +mkdir cm +cd cm +cmake -DBUILD_PYBULLET=ON -DCMAKE_BUILD_TYPE=Release -DPYTHON_INCLUDE_DIR=c:\python-3.5.2\include -DPYTHON_LIBRARY=c:\python-3.5.2\libs\python35.lib -DPYTHON_DEBUG_LIBRARY=c:\python-3.5.2\libs\python35_d.lib .. +start . diff --git a/build_visual_studio_vr_pybullet_double.bat b/build_visual_studio_vr_pybullet_double.bat index 6ca0652b9..f4c43cbb5 100644 --- a/build_visual_studio_vr_pybullet_double.bat +++ b/build_visual_studio_vr_pybullet_double.bat @@ -16,6 +16,6 @@ del tmp1234.txt cd build3 -premake4 --double --enable_openvr --enable_pybullet --python_include_dir="%myvar%/include" --python_lib_dir="%myvar%/libs" --targetdir="../bin" vs2010 +premake4 --double --midi --enable_openvr --enable_pybullet --python_include_dir="%myvar%/include" --python_lib_dir="%myvar%/libs" --targetdir="../bin" vs2010 start vs2010 diff --git a/data/gripper/wsg50_one_motor_gripper_free_base.sdf b/data/gripper/wsg50_one_motor_gripper_free_base.sdf index 7fc3ed2b2..552c36d28 100644 --- a/data/gripper/wsg50_one_motor_gripper_free_base.sdf +++ b/data/gripper/wsg50_one_motor_gripper_free_base.sdf @@ -303,6 +303,10 @@ + + + + 0.042 0 0.145 0 0 1.5708 0.2 @@ -343,6 +347,10 @@ + + + + -0.042 0 0.145 0 0 4.71239 0.2 diff --git a/data/gripper/wsg50_one_motor_gripper_left_finger.urdf b/data/gripper/wsg50_one_motor_gripper_left_finger.urdf new file mode 100644 index 000000000..a5e58f6c4 --- /dev/null +++ b/data/gripper/wsg50_one_motor_gripper_left_finger.urdf @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/data/gripper/wsg50_one_motor_gripper_new_free_base.sdf b/data/gripper/wsg50_one_motor_gripper_new_free_base.sdf index 68e2a0a6e..0358f7a6a 100644 --- a/data/gripper/wsg50_one_motor_gripper_new_free_base.sdf +++ b/data/gripper/wsg50_one_motor_gripper_new_free_base.sdf @@ -300,6 +300,10 @@ + + 1.0 + 1.5 + 0.062 0 0.145 0 0 1.5708 0.2 @@ -340,6 +344,10 @@ + + 1.0 + 1.5 + -0.062 0 0.145 0 0 4.71239 0.2 diff --git a/data/gripper/wsg50_one_motor_gripper_no_finger.sdf b/data/gripper/wsg50_one_motor_gripper_no_finger.sdf new file mode 100644 index 000000000..878b1ee14 --- /dev/null +++ b/data/gripper/wsg50_one_motor_gripper_no_finger.sdf @@ -0,0 +1,307 @@ + + + + + 0 0 0.4 3.14 0 0 + + + + + + world + base_link + + 0 0 1 + + -10 + 10 + 1 + 1 + + + 0 + 0 + 0 + 0 + + + + + + 0 0 0 0 0 0 + + 0 0 0 0 0 0 + 1.2 + + 1 + 0 + 0 + 1 + 0 + 1 + + + + + 0 0 0 0 -0 0 + + + 1 1 1 + meshes/WSG50_110.stl + + + + + + + + + + + 0 0 0.03 0 0 0 + + 0 0 0 0 0 0 + 0.1 + + 0.1 + 0 + 0 + 0.1 + 0 + 0.1 + + + + 0 0 0.01 0 0 0 + + + 0.02 0.02 0.02 + + + + + + + motor + base_link + + 0 0 1 + + -0.055 + 0.001 + 10.0 + 10.0 + + + 0 + 0 + 0 + 0 + + + + + + 0 0 0.04 0 0 0 + + 0 0 0.035 0 0 0 + 0.1 + + 0.1 + 0 + 0 + 0.1 + 0 + 0.1 + + + + -0.03 0 0.01 0 -1.2 0 + + + 0.02 0.02 0.07 + + + + + + + left_hinge + motor + + 0 1 0 + + -20.0 + 20.0 + 10 + 10 + + + 0 + 0 + 0 + 0 + + 0 + + + + + 0 0 0.04 0 0 0 + + 0 0 0.035 0 0 0 + 0.1 + + 0.1 + 0 + 0 + 0.1 + 0 + 0.1 + + + + 0.03 0 0.01 0 1.2 0 + + + 0.02 0.02 0.07 + + + + + + + right_hinge + motor + + 0 1 0 + + -20.0 + 20.0 + 10 + 10 + + + 0 + 0 + 0 + 0 + + 0 + + + + + -0.055 0 0.06 0 -0 0 + + 0 0 0.0115 0 -0 0 + 0.2 + + 0.1 + 0 + 0 + 0.1 + 0 + 0.1 + + + + + 0 0 -0.06 0 0 0 + + + 0.001 0.001 0.001 + meshes/GUIDE_WSG50_110.stl + + + + + 0 0 -0.037 0 0 0 + + + 0.001 0.001 0.001 + meshes/WSG-FMF.stl + + + + + + + + gripper_left + base_link + + 1 0 0 + + -0.01 + 0.04 + 1 + 1 + + + 0 + 0 + 0 + 0 + + + + + + 0.055 0 0.06 0 0 0 + + 0 0 0.0115 0 -0 0 + 0.2 + + 0.1 + 0 + 0 + 0.1 + 0 + 0.1 + + + + + 0 0 -0.06 0 0 3.14159 + + + 0.001 0.001 0.001 + meshes/GUIDE_WSG50_110.stl + + + + + 0 0 -0.037 0 0 3.14159 + + + 0.001 0.001 0.001 + meshes/WSG-FMF.stl + + + + + + + gripper_right + base_link + + 1 0 0 + + -0.04 + 0.01 + 1 + 1 + + + 0 + 0 + 0 + 0 + + + + + + + \ No newline at end of file diff --git a/data/gripper/wsg50_one_motor_gripper_right_finger.urdf b/data/gripper/wsg50_one_motor_gripper_right_finger.urdf new file mode 100644 index 000000000..c6257e399 --- /dev/null +++ b/data/gripper/wsg50_one_motor_gripper_right_finger.urdf @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/data/humanoid/LICENSE.txt b/data/humanoid/LICENSE.txt new file mode 100644 index 000000000..8922f23f1 --- /dev/null +++ b/data/humanoid/LICENSE.txt @@ -0,0 +1,26 @@ +Copyright (c) 2009-2013, A. Hornung, University of Freiburg +All rights reserved. + +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 University of Freiburg 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. \ No newline at end of file diff --git a/data/humanoid/nao.urdf b/data/humanoid/nao.urdf new file mode 100644 index 000000000..ed0f7cbbd --- /dev/null +++ b/data/humanoid/nao.urdf @@ -0,0 +1,2663 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + /nao_dcm + gazebo_ros_control/DefaultRobotHWSim + + + + + + LHipYawPitch + RHipYawPitch + 1.0 + 0.0 + + + LHand + LFinger11 + -0.785398163398 + 0.785398163398 + + + LHand + LFinger12 + -0.785398163398 + 0.785398163398 + + + LHand + LFinger13 + -0.785398163398 + 0.785398163398 + + + LHand + LFinger21 + -0.785398163398 + 0.785398163398 + + + LHand + LFinger22 + -0.785398163398 + 0.785398163398 + + + LHand + LFinger23 + -0.785398163398 + 0.785398163398 + + + RHand + RFinger11 + -0.785398163398 + 0.785398163398 + + + RHand + RFinger12 + -0.785398163398 + 0.785398163398 + + + RHand + RFinger13 + -0.785398163398 + 0.785398163398 + + + RHand + RFinger21 + -0.785398163398 + 0.785398163398 + + + RHand + RFinger22 + -0.785398163398 + 0.785398163398 + + + RHand + RFinger23 + -0.785398163398 + 0.785398163398 + + + LHand + LThumb1 + -0.785398163398 + 0.785398163398 + + + LHand + LThumb2 + -0.785398163398 + 0.785398163398 + + + RHand + RThumb1 + -0.785398163398 + 0.785398163398 + + + RHand + RThumb2 + -0.785398163398 + 0.785398163398 + + + LFinger11_link + + + LFinger12_link + + + LFinger13_link + + + LFinger21_link + + + LFinger22_link + + + LFinger23_link + + + LThumb1_link + + + LThumb2_link + + + l_gripper + + + RFinger11_link + + + RFinger12_link + + + RFinger13_link + + + RFinger21_link + + + RFinger22_link + + + RFinger23_link + + + RThumb1_link + + + RThumb2_link + + + r_gripper + + + + + + 0.5 + 0.5 + false + false + + + 0.5 + 0.5 + false + false + + + 0.5 + 0.5 + false + false + + + 0.5 + 0.5 + false + false + + + + + 0.5 + 0.5 + false + false + + + 0.5 + 0.5 + false + false + + + 0.5 + 0.5 + false + false + + + 0.5 + 0.5 + false + false + + + 0.5 + 0.5 + false + false + + + 0.5 + 0.5 + false + true + + + 0.5 + 0.5 + false + false + + + 0.5 + 0.5 + false + false + + + 0.5 + 0.5 + false + false + + + 0.5 + 0.5 + false + false + + + 0.5 + 0.5 + false + false + + + 0.5 + 0.5 + false + true + + + + 0.5 + 0.5 + false + true + + + 0.5 + 0.5 + false + true + + + 0.5 + 0.5 + false + true + + + 0.5 + 0.5 + false + true + + + 0.5 + 0.5 + false + true + + + 0.5 + 0.5 + false + true + + + 0.5 + 0.5 + false + true + + + 0.5 + 0.5 + false + true + + + 0.5 + 0.5 + false + false + + + 0.5 + 0.5 + false + false + + + 0.5 + 0.5 + false + false + + + 0.5 + 0.5 + false + false + + + 0.5 + 0.5 + false + false + + + 0.5 + 0.5 + false + false + 1 0 0 + 0.1 + 0.003 + + + 0.5 + 0.5 + false + false + + + 0.5 + 0.5 + false + false + + + 0.5 + 0.5 + false + false + + + 0.5 + 0.5 + false + false + + + 0.5 + 0.5 + false + false + + + 0.5 + 0.5 + false + false + 1 0 0 + 0.1 + 0.003 + + + 0.5 + 0.5 + false + true + + + 0.5 + 0.5 + false + true + + + 0.5 + 0.5 + false + true + + + 0.5 + 0.5 + false + true + + + 0.5 + 0.5 + false + true + + + 0.5 + 0.5 + false + true + + + 0.5 + 0.5 + false + true + + + 0.5 + 0.5 + false + true + + + + + 5.0 + + 1.06290551 + + 640 + 480 + R8G8B8 + + + 0.3 + 500 + + + gaussian + 0.0 + 0.007 + + + + nao_robot + true + 5.0 + camera/top + image_raw + camera_info + CameraTop_optical_frame + 0.07 + -0.0545211 + 0.06919734 + -0.0241095 + -0.0112245 + 0.0 + + + + + + 5.0 + + 1.06290551 + + 640 + 480 + R8G8B8 + + + 0.05 + 500 + + + gaussian + 0.0 + 0.007 + + + + /nao_robot + true + 5.0 + camera_bottom + image_raw + camera_info + CameraBottom_optical_frame + 0.07 + -0.0648764 + 0.06125202 + 0.00382815 + -0.00551104 + 0.0 + + + + + + + 0.5 + 0.5 + false + false + 1 0 0 + 0.1 + 0.003 + + 1 + 20 + false + + RFsrFL_frame_collision + + + nao_robot + true + FSR/RFoot/FrontLeft + RFsrFL_frame + + + + + 0.5 + 0.5 + false + false + 1 0 0 + 0.1 + 0.003 + + 1 + 20 + false + + RFsrFR_frame_collision + + + nao_robot + true + FSR/RFoot/FrontRight + RFsrFR_frame + + + + + 0.5 + 0.5 + false + false + 1 0 0 + 0.1 + 0.003 + + 1 + 20 + false + + RFsrRL_frame_collision + + + nao_robot + true + FSR/RFoot/RearLeft + RFsrRL_frame + + + + + 0.5 + 0.5 + false + false + 1 0 0 + 0.1 + 0.003 + + 1 + 20 + false + + RFsrRR_frame_collision + + + nao_robot + true + FSR/RFoot/RearRight + RFsrRR_frame + + + + + 0.5 + 0.5 + false + false + 1 0 0 + 0.1 + 0.003 + + 1 + 20 + false + + LFsrFL_frame_collision + + + nao_robot + true + FSR/LFoot/FrontLeft + RFsrFL_frame + + + + + 0.5 + 0.5 + false + false + 1 0 0 + 0.1 + 0.003 + + 1 + 20 + false + + LFsrFR_frame_collision + + + nao_robot + true + FSR/LFoot/FrontRight + LFsrFR_frame + + + + + 0.5 + 0.5 + false + false + 1 0 0 + 0.1 + 0.003 + + 1 + 20 + false + + LFsrRL_frame_collision + + + nao_robot + true + FSR/LFoot/RearLeft + LFsrRL_frame + + + + + 0.5 + 0.5 + false + false + 1 0 0 + 0.1 + 0.003 + + 1 + 20 + false + + LFsrRR_frame_collision + + + nao_robot + true + FSR/LFoot/RearRight + LFsrRR_frame + + + + + + + 0 0 0 0 0 0 + 20 + false + + + + 5 + 1 + -0.2617993877991494 + 0.2617993877991494 + + + + 5 + 1 + -0.13 + 0.13 + + + + + 0.025 + 2.55 + 1 + + + + nao_robot + 0.05 + true + 20 + sonar_left + LSonar_frame + 0.025 + 2.55 + 0.5235987755982988 + + ultrasound + + + + + + 0 0 0 0 0 0 + 20 + false + + + + 5 + 1 + -0.2617993877991494 + 0.2617993877991494 + + + 5 + 1 + -0.13 + 0.13 + + + + 0.025 + 2.55 + 1 + + + + nao_robot + 0.05 + true + 20 + sonar_right + RSonar_frame + 0.025 + 2.55 + 0.5235987755982988 + ultrasound + + + + + + transmission_interface/SimpleTransmission + + PositionJointInterface + + + + PositionJointInterface + 150.27 + + + + transmission_interface/SimpleTransmission + + PositionJointInterface + + + + PositionJointInterface + 173.22 + + + + transmission_interface/SimpleTransmission + + PositionJointInterface + + + PositionJointInterface + 150.27 + + + + transmission_interface/SimpleTransmission + + PositionJointInterface + + + PositionJointInterface + 173.22 + + + + transmission_interface/SimpleTransmission + + PositionJointInterface + + + PositionJointInterface + 150.27 + + + + transmission_interface/SimpleTransmission + + PositionJointInterface + + + PositionJointInterface + 173.22 + + + + transmission_interface/SimpleTransmission + + PositionJointInterface + + + PositionJointInterface + 50.61 + + + + transmission_interface/SimpleTransmission + + PositionJointInterface + + + PositionJointInterface + 36.24 + + + + transmission_interface/SimpleTransmission + + PositionJointInterface + + + PositionJointInterface + 150.27 + + + + transmission_interface/SimpleTransmission + + PositionJointInterface + + + PositionJointInterface + 173.22 + + + + transmission_interface/SimpleTransmission + + PositionJointInterface + + + PositionJointInterface + 150.27 + + + + transmission_interface/SimpleTransmission + + PositionJointInterface + + + PositionJointInterface + 173.22 + + + + transmission_interface/SimpleTransmission + + PositionJointInterface + + + PositionJointInterface + 50.61 + + + + transmission_interface/SimpleTransmission + + PositionJointInterface + + + PositionJointInterface + 36.24 + + + + transmission_interface/SimpleTransmission + + PositionJointInterface + + + + PositionJointInterface + 201.3 + + + + transmission_interface/SimpleTransmission + + PositionJointInterface + + + + PositionJointInterface + 201.3 + + + + transmission_interface/SimpleTransmission + + PositionJointInterface + + + + PositionJointInterface + 130.85 + + + + transmission_interface/SimpleTransmission + + PositionJointInterface + + + + PositionJointInterface + 130.85 + + + + transmission_interface/SimpleTransmission + + PositionJointInterface + + + + PositionJointInterface + 130.85 + + + + transmission_interface/SimpleTransmission + + PositionJointInterface + + + + PositionJointInterface + 201.3 + + + + transmission_interface/SimpleTransmission + + PositionJointInterface + + + + PositionJointInterface + 201.3 + + + + transmission_interface/SimpleTransmission + + PositionJointInterface + + + + PositionJointInterface + 201.3 + + + + transmission_interface/SimpleTransmission + + PositionJointInterface + + + + PositionJointInterface + 130.85 + + + + transmission_interface/SimpleTransmission + + PositionJointInterface + + + + PositionJointInterface + 130.85 + + + + transmission_interface/SimpleTransmission + + PositionJointInterface + + + + PositionJointInterface + 130.85 + + + + transmission_interface/SimpleTransmission + + PositionJointInterface + + + + PositionJointInterface + 201.3 + + + diff --git a/data/humanoid/nao_meshes/meshes/V40/HeadPitch_0.10.stl b/data/humanoid/nao_meshes/meshes/V40/HeadPitch_0.10.stl new file mode 100644 index 000000000..f7d4abf23 Binary files /dev/null and b/data/humanoid/nao_meshes/meshes/V40/HeadPitch_0.10.stl differ diff --git a/data/humanoid/nao_meshes/meshes/V40/HeadYaw_0.10.stl b/data/humanoid/nao_meshes/meshes/V40/HeadYaw_0.10.stl new file mode 100644 index 000000000..064ec3268 Binary files /dev/null and b/data/humanoid/nao_meshes/meshes/V40/HeadYaw_0.10.stl differ diff --git a/data/humanoid/nao_meshes/meshes/V40/LAnklePitch_0.10.stl b/data/humanoid/nao_meshes/meshes/V40/LAnklePitch_0.10.stl new file mode 100644 index 000000000..3e131386b Binary files /dev/null and b/data/humanoid/nao_meshes/meshes/V40/LAnklePitch_0.10.stl differ diff --git a/data/humanoid/nao_meshes/meshes/V40/LAnkleRoll_0.10.stl b/data/humanoid/nao_meshes/meshes/V40/LAnkleRoll_0.10.stl new file mode 100644 index 000000000..361cd5cf0 Binary files /dev/null and b/data/humanoid/nao_meshes/meshes/V40/LAnkleRoll_0.10.stl differ diff --git a/data/humanoid/nao_meshes/meshes/V40/LElbowRoll_0.10.stl b/data/humanoid/nao_meshes/meshes/V40/LElbowRoll_0.10.stl new file mode 100644 index 000000000..285486857 Binary files /dev/null and b/data/humanoid/nao_meshes/meshes/V40/LElbowRoll_0.10.stl differ diff --git a/data/humanoid/nao_meshes/meshes/V40/LFinger11_0.10.stl b/data/humanoid/nao_meshes/meshes/V40/LFinger11_0.10.stl new file mode 100644 index 000000000..088beaa2c Binary files /dev/null and b/data/humanoid/nao_meshes/meshes/V40/LFinger11_0.10.stl differ diff --git a/data/humanoid/nao_meshes/meshes/V40/LFinger12_0.10.stl b/data/humanoid/nao_meshes/meshes/V40/LFinger12_0.10.stl new file mode 100644 index 000000000..c88375645 Binary files /dev/null and b/data/humanoid/nao_meshes/meshes/V40/LFinger12_0.10.stl differ diff --git a/data/humanoid/nao_meshes/meshes/V40/LFinger13_0.10.stl b/data/humanoid/nao_meshes/meshes/V40/LFinger13_0.10.stl new file mode 100644 index 000000000..49aeecafb Binary files /dev/null and b/data/humanoid/nao_meshes/meshes/V40/LFinger13_0.10.stl differ diff --git a/data/humanoid/nao_meshes/meshes/V40/LFinger21_0.10.stl b/data/humanoid/nao_meshes/meshes/V40/LFinger21_0.10.stl new file mode 100644 index 000000000..7283509f5 Binary files /dev/null and b/data/humanoid/nao_meshes/meshes/V40/LFinger21_0.10.stl differ diff --git a/data/humanoid/nao_meshes/meshes/V40/LFinger22_0.10.stl b/data/humanoid/nao_meshes/meshes/V40/LFinger22_0.10.stl new file mode 100644 index 000000000..d096469cc Binary files /dev/null and b/data/humanoid/nao_meshes/meshes/V40/LFinger22_0.10.stl differ diff --git a/data/humanoid/nao_meshes/meshes/V40/LFinger23_0.10.stl b/data/humanoid/nao_meshes/meshes/V40/LFinger23_0.10.stl new file mode 100644 index 000000000..fe488fead Binary files /dev/null and b/data/humanoid/nao_meshes/meshes/V40/LFinger23_0.10.stl differ diff --git a/data/humanoid/nao_meshes/meshes/V40/LHipPitch_0.10.stl b/data/humanoid/nao_meshes/meshes/V40/LHipPitch_0.10.stl new file mode 100644 index 000000000..030e9e1f7 Binary files /dev/null and b/data/humanoid/nao_meshes/meshes/V40/LHipPitch_0.10.stl differ diff --git a/data/humanoid/nao_meshes/meshes/V40/LHipRoll_0.10.stl b/data/humanoid/nao_meshes/meshes/V40/LHipRoll_0.10.stl new file mode 100644 index 000000000..ac6420665 Binary files /dev/null and b/data/humanoid/nao_meshes/meshes/V40/LHipRoll_0.10.stl differ diff --git a/data/humanoid/nao_meshes/meshes/V40/LHipYawPitch_0.10.stl b/data/humanoid/nao_meshes/meshes/V40/LHipYawPitch_0.10.stl new file mode 100644 index 000000000..d6997c827 Binary files /dev/null and b/data/humanoid/nao_meshes/meshes/V40/LHipYawPitch_0.10.stl differ diff --git a/data/humanoid/nao_meshes/meshes/V40/LKneePitch_0.10.stl b/data/humanoid/nao_meshes/meshes/V40/LKneePitch_0.10.stl new file mode 100644 index 000000000..66b042675 Binary files /dev/null and b/data/humanoid/nao_meshes/meshes/V40/LKneePitch_0.10.stl differ diff --git a/data/humanoid/nao_meshes/meshes/V40/LShoulderPitch_0.10.stl b/data/humanoid/nao_meshes/meshes/V40/LShoulderPitch_0.10.stl new file mode 100644 index 000000000..8e761ec68 Binary files /dev/null and b/data/humanoid/nao_meshes/meshes/V40/LShoulderPitch_0.10.stl differ diff --git a/data/humanoid/nao_meshes/meshes/V40/LShoulderRoll_0.10.stl b/data/humanoid/nao_meshes/meshes/V40/LShoulderRoll_0.10.stl new file mode 100644 index 000000000..6fd3957d4 Binary files /dev/null and b/data/humanoid/nao_meshes/meshes/V40/LShoulderRoll_0.10.stl differ diff --git a/data/humanoid/nao_meshes/meshes/V40/LThumb1_0.10.stl b/data/humanoid/nao_meshes/meshes/V40/LThumb1_0.10.stl new file mode 100644 index 000000000..d784d0dde Binary files /dev/null and b/data/humanoid/nao_meshes/meshes/V40/LThumb1_0.10.stl differ diff --git a/data/humanoid/nao_meshes/meshes/V40/LThumb2_0.10.stl b/data/humanoid/nao_meshes/meshes/V40/LThumb2_0.10.stl new file mode 100644 index 000000000..142741fb6 Binary files /dev/null and b/data/humanoid/nao_meshes/meshes/V40/LThumb2_0.10.stl differ diff --git a/data/humanoid/nao_meshes/meshes/V40/LWristYaw_0.10.stl b/data/humanoid/nao_meshes/meshes/V40/LWristYaw_0.10.stl new file mode 100644 index 000000000..12fe18bf9 Binary files /dev/null and b/data/humanoid/nao_meshes/meshes/V40/LWristYaw_0.10.stl differ diff --git a/data/humanoid/nao_meshes/meshes/V40/RAnklePitch_0.10.stl b/data/humanoid/nao_meshes/meshes/V40/RAnklePitch_0.10.stl new file mode 100644 index 000000000..23afaf696 Binary files /dev/null and b/data/humanoid/nao_meshes/meshes/V40/RAnklePitch_0.10.stl differ diff --git a/data/humanoid/nao_meshes/meshes/V40/RAnkleRoll_0.10.stl b/data/humanoid/nao_meshes/meshes/V40/RAnkleRoll_0.10.stl new file mode 100644 index 000000000..c44b29ac9 Binary files /dev/null and b/data/humanoid/nao_meshes/meshes/V40/RAnkleRoll_0.10.stl differ diff --git a/data/humanoid/nao_meshes/meshes/V40/RElbowRoll_0.10.stl b/data/humanoid/nao_meshes/meshes/V40/RElbowRoll_0.10.stl new file mode 100644 index 000000000..848b6afec Binary files /dev/null and b/data/humanoid/nao_meshes/meshes/V40/RElbowRoll_0.10.stl differ diff --git a/data/humanoid/nao_meshes/meshes/V40/RFinger11_0.10.stl b/data/humanoid/nao_meshes/meshes/V40/RFinger11_0.10.stl new file mode 100644 index 000000000..95811bbf6 Binary files /dev/null and b/data/humanoid/nao_meshes/meshes/V40/RFinger11_0.10.stl differ diff --git a/data/humanoid/nao_meshes/meshes/V40/RFinger12_0.10.stl b/data/humanoid/nao_meshes/meshes/V40/RFinger12_0.10.stl new file mode 100644 index 000000000..be7cee53a Binary files /dev/null and b/data/humanoid/nao_meshes/meshes/V40/RFinger12_0.10.stl differ diff --git a/data/humanoid/nao_meshes/meshes/V40/RFinger13_0.10.stl b/data/humanoid/nao_meshes/meshes/V40/RFinger13_0.10.stl new file mode 100644 index 000000000..a1f2ffbd3 Binary files /dev/null and b/data/humanoid/nao_meshes/meshes/V40/RFinger13_0.10.stl differ diff --git a/data/humanoid/nao_meshes/meshes/V40/RFinger21_0.10.stl b/data/humanoid/nao_meshes/meshes/V40/RFinger21_0.10.stl new file mode 100644 index 000000000..4a2af7468 Binary files /dev/null and b/data/humanoid/nao_meshes/meshes/V40/RFinger21_0.10.stl differ diff --git a/data/humanoid/nao_meshes/meshes/V40/RFinger22_0.10.stl b/data/humanoid/nao_meshes/meshes/V40/RFinger22_0.10.stl new file mode 100644 index 000000000..4260f54f2 Binary files /dev/null and b/data/humanoid/nao_meshes/meshes/V40/RFinger22_0.10.stl differ diff --git a/data/humanoid/nao_meshes/meshes/V40/RFinger23_0.10.stl b/data/humanoid/nao_meshes/meshes/V40/RFinger23_0.10.stl new file mode 100644 index 000000000..663cb1f5f Binary files /dev/null and b/data/humanoid/nao_meshes/meshes/V40/RFinger23_0.10.stl differ diff --git a/data/humanoid/nao_meshes/meshes/V40/RHipPitch_0.10.stl b/data/humanoid/nao_meshes/meshes/V40/RHipPitch_0.10.stl new file mode 100644 index 000000000..9d6ef12e6 Binary files /dev/null and b/data/humanoid/nao_meshes/meshes/V40/RHipPitch_0.10.stl differ diff --git a/data/humanoid/nao_meshes/meshes/V40/RHipRoll_0.10.stl b/data/humanoid/nao_meshes/meshes/V40/RHipRoll_0.10.stl new file mode 100644 index 000000000..36d67b9b4 Binary files /dev/null and b/data/humanoid/nao_meshes/meshes/V40/RHipRoll_0.10.stl differ diff --git a/data/humanoid/nao_meshes/meshes/V40/RHipYawPitch_0.10.stl b/data/humanoid/nao_meshes/meshes/V40/RHipYawPitch_0.10.stl new file mode 100644 index 000000000..6697ebb7b Binary files /dev/null and b/data/humanoid/nao_meshes/meshes/V40/RHipYawPitch_0.10.stl differ diff --git a/data/humanoid/nao_meshes/meshes/V40/RKneePitch_0.10.stl b/data/humanoid/nao_meshes/meshes/V40/RKneePitch_0.10.stl new file mode 100644 index 000000000..54fa06e50 Binary files /dev/null and b/data/humanoid/nao_meshes/meshes/V40/RKneePitch_0.10.stl differ diff --git a/data/humanoid/nao_meshes/meshes/V40/RShoulderPitch_0.10.stl b/data/humanoid/nao_meshes/meshes/V40/RShoulderPitch_0.10.stl new file mode 100644 index 000000000..8333a4817 Binary files /dev/null and b/data/humanoid/nao_meshes/meshes/V40/RShoulderPitch_0.10.stl differ diff --git a/data/humanoid/nao_meshes/meshes/V40/RShoulderRoll_0.10.stl b/data/humanoid/nao_meshes/meshes/V40/RShoulderRoll_0.10.stl new file mode 100644 index 000000000..3166375fe Binary files /dev/null and b/data/humanoid/nao_meshes/meshes/V40/RShoulderRoll_0.10.stl differ diff --git a/data/humanoid/nao_meshes/meshes/V40/RThumb1_0.10.stl b/data/humanoid/nao_meshes/meshes/V40/RThumb1_0.10.stl new file mode 100644 index 000000000..c7a3189cf Binary files /dev/null and b/data/humanoid/nao_meshes/meshes/V40/RThumb1_0.10.stl differ diff --git a/data/humanoid/nao_meshes/meshes/V40/RThumb2_0.10.stl b/data/humanoid/nao_meshes/meshes/V40/RThumb2_0.10.stl new file mode 100644 index 000000000..85777b605 Binary files /dev/null and b/data/humanoid/nao_meshes/meshes/V40/RThumb2_0.10.stl differ diff --git a/data/humanoid/nao_meshes/meshes/V40/RWristYaw_0.10.stl b/data/humanoid/nao_meshes/meshes/V40/RWristYaw_0.10.stl new file mode 100644 index 000000000..abc0c67b3 Binary files /dev/null and b/data/humanoid/nao_meshes/meshes/V40/RWristYaw_0.10.stl differ diff --git a/data/humanoid/nao_meshes/meshes/V40/Torso_0.10.stl b/data/humanoid/nao_meshes/meshes/V40/Torso_0.10.stl new file mode 100644 index 000000000..d4873f528 Binary files /dev/null and b/data/humanoid/nao_meshes/meshes/V40/Torso_0.10.stl differ diff --git a/data/husky/meshes/base_link.stl b/data/husky/meshes/base_link.stl new file mode 100644 index 000000000..db63bd20f Binary files /dev/null and b/data/husky/meshes/base_link.stl differ diff --git a/data/kiva_shelf/0_Bullet3Demo.txt b/data/kiva_shelf/0_Bullet3Demo.txt deleted file mode 100644 index eb396d29f..000000000 --- a/data/kiva_shelf/0_Bullet3Demo.txt +++ /dev/null @@ -1,7 +0,0 @@ ---start_demo_name=R2D2 Grasp ---mouse_move_multiplier=0.400000 ---mouse_wheel_multiplier=0.010000 ---background_color_red= 0.900000 ---background_color_green= 0.900000 ---background_color_blue= 1.000000 ---fixed_timestep= 0.000000 diff --git a/data/kuka_iiwa/model_free_base.urdf b/data/kuka_iiwa/model_free_base.urdf new file mode 100644 index 000000000..b87373346 --- /dev/null +++ b/data/kuka_iiwa/model_free_base.urdf @@ -0,0 +1,289 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/data/multibody.bullet b/data/multibody.bullet index 084ee5a8a..90aa45157 100644 Binary files a/data/multibody.bullet and b/data/multibody.bullet differ diff --git a/data/plane.obj b/data/plane.obj index 0b77a9912..606209531 100644 --- a/data/plane.obj +++ b/data/plane.obj @@ -2,14 +2,14 @@ # www.blender.org mtllib plane.mtl o Plane -v 5.000000 -5.000000 0.000000 -v 5.000000 5.000000 0.000000 -v -5.000000 5.000000 0.000000 -v -5.000000 -5.000000 0.000000 +v 15.000000 -15.000000 0.000000 +v 15.000000 15.000000 0.000000 +v -15.000000 15.000000 0.000000 +v -15.000000 -15.000000 0.000000 -vt 5.000000 0.000000 -vt 5.000000 5.000000 -vt 0.000000 5.000000 +vt 15.000000 0.000000 +vt 15.000000 15.000000 +vt 0.000000 15.000000 vt 0.000000 0.000000 usemtl Material diff --git a/data/plane.urdf b/data/plane.urdf index b2c2d7659..480b0752f 100644 --- a/data/plane.urdf +++ b/data/plane.urdf @@ -1,6 +1,9 @@ + + + @@ -16,9 +19,9 @@ - + - + diff --git a/data/quadruped/quadruped.urdf b/data/quadruped/quadruped.urdf new file mode 100644 index 000000000..32e9c131c --- /dev/null +++ b/data/quadruped/quadruped.urdf @@ -0,0 +1,712 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/data/torus/plane_only.mtl b/data/torus/plane_only.mtl new file mode 100644 index 000000000..70d3ba1da --- /dev/null +++ b/data/torus/plane_only.mtl @@ -0,0 +1,10 @@ +# Blender MTL File: 'None' +# Material Count: 1 + +newmtl None +Ns 0 +Ka 0.000000 0.000000 0.000000 +Kd 0.8 0.8 0.8 +Ks 0.8 0.8 0.8 +d 1 +illum 2 diff --git a/data/torus/plane_only.obj b/data/torus/plane_only.obj new file mode 100644 index 000000000..893742a69 --- /dev/null +++ b/data/torus/plane_only.obj @@ -0,0 +1,7913 @@ +# Blender v2.77 (sub 0) OBJ File: '' +# www.blender.org +mtllib plane_only.mtl +o Plane +v -2.312398 -6.126618 0.566384 +v 6.032325 -2.575601 0.280679 +v -5.874205 2.203907 0.074895 +v 2.470518 5.754926 -0.210810 +v -5.804365 2.040563 0.084532 +v -5.734526 1.877220 0.094169 +v -5.664686 1.713876 0.103806 +v -5.594847 1.550532 0.113443 +v -5.525007 1.387189 0.123080 +v -5.455168 1.223845 0.132717 +v -5.385328 1.060502 0.142354 +v -5.315490 0.897157 0.151991 +v -5.245650 0.733814 0.161628 +v -5.175811 0.570470 0.171265 +v -5.105971 0.407127 0.180902 +v -5.036132 0.243783 0.190539 +v -4.966292 0.080439 0.200176 +v -4.896453 -0.082904 0.209813 +v -4.826613 -0.246248 0.219450 +v -4.756775 -0.409592 0.229087 +v -4.686935 -0.572935 0.238724 +v -4.617096 -0.736279 0.248362 +v -4.547256 -0.899623 0.257998 +v -4.477417 -1.062966 0.267636 +v -4.407578 -1.226310 0.277273 +v -4.337738 -1.389654 0.286910 +v -4.267900 -1.552997 0.296547 +v -4.198060 -1.716341 0.306184 +v -4.128221 -1.879685 0.315821 +v -4.058381 -2.043028 0.325458 +v -3.988542 -2.206372 0.335095 +v -3.918703 -2.369716 0.344732 +v -3.848863 -2.533059 0.354369 +v -3.779024 -2.696403 0.364006 +v -3.709185 -2.859747 0.373643 +v -3.639345 -3.023091 0.383280 +v -3.569506 -3.186434 0.392917 +v -3.499667 -3.349777 0.402554 +v -3.429827 -3.513121 0.412191 +v -3.359988 -3.676465 0.421829 +v -3.290149 -3.839808 0.431465 +v -3.220309 -4.003152 0.441103 +v -3.150470 -4.166496 0.450740 +v -3.080631 -4.329839 0.460377 +v -3.010791 -4.493183 0.470014 +v -2.940952 -4.656527 0.479651 +v -2.871112 -4.819870 0.489288 +v -2.801273 -4.983214 0.498925 +v -2.731434 -5.146557 0.508562 +v -2.661594 -5.309901 0.518199 +v -2.591755 -5.473244 0.527836 +v -2.521916 -5.636589 0.537473 +v -2.452076 -5.799932 0.547110 +v -2.382237 -5.963276 0.556747 +v -2.148776 -6.056991 0.560782 +v -1.985154 -5.987363 0.555180 +v -1.821532 -5.917735 0.549578 +v -1.657910 -5.848107 0.543976 +v -1.494288 -5.778480 0.538374 +v -1.330665 -5.708852 0.532772 +v -1.167043 -5.639224 0.527170 +v -1.003422 -5.569596 0.521568 +v -0.839799 -5.499969 0.515965 +v -0.676177 -5.430341 0.510363 +v -0.512555 -5.360713 0.504761 +v -0.348933 -5.291085 0.499159 +v -0.185311 -5.221457 0.493557 +v -0.021689 -5.151829 0.487955 +v 0.141933 -5.082201 0.482353 +v 0.305555 -5.012573 0.476751 +v 0.469177 -4.942945 0.471149 +v 0.632799 -4.873318 0.465547 +v 0.796421 -4.803690 0.459945 +v 0.960043 -4.734062 0.454343 +v 1.123665 -4.664434 0.448741 +v 1.287287 -4.594807 0.443139 +v 1.450909 -4.525179 0.437537 +v 1.614531 -4.455551 0.431935 +v 1.778153 -4.385922 0.426333 +v 1.941775 -4.316295 0.420731 +v 2.105397 -4.246667 0.415129 +v 2.269019 -4.177039 0.409527 +v 2.432641 -4.107412 0.403924 +v 2.596263 -4.037785 0.398322 +v 2.759885 -3.968157 0.392720 +v 2.923507 -3.898529 0.387118 +v 3.087129 -3.828902 0.381516 +v 3.250751 -3.759273 0.375914 +v 3.414372 -3.689645 0.370312 +v 3.577994 -3.620018 0.364710 +v 3.741616 -3.550390 0.359108 +v 3.905239 -3.480762 0.353506 +v 4.068861 -3.411134 0.347904 +v 4.232483 -3.341506 0.342302 +v 4.396105 -3.271878 0.336700 +v 4.559727 -3.202251 0.331098 +v 4.723349 -3.132623 0.325496 +v 4.886971 -3.062995 0.319894 +v 5.050592 -2.993367 0.314292 +v 5.214214 -2.923740 0.308690 +v 5.377837 -2.854112 0.303087 +v 5.541458 -2.784484 0.297485 +v 5.705081 -2.714856 0.291883 +v 5.868702 -2.645229 0.286281 +v 5.962485 -2.412257 0.271042 +v 5.892646 -2.248913 0.261405 +v 5.822806 -2.085569 0.251768 +v 5.752967 -1.922226 0.242131 +v 5.683127 -1.758882 0.232494 +v 5.613288 -1.595538 0.222857 +v 5.543449 -1.432195 0.213220 +v 5.473610 -1.268851 0.203583 +v 5.403770 -1.105507 0.193946 +v 5.333931 -0.942164 0.184309 +v 5.264091 -0.778820 0.174672 +v 5.194252 -0.615476 0.165035 +v 5.124413 -0.452132 0.155398 +v 5.054573 -0.288789 0.145761 +v 4.984735 -0.125445 0.136124 +v 4.914895 0.037898 0.126487 +v 4.845056 0.201242 0.116849 +v 4.775216 0.364586 0.107213 +v 4.705377 0.527929 0.097575 +v 4.635537 0.691273 0.087938 +v 4.565698 0.854617 0.078301 +v 4.495859 1.017960 0.068664 +v 4.426020 1.181304 0.059027 +v 4.356180 1.344648 0.049390 +v 4.286341 1.507991 0.039753 +v 4.216501 1.671335 0.030116 +v 4.146662 1.834678 0.020479 +v 4.076822 1.998022 0.010842 +v 4.006983 2.161365 0.001205 +v 3.937144 2.324709 -0.008432 +v 3.867305 2.488053 -0.018069 +v 3.797465 2.651397 -0.027706 +v 3.727626 2.814740 -0.037343 +v 3.657787 2.978083 -0.046980 +v 3.587947 3.141428 -0.056617 +v 3.518108 3.304771 -0.066254 +v 3.448268 3.468114 -0.075891 +v 3.378429 3.631458 -0.085528 +v 3.308590 3.794802 -0.095165 +v 3.238750 3.958145 -0.104803 +v 3.168911 4.121490 -0.114440 +v 3.099072 4.284833 -0.124077 +v 3.029233 4.448177 -0.133714 +v 2.959393 4.611520 -0.143351 +v 2.889554 4.774864 -0.152988 +v 2.819715 4.938208 -0.162625 +v 2.749875 5.101552 -0.172262 +v 2.680036 5.264896 -0.181899 +v 2.610196 5.428238 -0.191536 +v 2.540357 5.591582 -0.201173 +v 2.306895 5.685298 -0.205208 +v 2.143273 5.615670 -0.199606 +v 1.979651 5.546042 -0.194004 +v 1.816030 5.476415 -0.188402 +v 1.652407 5.406787 -0.182800 +v 1.488786 5.337159 -0.177198 +v 1.325163 5.267531 -0.171596 +v 1.161541 5.197904 -0.165994 +v 0.997919 5.128276 -0.160392 +v 0.834297 5.058648 -0.154789 +v 0.670675 4.989020 -0.149187 +v 0.507053 4.919393 -0.143585 +v 0.343431 4.849765 -0.137983 +v 0.179809 4.780137 -0.132381 +v 0.016187 4.710509 -0.126779 +v -0.147435 4.640882 -0.121177 +v -0.311057 4.571253 -0.115575 +v -0.474679 4.501625 -0.109973 +v -0.638301 4.431997 -0.104371 +v -0.801923 4.362370 -0.098769 +v -0.965545 4.292742 -0.093167 +v -1.129167 4.223114 -0.087565 +v -1.292789 4.153486 -0.081963 +v -1.456411 4.083858 -0.076361 +v -1.620033 4.014231 -0.070759 +v -1.783655 3.944603 -0.065157 +v -1.947277 3.874975 -0.059554 +v -2.110899 3.805346 -0.053952 +v -2.274521 3.735718 -0.048350 +v -2.438143 3.666091 -0.042748 +v -2.601765 3.596463 -0.037146 +v -2.765387 3.526835 -0.031544 +v -2.929009 3.457207 -0.025942 +v -3.092631 3.387580 -0.020340 +v -3.256253 3.317952 -0.014738 +v -3.419875 3.248324 -0.009136 +v -3.583497 3.178696 -0.003534 +v -3.747118 3.109069 0.002068 +v -3.910740 3.039441 0.007670 +v -4.074363 2.969813 0.013272 +v -4.237985 2.900185 0.018874 +v -4.401607 2.830558 0.024476 +v -4.565228 2.760930 0.030078 +v -4.728850 2.691302 0.035680 +v -4.892472 2.621674 0.041282 +v -5.056094 2.552047 0.046885 +v -5.219716 2.482419 0.052487 +v -5.383339 2.412791 0.058089 +v -5.546961 2.343162 0.063691 +v -5.710583 2.273535 0.069293 +v -5.640743 2.110191 0.078930 +v -5.407282 2.016475 0.082965 +v -5.173820 1.922760 0.087000 +v -4.940358 1.829044 0.091035 +v -4.706897 1.735328 0.095070 +v -4.473435 1.641612 0.099105 +v -4.239974 1.547897 0.103140 +v -4.006513 1.454180 0.107175 +v -3.773051 1.360465 0.111210 +v -3.539590 1.266749 0.115245 +v -3.306129 1.173033 0.119280 +v -3.072667 1.079317 0.123315 +v -2.839206 0.985601 0.127350 +v -2.605745 0.891885 0.131385 +v -2.372283 0.798169 0.135420 +v -2.138822 0.704454 0.139455 +v -1.905361 0.610738 0.143490 +v -1.671899 0.517022 0.147525 +v -1.438438 0.423306 0.151560 +v -1.204977 0.329590 0.155595 +v -0.971515 0.235874 0.159630 +v -0.738054 0.142159 0.163665 +v -0.504593 0.048443 0.167700 +v -0.271131 -0.045273 0.171735 +v -0.037670 -0.138989 0.175770 +v 0.195791 -0.232705 0.179805 +v 0.429253 -0.326421 0.183840 +v 0.662714 -0.420136 0.187875 +v 0.896175 -0.513852 0.191910 +v 1.129637 -0.607568 0.195945 +v 1.363098 -0.701284 0.199980 +v 1.596559 -0.795000 0.204015 +v 1.830021 -0.888716 0.208049 +v 2.063482 -0.982431 0.212084 +v 2.296943 -1.076147 0.216119 +v 2.530405 -1.169863 0.220154 +v 2.763866 -1.263579 0.224189 +v 2.997327 -1.357295 0.228224 +v 3.230788 -1.451011 0.232259 +v 3.464250 -1.544726 0.236294 +v 3.697711 -1.638442 0.240329 +v 3.931173 -1.732158 0.244364 +v 4.164635 -1.825874 0.248399 +v 4.398096 -1.919590 0.252434 +v 4.631557 -2.013306 0.256469 +v 4.865018 -2.107021 0.260504 +v 5.098479 -2.200737 0.264539 +v 5.331941 -2.294453 0.268574 +v 5.565402 -2.388169 0.272609 +v 5.798862 -2.481885 0.276644 +v -5.477121 2.179819 0.073328 +v -5.243659 2.086103 0.077363 +v -5.313498 2.249447 0.067726 +v -5.010198 1.992388 0.081398 +v -5.080037 2.155731 0.071761 +v -5.149877 2.319074 0.062124 +v -4.776736 1.898672 0.085433 +v -4.846576 2.062015 0.075796 +v -4.916415 2.225359 0.066159 +v -4.986255 2.388702 0.056522 +v -4.543275 1.804956 0.089468 +v -4.613114 1.968299 0.079831 +v -4.682954 2.131643 0.070194 +v -4.752793 2.294986 0.060557 +v -4.822633 2.458330 0.050920 +v -4.309813 1.711240 0.093503 +v -4.379653 1.874583 0.083866 +v -4.449492 2.037927 0.074229 +v -4.519332 2.201271 0.064592 +v -4.589171 2.364614 0.054955 +v -4.659011 2.527958 0.045318 +v -4.076352 1.617524 0.097538 +v -4.146192 1.780868 0.087901 +v -4.216031 1.944211 0.078264 +v -4.285871 2.107555 0.068627 +v -4.355710 2.270899 0.058990 +v -4.425550 2.434242 0.049352 +v -4.495389 2.597585 0.039715 +v -3.842891 1.523808 0.101573 +v -3.912730 1.687152 0.091936 +v -3.982570 1.850495 0.082299 +v -4.052409 2.013839 0.072662 +v -4.122249 2.177183 0.063025 +v -4.192088 2.340526 0.053387 +v -4.261928 2.503870 0.043751 +v -4.331767 2.667213 0.034113 +v -3.609429 1.430092 0.105608 +v -3.679269 1.593436 0.095971 +v -3.749108 1.756780 0.086334 +v -3.818948 1.920124 0.076697 +v -3.888787 2.083467 0.067060 +v -3.958627 2.246810 0.057422 +v -4.028465 2.410154 0.047786 +v -4.098306 2.573498 0.038148 +v -4.168145 2.736841 0.028511 +v -3.375968 1.336377 0.109643 +v -3.445807 1.499720 0.100006 +v -3.515647 1.663064 0.090369 +v -3.585486 1.826408 0.080732 +v -3.655326 1.989751 0.071095 +v -3.725165 2.153095 0.061457 +v -3.795005 2.316438 0.051821 +v -3.864844 2.479782 0.042183 +v -3.934684 2.643125 0.032546 +v -4.004523 2.806469 0.022909 +v -3.142507 1.242661 0.113678 +v -3.212346 1.406005 0.104041 +v -3.282185 1.569348 0.094404 +v -3.352025 1.732692 0.084767 +v -3.421864 1.896036 0.075130 +v -3.491704 2.059379 0.065492 +v -3.561543 2.222723 0.055856 +v -3.631382 2.386066 0.046218 +v -3.701222 2.549410 0.036581 +v -3.771061 2.712753 0.026944 +v -3.840901 2.876097 0.017307 +v -2.909045 1.148945 0.117713 +v -2.978885 1.312288 0.108076 +v -3.048724 1.475632 0.098439 +v -3.118563 1.638976 0.088801 +v -3.188403 1.802320 0.079165 +v -3.258242 1.965663 0.069527 +v -3.328082 2.129007 0.059891 +v -3.397921 2.292350 0.050253 +v -3.467761 2.455694 0.040616 +v -3.537600 2.619037 0.030979 +v -3.607439 2.782381 0.021342 +v -3.677279 2.945725 0.011705 +v -2.675584 1.055229 0.121748 +v -2.745423 1.218573 0.112111 +v -2.815263 1.381916 0.102473 +v -2.885102 1.545260 0.092836 +v -2.954941 1.708604 0.083200 +v -3.024781 1.871947 0.073562 +v -3.094620 2.035291 0.063925 +v -3.164460 2.198635 0.054288 +v -3.234299 2.361978 0.044651 +v -3.304139 2.525321 0.035014 +v -3.373978 2.688665 0.025377 +v -3.443818 2.852009 0.015740 +v -3.513657 3.015353 0.006103 +v -2.442123 0.961513 0.125782 +v -2.511962 1.124857 0.116146 +v -2.581802 1.288201 0.106508 +v -2.651641 1.451544 0.096871 +v -2.721480 1.614888 0.087234 +v -2.791320 1.778232 0.077597 +v -2.861159 1.941575 0.067960 +v -2.930999 2.104919 0.058323 +v -3.000838 2.268262 0.048686 +v -3.070677 2.431606 0.039049 +v -3.140517 2.594950 0.029412 +v -3.210356 2.758293 0.019775 +v -3.280196 2.921637 0.010138 +v -3.350035 3.084981 0.000501 +v -2.208661 0.867797 0.129817 +v -2.278501 1.031141 0.120181 +v -2.348340 1.194485 0.110543 +v -2.418180 1.357828 0.100906 +v -2.488019 1.521172 0.091269 +v -2.557858 1.684516 0.081632 +v -2.627698 1.847859 0.071995 +v -2.697537 2.011203 0.062358 +v -2.767377 2.174546 0.052721 +v -2.837216 2.337890 0.043084 +v -2.907056 2.501234 0.033447 +v -2.976895 2.664578 0.023810 +v -3.046734 2.827921 0.014173 +v -3.116574 2.991265 0.004536 +v -3.186413 3.154608 -0.005101 +v -1.975200 0.774081 0.133852 +v -2.045039 0.937425 0.124216 +v -2.114879 1.100769 0.114578 +v -2.184718 1.264112 0.104941 +v -2.254558 1.427456 0.095304 +v -2.324397 1.590800 0.085667 +v -2.394237 1.754144 0.076030 +v -2.464076 1.917487 0.066393 +v -2.533916 2.080831 0.056756 +v -2.603755 2.244174 0.047119 +v -2.673594 2.407518 0.037482 +v -2.743433 2.570862 0.027845 +v -2.813273 2.734205 0.018208 +v -2.883112 2.897548 0.008571 +v -2.952952 3.060892 -0.001066 +v -3.022791 3.224236 -0.010703 +v -1.741739 0.680366 0.137887 +v -1.811578 0.843709 0.128251 +v -1.881418 1.007053 0.118613 +v -1.951257 1.170397 0.108976 +v -2.021096 1.333740 0.099339 +v -2.090936 1.497084 0.089702 +v -2.160775 1.660428 0.080065 +v -2.230615 1.823772 0.070428 +v -2.300454 1.987115 0.060791 +v -2.370294 2.150458 0.051154 +v -2.440133 2.313802 0.041517 +v -2.509972 2.477146 0.031880 +v -2.579812 2.640490 0.022243 +v -2.649651 2.803833 0.012606 +v -2.719491 2.967177 0.002969 +v -2.789330 3.130521 -0.006668 +v -2.859169 3.293864 -0.016305 +v -1.508277 0.586650 0.141922 +v -1.578117 0.749993 0.132286 +v -1.647956 0.913337 0.122648 +v -1.717796 1.076681 0.113011 +v -1.787635 1.240025 0.103374 +v -1.857474 1.403368 0.093737 +v -1.927314 1.566712 0.084100 +v -1.997153 1.730055 0.074463 +v -2.066993 1.893399 0.064826 +v -2.136832 2.056743 0.055189 +v -2.206672 2.220086 0.045552 +v -2.276511 2.383430 0.035915 +v -2.346350 2.546774 0.026278 +v -2.416190 2.710117 0.016641 +v -2.486029 2.873461 0.007004 +v -2.555869 3.036804 -0.002633 +v -2.625708 3.200148 -0.012270 +v -2.695547 3.363492 -0.021907 +v -1.274816 0.492934 0.145957 +v -1.344656 0.656278 0.136321 +v -1.414495 0.819621 0.126683 +v -1.484334 0.982965 0.117046 +v -1.554174 1.146308 0.107409 +v -1.624013 1.309652 0.097772 +v -1.693853 1.472996 0.088135 +v -1.763692 1.636340 0.078498 +v -1.833531 1.799683 0.068861 +v -1.903371 1.963027 0.059224 +v -1.973210 2.126370 0.049587 +v -2.043050 2.289714 0.039950 +v -2.112889 2.453058 0.030313 +v -2.182729 2.616402 0.020676 +v -2.252568 2.779745 0.011039 +v -2.322407 2.943089 0.001402 +v -2.392247 3.106432 -0.008235 +v -2.462086 3.269776 -0.017872 +v -2.531925 3.433120 -0.027509 +v -1.041355 0.399218 0.149992 +v -1.111194 0.562562 0.140356 +v -1.181034 0.725905 0.130718 +v -1.250873 0.889249 0.121081 +v -1.320712 1.052593 0.111444 +v -1.390552 1.215936 0.101807 +v -1.460391 1.379280 0.092170 +v -1.530231 1.542624 0.082533 +v -1.600070 1.705968 0.072896 +v -1.669910 1.869311 0.063259 +v -1.739749 2.032655 0.053622 +v -1.809589 2.195998 0.043985 +v -1.879428 2.359342 0.034348 +v -1.949267 2.522686 0.024711 +v -2.019107 2.686029 0.015074 +v -2.088946 2.849373 0.005437 +v -2.158785 3.012717 -0.004200 +v -2.228625 3.176060 -0.013837 +v -2.298464 3.339404 -0.023474 +v -2.368304 3.502747 -0.033111 +v -0.807893 0.305502 0.154027 +v -0.877733 0.468846 0.144391 +v -0.947572 0.632190 0.134753 +v -1.017412 0.795533 0.125116 +v -1.087251 0.958877 0.115479 +v -1.157091 1.122221 0.105842 +v -1.226930 1.285564 0.096205 +v -1.296769 1.448908 0.086568 +v -1.366609 1.612251 0.076931 +v -1.436448 1.775595 0.067294 +v -1.506288 1.938939 0.057657 +v -1.576127 2.102283 0.048020 +v -1.645967 2.265626 0.038383 +v -1.715806 2.428969 0.028746 +v -1.785645 2.592313 0.019109 +v -1.855485 2.755657 0.009472 +v -1.925324 2.919001 -0.000165 +v -1.995163 3.082345 -0.009802 +v -2.065003 3.245688 -0.019439 +v -2.134842 3.409032 -0.029076 +v -2.204681 3.572375 -0.038713 +v -0.574432 0.211786 0.158062 +v -0.644271 0.375130 0.148426 +v -0.714111 0.538474 0.138788 +v -0.783950 0.701817 0.129151 +v -0.853790 0.865161 0.119514 +v -0.923629 1.028505 0.109877 +v -0.993469 1.191848 0.100240 +v -1.063308 1.355192 0.090603 +v -1.133147 1.518536 0.080966 +v -1.202987 1.681879 0.071329 +v -1.272826 1.845223 0.061692 +v -1.342666 2.008567 0.052055 +v -1.412505 2.171911 0.042418 +v -1.482344 2.335254 0.032781 +v -1.552184 2.498598 0.023144 +v -1.622023 2.661941 0.013507 +v -1.691863 2.825285 0.003870 +v -1.761702 2.988628 -0.005767 +v -1.831541 3.151972 -0.015404 +v -1.901381 3.315316 -0.025041 +v -1.971220 3.478660 -0.034678 +v -2.041059 3.642003 -0.044315 +v -0.340971 0.118071 0.162097 +v -0.410810 0.281414 0.152461 +v -0.480650 0.444758 0.142823 +v -0.550489 0.608102 0.133186 +v -0.620328 0.771445 0.123549 +v -0.690168 0.934789 0.113912 +v -0.760007 1.098133 0.104275 +v -0.829847 1.261476 0.094638 +v -0.899686 1.424820 0.085001 +v -0.969525 1.588164 0.075364 +v -1.039365 1.751507 0.065727 +v -1.109204 1.914851 0.056090 +v -1.179044 2.078194 0.046453 +v -1.248883 2.241538 0.036816 +v -1.318722 2.404882 0.027179 +v -1.388562 2.568226 0.017542 +v -1.458401 2.731569 0.007905 +v -1.528241 2.894913 -0.001732 +v -1.598080 3.058257 -0.011369 +v -1.667919 3.221600 -0.021006 +v -1.737759 3.384944 -0.030643 +v -1.807598 3.548288 -0.040280 +v -1.877437 3.711631 -0.049917 +v -0.107509 0.024355 0.166132 +v -0.177349 0.187698 0.156495 +v -0.247188 0.351042 0.146858 +v -0.317028 0.514386 0.137221 +v -0.386867 0.677729 0.127584 +v -0.456706 0.841073 0.117947 +v -0.526546 1.004417 0.108310 +v -0.596385 1.167760 0.098673 +v -0.666225 1.331104 0.089036 +v -0.736064 1.494448 0.079399 +v -0.805903 1.657791 0.069762 +v -0.875743 1.821135 0.060125 +v -0.945582 1.984479 0.050488 +v -1.015422 2.147822 0.040851 +v -1.085261 2.311166 0.031214 +v -1.155100 2.474510 0.021577 +v -1.224940 2.637853 0.011940 +v -1.294779 2.801197 0.002303 +v -1.364619 2.964541 -0.007334 +v -1.434458 3.127884 -0.016971 +v -1.504297 3.291228 -0.026608 +v -1.574137 3.454572 -0.036245 +v -1.643976 3.617915 -0.045882 +v -1.713815 3.781258 -0.055519 +v 0.125952 -0.069361 0.170167 +v 0.056113 0.093983 0.160530 +v -0.013727 0.257326 0.150893 +v -0.083566 0.420670 0.141256 +v -0.153406 0.584014 0.131619 +v -0.223245 0.747357 0.121982 +v -0.293084 0.910701 0.112345 +v -0.362924 1.074044 0.102708 +v -0.432763 1.237388 0.093071 +v -0.502603 1.400732 0.083434 +v -0.572442 1.564076 0.073797 +v -0.642281 1.727419 0.064160 +v -0.712121 1.890763 0.054523 +v -0.781960 2.054106 0.044886 +v -0.851800 2.217450 0.035249 +v -0.921639 2.380794 0.025612 +v -0.991478 2.544138 0.015975 +v -1.061318 2.707481 0.006338 +v -1.131157 2.870825 -0.003299 +v -1.200997 3.034168 -0.012936 +v -1.270836 3.197512 -0.022573 +v -1.340675 3.360856 -0.032210 +v -1.410515 3.524200 -0.041847 +v -1.480354 3.687543 -0.051485 +v -1.550194 3.850887 -0.061122 +v 0.359413 -0.163077 0.174202 +v 0.289574 0.000267 0.164565 +v 0.219735 0.163610 0.154928 +v 0.149895 0.326954 0.145291 +v 0.080056 0.490298 0.135654 +v 0.010216 0.653641 0.126017 +v -0.059623 0.816985 0.116380 +v -0.129462 0.980329 0.106743 +v -0.199302 1.143672 0.097106 +v -0.269141 1.307016 0.087469 +v -0.338981 1.470360 0.077832 +v -0.408820 1.633703 0.068195 +v -0.478659 1.797047 0.058558 +v -0.548499 1.960391 0.048921 +v -0.618338 2.123734 0.039284 +v -0.688178 2.287078 0.029647 +v -0.758017 2.450422 0.020010 +v -0.827856 2.613765 0.010373 +v -0.897696 2.777109 0.000736 +v -0.967535 2.940452 -0.008901 +v -1.037375 3.103796 -0.018538 +v -1.107214 3.267140 -0.028175 +v -1.177053 3.430484 -0.037812 +v -1.246893 3.593827 -0.047450 +v -1.316732 3.757171 -0.057087 +v -1.386572 3.920515 -0.066724 +v 0.592875 -0.256793 0.178237 +v 0.523035 -0.093449 0.168600 +v 0.453196 0.069894 0.158963 +v 0.383356 0.233238 0.149326 +v 0.313517 0.396582 0.139689 +v 0.243678 0.559926 0.130052 +v 0.173838 0.723269 0.120415 +v 0.103999 0.886613 0.110778 +v 0.034160 1.049956 0.101141 +v -0.035680 1.213300 0.091504 +v -0.105519 1.376644 0.081867 +v -0.175359 1.539987 0.072230 +v -0.245198 1.703331 0.062593 +v -0.315037 1.866675 0.052956 +v -0.384877 2.030019 0.043319 +v -0.454716 2.193362 0.033682 +v -0.524556 2.356706 0.024045 +v -0.594395 2.520050 0.014408 +v -0.664234 2.683393 0.004771 +v -0.734074 2.846737 -0.004866 +v -0.803913 3.010080 -0.014503 +v -0.873753 3.173424 -0.024140 +v -0.943592 3.336768 -0.033778 +v -1.013431 3.500112 -0.043415 +v -1.083271 3.663455 -0.053052 +v -1.153110 3.826799 -0.062689 +v -1.222950 3.990143 -0.072326 +v 0.826336 -0.350509 0.182272 +v 0.756497 -0.187165 0.172635 +v 0.686657 -0.023821 0.162998 +v 0.616818 0.139522 0.153361 +v 0.546978 0.302866 0.143724 +v 0.477139 0.466210 0.134087 +v 0.407299 0.629553 0.124450 +v 0.337460 0.792897 0.114813 +v 0.267621 0.956241 0.105176 +v 0.197781 1.119584 0.095539 +v 0.127942 1.282928 0.085902 +v 0.058103 1.446272 0.076265 +v -0.011737 1.609615 0.066628 +v -0.081576 1.772959 0.056991 +v -0.151416 1.936302 0.047354 +v -0.221255 2.099646 0.037717 +v -0.291094 2.262990 0.028080 +v -0.360934 2.426333 0.018443 +v -0.430773 2.589677 0.008806 +v -0.500613 2.753021 -0.000831 +v -0.570452 2.916364 -0.010468 +v -0.640291 3.079708 -0.020105 +v -0.710131 3.243052 -0.029743 +v -0.779970 3.406395 -0.039380 +v -0.849809 3.569739 -0.049017 +v -0.919649 3.733083 -0.058654 +v -0.989488 3.896427 -0.068291 +v -1.059328 4.059771 -0.077928 +v 1.059797 -0.444224 0.186307 +v 0.989958 -0.280881 0.176670 +v 0.920118 -0.117537 0.167033 +v 0.850279 0.045806 0.157396 +v 0.780440 0.209150 0.147759 +v 0.710600 0.372494 0.138122 +v 0.640761 0.535838 0.128485 +v 0.570921 0.699181 0.118848 +v 0.501082 0.862525 0.109211 +v 0.431243 1.025868 0.099574 +v 0.361403 1.189212 0.089937 +v 0.291564 1.352556 0.080300 +v 0.221724 1.515899 0.070663 +v 0.151885 1.679243 0.061026 +v 0.082046 1.842587 0.051389 +v 0.012206 2.005930 0.041752 +v -0.057633 2.169274 0.032115 +v -0.127473 2.332618 0.022478 +v -0.197312 2.495961 0.012841 +v -0.267151 2.659305 0.003203 +v -0.336991 2.822649 -0.006433 +v -0.406830 2.985992 -0.016070 +v -0.476670 3.149336 -0.025708 +v -0.546509 3.312680 -0.035345 +v -0.616348 3.476023 -0.044982 +v -0.686188 3.639367 -0.054619 +v -0.756027 3.802711 -0.064256 +v -0.825866 3.966055 -0.073893 +v -0.895706 4.129398 -0.083530 +v 1.293259 -0.537940 0.190342 +v 1.223419 -0.374597 0.180705 +v 1.153580 -0.211253 0.171068 +v 1.083740 -0.047909 0.161431 +v 1.013901 0.115434 0.151794 +v 0.944062 0.278778 0.142157 +v 0.874222 0.442122 0.132520 +v 0.804383 0.605465 0.122883 +v 0.734543 0.768809 0.113246 +v 0.664704 0.932153 0.103609 +v 0.594865 1.095496 0.093972 +v 0.525025 1.258840 0.084335 +v 0.455186 1.422184 0.074698 +v 0.385347 1.585527 0.065061 +v 0.315507 1.748871 0.055424 +v 0.245668 1.912214 0.045787 +v 0.175828 2.075558 0.036150 +v 0.105989 2.238902 0.026513 +v 0.036150 2.402245 0.016876 +v -0.033690 2.565589 0.007238 +v -0.103529 2.728933 -0.002398 +v -0.173369 2.892277 -0.012035 +v -0.243208 3.055620 -0.021673 +v -0.313048 3.218964 -0.031310 +v -0.382887 3.382308 -0.040947 +v -0.452726 3.545651 -0.050584 +v -0.522565 3.708995 -0.060221 +v -0.592405 3.872339 -0.069858 +v -0.662244 4.035683 -0.079495 +v -0.732084 4.199026 -0.089132 +v 1.526720 -0.631656 0.194377 +v 1.456881 -0.468312 0.184740 +v 1.387041 -0.304969 0.175103 +v 1.317202 -0.141625 0.165466 +v 1.247363 0.021719 0.155829 +v 1.177523 0.185062 0.146192 +v 1.107684 0.348406 0.136555 +v 1.037845 0.511750 0.126918 +v 0.968005 0.675093 0.117281 +v 0.898166 0.838437 0.107644 +v 0.828327 1.001781 0.098007 +v 0.758487 1.165124 0.088370 +v 0.688648 1.328468 0.078733 +v 0.618808 1.491812 0.069096 +v 0.548969 1.655155 0.059459 +v 0.479130 1.818499 0.049822 +v 0.409290 1.981842 0.040185 +v 0.339451 2.145186 0.030548 +v 0.269611 2.308530 0.020911 +v 0.199772 2.471873 0.011274 +v 0.129933 2.635217 0.001636 +v 0.060093 2.798561 -0.008000 +v -0.009746 2.961904 -0.017638 +v -0.079586 3.125248 -0.027275 +v -0.149425 3.288592 -0.036912 +v -0.219265 3.451936 -0.046549 +v -0.289104 3.615279 -0.056186 +v -0.358943 3.778623 -0.065823 +v -0.428783 3.941966 -0.075460 +v -0.498622 4.105311 -0.085097 +v -0.568462 4.268654 -0.094734 +v 1.760181 -0.725372 0.198412 +v 1.690342 -0.562028 0.188775 +v 1.620502 -0.398685 0.179138 +v 1.550663 -0.235341 0.169501 +v 1.480824 -0.071997 0.159864 +v 1.410985 0.091346 0.150227 +v 1.341145 0.254690 0.140590 +v 1.271306 0.418034 0.130953 +v 1.201466 0.581377 0.121316 +v 1.131627 0.744721 0.111679 +v 1.061788 0.908065 0.102042 +v 0.991948 1.071408 0.092405 +v 0.922109 1.234752 0.082768 +v 0.852270 1.398096 0.073131 +v 0.782430 1.561439 0.063494 +v 0.712591 1.724783 0.053857 +v 0.642752 1.888126 0.044220 +v 0.572912 2.051470 0.034583 +v 0.503073 2.214814 0.024946 +v 0.433233 2.378157 0.015309 +v 0.363394 2.541501 0.005672 +v 0.293555 2.704845 -0.003965 +v 0.223715 2.868189 -0.013603 +v 0.153876 3.031532 -0.023240 +v 0.084036 3.194876 -0.032877 +v 0.014197 3.358220 -0.042514 +v -0.055643 3.521563 -0.052151 +v -0.125482 3.684907 -0.061788 +v -0.195321 3.848251 -0.071425 +v -0.265161 4.011594 -0.081062 +v -0.335000 4.174939 -0.090699 +v -0.404840 4.338282 -0.100336 +v 1.993642 -0.819088 0.202447 +v 1.923803 -0.655744 0.192810 +v 1.853964 -0.492400 0.183173 +v 1.784124 -0.329057 0.173536 +v 1.714285 -0.165713 0.163899 +v 1.644446 -0.002369 0.154262 +v 1.574606 0.160974 0.144625 +v 1.504767 0.324318 0.134988 +v 1.434928 0.487662 0.125351 +v 1.365088 0.651005 0.115714 +v 1.295249 0.814349 0.106077 +v 1.225410 0.977692 0.096440 +v 1.155570 1.141036 0.086803 +v 1.085731 1.304380 0.077166 +v 1.015892 1.467724 0.067529 +v 0.946052 1.631067 0.057892 +v 0.876213 1.794411 0.048255 +v 0.806373 1.957754 0.038618 +v 0.736534 2.121098 0.028981 +v 0.666695 2.284442 0.019344 +v 0.596855 2.447785 0.009706 +v 0.527016 2.611129 0.000069 +v 0.457176 2.774473 -0.009568 +v 0.387337 2.937817 -0.019205 +v 0.317498 3.101161 -0.028842 +v 0.247658 3.264504 -0.038479 +v 0.177819 3.427847 -0.048116 +v 0.107979 3.591191 -0.057753 +v 0.038140 3.754535 -0.067390 +v -0.031699 3.917878 -0.077027 +v -0.101539 4.081222 -0.086664 +v -0.171378 4.244566 -0.096301 +v -0.241217 4.407909 -0.105938 +v 2.227104 -0.912804 0.206482 +v 2.157264 -0.749460 0.196845 +v 2.087425 -0.586116 0.187208 +v 2.017586 -0.422773 0.177571 +v 1.947746 -0.259429 0.167934 +v 1.877907 -0.096085 0.158297 +v 1.808068 0.067258 0.148660 +v 1.738228 0.230602 0.139023 +v 1.668389 0.393946 0.129386 +v 1.598550 0.557289 0.119749 +v 1.528710 0.720633 0.110112 +v 1.458871 0.883977 0.100475 +v 1.389032 1.047320 0.090838 +v 1.319192 1.210664 0.081201 +v 1.249353 1.374008 0.071564 +v 1.179514 1.537351 0.061927 +v 1.109674 1.700695 0.052290 +v 1.039835 1.864038 0.042653 +v 0.969995 2.027382 0.033016 +v 0.900156 2.190726 0.023379 +v 0.830317 2.354070 0.013741 +v 0.760477 2.517413 0.004105 +v 0.690638 2.680757 -0.005533 +v 0.620798 2.844100 -0.015170 +v 0.550959 3.007444 -0.024807 +v 0.481119 3.170788 -0.034444 +v 0.411280 3.334132 -0.044081 +v 0.341441 3.497475 -0.053718 +v 0.271601 3.660819 -0.063355 +v 0.201762 3.824162 -0.072992 +v 0.131922 3.987506 -0.082629 +v 0.062083 4.150850 -0.092266 +v -0.007756 4.314194 -0.101903 +v -0.077596 4.477537 -0.111540 +v 2.460565 -1.006519 0.210517 +v 2.390726 -0.843176 0.200880 +v 2.320886 -0.679832 0.191243 +v 2.251047 -0.516488 0.181606 +v 2.181208 -0.353145 0.171969 +v 2.111368 -0.189801 0.162332 +v 2.041529 -0.026457 0.152695 +v 1.971690 0.136886 0.143058 +v 1.901850 0.300230 0.133421 +v 1.832011 0.463574 0.123784 +v 1.762172 0.626917 0.114147 +v 1.692332 0.790261 0.104510 +v 1.622493 0.953604 0.094873 +v 1.552653 1.116948 0.085236 +v 1.482814 1.280292 0.075599 +v 1.412975 1.443635 0.065962 +v 1.343135 1.606979 0.056325 +v 1.273296 1.770323 0.046688 +v 1.203457 1.933666 0.037051 +v 1.133617 2.097010 0.027414 +v 1.063778 2.260354 0.017776 +v 0.993939 2.423697 0.008140 +v 0.924099 2.587041 -0.001498 +v 0.854260 2.750385 -0.011135 +v 0.784420 2.913728 -0.020772 +v 0.714581 3.077072 -0.030409 +v 0.644741 3.240416 -0.040046 +v 0.574902 3.403759 -0.049683 +v 0.505063 3.567103 -0.059320 +v 0.435223 3.730447 -0.068957 +v 0.365384 3.893790 -0.078594 +v 0.295545 4.057134 -0.088231 +v 0.225705 4.220478 -0.097868 +v 0.155866 4.383822 -0.107505 +v 0.086026 4.547165 -0.117142 +v 2.694026 -1.100235 0.214552 +v 2.624187 -0.936891 0.204915 +v 2.554348 -0.773548 0.195278 +v 2.484508 -0.610204 0.185641 +v 2.414669 -0.446860 0.176004 +v 2.344830 -0.283517 0.166367 +v 2.274990 -0.120173 0.156730 +v 2.205151 0.043171 0.147093 +v 2.135312 0.206514 0.137456 +v 2.065472 0.369858 0.127819 +v 1.995633 0.533202 0.118182 +v 1.925793 0.696545 0.108545 +v 1.855954 0.859889 0.098908 +v 1.786115 1.023233 0.089271 +v 1.716275 1.186576 0.079634 +v 1.646436 1.349920 0.069997 +v 1.576597 1.513264 0.060360 +v 1.506757 1.676607 0.050723 +v 1.436918 1.839951 0.041086 +v 1.367079 2.003294 0.031449 +v 1.297239 2.166638 0.021811 +v 1.227400 2.329982 0.012175 +v 1.157561 2.493325 0.002537 +v 1.087721 2.656669 -0.007100 +v 1.017882 2.820013 -0.016737 +v 0.948043 2.983356 -0.026374 +v 0.878203 3.146700 -0.036011 +v 0.808364 3.310044 -0.045648 +v 0.738524 3.473387 -0.055285 +v 0.668685 3.636731 -0.064922 +v 0.598846 3.800074 -0.074559 +v 0.529006 3.963418 -0.084196 +v 0.459167 4.126763 -0.093833 +v 0.389327 4.290105 -0.103470 +v 0.319488 4.453450 -0.113107 +v 0.249648 4.616793 -0.122744 +v 2.927488 -1.193951 0.218587 +v 2.857649 -1.030607 0.208950 +v 2.787809 -0.867264 0.199313 +v 2.717970 -0.703920 0.189676 +v 2.648130 -0.540576 0.180039 +v 2.578291 -0.377233 0.170402 +v 2.508452 -0.213889 0.160765 +v 2.438612 -0.050545 0.151128 +v 2.368773 0.112799 0.141491 +v 2.298934 0.276142 0.131854 +v 2.229095 0.439486 0.122217 +v 2.159255 0.602829 0.112580 +v 2.089416 0.766173 0.102943 +v 2.019576 0.929517 0.093306 +v 1.949737 1.092860 0.083669 +v 1.879898 1.256204 0.074032 +v 1.810058 1.419548 0.064395 +v 1.740219 1.582891 0.054758 +v 1.670380 1.746235 0.045121 +v 1.600540 1.909578 0.035484 +v 1.530701 2.072922 0.025846 +v 1.460862 2.236266 0.016210 +v 1.391022 2.399609 0.006572 +v 1.321183 2.562953 -0.003065 +v 1.251343 2.726297 -0.012702 +v 1.181504 2.889640 -0.022339 +v 1.111665 3.052984 -0.031976 +v 1.041825 3.216328 -0.041613 +v 0.971986 3.379672 -0.051250 +v 0.902147 3.543015 -0.060887 +v 0.832307 3.706359 -0.070524 +v 0.762468 3.869703 -0.080161 +v 0.692628 4.033046 -0.089798 +v 0.622789 4.196391 -0.099435 +v 0.552949 4.359733 -0.109072 +v 0.483110 4.523077 -0.118709 +v 0.413270 4.686420 -0.128346 +v 3.160949 -1.287667 0.222622 +v 3.091110 -1.124323 0.212985 +v 3.021271 -0.960980 0.203348 +v 2.951431 -0.797636 0.193711 +v 2.881592 -0.634292 0.184074 +v 2.811752 -0.470948 0.174437 +v 2.741913 -0.307605 0.164800 +v 2.672074 -0.144261 0.155163 +v 2.602234 0.019083 0.145526 +v 2.532395 0.182426 0.135889 +v 2.462556 0.345770 0.126252 +v 2.392716 0.509114 0.116615 +v 2.322877 0.672457 0.106978 +v 2.253038 0.835801 0.097341 +v 2.183198 0.999145 0.087704 +v 2.113359 1.162488 0.078067 +v 2.043519 1.325832 0.068430 +v 1.973680 1.489176 0.058793 +v 1.903841 1.652519 0.049156 +v 1.834001 1.815863 0.039519 +v 1.764162 1.979206 0.029881 +v 1.694323 2.142550 0.020245 +v 1.624483 2.305894 0.010607 +v 1.554644 2.469237 0.000970 +v 1.484805 2.632581 -0.008667 +v 1.414965 2.795925 -0.018304 +v 1.345126 2.959268 -0.027941 +v 1.275287 3.122612 -0.037578 +v 1.205447 3.285956 -0.047215 +v 1.135608 3.449299 -0.056852 +v 1.065768 3.612643 -0.066489 +v 0.995929 3.775987 -0.076126 +v 0.926090 3.939330 -0.085763 +v 0.856250 4.102675 -0.095400 +v 0.786411 4.266018 -0.105037 +v 0.716572 4.429361 -0.114674 +v 0.646732 4.592705 -0.124311 +v 0.576893 4.756048 -0.133948 +v 3.394411 -1.381383 0.226657 +v 3.324571 -1.218039 0.217020 +v 3.254732 -1.054695 0.207383 +v 3.184893 -0.891352 0.197746 +v 3.115053 -0.728008 0.188109 +v 3.045214 -0.564664 0.178472 +v 2.975374 -0.401321 0.168835 +v 2.905535 -0.237977 0.159198 +v 2.835696 -0.074633 0.149561 +v 2.765857 0.088711 0.139924 +v 2.696017 0.252054 0.130287 +v 2.626178 0.415398 0.120650 +v 2.556339 0.578741 0.111013 +v 2.486499 0.742085 0.101376 +v 2.416660 0.905429 0.091739 +v 2.346820 1.068772 0.082102 +v 2.276981 1.232116 0.072465 +v 2.207142 1.395460 0.062828 +v 2.137302 1.558803 0.053190 +v 2.067463 1.722147 0.043554 +v 1.997624 1.885490 0.033916 +v 1.927784 2.048834 0.024279 +v 1.857945 2.212178 0.014642 +v 1.788106 2.375521 0.005005 +v 1.718266 2.538865 -0.004632 +v 1.648427 2.702209 -0.014269 +v 1.578587 2.865552 -0.023906 +v 1.508748 3.028896 -0.033543 +v 1.438909 3.192240 -0.043180 +v 1.369069 3.355584 -0.052817 +v 1.299230 3.518927 -0.062454 +v 1.229391 3.682271 -0.072091 +v 1.159551 3.845615 -0.081728 +v 1.089712 4.008958 -0.091365 +v 1.019872 4.172303 -0.101002 +v 0.950033 4.335646 -0.110639 +v 0.880193 4.498990 -0.120276 +v 0.810354 4.662333 -0.129913 +v 0.740515 4.825676 -0.139550 +v 3.627872 -1.475098 0.230692 +v 3.558033 -1.311755 0.221055 +v 3.488194 -1.148411 0.211418 +v 3.418354 -0.985067 0.201781 +v 3.348515 -0.821724 0.192144 +v 3.278676 -0.658380 0.182507 +v 3.208836 -0.495036 0.172870 +v 3.138997 -0.331693 0.163233 +v 3.069157 -0.168349 0.153596 +v 2.999318 -0.005005 0.143959 +v 2.929479 0.158338 0.134322 +v 2.859639 0.321682 0.124685 +v 2.789800 0.485026 0.115048 +v 2.719961 0.648369 0.105411 +v 2.650121 0.811713 0.095774 +v 2.580282 0.975057 0.086137 +v 2.510442 1.138400 0.076500 +v 2.440603 1.301744 0.066863 +v 2.370764 1.465088 0.057225 +v 2.300925 1.628431 0.047589 +v 2.231085 1.791775 0.037951 +v 2.161246 1.955118 0.028314 +v 2.091406 2.118462 0.018677 +v 2.021567 2.281806 0.009040 +v 1.951728 2.445150 -0.000597 +v 1.881888 2.608493 -0.010234 +v 1.812049 2.771837 -0.019871 +v 1.742210 2.935180 -0.029508 +v 1.672370 3.098524 -0.039145 +v 1.602531 3.261868 -0.048782 +v 1.532691 3.425211 -0.058419 +v 1.462852 3.588555 -0.068056 +v 1.393013 3.751899 -0.077693 +v 1.323173 3.915242 -0.087330 +v 1.253334 4.078587 -0.096967 +v 1.183494 4.241930 -0.106604 +v 1.113655 4.405274 -0.116241 +v 1.043816 4.568617 -0.125878 +v 0.973976 4.731961 -0.135515 +v 0.904137 4.895304 -0.145152 +v 3.861333 -1.568815 0.234727 +v 3.791494 -1.405471 0.225090 +v 3.721655 -1.242127 0.215453 +v 3.651815 -1.078783 0.205816 +v 3.581976 -0.915440 0.196179 +v 3.512137 -0.752096 0.186542 +v 3.442297 -0.588752 0.176905 +v 3.372458 -0.425409 0.167268 +v 3.302619 -0.262065 0.157631 +v 3.232779 -0.098721 0.147994 +v 3.162940 0.064623 0.138357 +v 3.093101 0.227966 0.128720 +v 3.023261 0.391310 0.119083 +v 2.953422 0.554654 0.109446 +v 2.883583 0.717997 0.099809 +v 2.813743 0.881341 0.090172 +v 2.743904 1.044684 0.080535 +v 2.674064 1.208028 0.070898 +v 2.604225 1.371372 0.061260 +v 2.534386 1.534715 0.051624 +v 2.464546 1.698059 0.041986 +v 2.394707 1.861402 0.032349 +v 2.324868 2.024746 0.022712 +v 2.255028 2.188090 0.013075 +v 2.185189 2.351433 0.003438 +v 2.115350 2.514777 -0.006199 +v 2.045510 2.678120 -0.015836 +v 1.975671 2.841465 -0.025473 +v 1.905831 3.004808 -0.035110 +v 1.835992 3.168152 -0.044747 +v 1.766153 3.331496 -0.054384 +v 1.696313 3.494839 -0.064021 +v 1.626474 3.658183 -0.073658 +v 1.556635 3.821527 -0.083295 +v 1.486795 3.984870 -0.092932 +v 1.416956 4.148214 -0.102569 +v 1.347116 4.311558 -0.112206 +v 1.277277 4.474902 -0.121843 +v 1.207438 4.638245 -0.131480 +v 1.137598 4.801589 -0.141117 +v 1.067759 4.964931 -0.150754 +v 4.094795 -1.662530 0.238762 +v 4.024956 -1.499186 0.229125 +v 3.955116 -1.335843 0.219488 +v 3.885277 -1.172499 0.209851 +v 3.815438 -1.009155 0.200214 +v 3.745598 -0.845812 0.190577 +v 3.675759 -0.682468 0.180940 +v 3.605919 -0.519124 0.171303 +v 3.536080 -0.355781 0.161666 +v 3.466241 -0.192437 0.152029 +v 3.396401 -0.029093 0.142392 +v 3.326562 0.134250 0.132755 +v 3.256723 0.297594 0.123118 +v 3.186883 0.460938 0.113481 +v 3.117044 0.624281 0.103844 +v 3.047205 0.787625 0.094207 +v 2.977365 0.950969 0.084570 +v 2.907526 1.114312 0.074933 +v 2.837687 1.277656 0.065295 +v 2.767847 1.440999 0.055659 +v 2.698008 1.604343 0.046021 +v 2.628169 1.767687 0.036384 +v 2.558329 1.931030 0.026747 +v 2.488490 2.094374 0.017110 +v 2.418651 2.257718 0.007473 +v 2.348811 2.421061 -0.002164 +v 2.278972 2.584405 -0.011801 +v 2.209132 2.747748 -0.021438 +v 2.139293 2.911092 -0.031075 +v 2.069454 3.074436 -0.040712 +v 1.999614 3.237780 -0.050349 +v 1.929775 3.401124 -0.059986 +v 1.859936 3.564467 -0.069623 +v 1.790096 3.727811 -0.079260 +v 1.720257 3.891155 -0.088897 +v 1.650417 4.054498 -0.098534 +v 1.580578 4.217842 -0.108171 +v 1.510738 4.381186 -0.117808 +v 1.440899 4.544529 -0.127445 +v 1.371060 4.707873 -0.137082 +v 1.301220 4.871216 -0.146720 +v 1.231381 5.034559 -0.156357 +v 4.328257 -1.756246 0.242797 +v 4.258417 -1.592903 0.233160 +v 4.188578 -1.429559 0.223523 +v 4.118738 -1.266215 0.213886 +v 4.048899 -1.102871 0.204249 +v 3.979060 -0.939528 0.194612 +v 3.909220 -0.776184 0.184975 +v 3.839381 -0.612840 0.175338 +v 3.769542 -0.449497 0.165701 +v 3.699702 -0.286153 0.156064 +v 3.629863 -0.122809 0.146427 +v 3.560024 0.040535 0.136790 +v 3.490184 0.203878 0.127153 +v 3.420345 0.367222 0.117516 +v 3.350505 0.530566 0.107879 +v 3.280666 0.693909 0.098242 +v 3.210827 0.857253 0.088605 +v 3.140987 1.020596 0.078968 +v 3.071148 1.183940 0.069330 +v 3.001309 1.347284 0.059694 +v 2.931469 1.510627 0.050056 +v 2.861630 1.673971 0.040419 +v 2.791791 1.837314 0.030782 +v 2.721951 2.000658 0.021145 +v 2.652112 2.164002 0.011508 +v 2.582273 2.327345 0.001871 +v 2.512433 2.490689 -0.007766 +v 2.442594 2.654033 -0.017403 +v 2.372755 2.817376 -0.027040 +v 2.302915 2.980720 -0.036677 +v 2.233076 3.144064 -0.046314 +v 2.163237 3.307407 -0.055951 +v 2.093397 3.470751 -0.065588 +v 2.023558 3.634095 -0.075225 +v 1.953718 3.797439 -0.084862 +v 1.883879 3.960782 -0.094499 +v 1.814040 4.124126 -0.104136 +v 1.744200 4.287470 -0.113773 +v 1.674361 4.450814 -0.123410 +v 1.604521 4.614157 -0.133048 +v 1.534682 4.777501 -0.142685 +v 1.464842 4.940844 -0.152322 +v 1.395003 5.104187 -0.161959 +v 4.561718 -1.849962 0.246832 +v 4.491879 -1.686618 0.237195 +v 4.422039 -1.523275 0.227558 +v 4.352200 -1.359931 0.217921 +v 4.282360 -1.196587 0.208284 +v 4.212521 -1.033243 0.198647 +v 4.142681 -0.869900 0.189010 +v 4.072842 -0.706556 0.179373 +v 4.003003 -0.543212 0.169736 +v 3.933163 -0.379869 0.160099 +v 3.863324 -0.216525 0.150462 +v 3.793484 -0.053181 0.140825 +v 3.723645 0.110162 0.131188 +v 3.653806 0.273506 0.121551 +v 3.583966 0.436850 0.111914 +v 3.514127 0.600194 0.102277 +v 3.444288 0.763537 0.092639 +v 3.374448 0.926881 0.083003 +v 3.304609 1.090224 0.073365 +v 3.234770 1.253568 0.063729 +v 3.164930 1.416912 0.054091 +v 3.095091 1.580255 0.044454 +v 3.025252 1.743599 0.034817 +v 2.955412 1.906943 0.025180 +v 2.885573 2.070286 0.015543 +v 2.815734 2.233629 0.005906 +v 2.745894 2.396973 -0.003731 +v 2.676055 2.560317 -0.013368 +v 2.606216 2.723661 -0.023005 +v 2.536376 2.887004 -0.032642 +v 2.466537 3.050348 -0.042279 +v 2.396698 3.213691 -0.051916 +v 2.326858 3.377035 -0.061553 +v 2.257019 3.540379 -0.071190 +v 2.187180 3.703722 -0.080827 +v 2.117340 3.867067 -0.090464 +v 2.047501 4.030410 -0.100101 +v 1.977661 4.193754 -0.109738 +v 1.907822 4.357098 -0.119375 +v 1.837982 4.520442 -0.129013 +v 1.768143 4.683785 -0.138650 +v 1.698304 4.847129 -0.148287 +v 1.628464 5.010472 -0.157924 +v 1.558625 5.173815 -0.167561 +v 4.795178 -1.943678 0.250867 +v 4.725339 -1.780334 0.241230 +v 4.655500 -1.616990 0.231593 +v 4.585661 -1.453647 0.221956 +v 4.515821 -1.290303 0.212319 +v 4.445982 -1.126959 0.202682 +v 4.376143 -0.963615 0.193045 +v 4.306303 -0.800272 0.183408 +v 4.236464 -0.636928 0.173771 +v 4.166625 -0.473584 0.164134 +v 4.096786 -0.310241 0.154497 +v 4.026946 -0.146897 0.144860 +v 3.957106 0.016446 0.135223 +v 3.887267 0.179790 0.125586 +v 3.817428 0.343134 0.115949 +v 3.747588 0.506478 0.106312 +v 3.677749 0.669821 0.096674 +v 3.607910 0.833165 0.087038 +v 3.538070 0.996508 0.077400 +v 3.468231 1.159852 0.067763 +v 3.398391 1.323196 0.058126 +v 3.328552 1.486539 0.048489 +v 3.258713 1.649883 0.038852 +v 3.188874 1.813227 0.029215 +v 3.119034 1.976570 0.019578 +v 3.049195 2.139914 0.009941 +v 2.979356 2.303257 0.000304 +v 2.909516 2.466601 -0.009333 +v 2.839677 2.629944 -0.018970 +v 2.769838 2.793288 -0.028607 +v 2.699998 2.956631 -0.038244 +v 2.630159 3.119976 -0.047881 +v 2.560319 3.283319 -0.057518 +v 2.490480 3.446663 -0.067155 +v 2.420641 3.610007 -0.076792 +v 2.350801 3.773350 -0.086429 +v 2.280962 3.936694 -0.096066 +v 2.211123 4.100038 -0.105703 +v 2.141283 4.263381 -0.115340 +v 2.071444 4.426725 -0.124978 +v 2.001605 4.590069 -0.134615 +v 1.931765 4.753413 -0.144252 +v 1.861926 4.916757 -0.153889 +v 1.792086 5.080100 -0.163526 +v 1.722247 5.243443 -0.173163 +v 5.028641 -2.037393 0.254902 +v 4.958801 -1.874050 0.245265 +v 4.888962 -1.710706 0.235628 +v 4.819122 -1.547362 0.225991 +v 4.749283 -1.384019 0.216354 +v 4.679443 -1.220675 0.206717 +v 4.609604 -1.057331 0.197080 +v 4.539764 -0.893988 0.187443 +v 4.469925 -0.730644 0.177806 +v 4.400086 -0.567300 0.168169 +v 4.330247 -0.403957 0.158532 +v 4.260407 -0.240613 0.148895 +v 4.190568 -0.077269 0.139258 +v 4.120728 0.086074 0.129621 +v 4.050889 0.249418 0.119984 +v 3.981050 0.412762 0.110347 +v 3.911211 0.576105 0.100709 +v 3.841371 0.739449 0.091073 +v 3.771532 0.902793 0.081435 +v 3.701692 1.066136 0.071798 +v 3.631853 1.229480 0.062161 +v 3.562014 1.392824 0.052524 +v 3.492174 1.556167 0.042887 +v 3.422335 1.719511 0.033250 +v 3.352496 1.882854 0.023613 +v 3.282656 2.046198 0.013976 +v 3.212817 2.209542 0.004339 +v 3.142978 2.372885 -0.005298 +v 3.073138 2.536229 -0.014935 +v 3.003299 2.699573 -0.024572 +v 2.933460 2.862916 -0.034209 +v 2.863620 3.026260 -0.043846 +v 2.793781 3.189603 -0.053483 +v 2.723942 3.352947 -0.063120 +v 2.654102 3.516291 -0.072757 +v 2.584263 3.679635 -0.082394 +v 2.514423 3.842979 -0.092031 +v 2.444584 4.006322 -0.101668 +v 2.374745 4.169666 -0.111305 +v 2.304905 4.333009 -0.120943 +v 2.235066 4.496353 -0.130580 +v 2.165227 4.659697 -0.140217 +v 2.095387 4.823040 -0.149854 +v 2.025548 4.986385 -0.159491 +v 1.955708 5.149727 -0.169128 +v 1.885869 5.313070 -0.178765 +v 5.262101 -2.131109 0.258937 +v 5.192262 -1.967766 0.249300 +v 5.122422 -1.804422 0.239663 +v 5.052583 -1.641078 0.230026 +v 4.982744 -1.477734 0.220389 +v 4.912905 -1.314391 0.210752 +v 4.843065 -1.151047 0.201115 +v 4.773226 -0.987703 0.191478 +v 4.703386 -0.824360 0.181841 +v 4.633547 -0.661016 0.172204 +v 4.563707 -0.497672 0.162567 +v 4.493869 -0.334329 0.152930 +v 4.424029 -0.170985 0.143293 +v 4.354190 -0.007642 0.133656 +v 4.284350 0.155702 0.124019 +v 4.214511 0.319046 0.114382 +v 4.144671 0.482390 0.104744 +v 4.074832 0.645733 0.095108 +v 4.004992 0.809077 0.085470 +v 3.935153 0.972420 0.075833 +v 3.865314 1.135764 0.066196 +v 3.795475 1.299108 0.056559 +v 3.725635 1.462451 0.046922 +v 3.655796 1.625795 0.037285 +v 3.585957 1.789138 0.027648 +v 3.516117 1.952482 0.018011 +v 3.446278 2.115826 0.008374 +v 3.376439 2.279169 -0.001263 +v 3.306599 2.442513 -0.010900 +v 3.236760 2.605856 -0.020537 +v 3.166921 2.769200 -0.030174 +v 3.097081 2.932544 -0.039811 +v 3.027242 3.095887 -0.049448 +v 2.957403 3.259231 -0.059085 +v 2.887563 3.422575 -0.068722 +v 2.817724 3.585918 -0.078359 +v 2.747885 3.749262 -0.087996 +v 2.678045 3.912606 -0.097633 +v 2.608206 4.075950 -0.107270 +v 2.538366 4.239294 -0.116908 +v 2.468527 4.402637 -0.126545 +v 2.398688 4.565981 -0.136182 +v 2.328848 4.729325 -0.145819 +v 2.259009 4.892668 -0.155456 +v 2.189170 5.056013 -0.165093 +v 2.119330 5.219355 -0.174730 +v 2.049491 5.382698 -0.184367 +v 5.495563 -2.224826 0.262972 +v 5.425723 -2.061481 0.253335 +v 5.355885 -1.898138 0.243698 +v 5.286045 -1.734794 0.234061 +v 5.216206 -1.571451 0.224424 +v 5.146366 -1.408107 0.214787 +v 5.076527 -1.244763 0.205150 +v 5.006687 -1.081420 0.195513 +v 4.936848 -0.918076 0.185876 +v 4.867008 -0.754732 0.176239 +v 4.797169 -0.591388 0.166602 +v 4.727330 -0.428045 0.156965 +v 4.657491 -0.264701 0.147328 +v 4.587651 -0.101357 0.137691 +v 4.517812 0.061986 0.128054 +v 4.447972 0.225330 0.118417 +v 4.378133 0.388674 0.108779 +v 4.308293 0.552017 0.099143 +v 4.238455 0.715361 0.089505 +v 4.168615 0.878705 0.079868 +v 4.098776 1.042048 0.070231 +v 4.028936 1.205392 0.060594 +v 3.959097 1.368735 0.050957 +v 3.889257 1.532079 0.041320 +v 3.819418 1.695423 0.031683 +v 3.749579 1.858766 0.022046 +v 3.679739 2.022110 0.012409 +v 3.609900 2.185454 0.002772 +v 3.540061 2.348797 -0.006865 +v 3.470222 2.512141 -0.016502 +v 3.400382 2.675484 -0.026139 +v 3.330543 2.838828 -0.035776 +v 3.260704 3.002172 -0.045413 +v 3.190864 3.165515 -0.055050 +v 3.121025 3.328859 -0.064687 +v 3.051185 3.492203 -0.074324 +v 2.981346 3.655546 -0.083961 +v 2.911507 3.818890 -0.093598 +v 2.841667 3.982234 -0.103236 +v 2.771828 4.145578 -0.112873 +v 2.701989 4.308921 -0.122510 +v 2.632149 4.472265 -0.132147 +v 2.562310 4.635609 -0.141784 +v 2.492471 4.798953 -0.151421 +v 2.422631 4.962296 -0.161058 +v 2.352792 5.125640 -0.170695 +v 2.282953 5.288983 -0.180332 +v 2.213113 5.452327 -0.189969 +v 5.729023 -2.318541 0.267007 +v 5.659184 -2.155197 0.257370 +v 5.589345 -1.991854 0.247733 +v 5.519506 -1.828510 0.238096 +v 5.449666 -1.665166 0.228459 +v 5.379827 -1.501822 0.218822 +v 5.309987 -1.338479 0.209185 +v 5.240148 -1.175135 0.199548 +v 5.170308 -1.011791 0.189911 +v 5.100470 -0.848448 0.180274 +v 5.030630 -0.685104 0.170637 +v 4.960791 -0.521760 0.161000 +v 4.890951 -0.358416 0.151363 +v 4.821112 -0.195073 0.141726 +v 4.751272 -0.031729 0.132089 +v 4.681433 0.131614 0.122452 +v 4.611594 0.294958 0.112814 +v 4.541755 0.458302 0.103178 +v 4.471915 0.621645 0.093540 +v 4.402076 0.784989 0.083903 +v 4.332236 0.948332 0.074266 +v 4.262397 1.111676 0.064629 +v 4.192557 1.275020 0.054992 +v 4.122719 1.438363 0.045355 +v 4.052879 1.601707 0.035718 +v 3.983040 1.765051 0.026081 +v 3.913200 1.928394 0.016444 +v 3.843361 2.091738 0.006807 +v 3.773521 2.255081 -0.002830 +v 3.703682 2.418425 -0.012467 +v 3.633843 2.581769 -0.022104 +v 3.564003 2.745112 -0.031741 +v 3.494164 2.908456 -0.041378 +v 3.424325 3.071799 -0.051015 +v 3.354486 3.235143 -0.060652 +v 3.284646 3.398487 -0.070289 +v 3.214807 3.561830 -0.079926 +v 3.144968 3.725174 -0.089563 +v 3.075128 3.888518 -0.099200 +v 3.005289 4.051861 -0.108838 +v 2.935449 4.215206 -0.118475 +v 2.865610 4.378549 -0.128112 +v 2.795771 4.541893 -0.137749 +v 2.725931 4.705236 -0.147386 +v 2.656092 4.868580 -0.157023 +v 2.586253 5.031924 -0.166660 +v 2.516413 5.195268 -0.176297 +v 2.446574 5.358611 -0.185934 +v 2.376735 5.521955 -0.195571 +v -2.218616 -5.893647 0.551145 +v -2.054993 -5.824019 0.545543 +v -2.288455 -5.730304 0.541508 +v -1.891371 -5.754392 0.539941 +v -2.124833 -5.660676 0.535906 +v -2.358294 -5.566959 0.531871 +v -1.727749 -5.684764 0.534339 +v -1.961210 -5.591048 0.530304 +v -2.194672 -5.497332 0.526269 +v -2.428133 -5.403617 0.522234 +v -1.564127 -5.615136 0.528737 +v -1.797588 -5.521420 0.524702 +v -2.031050 -5.427704 0.520667 +v -2.264511 -5.333989 0.516632 +v -2.497972 -5.240272 0.512597 +v -1.400505 -5.545508 0.523135 +v -1.633966 -5.451793 0.519100 +v -1.867428 -5.358076 0.515065 +v -2.100889 -5.264361 0.511030 +v -2.334351 -5.170644 0.506995 +v -2.567812 -5.076930 0.502960 +v -1.236883 -5.475881 0.517533 +v -1.470344 -5.382164 0.513498 +v -1.703806 -5.288448 0.509463 +v -1.937267 -5.194733 0.505428 +v -2.170728 -5.101017 0.501393 +v -2.404190 -5.007302 0.497358 +v -2.637651 -4.913586 0.493323 +v -1.073261 -5.406252 0.511930 +v -1.306722 -5.312536 0.507895 +v -1.540184 -5.218821 0.503860 +v -1.773645 -5.125105 0.499825 +v -2.007106 -5.031389 0.495791 +v -2.240568 -4.937673 0.491756 +v -2.474029 -4.843958 0.487721 +v -2.707490 -4.750243 0.483686 +v -0.909639 -5.336624 0.506329 +v -1.143100 -5.242908 0.502294 +v -1.376562 -5.149193 0.498259 +v -1.610023 -5.055477 0.494224 +v -1.843484 -4.961761 0.490189 +v -2.076945 -4.868045 0.486154 +v -2.310407 -4.774330 0.482119 +v -2.543869 -4.680614 0.478084 +v -2.777330 -4.586899 0.474049 +v -0.746017 -5.266996 0.500726 +v -0.979478 -5.173281 0.496691 +v -1.212940 -5.079565 0.492656 +v -1.446401 -4.985850 0.488621 +v -1.679862 -4.892134 0.484586 +v -1.913324 -4.798418 0.480551 +v -2.146785 -4.704702 0.476516 +v -2.380247 -4.610986 0.472481 +v -2.613708 -4.517271 0.468446 +v -2.847169 -4.423555 0.464411 +v -0.582395 -5.197369 0.495124 +v -0.815856 -5.103653 0.491089 +v -1.049317 -5.009937 0.487054 +v -1.282779 -4.916221 0.483019 +v -1.516240 -4.822505 0.478984 +v -1.749701 -4.728789 0.474949 +v -1.983163 -4.635074 0.470914 +v -2.216624 -4.541358 0.466880 +v -2.450086 -4.447642 0.462845 +v -2.683547 -4.353927 0.458810 +v -2.917009 -4.260211 0.454775 +v -0.418772 -5.127741 0.489522 +v -0.652234 -5.034025 0.485487 +v -0.885695 -4.940310 0.481452 +v -1.119157 -4.846593 0.477417 +v -1.352618 -4.752878 0.473382 +v -1.586080 -4.659162 0.469347 +v -1.819541 -4.565446 0.465312 +v -2.053002 -4.471730 0.461277 +v -2.286463 -4.378014 0.457242 +v -2.519925 -4.284298 0.453207 +v -2.753386 -4.190583 0.449172 +v -2.986848 -4.096868 0.445138 +v -0.255151 -5.058113 0.483920 +v -0.488612 -4.964397 0.479885 +v -0.722073 -4.870682 0.475850 +v -0.955535 -4.776966 0.471815 +v -1.188996 -4.683250 0.467780 +v -1.422458 -4.589534 0.463745 +v -1.655919 -4.495819 0.459710 +v -1.889380 -4.402102 0.455675 +v -2.122842 -4.308386 0.451640 +v -2.356303 -4.214671 0.447605 +v -2.589765 -4.120955 0.443570 +v -2.823226 -4.027239 0.439535 +v -3.056687 -3.933524 0.435500 +v -0.091529 -4.988485 0.478318 +v -0.324990 -4.894770 0.474283 +v -0.558451 -4.801054 0.470248 +v -0.791913 -4.707338 0.466213 +v -1.025374 -4.613622 0.462178 +v -1.258836 -4.519907 0.458143 +v -1.492297 -4.426191 0.454108 +v -1.725758 -4.332475 0.450073 +v -1.959220 -4.238759 0.446038 +v -2.192681 -4.145043 0.442003 +v -2.426142 -4.051328 0.437968 +v -2.659604 -3.957612 0.433933 +v -2.893065 -3.863896 0.429899 +v -3.126527 -3.770180 0.425864 +v 0.072093 -4.918858 0.472716 +v -0.161368 -4.825142 0.468681 +v -0.394830 -4.731426 0.464646 +v -0.628291 -4.637710 0.460611 +v -0.861752 -4.543994 0.456576 +v -1.095214 -4.450279 0.452541 +v -1.328675 -4.356562 0.448506 +v -1.562136 -4.262847 0.444471 +v -1.795598 -4.169131 0.440436 +v -2.029059 -4.075416 0.436401 +v -2.262521 -3.981699 0.432366 +v -2.495982 -3.887984 0.428331 +v -2.729443 -3.794269 0.424296 +v -2.962905 -3.700552 0.420261 +v -3.196366 -3.606837 0.416226 +v 0.235715 -4.849230 0.467114 +v 0.002254 -4.755514 0.463079 +v -0.231208 -4.661798 0.459044 +v -0.464669 -4.568082 0.455009 +v -0.698130 -4.474367 0.450974 +v -0.931592 -4.380651 0.446939 +v -1.165053 -4.286934 0.442904 +v -1.398514 -4.193219 0.438869 +v -1.631976 -4.099504 0.434834 +v -1.865437 -4.005788 0.430799 +v -2.098898 -3.912072 0.426764 +v -2.332360 -3.818356 0.422729 +v -2.565821 -3.724640 0.418694 +v -2.799283 -3.630925 0.414659 +v -3.032744 -3.537209 0.410624 +v -3.266205 -3.443493 0.406589 +v 0.399337 -4.779602 0.461512 +v 0.165876 -4.685886 0.457477 +v -0.067586 -4.592171 0.453442 +v -0.301047 -4.498455 0.449407 +v -0.534508 -4.404739 0.445372 +v -0.767970 -4.311023 0.441337 +v -1.001431 -4.217307 0.437302 +v -1.234892 -4.123591 0.433267 +v -1.468354 -4.029876 0.429232 +v -1.701815 -3.936160 0.425197 +v -1.935277 -3.842444 0.421162 +v -2.168738 -3.748729 0.417127 +v -2.402199 -3.655013 0.413092 +v -2.635661 -3.561297 0.409057 +v -2.869122 -3.467582 0.405022 +v -3.102583 -3.373866 0.400987 +v -3.336045 -3.280150 0.396952 +v 0.562959 -4.709974 0.455910 +v 0.329498 -4.616258 0.451875 +v 0.096036 -4.522543 0.447840 +v -0.137425 -4.428827 0.443805 +v -0.370887 -4.335111 0.439770 +v -0.604348 -4.241395 0.435735 +v -0.837809 -4.147679 0.431700 +v -1.071271 -4.053964 0.427665 +v -1.304732 -3.960248 0.423630 +v -1.538193 -3.866532 0.419595 +v -1.771655 -3.772816 0.415560 +v -2.005116 -3.679101 0.411525 +v -2.238577 -3.585385 0.407490 +v -2.472039 -3.491669 0.403455 +v -2.705500 -3.397954 0.399420 +v -2.938962 -3.304238 0.395385 +v -3.172423 -3.210522 0.391350 +v -3.405884 -3.116806 0.387315 +v 0.726581 -4.640347 0.450308 +v 0.493120 -4.546630 0.446273 +v 0.259658 -4.452915 0.442238 +v 0.026197 -4.359199 0.438203 +v -0.207264 -4.265483 0.434168 +v -0.440726 -4.171768 0.430133 +v -0.674187 -4.078052 0.426098 +v -0.907648 -3.984335 0.422063 +v -1.141110 -3.890620 0.418028 +v -1.374571 -3.796905 0.413993 +v -1.608033 -3.703188 0.409958 +v -1.841494 -3.609473 0.405923 +v -2.074955 -3.515757 0.401888 +v -2.308417 -3.422041 0.397853 +v -2.541878 -3.328326 0.393818 +v -2.775339 -3.234610 0.389783 +v -3.008801 -3.140894 0.385748 +v -3.242262 -3.047179 0.381713 +v -3.475723 -2.953463 0.377678 +v 0.890203 -4.570719 0.444706 +v 0.656742 -4.477002 0.440671 +v 0.423280 -4.383287 0.436636 +v 0.189819 -4.289571 0.432601 +v -0.043642 -4.195856 0.428566 +v -0.277104 -4.102139 0.424531 +v -0.510565 -4.008424 0.420496 +v -0.744026 -3.914708 0.416461 +v -0.977488 -3.820992 0.412426 +v -1.210949 -3.727276 0.408391 +v -1.444410 -3.633561 0.404356 +v -1.677872 -3.539845 0.400321 +v -1.911333 -3.446129 0.396286 +v -2.144794 -3.352414 0.392251 +v -2.378256 -3.258698 0.388216 +v -2.611717 -3.164982 0.384181 +v -2.845179 -3.071266 0.380146 +v -3.078640 -2.977550 0.376111 +v -3.312101 -2.883835 0.372076 +v -3.545563 -2.790119 0.368041 +v 1.053825 -4.501091 0.439104 +v 0.820364 -4.407374 0.435069 +v 0.586903 -4.313660 0.431034 +v 0.353441 -4.219944 0.426999 +v 0.119980 -4.126228 0.422964 +v -0.113482 -4.032512 0.418929 +v -0.346943 -3.938796 0.414894 +v -0.580405 -3.845080 0.410859 +v -0.813866 -3.751364 0.406824 +v -1.047327 -3.657649 0.402789 +v -1.280789 -3.563933 0.398754 +v -1.514250 -3.470217 0.394719 +v -1.747711 -3.376501 0.390684 +v -1.981173 -3.282785 0.386649 +v -2.214634 -3.189070 0.382614 +v -2.448095 -3.095354 0.378579 +v -2.681557 -3.001638 0.374544 +v -2.915018 -2.907923 0.370509 +v -3.148480 -2.814207 0.366474 +v -3.381941 -2.720491 0.362439 +v -3.615402 -2.626775 0.358404 +v 1.217447 -4.431463 0.433502 +v 0.983986 -4.337747 0.429467 +v 0.750524 -4.244032 0.425432 +v 0.517063 -4.150316 0.421397 +v 0.283602 -4.056600 0.417362 +v 0.050140 -3.962884 0.413327 +v -0.183321 -3.869168 0.409292 +v -0.416783 -3.775452 0.405257 +v -0.650244 -3.681736 0.401222 +v -0.883705 -3.588021 0.397187 +v -1.117167 -3.494305 0.393152 +v -1.350628 -3.400589 0.389117 +v -1.584089 -3.306873 0.385082 +v -1.817551 -3.213157 0.381047 +v -2.051012 -3.119442 0.377012 +v -2.284473 -3.025727 0.372977 +v -2.517935 -2.932010 0.368942 +v -2.751396 -2.838295 0.364907 +v -2.984857 -2.744579 0.360872 +v -3.218319 -2.650863 0.356837 +v -3.451780 -2.557148 0.352802 +v -3.685241 -2.463431 0.348767 +v 1.381069 -4.361835 0.427900 +v 1.147608 -4.268119 0.423865 +v 0.914147 -4.174404 0.419830 +v 0.680685 -4.080688 0.415795 +v 0.447224 -3.986972 0.411760 +v 0.213762 -3.893256 0.407725 +v -0.019699 -3.799540 0.403690 +v -0.253161 -3.705824 0.399655 +v -0.486622 -3.612109 0.395620 +v -0.720084 -3.518393 0.391585 +v -0.953545 -3.424677 0.387550 +v -1.187006 -3.330961 0.383515 +v -1.420467 -3.237246 0.379480 +v -1.653929 -3.143530 0.375445 +v -1.887390 -3.049814 0.371410 +v -2.120852 -2.956098 0.367375 +v -2.354313 -2.862382 0.363340 +v -2.587774 -2.768667 0.359305 +v -2.821235 -2.674951 0.355270 +v -3.054697 -2.581235 0.351235 +v -3.288158 -2.487519 0.347200 +v -3.521620 -2.393804 0.343165 +v -3.755081 -2.300088 0.339130 +v 1.544691 -4.292208 0.422298 +v 1.311230 -4.198491 0.418263 +v 1.077768 -4.104776 0.414228 +v 0.844307 -4.011060 0.410193 +v 0.610846 -3.917344 0.406158 +v 0.377384 -3.823628 0.402123 +v 0.143923 -3.729912 0.398088 +v -0.089539 -3.636197 0.394053 +v -0.323000 -3.542481 0.390018 +v -0.556461 -3.448765 0.385983 +v -0.789923 -3.355049 0.381948 +v -1.023384 -3.261333 0.377913 +v -1.256845 -3.167618 0.373878 +v -1.490307 -3.073902 0.369843 +v -1.723768 -2.980186 0.365808 +v -1.957229 -2.886470 0.361773 +v -2.190691 -2.792754 0.357738 +v -2.424152 -2.699039 0.353703 +v -2.657614 -2.605323 0.349668 +v -2.891075 -2.511607 0.345633 +v -3.124536 -2.417892 0.341598 +v -3.357998 -2.324176 0.337563 +v -3.591459 -2.230460 0.333528 +v -3.824920 -2.136744 0.329493 +v 1.708313 -4.222580 0.416696 +v 1.474852 -4.128863 0.412661 +v 1.241390 -4.035148 0.408626 +v 1.007929 -3.941432 0.404591 +v 0.774468 -3.847716 0.400556 +v 0.541006 -3.754000 0.396521 +v 0.307545 -3.660285 0.392486 +v 0.074084 -3.566569 0.388451 +v -0.159378 -3.472853 0.384416 +v -0.392839 -3.379137 0.380381 +v -0.626301 -3.285421 0.376346 +v -0.859762 -3.191705 0.372311 +v -1.093223 -3.097989 0.368276 +v -1.326685 -3.004274 0.364241 +v -1.560146 -2.910558 0.360206 +v -1.793607 -2.816843 0.356171 +v -2.027069 -2.723127 0.352136 +v -2.260530 -2.629411 0.348101 +v -2.493991 -2.535695 0.344066 +v -2.727453 -2.441979 0.340031 +v -2.960914 -2.348264 0.335996 +v -3.194375 -2.254548 0.331961 +v -3.427837 -2.160832 0.327926 +v -3.661298 -2.067116 0.323891 +v -3.894759 -1.973400 0.319856 +v 1.871935 -4.152952 0.411094 +v 1.638474 -4.059236 0.407059 +v 1.405012 -3.965520 0.403024 +v 1.171551 -3.871805 0.398989 +v 0.938090 -3.778089 0.394954 +v 0.704628 -3.684372 0.390919 +v 0.471167 -3.590657 0.386884 +v 0.237706 -3.496941 0.382849 +v 0.004244 -3.403225 0.378814 +v -0.229217 -3.309509 0.374779 +v -0.462679 -3.215794 0.370744 +v -0.696140 -3.122078 0.366709 +v -0.929602 -3.028362 0.362674 +v -1.163063 -2.934646 0.358639 +v -1.396524 -2.840931 0.354604 +v -1.629985 -2.747215 0.350569 +v -1.863447 -2.653499 0.346534 +v -2.096908 -2.559783 0.342499 +v -2.330369 -2.466068 0.338464 +v -2.563831 -2.372352 0.334429 +v -2.797292 -2.278636 0.330394 +v -3.030753 -2.184920 0.326359 +v -3.264215 -2.091204 0.322324 +v -3.497676 -1.997488 0.318289 +v -3.731138 -1.903773 0.314254 +v -3.964599 -1.810057 0.310219 +v 2.035557 -4.083324 0.405492 +v 1.802096 -3.989609 0.401457 +v 1.568634 -3.895892 0.397422 +v 1.335173 -3.802177 0.393387 +v 1.101712 -3.708461 0.389352 +v 0.868250 -3.614745 0.385317 +v 0.634789 -3.521029 0.381282 +v 0.401328 -3.427313 0.377247 +v 0.167866 -3.333597 0.373212 +v -0.065595 -3.239882 0.369177 +v -0.299057 -3.146165 0.365142 +v -0.532518 -3.052450 0.361107 +v -0.765979 -2.958734 0.357072 +v -0.999441 -2.865018 0.353036 +v -1.232902 -2.771303 0.349001 +v -1.466363 -2.677587 0.344966 +v -1.699825 -2.583871 0.340932 +v -1.933286 -2.490155 0.336897 +v -2.166747 -2.396440 0.332862 +v -2.400209 -2.302724 0.328827 +v -2.633670 -2.209008 0.324792 +v -2.867131 -2.115292 0.320757 +v -3.100593 -2.021576 0.316722 +v -3.334054 -1.927860 0.312687 +v -3.567516 -1.834145 0.308652 +v -3.800977 -1.740429 0.304617 +v -4.034438 -1.646713 0.300582 +v 2.199179 -4.013697 0.399889 +v 1.965718 -3.919981 0.395854 +v 1.732256 -3.826265 0.391819 +v 1.498795 -3.732549 0.387784 +v 1.265334 -3.638833 0.383749 +v 1.031872 -3.545117 0.379714 +v 0.798411 -3.451401 0.375679 +v 0.564950 -3.357686 0.371644 +v 0.331488 -3.263969 0.367610 +v 0.098027 -3.170254 0.363575 +v -0.135435 -3.076538 0.359540 +v -0.368896 -2.982822 0.355505 +v -0.602357 -2.889106 0.351470 +v -0.835819 -2.795390 0.347435 +v -1.069280 -2.701675 0.343400 +v -1.302741 -2.607959 0.339365 +v -1.536203 -2.514243 0.335330 +v -1.769664 -2.420527 0.331295 +v -2.003125 -2.326812 0.327260 +v -2.236587 -2.233096 0.323225 +v -2.470048 -2.139380 0.319190 +v -2.703509 -2.045664 0.315155 +v -2.936971 -1.951948 0.311120 +v -3.170432 -1.858232 0.307085 +v -3.403893 -1.764517 0.303050 +v -3.637355 -1.670801 0.299015 +v -3.870816 -1.577085 0.294980 +v -4.104278 -1.483369 0.290945 +v 2.362801 -3.944069 0.394287 +v 2.129340 -3.850353 0.390253 +v 1.895878 -3.756637 0.386218 +v 1.662417 -3.662921 0.382183 +v 1.428956 -3.569205 0.378148 +v 1.195494 -3.475489 0.374113 +v 0.962033 -3.381773 0.370078 +v 0.728572 -3.288058 0.366043 +v 0.495110 -3.194342 0.362008 +v 0.261649 -3.100626 0.357973 +v 0.028187 -3.006910 0.353938 +v -0.205274 -2.913194 0.349903 +v -0.438735 -2.819478 0.345867 +v -0.672197 -2.725763 0.341832 +v -0.905658 -2.632047 0.337797 +v -1.139120 -2.538331 0.333762 +v -1.372581 -2.444616 0.329727 +v -1.606042 -2.350899 0.325692 +v -1.839504 -2.257183 0.321657 +v -2.072965 -2.163467 0.317622 +v -2.306426 -2.069752 0.313587 +v -2.539887 -1.976036 0.309552 +v -2.773349 -1.882320 0.305517 +v -3.006810 -1.788605 0.301483 +v -3.240271 -1.694889 0.297448 +v -3.473733 -1.601173 0.293413 +v -3.707194 -1.507457 0.289378 +v -3.940656 -1.413742 0.285343 +v -4.174116 -1.320026 0.281308 +v 2.526423 -3.874441 0.388685 +v 2.292962 -3.780725 0.384650 +v 2.059500 -3.687009 0.380615 +v 1.826039 -3.593294 0.376580 +v 1.592578 -3.499577 0.372545 +v 1.359116 -3.405861 0.368510 +v 1.125655 -3.312146 0.364475 +v 0.892194 -3.218430 0.360440 +v 0.658732 -3.124714 0.356405 +v 0.425271 -3.030998 0.352371 +v 0.191809 -2.937282 0.348336 +v -0.041652 -2.843566 0.344300 +v -0.275113 -2.749850 0.340265 +v -0.508575 -2.656135 0.336230 +v -0.742036 -2.562419 0.332195 +v -0.975497 -2.468703 0.328160 +v -1.208959 -2.374988 0.324125 +v -1.442420 -2.281271 0.320090 +v -1.675881 -2.187556 0.316055 +v -1.909343 -2.093840 0.312021 +v -2.142804 -2.000124 0.307986 +v -2.376266 -1.906408 0.303951 +v -2.609727 -1.812692 0.299916 +v -2.843188 -1.718977 0.295881 +v -3.076649 -1.625261 0.291846 +v -3.310111 -1.531545 0.287811 +v -3.543572 -1.437829 0.283776 +v -3.777034 -1.344114 0.279741 +v -4.010494 -1.250398 0.275706 +v -4.243956 -1.156682 0.271671 +v 2.690045 -3.804814 0.383083 +v 2.456584 -3.711097 0.379048 +v 2.223123 -3.617381 0.375013 +v 1.989661 -3.523665 0.370978 +v 1.756200 -3.429949 0.366943 +v 1.522738 -3.336234 0.362908 +v 1.289277 -3.242518 0.358873 +v 1.055816 -3.148802 0.354838 +v 0.822354 -3.055086 0.350803 +v 0.588893 -2.961370 0.346768 +v 0.355431 -2.867654 0.342733 +v 0.121970 -2.773938 0.338698 +v -0.111491 -2.680223 0.334663 +v -0.344953 -2.586506 0.330628 +v -0.578414 -2.492791 0.326593 +v -0.811875 -2.399075 0.322558 +v -1.045337 -2.305359 0.318523 +v -1.278798 -2.211644 0.314488 +v -1.512259 -2.117928 0.310453 +v -1.745721 -2.024212 0.306418 +v -1.979182 -1.930496 0.302383 +v -2.212643 -1.836780 0.298348 +v -2.446105 -1.743064 0.294313 +v -2.679566 -1.649349 0.290278 +v -2.913028 -1.555633 0.286243 +v -3.146489 -1.461917 0.282208 +v -3.379950 -1.368201 0.278173 +v -3.613411 -1.274486 0.274138 +v -3.846873 -1.180770 0.270103 +v -4.080334 -1.087054 0.266068 +v -4.313795 -0.993338 0.262033 +v 2.853667 -3.735186 0.377481 +v 2.620206 -3.641469 0.373446 +v 2.386744 -3.547754 0.369411 +v 2.153283 -3.454038 0.365376 +v 1.919822 -3.360322 0.361341 +v 1.686360 -3.266606 0.357306 +v 1.452899 -3.172890 0.353271 +v 1.219437 -3.079174 0.349236 +v 0.985976 -2.985458 0.345201 +v 0.752515 -2.891742 0.341166 +v 0.519053 -2.798027 0.337131 +v 0.285592 -2.704310 0.333096 +v 0.052131 -2.610595 0.329061 +v -0.181331 -2.516879 0.325026 +v -0.414792 -2.423163 0.320991 +v -0.648253 -2.329447 0.316956 +v -0.881715 -2.235731 0.312921 +v -1.115176 -2.142015 0.308886 +v -1.348638 -2.048300 0.304851 +v -1.582099 -1.954584 0.300816 +v -1.815560 -1.860868 0.296781 +v -2.049021 -1.767152 0.292746 +v -2.282483 -1.673437 0.288711 +v -2.515944 -1.579721 0.284676 +v -2.749406 -1.486005 0.280641 +v -2.982867 -1.392290 0.276606 +v -3.216328 -1.298574 0.272572 +v -3.449790 -1.204858 0.268537 +v -3.683251 -1.111142 0.264502 +v -3.916712 -1.017426 0.260467 +v -4.150173 -0.923711 0.256432 +v -4.383635 -0.829995 0.252397 +v 3.017289 -3.665558 0.371879 +v 2.783828 -3.571841 0.367844 +v 2.550366 -3.478126 0.363809 +v 2.316905 -3.384410 0.359774 +v 2.083444 -3.290694 0.355739 +v 1.849982 -3.196978 0.351704 +v 1.616521 -3.103262 0.347669 +v 1.383060 -3.009546 0.343634 +v 1.149598 -2.915830 0.339599 +v 0.916137 -2.822114 0.335564 +v 0.682675 -2.728399 0.331529 +v 0.449214 -2.634683 0.327494 +v 0.215753 -2.540967 0.323459 +v -0.017709 -2.447251 0.319424 +v -0.251170 -2.353535 0.315389 +v -0.484631 -2.259820 0.311354 +v -0.718093 -2.166104 0.307319 +v -0.951554 -2.072388 0.303284 +v -1.185016 -1.978672 0.299249 +v -1.418477 -1.884956 0.295214 +v -1.651938 -1.791241 0.291179 +v -1.885400 -1.697525 0.287144 +v -2.118861 -1.603809 0.283109 +v -2.352322 -1.510093 0.279074 +v -2.585784 -1.416377 0.275039 +v -2.819245 -1.322662 0.271004 +v -3.052706 -1.228946 0.266969 +v -3.286168 -1.135230 0.262934 +v -3.519629 -1.041514 0.258899 +v -3.753090 -0.947798 0.254864 +v -3.986552 -0.854083 0.250829 +v -4.220013 -0.760367 0.246794 +v -4.453474 -0.666651 0.242759 +v 3.180911 -3.595930 0.366277 +v 2.947450 -3.502214 0.362242 +v 2.713988 -3.408498 0.358207 +v 2.480527 -3.314782 0.354172 +v 2.247066 -3.221066 0.350137 +v 2.013604 -3.127350 0.346102 +v 1.780143 -3.033635 0.342067 +v 1.546681 -2.939919 0.338032 +v 1.313220 -2.846202 0.333997 +v 1.079759 -2.752487 0.329962 +v 0.846297 -2.658771 0.325927 +v 0.612836 -2.565055 0.321892 +v 0.379375 -2.471339 0.317857 +v 0.145913 -2.377623 0.313822 +v -0.087548 -2.283908 0.309787 +v -0.321009 -2.190192 0.305752 +v -0.554471 -2.096476 0.301717 +v -0.787932 -2.002760 0.297682 +v -1.021394 -1.909044 0.293647 +v -1.254855 -1.815328 0.289612 +v -1.488316 -1.721613 0.285577 +v -1.721778 -1.627897 0.281542 +v -1.955239 -1.534181 0.277507 +v -2.188700 -1.440465 0.273472 +v -2.422162 -1.346750 0.269437 +v -2.655623 -1.253034 0.265402 +v -2.889084 -1.159318 0.261367 +v -3.122546 -1.065602 0.257332 +v -3.356007 -0.971886 0.253297 +v -3.589468 -0.878170 0.249262 +v -3.822929 -0.784455 0.245227 +v -4.056391 -0.690739 0.241192 +v -4.289852 -0.597024 0.237157 +v -4.523314 -0.503308 0.233122 +v 3.344533 -3.526303 0.360675 +v 3.111072 -3.432586 0.356640 +v 2.877610 -3.338870 0.352605 +v 2.644149 -3.245154 0.348570 +v 2.410687 -3.151438 0.344535 +v 2.177226 -3.057723 0.340500 +v 1.943765 -2.964007 0.336465 +v 1.710303 -2.870291 0.332430 +v 1.476842 -2.776575 0.328395 +v 1.243381 -2.682859 0.324360 +v 1.009919 -2.589143 0.320325 +v 0.776458 -2.495427 0.316290 +v 0.542997 -2.401711 0.312255 +v 0.309535 -2.307995 0.308220 +v 0.076074 -2.214280 0.304185 +v -0.157387 -2.120564 0.300150 +v -0.390849 -2.026848 0.296115 +v -0.624310 -1.933132 0.292080 +v -0.857772 -1.839417 0.288045 +v -1.091233 -1.745700 0.284010 +v -1.324694 -1.651985 0.279975 +v -1.558156 -1.558269 0.275940 +v -1.791617 -1.464553 0.271905 +v -2.025078 -1.370837 0.267870 +v -2.258540 -1.277122 0.263835 +v -2.492001 -1.183406 0.259800 +v -2.725462 -1.089690 0.255765 +v -2.958924 -0.995974 0.251730 +v -3.192385 -0.902259 0.247695 +v -3.425846 -0.808543 0.243660 +v -3.659307 -0.714827 0.239625 +v -3.892769 -0.621111 0.235590 +v -4.126230 -0.527396 0.231555 +v -4.359692 -0.433680 0.227520 +v -4.593153 -0.339964 0.223485 +v 3.508155 -3.456674 0.355073 +v 3.274693 -3.362958 0.351038 +v 3.041232 -3.269243 0.347003 +v 2.807771 -3.175527 0.342968 +v 2.574309 -3.081810 0.338933 +v 2.340848 -2.988095 0.334898 +v 2.107387 -2.894379 0.330863 +v 1.873925 -2.800663 0.326828 +v 1.640464 -2.706947 0.322793 +v 1.407002 -2.613231 0.318758 +v 1.173541 -2.519516 0.314723 +v 0.940080 -2.425799 0.310688 +v 0.706618 -2.332083 0.306653 +v 0.473157 -2.238368 0.302618 +v 0.239696 -2.144652 0.298583 +v 0.006234 -2.050936 0.294548 +v -0.227227 -1.957220 0.290513 +v -0.460688 -1.863505 0.286478 +v -0.694150 -1.769789 0.282443 +v -0.927611 -1.676073 0.278408 +v -1.161072 -1.582357 0.274373 +v -1.394534 -1.488641 0.270338 +v -1.627995 -1.394925 0.266303 +v -1.861456 -1.301210 0.262268 +v -2.094918 -1.207494 0.258233 +v -2.328379 -1.113778 0.254198 +v -2.561840 -1.020062 0.250163 +v -2.795302 -0.926347 0.246128 +v -3.028763 -0.832631 0.242093 +v -3.262224 -0.738915 0.238058 +v -3.495686 -0.645199 0.234023 +v -3.729147 -0.551483 0.229988 +v -3.962608 -0.457768 0.225953 +v -4.196070 -0.364052 0.221918 +v -4.429531 -0.270336 0.217883 +v -4.662992 -0.176620 0.213848 +v 3.671777 -3.387047 0.349471 +v 3.438316 -3.293330 0.345436 +v 3.204854 -3.199615 0.341401 +v 2.971393 -3.105899 0.337366 +v 2.737931 -3.012183 0.333331 +v 2.504470 -2.918467 0.329296 +v 2.271009 -2.824751 0.325261 +v 2.037547 -2.731035 0.321226 +v 1.804086 -2.637319 0.317191 +v 1.570624 -2.543603 0.313156 +v 1.337163 -2.449888 0.309121 +v 1.103702 -2.356172 0.305086 +v 0.870240 -2.262455 0.301051 +v 0.636779 -2.168740 0.297016 +v 0.403318 -2.075024 0.292981 +v 0.169856 -1.981308 0.288946 +v -0.063605 -1.887592 0.284911 +v -0.297066 -1.793877 0.280876 +v -0.530528 -1.700161 0.276841 +v -0.763989 -1.606445 0.272806 +v -0.997450 -1.512729 0.268771 +v -1.230912 -1.419013 0.264736 +v -1.464373 -1.325298 0.260701 +v -1.697834 -1.231582 0.256666 +v -1.931295 -1.137866 0.252631 +v -2.164757 -1.044150 0.248596 +v -2.398218 -0.950434 0.244561 +v -2.631680 -0.856719 0.240526 +v -2.865141 -0.763003 0.236491 +v -3.098603 -0.669287 0.232456 +v -3.332064 -0.575571 0.228421 +v -3.565525 -0.481856 0.224386 +v -3.798986 -0.388140 0.220351 +v -4.032447 -0.294424 0.216316 +v -4.265909 -0.200708 0.212281 +v -4.499370 -0.106993 0.208246 +v -4.732831 -0.013277 0.204211 +v 3.835399 -3.317418 0.343869 +v 3.601938 -3.223703 0.339834 +v 3.368476 -3.129987 0.335799 +v 3.135015 -3.036271 0.331764 +v 2.901554 -2.942555 0.327729 +v 2.668092 -2.848839 0.323694 +v 2.434631 -2.755123 0.319659 +v 2.201169 -2.661407 0.315624 +v 1.967708 -2.567691 0.311589 +v 1.734246 -2.473976 0.307554 +v 1.500785 -2.380260 0.303519 +v 1.267324 -2.286544 0.299484 +v 1.033862 -2.192828 0.295449 +v 0.800401 -2.099112 0.291414 +v 0.566940 -2.005396 0.287379 +v 0.333478 -1.911680 0.283344 +v 0.100017 -1.817965 0.279309 +v -0.133444 -1.724249 0.275274 +v -0.366906 -1.630533 0.271239 +v -0.600367 -1.536817 0.267204 +v -0.833828 -1.443102 0.263169 +v -1.067290 -1.349386 0.259134 +v -1.300751 -1.255670 0.255099 +v -1.534212 -1.161954 0.251064 +v -1.767674 -1.068238 0.247029 +v -2.001135 -0.974522 0.242994 +v -2.234596 -0.880807 0.238959 +v -2.468058 -0.787091 0.234924 +v -2.701519 -0.693375 0.230889 +v -2.934980 -0.599659 0.226854 +v -3.168442 -0.505944 0.222819 +v -3.401903 -0.412228 0.218784 +v -3.635364 -0.318512 0.214749 +v -3.868825 -0.224796 0.210714 +v -4.102286 -0.131081 0.206679 +v -4.335748 -0.037365 0.202644 +v -4.569209 0.056351 0.198609 +v -4.802670 0.150067 0.194574 +v 3.999021 -3.247791 0.338267 +v 3.765560 -3.154075 0.334232 +v 3.532098 -3.060359 0.330197 +v 3.298637 -2.966643 0.326162 +v 3.065176 -2.872927 0.322127 +v 2.831714 -2.779212 0.318092 +v 2.598253 -2.685495 0.314057 +v 2.364791 -2.591780 0.310022 +v 2.131330 -2.498064 0.305987 +v 1.897868 -2.404348 0.301952 +v 1.664407 -2.310632 0.297917 +v 1.430946 -2.216916 0.293882 +v 1.197484 -2.123200 0.289847 +v 0.964023 -2.029484 0.285812 +v 0.730562 -1.935768 0.281777 +v 0.497100 -1.842052 0.277742 +v 0.263639 -1.748337 0.273707 +v 0.030178 -1.654621 0.269672 +v -0.203284 -1.560905 0.265637 +v -0.436745 -1.467189 0.261602 +v -0.670206 -1.373474 0.257567 +v -0.903668 -1.279758 0.253532 +v -1.137129 -1.186042 0.249497 +v -1.370590 -1.092326 0.245462 +v -1.604052 -0.998610 0.241427 +v -1.837513 -0.904895 0.237392 +v -2.070974 -0.811179 0.233357 +v -2.304435 -0.717463 0.229322 +v -2.537897 -0.623747 0.225287 +v -2.771358 -0.530031 0.221252 +v -3.004820 -0.436316 0.217217 +v -3.238281 -0.342600 0.213182 +v -3.471742 -0.248884 0.209147 +v -3.705204 -0.155168 0.205112 +v -3.938665 -0.061453 0.201077 +v -4.172126 0.032263 0.197042 +v -4.405587 0.125979 0.193007 +v -4.639049 0.219695 0.188972 +v -4.872510 0.313411 0.184937 +v 4.162643 -3.178163 0.332665 +v 3.929182 -3.084447 0.328630 +v 3.695721 -2.990731 0.324595 +v 3.462259 -2.897015 0.320560 +v 3.228797 -2.803299 0.316525 +v 2.995336 -2.709584 0.312490 +v 2.761875 -2.615868 0.308455 +v 2.528413 -2.522151 0.304420 +v 2.294952 -2.428436 0.300385 +v 2.061491 -2.334720 0.296350 +v 1.828029 -2.241004 0.292315 +v 1.594568 -2.147288 0.288280 +v 1.361106 -2.053572 0.284245 +v 1.127645 -1.959856 0.280210 +v 0.894184 -1.866141 0.276175 +v 0.660722 -1.772425 0.272140 +v 0.427261 -1.678709 0.268105 +v 0.193800 -1.584993 0.264070 +v -0.039662 -1.491277 0.260035 +v -0.273123 -1.397561 0.256000 +v -0.506584 -1.303846 0.251965 +v -0.740046 -1.210130 0.247930 +v -0.973507 -1.116414 0.243895 +v -1.206968 -1.022698 0.239860 +v -1.440430 -0.928983 0.235825 +v -1.673891 -0.835267 0.231790 +v -1.907352 -0.741551 0.227755 +v -2.140813 -0.647835 0.223720 +v -2.374275 -0.554119 0.219685 +v -2.607736 -0.460404 0.215650 +v -2.841197 -0.366688 0.211615 +v -3.074659 -0.272972 0.207580 +v -3.308120 -0.179256 0.203545 +v -3.541582 -0.085541 0.199510 +v -3.775043 0.008175 0.195475 +v -4.008504 0.101891 0.191440 +v -4.241965 0.195607 0.187405 +v -4.475427 0.289323 0.183370 +v -4.708888 0.383039 0.179335 +v -4.942349 0.476755 0.175300 +v 4.326265 -3.108535 0.327063 +v 4.092804 -3.014819 0.323028 +v 3.859343 -2.921103 0.318993 +v 3.625881 -2.827387 0.314958 +v 3.392420 -2.733672 0.310923 +v 3.158958 -2.639956 0.306888 +v 2.925497 -2.546240 0.302853 +v 2.692035 -2.452524 0.298818 +v 2.458574 -2.358808 0.294783 +v 2.225112 -2.265092 0.290748 +v 1.991651 -2.171377 0.286713 +v 1.758190 -2.077660 0.282678 +v 1.524728 -1.983944 0.278643 +v 1.291267 -1.890228 0.274608 +v 1.057806 -1.796513 0.270573 +v 0.824344 -1.702797 0.266538 +v 0.590883 -1.609081 0.262503 +v 0.357422 -1.515365 0.258468 +v 0.123960 -1.421649 0.254433 +v -0.109501 -1.327934 0.250398 +v -0.342962 -1.234218 0.246363 +v -0.576424 -1.140502 0.242328 +v -0.809885 -1.046786 0.238293 +v -1.043346 -0.953071 0.234258 +v -1.276808 -0.859355 0.230223 +v -1.510269 -0.765639 0.226188 +v -1.743730 -0.671923 0.222153 +v -1.977192 -0.578207 0.218118 +v -2.210653 -0.484491 0.214083 +v -2.444114 -0.390776 0.210048 +v -2.677576 -0.297060 0.206013 +v -2.911037 -0.203344 0.201978 +v -3.144498 -0.109628 0.197943 +v -3.377960 -0.015913 0.193908 +v -3.611421 0.077803 0.189873 +v -3.844882 0.171519 0.185838 +v -4.078343 0.265235 0.181803 +v -4.311805 0.358951 0.177768 +v -4.545266 0.452667 0.173733 +v -4.778728 0.546382 0.169698 +v -5.012189 0.640098 0.165663 +v 4.489887 -3.038907 0.321461 +v 4.256426 -2.945192 0.317426 +v 4.022964 -2.851475 0.313390 +v 3.789503 -2.757760 0.309355 +v 3.556042 -2.664043 0.305321 +v 3.322580 -2.570328 0.301286 +v 3.089119 -2.476612 0.297251 +v 2.855658 -2.382896 0.293216 +v 2.622196 -2.289180 0.289181 +v 2.388735 -2.195465 0.285146 +v 2.155273 -2.101748 0.281111 +v 1.921812 -2.008032 0.277076 +v 1.688350 -1.914317 0.273041 +v 1.454889 -1.820600 0.269006 +v 1.221428 -1.726885 0.264971 +v 0.987966 -1.633169 0.260936 +v 0.754505 -1.539453 0.256901 +v 0.521044 -1.445737 0.252866 +v 0.287582 -1.352022 0.248831 +v 0.054121 -1.258306 0.244796 +v -0.179340 -1.164590 0.240761 +v -0.412802 -1.070874 0.236726 +v -0.646263 -0.977158 0.232691 +v -0.879724 -0.883443 0.228656 +v -1.113186 -0.789727 0.224621 +v -1.346647 -0.696011 0.220586 +v -1.580108 -0.602295 0.216551 +v -1.813570 -0.508579 0.212516 +v -2.047031 -0.414864 0.208481 +v -2.280492 -0.321148 0.204446 +v -2.513954 -0.227432 0.200411 +v -2.747415 -0.133716 0.196376 +v -2.980876 -0.040001 0.192341 +v -3.214338 0.053715 0.188306 +v -3.447799 0.147431 0.184271 +v -3.681260 0.241147 0.180236 +v -3.914722 0.334863 0.176201 +v -4.148183 0.428579 0.172166 +v -4.381644 0.522295 0.168131 +v -4.615106 0.616011 0.164096 +v -4.848567 0.709726 0.160061 +v -5.082028 0.803442 0.156026 +v 4.653510 -2.969280 0.315859 +v 4.420048 -2.875564 0.311824 +v 4.186587 -2.781847 0.307789 +v 3.953125 -2.688132 0.303754 +v 3.719664 -2.594416 0.299719 +v 3.486202 -2.500700 0.295684 +v 3.252741 -2.406984 0.291649 +v 3.019279 -2.313268 0.287614 +v 2.785818 -2.219553 0.283579 +v 2.552357 -2.125836 0.279544 +v 2.318895 -2.032120 0.275509 +v 2.085434 -1.938404 0.271474 +v 1.851972 -1.844689 0.267439 +v 1.618511 -1.750973 0.263404 +v 1.385050 -1.657257 0.259369 +v 1.151588 -1.563541 0.255334 +v 0.918127 -1.469826 0.251299 +v 0.684666 -1.376110 0.247264 +v 0.451204 -1.282394 0.243229 +v 0.217743 -1.188678 0.239194 +v -0.015718 -1.094962 0.235159 +v -0.249180 -1.001246 0.231124 +v -0.482641 -0.907531 0.227089 +v -0.716102 -0.813815 0.223054 +v -0.949564 -0.720099 0.219019 +v -1.183025 -0.626383 0.214984 +v -1.416486 -0.532667 0.210949 +v -1.649948 -0.438952 0.206914 +v -1.883409 -0.345236 0.202879 +v -2.116870 -0.251520 0.198844 +v -2.350331 -0.157804 0.194809 +v -2.583793 -0.064088 0.190774 +v -2.817254 0.029627 0.186739 +v -3.050715 0.123343 0.182704 +v -3.284177 0.217059 0.178669 +v -3.517638 0.310775 0.174634 +v -3.751100 0.404491 0.170599 +v -3.984561 0.498207 0.166564 +v -4.218022 0.591923 0.162529 +v -4.451484 0.685638 0.158494 +v -4.684945 0.779354 0.154459 +v -4.918406 0.873070 0.150424 +v -5.151868 0.966786 0.146389 +v 4.817132 -2.899652 0.310257 +v 4.583670 -2.805936 0.306221 +v 4.350208 -2.712219 0.302186 +v 4.116747 -2.618504 0.298151 +v 3.883286 -2.524788 0.294116 +v 3.649824 -2.431072 0.290082 +v 3.416363 -2.337356 0.286047 +v 3.182901 -2.243640 0.282012 +v 2.949440 -2.149925 0.277977 +v 2.715979 -2.056208 0.273942 +v 2.482517 -1.962493 0.269907 +v 2.249056 -1.868777 0.265872 +v 2.015594 -1.775061 0.261837 +v 1.782133 -1.681345 0.257802 +v 1.548671 -1.587629 0.253767 +v 1.315210 -1.493914 0.249732 +v 1.081749 -1.400198 0.245697 +v 0.848288 -1.306482 0.241662 +v 0.614826 -1.212766 0.237627 +v 0.381365 -1.119050 0.233592 +v 0.147904 -1.025334 0.229557 +v -0.085558 -0.931619 0.225522 +v -0.319019 -0.837903 0.221487 +v -0.552480 -0.744187 0.217452 +v -0.785942 -0.650471 0.213417 +v -1.019403 -0.556755 0.209382 +v -1.252864 -0.463039 0.205347 +v -1.486326 -0.369324 0.201312 +v -1.719787 -0.275608 0.197277 +v -1.953248 -0.181892 0.193242 +v -2.186710 -0.088176 0.189207 +v -2.420171 0.005539 0.185172 +v -2.653632 0.099255 0.181137 +v -2.887094 0.192971 0.177102 +v -3.120555 0.286687 0.173067 +v -3.354016 0.380403 0.169032 +v -3.587478 0.474118 0.164997 +v -3.820939 0.567834 0.160962 +v -4.054400 0.661550 0.156927 +v -4.287862 0.755266 0.152892 +v -4.521323 0.848982 0.148857 +v -4.754785 0.942698 0.144822 +v -4.988246 1.036414 0.140787 +v -5.221706 1.130129 0.136752 +v 4.980753 -2.830024 0.304654 +v 4.747292 -2.736308 0.300619 +v 4.513830 -2.642592 0.296584 +v 4.280369 -2.548876 0.292549 +v 4.046907 -2.455160 0.288514 +v 3.813446 -2.361444 0.284479 +v 3.579985 -2.267728 0.280444 +v 3.346523 -2.174013 0.276409 +v 3.113062 -2.080297 0.272375 +v 2.879601 -1.986581 0.268340 +v 2.646139 -1.892865 0.264305 +v 2.412678 -1.799149 0.260270 +v 2.179216 -1.705433 0.256235 +v 1.945755 -1.611717 0.252200 +v 1.712294 -1.518002 0.248165 +v 1.478832 -1.424286 0.244130 +v 1.245371 -1.330570 0.240095 +v 1.011909 -1.236854 0.236060 +v 0.778448 -1.143138 0.232025 +v 0.544987 -1.049423 0.227990 +v 0.311526 -0.955707 0.223955 +v 0.078064 -0.861991 0.219920 +v -0.155397 -0.768275 0.215885 +v -0.388859 -0.674559 0.211850 +v -0.622320 -0.580843 0.207815 +v -0.855781 -0.487128 0.203780 +v -1.089242 -0.393412 0.199745 +v -1.322704 -0.299696 0.195710 +v -1.556165 -0.205980 0.191675 +v -1.789626 -0.112264 0.187640 +v -2.023088 -0.018548 0.183605 +v -2.256549 0.075167 0.179570 +v -2.490010 0.168883 0.175535 +v -2.723472 0.262599 0.171500 +v -2.956933 0.356315 0.167465 +v -3.190394 0.450030 0.163430 +v -3.423856 0.543746 0.159395 +v -3.657317 0.637462 0.155360 +v -3.890779 0.731178 0.151325 +v -4.124240 0.824894 0.147290 +v -4.357701 0.918610 0.143255 +v -4.591162 1.012325 0.139220 +v -4.824624 1.106042 0.135185 +v -5.058085 1.199757 0.131150 +v -5.291546 1.293473 0.127115 +v 5.144376 -2.760396 0.299052 +v 4.910913 -2.666680 0.295017 +v 4.677453 -2.572964 0.290982 +v 4.443991 -2.479249 0.286947 +v 4.210530 -2.385532 0.282912 +v 3.977068 -2.291817 0.278877 +v 3.743607 -2.198101 0.274843 +v 3.510145 -2.104385 0.270808 +v 3.276684 -2.010669 0.266773 +v 3.043222 -1.916953 0.262738 +v 2.809761 -1.823237 0.258703 +v 2.576299 -1.729521 0.254668 +v 2.342838 -1.635805 0.250633 +v 2.109377 -1.542089 0.246598 +v 1.875915 -1.448374 0.242563 +v 1.642454 -1.354658 0.238528 +v 1.408993 -1.260942 0.234493 +v 1.175532 -1.167226 0.230458 +v 0.942070 -1.073511 0.226423 +v 0.708609 -0.979795 0.222388 +v 0.475148 -0.886079 0.218353 +v 0.241686 -0.792363 0.214318 +v 0.008225 -0.698647 0.210283 +v -0.225236 -0.604931 0.206248 +v -0.458698 -0.511216 0.202213 +v -0.692159 -0.417500 0.198178 +v -0.925620 -0.323784 0.194143 +v -1.159082 -0.230068 0.190108 +v -1.392543 -0.136352 0.186073 +v -1.626004 -0.042636 0.182038 +v -1.859466 0.051079 0.178003 +v -2.092927 0.144795 0.173968 +v -2.326388 0.238511 0.169933 +v -2.559850 0.332227 0.165898 +v -2.793311 0.425943 0.161863 +v -3.026772 0.519658 0.157828 +v -3.260234 0.613374 0.153793 +v -3.493695 0.707090 0.149758 +v -3.727157 0.800806 0.145723 +v -3.960618 0.894522 0.141688 +v -4.194079 0.988238 0.137653 +v -4.427540 1.081954 0.133618 +v -4.661001 1.175669 0.129583 +v -4.894464 1.269385 0.125548 +v -5.127924 1.363101 0.121513 +v -5.361385 1.456817 0.117478 +v 5.307998 -2.690768 0.293450 +v 5.074536 -2.597052 0.289415 +v 4.841075 -2.503336 0.285380 +v 4.607614 -2.409621 0.281345 +v 4.374152 -2.315905 0.277310 +v 4.140691 -2.222188 0.273275 +v 3.907229 -2.128473 0.269240 +v 3.673767 -2.034757 0.265205 +v 3.440306 -1.941041 0.261170 +v 3.206845 -1.847325 0.257135 +v 2.973383 -1.753609 0.253100 +v 2.739922 -1.659893 0.249065 +v 2.506460 -1.566177 0.245030 +v 2.272999 -1.472462 0.240995 +v 2.039538 -1.378746 0.236960 +v 1.806076 -1.285030 0.232925 +v 1.572615 -1.191314 0.228890 +v 1.339153 -1.097599 0.224855 +v 1.105692 -1.003883 0.220821 +v 0.872231 -0.910167 0.216786 +v 0.638770 -0.816451 0.212751 +v 0.405308 -0.722735 0.208716 +v 0.171847 -0.629019 0.204681 +v -0.061614 -0.535303 0.200646 +v -0.295076 -0.441588 0.196611 +v -0.528537 -0.347872 0.192576 +v -0.761998 -0.254156 0.188541 +v -0.995460 -0.160440 0.184506 +v -1.228921 -0.066724 0.180471 +v -1.462382 0.026991 0.176436 +v -1.695844 0.120707 0.172401 +v -1.929305 0.214423 0.168366 +v -2.162766 0.308139 0.164331 +v -2.396228 0.401855 0.160296 +v -2.629689 0.495571 0.156261 +v -2.863150 0.589286 0.152226 +v -3.096612 0.683002 0.148191 +v -3.330073 0.776718 0.144156 +v -3.563535 0.870434 0.140121 +v -3.796996 0.964150 0.136086 +v -4.030457 1.057866 0.132051 +v -4.263918 1.151582 0.128016 +v -4.497379 1.245297 0.123981 +v -4.730841 1.339013 0.119946 +v -4.964303 1.432729 0.115911 +v -5.197763 1.526445 0.111876 +v -5.431225 1.620160 0.107841 +v 5.471620 -2.621141 0.287848 +v 5.238158 -2.527424 0.283813 +v 5.004697 -2.433708 0.279778 +v 4.771235 -2.339993 0.275743 +v 4.537774 -2.246277 0.271708 +v 4.304313 -2.152560 0.267673 +v 4.070851 -2.058845 0.263638 +v 3.837389 -1.965129 0.259603 +v 3.603928 -1.871413 0.255568 +v 3.370467 -1.777697 0.251533 +v 3.137005 -1.683981 0.247498 +v 2.903544 -1.590265 0.243463 +v 2.670082 -1.496549 0.239429 +v 2.436621 -1.402834 0.235394 +v 2.203160 -1.309118 0.231359 +v 1.969698 -1.215402 0.227324 +v 1.736237 -1.121686 0.223289 +v 1.502776 -1.027971 0.219254 +v 1.269314 -0.934255 0.215219 +v 1.035853 -0.840539 0.211184 +v 0.802391 -0.746823 0.207149 +v 0.568930 -0.653107 0.203114 +v 0.335469 -0.559391 0.199079 +v 0.102008 -0.465676 0.195044 +v -0.131454 -0.371960 0.191009 +v -0.364915 -0.278244 0.186974 +v -0.598377 -0.184528 0.182939 +v -0.831838 -0.090812 0.178904 +v -1.065299 0.002903 0.174869 +v -1.298761 0.096619 0.170834 +v -1.532222 0.190335 0.166799 +v -1.765683 0.284051 0.162764 +v -1.999144 0.377767 0.158729 +v -2.232605 0.471483 0.154694 +v -2.466067 0.565198 0.150659 +v -2.699528 0.658914 0.146624 +v -2.932990 0.752630 0.142589 +v -3.166451 0.846346 0.138554 +v -3.399912 0.940062 0.134519 +v -3.633374 1.033778 0.130484 +v -3.866836 1.127494 0.126449 +v -4.100297 1.221209 0.122414 +v -4.333757 1.314925 0.118379 +v -4.567219 1.408641 0.114344 +v -4.800680 1.502357 0.110309 +v -5.034142 1.596073 0.106274 +v -5.267603 1.689788 0.102239 +v -5.501064 1.783504 0.098204 +v 5.635241 -2.551513 0.282246 +v 5.401779 -2.457797 0.278211 +v 5.168319 -2.364081 0.274176 +v 4.934856 -2.270365 0.270141 +v 4.701396 -2.176649 0.266106 +v 4.467934 -2.082933 0.262071 +v 4.234472 -1.989217 0.258036 +v 4.001011 -1.895501 0.254001 +v 3.767550 -1.801785 0.249966 +v 3.534088 -1.708070 0.245931 +v 3.300627 -1.614354 0.241896 +v 3.067165 -1.520638 0.237861 +v 2.833704 -1.426922 0.233826 +v 2.600243 -1.333206 0.229791 +v 2.366781 -1.239491 0.225756 +v 2.133320 -1.145774 0.221721 +v 1.899859 -1.052059 0.217686 +v 1.666397 -0.958343 0.213651 +v 1.432936 -0.864627 0.209616 +v 1.199475 -0.770911 0.205581 +v 0.966013 -0.677196 0.201546 +v 0.732552 -0.583480 0.197511 +v 0.499091 -0.489764 0.193476 +v 0.265629 -0.396048 0.189441 +v 0.032168 -0.302332 0.185406 +v -0.201293 -0.208616 0.181371 +v -0.434755 -0.114901 0.177336 +v -0.668216 -0.021185 0.173302 +v -0.901677 0.072531 0.169267 +v -1.135139 0.166247 0.165232 +v -1.368600 0.259963 0.161197 +v -1.602061 0.353679 0.157162 +v -1.835523 0.447395 0.153127 +v -2.068984 0.541110 0.149092 +v -2.302445 0.634826 0.145057 +v -2.535906 0.728542 0.141022 +v -2.769368 0.822258 0.136987 +v -3.002829 0.915974 0.132952 +v -3.236290 1.009689 0.128917 +v -3.469752 1.103406 0.124882 +v -3.703213 1.197121 0.120847 +v -3.936675 1.290837 0.116812 +v -4.170135 1.384553 0.112777 +v -4.403597 1.478269 0.108742 +v -4.637058 1.571984 0.104707 +v -4.870520 1.665701 0.100672 +v -5.103981 1.759416 0.096637 +v -5.337442 1.853132 0.092602 +v -5.570904 1.946848 0.088567 +vn 0.0077 0.0622 0.9980 +usemtl None +s off +f 2//1 254//1 104//1 +f 2//1 105//1 254//1 +f 205//1 204//1 3//1 +f 206//1 255//1 205//1 +f 207//1 256//1 206//1 +f 208//1 258//1 207//1 +f 209//1 261//1 208//1 +f 210//1 265//1 209//1 +f 211//1 270//1 210//1 +f 212//1 276//1 211//1 +f 213//1 283//1 212//1 +f 214//1 291//1 213//1 +f 215//1 300//1 214//1 +f 216//1 310//1 215//1 +f 217//1 321//1 216//1 +f 218//1 333//1 217//1 +f 219//1 346//1 218//1 +f 220//1 360//1 219//1 +f 221//1 375//1 220//1 +f 222//1 391//1 221//1 +f 223//1 408//1 222//1 +f 224//1 426//1 223//1 +f 225//1 445//1 224//1 +f 226//1 465//1 225//1 +f 227//1 486//1 226//1 +f 228//1 508//1 227//1 +f 229//1 531//1 228//1 +f 230//1 555//1 229//1 +f 231//1 580//1 230//1 +f 232//1 606//1 231//1 +f 233//1 633//1 232//1 +f 234//1 661//1 233//1 +f 235//1 690//1 234//1 +f 236//1 720//1 235//1 +f 237//1 751//1 236//1 +f 238//1 783//1 237//1 +f 239//1 816//1 238//1 +f 240//1 850//1 239//1 +f 241//1 885//1 240//1 +f 242//1 921//1 241//1 +f 243//1 958//1 242//1 +f 244//1 996//1 243//1 +f 245//1 1035//1 244//1 +f 246//1 1075//1 245//1 +f 247//1 1116//1 246//1 +f 248//1 1158//1 247//1 +f 249//1 1201//1 248//1 +f 250//1 1245//1 249//1 +f 251//1 1290//1 250//1 +f 252//1 1336//1 251//1 +f 253//1 1383//1 252//1 +f 254//1 1431//1 253//1 +f 205//1 255//1 204//1 +f 255//1 203//1 204//1 +f 206//1 256//1 255//1 +f 256//1 257//1 255//1 +f 255//1 257//1 203//1 +f 257//1 202//1 203//1 +f 207//1 258//1 256//1 +f 258//1 259//1 256//1 +f 256//1 259//1 257//1 +f 259//1 260//1 257//1 +f 257//1 260//1 202//1 +f 260//1 201//1 202//1 +f 208//1 261//1 258//1 +f 261//1 262//1 258//1 +f 258//1 262//1 259//1 +f 262//1 263//1 259//1 +f 259//1 263//1 260//1 +f 263//1 264//1 260//1 +f 260//1 264//1 201//1 +f 264//1 200//1 201//1 +f 209//1 265//1 261//1 +f 265//1 266//1 261//1 +f 261//1 266//1 262//1 +f 266//1 267//1 262//1 +f 262//1 267//1 263//1 +f 267//1 268//1 263//1 +f 263//1 268//1 264//1 +f 268//1 269//1 264//1 +f 264//1 269//1 200//1 +f 269//1 199//1 200//1 +f 210//1 270//1 265//1 +f 270//1 271//1 265//1 +f 265//1 271//1 266//1 +f 271//1 272//1 266//1 +f 266//1 272//1 267//1 +f 272//1 273//1 267//1 +f 267//1 273//1 268//1 +f 273//1 274//1 268//1 +f 268//1 274//1 269//1 +f 274//1 275//1 269//1 +f 269//1 275//1 199//1 +f 275//1 198//1 199//1 +f 211//1 276//1 270//1 +f 276//1 277//1 270//1 +f 270//1 277//1 271//1 +f 277//1 278//1 271//1 +f 271//1 278//1 272//1 +f 278//1 279//1 272//1 +f 272//1 279//1 273//1 +f 279//1 280//1 273//1 +f 273//1 280//1 274//1 +f 280//1 281//1 274//1 +f 274//1 281//1 275//1 +f 281//1 282//1 275//1 +f 275//1 282//1 198//1 +f 282//1 197//1 198//1 +f 212//1 283//1 276//1 +f 283//1 284//1 276//1 +f 276//1 284//1 277//1 +f 284//1 285//1 277//1 +f 277//1 285//1 278//1 +f 285//1 286//1 278//1 +f 278//1 286//1 279//1 +f 286//1 287//1 279//1 +f 279//1 287//1 280//1 +f 287//1 288//1 280//1 +f 280//1 288//1 281//1 +f 288//1 289//1 281//1 +f 281//1 289//1 282//1 +f 289//1 290//1 282//1 +f 282//1 290//1 197//1 +f 290//1 196//1 197//1 +f 213//1 291//1 283//1 +f 291//1 292//1 283//1 +f 283//1 292//1 284//1 +f 292//1 293//1 284//1 +f 284//1 293//1 285//1 +f 293//1 294//1 285//1 +f 285//1 294//1 286//1 +f 294//1 295//1 286//1 +f 286//1 295//1 287//1 +f 295//1 296//1 287//1 +f 287//1 296//1 288//1 +f 296//1 297//1 288//1 +f 288//1 297//1 289//1 +f 297//1 298//1 289//1 +f 289//1 298//1 290//1 +f 298//1 299//1 290//1 +f 290//1 299//1 196//1 +f 299//1 195//1 196//1 +f 214//1 300//1 291//1 +f 300//1 301//1 291//1 +f 291//1 301//1 292//1 +f 301//1 302//1 292//1 +f 292//1 302//1 293//1 +f 302//1 303//1 293//1 +f 293//1 303//1 294//1 +f 303//1 304//1 294//1 +f 294//1 304//1 295//1 +f 304//1 305//1 295//1 +f 295//1 305//1 296//1 +f 305//1 306//1 296//1 +f 296//1 306//1 297//1 +f 306//1 307//1 297//1 +f 297//1 307//1 298//1 +f 307//1 308//1 298//1 +f 298//1 308//1 299//1 +f 308//1 309//1 299//1 +f 299//1 309//1 195//1 +f 309//1 194//1 195//1 +f 215//1 310//1 300//1 +f 310//1 311//1 300//1 +f 300//1 311//1 301//1 +f 311//1 312//1 301//1 +f 301//1 312//1 302//1 +f 312//1 313//1 302//1 +f 302//1 313//1 303//1 +f 313//1 314//1 303//1 +f 303//1 314//1 304//1 +f 314//1 315//1 304//1 +f 304//1 315//1 305//1 +f 315//1 316//1 305//1 +f 305//1 316//1 306//1 +f 316//1 317//1 306//1 +f 306//1 317//1 307//1 +f 317//1 318//1 307//1 +f 307//1 318//1 308//1 +f 318//1 319//1 308//1 +f 308//1 319//1 309//1 +f 319//1 320//1 309//1 +f 309//1 320//1 194//1 +f 320//1 193//1 194//1 +f 216//1 321//1 310//1 +f 321//1 322//1 310//1 +f 310//1 322//1 311//1 +f 322//1 323//1 311//1 +f 311//1 323//1 312//1 +f 323//1 324//1 312//1 +f 312//1 324//1 313//1 +f 324//1 325//1 313//1 +f 313//1 325//1 314//1 +f 325//1 326//1 314//1 +f 314//1 326//1 315//1 +f 326//1 327//1 315//1 +f 315//1 327//1 316//1 +f 327//1 328//1 316//1 +f 316//1 328//1 317//1 +f 328//1 329//1 317//1 +f 317//1 329//1 318//1 +f 329//1 330//1 318//1 +f 318//1 330//1 319//1 +f 330//1 331//1 319//1 +f 319//1 331//1 320//1 +f 331//1 332//1 320//1 +f 320//1 332//1 193//1 +f 332//1 192//1 193//1 +f 217//1 333//1 321//1 +f 333//1 334//1 321//1 +f 321//1 334//1 322//1 +f 334//1 335//1 322//1 +f 322//1 335//1 323//1 +f 335//1 336//1 323//1 +f 323//1 336//1 324//1 +f 336//1 337//1 324//1 +f 324//1 337//1 325//1 +f 337//1 338//1 325//1 +f 325//1 338//1 326//1 +f 338//1 339//1 326//1 +f 326//1 339//1 327//1 +f 339//1 340//1 327//1 +f 327//1 340//1 328//1 +f 340//1 341//1 328//1 +f 328//1 341//1 329//1 +f 341//1 342//1 329//1 +f 329//1 342//1 330//1 +f 342//1 343//1 330//1 +f 330//1 343//1 331//1 +f 343//1 344//1 331//1 +f 331//1 344//1 332//1 +f 344//1 345//1 332//1 +f 332//1 345//1 192//1 +f 345//1 191//1 192//1 +f 218//1 346//1 333//1 +f 346//1 347//1 333//1 +f 333//1 347//1 334//1 +f 347//1 348//1 334//1 +f 334//1 348//1 335//1 +f 348//1 349//1 335//1 +f 335//1 349//1 336//1 +f 349//1 350//1 336//1 +f 336//1 350//1 337//1 +f 350//1 351//1 337//1 +f 337//1 351//1 338//1 +f 351//1 352//1 338//1 +f 338//1 352//1 339//1 +f 352//1 353//1 339//1 +f 339//1 353//1 340//1 +f 353//1 354//1 340//1 +f 340//1 354//1 341//1 +f 354//1 355//1 341//1 +f 341//1 355//1 342//1 +f 355//1 356//1 342//1 +f 342//1 356//1 343//1 +f 356//1 357//1 343//1 +f 343//1 357//1 344//1 +f 357//1 358//1 344//1 +f 344//1 358//1 345//1 +f 358//1 359//1 345//1 +f 345//1 359//1 191//1 +f 359//1 190//1 191//1 +f 219//1 360//1 346//1 +f 360//1 361//1 346//1 +f 346//1 361//1 347//1 +f 361//1 362//1 347//1 +f 347//1 362//1 348//1 +f 362//1 363//1 348//1 +f 348//1 363//1 349//1 +f 363//1 364//1 349//1 +f 349//1 364//1 350//1 +f 364//1 365//1 350//1 +f 350//1 365//1 351//1 +f 365//1 366//1 351//1 +f 351//1 366//1 352//1 +f 366//1 367//1 352//1 +f 352//1 367//1 353//1 +f 367//1 368//1 353//1 +f 353//1 368//1 354//1 +f 368//1 369//1 354//1 +f 354//1 369//1 355//1 +f 369//1 370//1 355//1 +f 355//1 370//1 356//1 +f 370//1 371//1 356//1 +f 356//1 371//1 357//1 +f 371//1 372//1 357//1 +f 357//1 372//1 358//1 +f 372//1 373//1 358//1 +f 358//1 373//1 359//1 +f 373//1 374//1 359//1 +f 359//1 374//1 190//1 +f 374//1 189//1 190//1 +f 220//1 375//1 360//1 +f 375//1 376//1 360//1 +f 360//1 376//1 361//1 +f 376//1 377//1 361//1 +f 361//1 377//1 362//1 +f 377//1 378//1 362//1 +f 362//1 378//1 363//1 +f 378//1 379//1 363//1 +f 363//1 379//1 364//1 +f 379//1 380//1 364//1 +f 364//1 380//1 365//1 +f 380//1 381//1 365//1 +f 365//1 381//1 366//1 +f 381//1 382//1 366//1 +f 366//1 382//1 367//1 +f 382//1 383//1 367//1 +f 367//1 383//1 368//1 +f 383//1 384//1 368//1 +f 368//1 384//1 369//1 +f 384//1 385//1 369//1 +f 369//1 385//1 370//1 +f 385//1 386//1 370//1 +f 370//1 386//1 371//1 +f 386//1 387//1 371//1 +f 371//1 387//1 372//1 +f 387//1 388//1 372//1 +f 372//1 388//1 373//1 +f 388//1 389//1 373//1 +f 373//1 389//1 374//1 +f 389//1 390//1 374//1 +f 374//1 390//1 189//1 +f 390//1 188//1 189//1 +f 221//1 391//1 375//1 +f 391//1 392//1 375//1 +f 375//1 392//1 376//1 +f 392//1 393//1 376//1 +f 376//1 393//1 377//1 +f 393//1 394//1 377//1 +f 377//1 394//1 378//1 +f 394//1 395//1 378//1 +f 378//1 395//1 379//1 +f 395//1 396//1 379//1 +f 379//1 396//1 380//1 +f 396//1 397//1 380//1 +f 380//1 397//1 381//1 +f 397//1 398//1 381//1 +f 381//1 398//1 382//1 +f 398//1 399//1 382//1 +f 382//1 399//1 383//1 +f 399//1 400//1 383//1 +f 383//1 400//1 384//1 +f 400//1 401//1 384//1 +f 384//1 401//1 385//1 +f 401//1 402//1 385//1 +f 385//1 402//1 386//1 +f 402//1 403//1 386//1 +f 386//1 403//1 387//1 +f 403//1 404//1 387//1 +f 387//1 404//1 388//1 +f 404//1 405//1 388//1 +f 388//1 405//1 389//1 +f 405//1 406//1 389//1 +f 389//1 406//1 390//1 +f 406//1 407//1 390//1 +f 390//1 407//1 188//1 +f 407//1 187//1 188//1 +f 222//1 408//1 391//1 +f 408//1 409//1 391//1 +f 391//1 409//1 392//1 +f 409//1 410//1 392//1 +f 392//1 410//1 393//1 +f 410//1 411//1 393//1 +f 393//1 411//1 394//1 +f 411//1 412//1 394//1 +f 394//1 412//1 395//1 +f 412//1 413//1 395//1 +f 395//1 413//1 396//1 +f 413//1 414//1 396//1 +f 396//1 414//1 397//1 +f 414//1 415//1 397//1 +f 397//1 415//1 398//1 +f 415//1 416//1 398//1 +f 398//1 416//1 399//1 +f 416//1 417//1 399//1 +f 399//1 417//1 400//1 +f 417//1 418//1 400//1 +f 400//1 418//1 401//1 +f 418//1 419//1 401//1 +f 401//1 419//1 402//1 +f 419//1 420//1 402//1 +f 402//1 420//1 403//1 +f 420//1 421//1 403//1 +f 403//1 421//1 404//1 +f 421//1 422//1 404//1 +f 404//1 422//1 405//1 +f 422//1 423//1 405//1 +f 405//1 423//1 406//1 +f 423//1 424//1 406//1 +f 406//1 424//1 407//1 +f 424//1 425//1 407//1 +f 407//1 425//1 187//1 +f 425//1 186//1 187//1 +f 223//1 426//1 408//1 +f 426//1 427//1 408//1 +f 408//1 427//1 409//1 +f 427//1 428//1 409//1 +f 409//1 428//1 410//1 +f 428//1 429//1 410//1 +f 410//1 429//1 411//1 +f 429//1 430//1 411//1 +f 411//1 430//1 412//1 +f 430//1 431//1 412//1 +f 412//1 431//1 413//1 +f 431//1 432//1 413//1 +f 413//1 432//1 414//1 +f 432//1 433//1 414//1 +f 414//1 433//1 415//1 +f 433//1 434//1 415//1 +f 415//1 434//1 416//1 +f 434//1 435//1 416//1 +f 416//1 435//1 417//1 +f 435//1 436//1 417//1 +f 417//1 436//1 418//1 +f 436//1 437//1 418//1 +f 418//1 437//1 419//1 +f 437//1 438//1 419//1 +f 419//1 438//1 420//1 +f 438//1 439//1 420//1 +f 420//1 439//1 421//1 +f 439//1 440//1 421//1 +f 421//1 440//1 422//1 +f 440//1 441//1 422//1 +f 422//1 441//1 423//1 +f 441//1 442//1 423//1 +f 423//1 442//1 424//1 +f 442//1 443//1 424//1 +f 424//1 443//1 425//1 +f 443//1 444//1 425//1 +f 425//1 444//1 186//1 +f 444//1 185//1 186//1 +f 224//1 445//1 426//1 +f 445//1 446//1 426//1 +f 426//1 446//1 427//1 +f 446//1 447//1 427//1 +f 427//1 447//1 428//1 +f 447//1 448//1 428//1 +f 428//1 448//1 429//1 +f 448//1 449//1 429//1 +f 429//1 449//1 430//1 +f 449//1 450//1 430//1 +f 430//1 450//1 431//1 +f 450//1 451//1 431//1 +f 431//1 451//1 432//1 +f 451//1 452//1 432//1 +f 432//1 452//1 433//1 +f 452//1 453//1 433//1 +f 433//1 453//1 434//1 +f 453//1 454//1 434//1 +f 434//1 454//1 435//1 +f 454//1 455//1 435//1 +f 435//1 455//1 436//1 +f 455//1 456//1 436//1 +f 436//1 456//1 437//1 +f 456//1 457//1 437//1 +f 437//1 457//1 438//1 +f 457//1 458//1 438//1 +f 438//1 458//1 439//1 +f 458//1 459//1 439//1 +f 439//1 459//1 440//1 +f 459//1 460//1 440//1 +f 440//1 460//1 441//1 +f 460//1 461//1 441//1 +f 441//1 461//1 442//1 +f 461//1 462//1 442//1 +f 442//1 462//1 443//1 +f 462//1 463//1 443//1 +f 443//1 463//1 444//1 +f 463//1 464//1 444//1 +f 444//1 464//1 185//1 +f 464//1 184//1 185//1 +f 225//1 465//1 445//1 +f 465//1 466//1 445//1 +f 445//1 466//1 446//1 +f 466//1 467//1 446//1 +f 446//1 467//1 447//1 +f 467//1 468//1 447//1 +f 447//1 468//1 448//1 +f 468//1 469//1 448//1 +f 448//1 469//1 449//1 +f 469//1 470//1 449//1 +f 449//1 470//1 450//1 +f 470//1 471//1 450//1 +f 450//1 471//1 451//1 +f 471//1 472//1 451//1 +f 451//1 472//1 452//1 +f 472//1 473//1 452//1 +f 452//1 473//1 453//1 +f 473//1 474//1 453//1 +f 453//1 474//1 454//1 +f 474//1 475//1 454//1 +f 454//1 475//1 455//1 +f 475//1 476//1 455//1 +f 455//1 476//1 456//1 +f 476//1 477//1 456//1 +f 456//1 477//1 457//1 +f 477//1 478//1 457//1 +f 457//1 478//1 458//1 +f 478//1 479//1 458//1 +f 458//1 479//1 459//1 +f 479//1 480//1 459//1 +f 459//1 480//1 460//1 +f 480//1 481//1 460//1 +f 460//1 481//1 461//1 +f 481//1 482//1 461//1 +f 461//1 482//1 462//1 +f 482//1 483//1 462//1 +f 462//1 483//1 463//1 +f 483//1 484//1 463//1 +f 463//1 484//1 464//1 +f 484//1 485//1 464//1 +f 464//1 485//1 184//1 +f 485//1 183//1 184//1 +f 226//1 486//1 465//1 +f 486//1 487//1 465//1 +f 465//1 487//1 466//1 +f 487//1 488//1 466//1 +f 466//1 488//1 467//1 +f 488//1 489//1 467//1 +f 467//1 489//1 468//1 +f 489//1 490//1 468//1 +f 468//1 490//1 469//1 +f 490//1 491//1 469//1 +f 469//1 491//1 470//1 +f 491//1 492//1 470//1 +f 470//1 492//1 471//1 +f 492//1 493//1 471//1 +f 471//1 493//1 472//1 +f 493//1 494//1 472//1 +f 472//1 494//1 473//1 +f 494//1 495//1 473//1 +f 473//1 495//1 474//1 +f 495//1 496//1 474//1 +f 474//1 496//1 475//1 +f 496//1 497//1 475//1 +f 475//1 497//1 476//1 +f 497//1 498//1 476//1 +f 476//1 498//1 477//1 +f 498//1 499//1 477//1 +f 477//1 499//1 478//1 +f 499//1 500//1 478//1 +f 478//1 500//1 479//1 +f 500//1 501//1 479//1 +f 479//1 501//1 480//1 +f 501//1 502//1 480//1 +f 480//1 502//1 481//1 +f 502//1 503//1 481//1 +f 481//1 503//1 482//1 +f 503//1 504//1 482//1 +f 482//1 504//1 483//1 +f 504//1 505//1 483//1 +f 483//1 505//1 484//1 +f 505//1 506//1 484//1 +f 484//1 506//1 485//1 +f 506//1 507//1 485//1 +f 485//1 507//1 183//1 +f 507//1 182//1 183//1 +f 227//1 508//1 486//1 +f 508//1 509//1 486//1 +f 486//1 509//1 487//1 +f 509//1 510//1 487//1 +f 487//1 510//1 488//1 +f 510//1 511//1 488//1 +f 488//1 511//1 489//1 +f 511//1 512//1 489//1 +f 489//1 512//1 490//1 +f 512//1 513//1 490//1 +f 490//1 513//1 491//1 +f 513//1 514//1 491//1 +f 491//1 514//1 492//1 +f 514//1 515//1 492//1 +f 492//1 515//1 493//1 +f 515//1 516//1 493//1 +f 493//1 516//1 494//1 +f 516//1 517//1 494//1 +f 494//1 517//1 495//1 +f 517//1 518//1 495//1 +f 495//1 518//1 496//1 +f 518//1 519//1 496//1 +f 496//1 519//1 497//1 +f 519//1 520//1 497//1 +f 497//1 520//1 498//1 +f 520//1 521//1 498//1 +f 498//1 521//1 499//1 +f 521//1 522//1 499//1 +f 499//1 522//1 500//1 +f 522//1 523//1 500//1 +f 500//1 523//1 501//1 +f 523//1 524//1 501//1 +f 501//1 524//1 502//1 +f 524//1 525//1 502//1 +f 502//1 525//1 503//1 +f 525//1 526//1 503//1 +f 503//1 526//1 504//1 +f 526//1 527//1 504//1 +f 504//1 527//1 505//1 +f 527//1 528//1 505//1 +f 505//1 528//1 506//1 +f 528//1 529//1 506//1 +f 506//1 529//1 507//1 +f 529//1 530//1 507//1 +f 507//1 530//1 182//1 +f 530//1 181//1 182//1 +f 228//1 531//1 508//1 +f 531//1 532//1 508//1 +f 508//1 532//1 509//1 +f 532//1 533//1 509//1 +f 509//1 533//1 510//1 +f 533//1 534//1 510//1 +f 510//1 534//1 511//1 +f 534//1 535//1 511//1 +f 511//1 535//1 512//1 +f 535//1 536//1 512//1 +f 512//1 536//1 513//1 +f 536//1 537//1 513//1 +f 513//1 537//1 514//1 +f 537//1 538//1 514//1 +f 514//1 538//1 515//1 +f 538//1 539//1 515//1 +f 515//1 539//1 516//1 +f 539//1 540//1 516//1 +f 516//1 540//1 517//1 +f 540//1 541//1 517//1 +f 517//1 541//1 518//1 +f 541//1 542//1 518//1 +f 518//1 542//1 519//1 +f 542//1 543//1 519//1 +f 519//1 543//1 520//1 +f 543//1 544//1 520//1 +f 520//1 544//1 521//1 +f 544//1 545//1 521//1 +f 521//1 545//1 522//1 +f 545//1 546//1 522//1 +f 522//1 546//1 523//1 +f 546//1 547//1 523//1 +f 523//1 547//1 524//1 +f 547//1 548//1 524//1 +f 524//1 548//1 525//1 +f 548//1 549//1 525//1 +f 525//1 549//1 526//1 +f 549//1 550//1 526//1 +f 526//1 550//1 527//1 +f 550//1 551//1 527//1 +f 527//1 551//1 528//1 +f 551//1 552//1 528//1 +f 528//1 552//1 529//1 +f 552//1 553//1 529//1 +f 529//1 553//1 530//1 +f 553//1 554//1 530//1 +f 530//1 554//1 181//1 +f 554//1 180//1 181//1 +f 229//1 555//1 531//1 +f 555//1 556//1 531//1 +f 531//1 556//1 532//1 +f 556//1 557//1 532//1 +f 532//1 557//1 533//1 +f 557//1 558//1 533//1 +f 533//1 558//1 534//1 +f 558//1 559//1 534//1 +f 534//1 559//1 535//1 +f 559//1 560//1 535//1 +f 535//1 560//1 536//1 +f 560//1 561//1 536//1 +f 536//1 561//1 537//1 +f 561//1 562//1 537//1 +f 537//1 562//1 538//1 +f 562//1 563//1 538//1 +f 538//1 563//1 539//1 +f 563//1 564//1 539//1 +f 539//1 564//1 540//1 +f 564//1 565//1 540//1 +f 540//1 565//1 541//1 +f 565//1 566//1 541//1 +f 541//1 566//1 542//1 +f 566//1 567//1 542//1 +f 542//1 567//1 543//1 +f 567//1 568//1 543//1 +f 543//1 568//1 544//1 +f 568//1 569//1 544//1 +f 544//1 569//1 545//1 +f 569//1 570//1 545//1 +f 545//1 570//1 546//1 +f 570//1 571//1 546//1 +f 546//1 571//1 547//1 +f 571//1 572//1 547//1 +f 547//1 572//1 548//1 +f 572//1 573//1 548//1 +f 548//1 573//1 549//1 +f 573//1 574//1 549//1 +f 549//1 574//1 550//1 +f 574//1 575//1 550//1 +f 550//1 575//1 551//1 +f 575//1 576//1 551//1 +f 551//1 576//1 552//1 +f 576//1 577//1 552//1 +f 552//1 577//1 553//1 +f 577//1 578//1 553//1 +f 553//1 578//1 554//1 +f 578//1 579//1 554//1 +f 554//1 579//1 180//1 +f 579//1 179//1 180//1 +f 230//1 580//1 555//1 +f 580//1 581//1 555//1 +f 555//1 581//1 556//1 +f 581//1 582//1 556//1 +f 556//1 582//1 557//1 +f 582//1 583//1 557//1 +f 557//1 583//1 558//1 +f 583//1 584//1 558//1 +f 558//1 584//1 559//1 +f 584//1 585//1 559//1 +f 559//1 585//1 560//1 +f 585//1 586//1 560//1 +f 560//1 586//1 561//1 +f 586//1 587//1 561//1 +f 561//1 587//1 562//1 +f 587//1 588//1 562//1 +f 562//1 588//1 563//1 +f 588//1 589//1 563//1 +f 563//1 589//1 564//1 +f 589//1 590//1 564//1 +f 564//1 590//1 565//1 +f 590//1 591//1 565//1 +f 565//1 591//1 566//1 +f 591//1 592//1 566//1 +f 566//1 592//1 567//1 +f 592//1 593//1 567//1 +f 567//1 593//1 568//1 +f 593//1 594//1 568//1 +f 568//1 594//1 569//1 +f 594//1 595//1 569//1 +f 569//1 595//1 570//1 +f 595//1 596//1 570//1 +f 570//1 596//1 571//1 +f 596//1 597//1 571//1 +f 571//1 597//1 572//1 +f 597//1 598//1 572//1 +f 572//1 598//1 573//1 +f 598//1 599//1 573//1 +f 573//1 599//1 574//1 +f 599//1 600//1 574//1 +f 574//1 600//1 575//1 +f 600//1 601//1 575//1 +f 575//1 601//1 576//1 +f 601//1 602//1 576//1 +f 576//1 602//1 577//1 +f 602//1 603//1 577//1 +f 577//1 603//1 578//1 +f 603//1 604//1 578//1 +f 578//1 604//1 579//1 +f 604//1 605//1 579//1 +f 579//1 605//1 179//1 +f 605//1 178//1 179//1 +f 231//1 606//1 580//1 +f 606//1 607//1 580//1 +f 580//1 607//1 581//1 +f 607//1 608//1 581//1 +f 581//1 608//1 582//1 +f 608//1 609//1 582//1 +f 582//1 609//1 583//1 +f 609//1 610//1 583//1 +f 583//1 610//1 584//1 +f 610//1 611//1 584//1 +f 584//1 611//1 585//1 +f 611//1 612//1 585//1 +f 585//1 612//1 586//1 +f 612//1 613//1 586//1 +f 586//1 613//1 587//1 +f 613//1 614//1 587//1 +f 587//1 614//1 588//1 +f 614//1 615//1 588//1 +f 588//1 615//1 589//1 +f 615//1 616//1 589//1 +f 589//1 616//1 590//1 +f 616//1 617//1 590//1 +f 590//1 617//1 591//1 +f 617//1 618//1 591//1 +f 591//1 618//1 592//1 +f 618//1 619//1 592//1 +f 592//1 619//1 593//1 +f 619//1 620//1 593//1 +f 593//1 620//1 594//1 +f 620//1 621//1 594//1 +f 594//1 621//1 595//1 +f 621//1 622//1 595//1 +f 595//1 622//1 596//1 +f 622//1 623//1 596//1 +f 596//1 623//1 597//1 +f 623//1 624//1 597//1 +f 597//1 624//1 598//1 +f 624//1 625//1 598//1 +f 598//1 625//1 599//1 +f 625//1 626//1 599//1 +f 599//1 626//1 600//1 +f 626//1 627//1 600//1 +f 600//1 627//1 601//1 +f 627//1 628//1 601//1 +f 601//1 628//1 602//1 +f 628//1 629//1 602//1 +f 602//1 629//1 603//1 +f 629//1 630//1 603//1 +f 603//1 630//1 604//1 +f 630//1 631//1 604//1 +f 604//1 631//1 605//1 +f 631//1 632//1 605//1 +f 605//1 632//1 178//1 +f 632//1 177//1 178//1 +f 232//1 633//1 606//1 +f 633//1 634//1 606//1 +f 606//1 634//1 607//1 +f 634//1 635//1 607//1 +f 607//1 635//1 608//1 +f 635//1 636//1 608//1 +f 608//1 636//1 609//1 +f 636//1 637//1 609//1 +f 609//1 637//1 610//1 +f 637//1 638//1 610//1 +f 610//1 638//1 611//1 +f 638//1 639//1 611//1 +f 611//1 639//1 612//1 +f 639//1 640//1 612//1 +f 612//1 640//1 613//1 +f 640//1 641//1 613//1 +f 613//1 641//1 614//1 +f 641//1 642//1 614//1 +f 614//1 642//1 615//1 +f 642//1 643//1 615//1 +f 615//1 643//1 616//1 +f 643//1 644//1 616//1 +f 616//1 644//1 617//1 +f 644//1 645//1 617//1 +f 617//1 645//1 618//1 +f 645//1 646//1 618//1 +f 618//1 646//1 619//1 +f 646//1 647//1 619//1 +f 619//1 647//1 620//1 +f 647//1 648//1 620//1 +f 620//1 648//1 621//1 +f 648//1 649//1 621//1 +f 621//1 649//1 622//1 +f 649//1 650//1 622//1 +f 622//1 650//1 623//1 +f 650//1 651//1 623//1 +f 623//1 651//1 624//1 +f 651//1 652//1 624//1 +f 624//1 652//1 625//1 +f 652//1 653//1 625//1 +f 625//1 653//1 626//1 +f 653//1 654//1 626//1 +f 626//1 654//1 627//1 +f 654//1 655//1 627//1 +f 627//1 655//1 628//1 +f 655//1 656//1 628//1 +f 628//1 656//1 629//1 +f 656//1 657//1 629//1 +f 629//1 657//1 630//1 +f 657//1 658//1 630//1 +f 630//1 658//1 631//1 +f 658//1 659//1 631//1 +f 631//1 659//1 632//1 +f 659//1 660//1 632//1 +f 632//1 660//1 177//1 +f 660//1 176//1 177//1 +f 233//1 661//1 633//1 +f 661//1 662//1 633//1 +f 633//1 662//1 634//1 +f 662//1 663//1 634//1 +f 634//1 663//1 635//1 +f 663//1 664//1 635//1 +f 635//1 664//1 636//1 +f 664//1 665//1 636//1 +f 636//1 665//1 637//1 +f 665//1 666//1 637//1 +f 637//1 666//1 638//1 +f 666//1 667//1 638//1 +f 638//1 667//1 639//1 +f 667//1 668//1 639//1 +f 639//1 668//1 640//1 +f 668//1 669//1 640//1 +f 640//1 669//1 641//1 +f 669//1 670//1 641//1 +f 641//1 670//1 642//1 +f 670//1 671//1 642//1 +f 642//1 671//1 643//1 +f 671//1 672//1 643//1 +f 643//1 672//1 644//1 +f 672//1 673//1 644//1 +f 644//1 673//1 645//1 +f 673//1 674//1 645//1 +f 645//1 674//1 646//1 +f 674//1 675//1 646//1 +f 646//1 675//1 647//1 +f 675//1 676//1 647//1 +f 647//1 676//1 648//1 +f 676//1 677//1 648//1 +f 648//1 677//1 649//1 +f 677//1 678//1 649//1 +f 649//1 678//1 650//1 +f 678//1 679//1 650//1 +f 650//1 679//1 651//1 +f 679//1 680//1 651//1 +f 651//1 680//1 652//1 +f 680//1 681//1 652//1 +f 652//1 681//1 653//1 +f 681//1 682//1 653//1 +f 653//1 682//1 654//1 +f 682//1 683//1 654//1 +f 654//1 683//1 655//1 +f 683//1 684//1 655//1 +f 655//1 684//1 656//1 +f 684//1 685//1 656//1 +f 656//1 685//1 657//1 +f 685//1 686//1 657//1 +f 657//1 686//1 658//1 +f 686//1 687//1 658//1 +f 658//1 687//1 659//1 +f 687//1 688//1 659//1 +f 659//1 688//1 660//1 +f 688//1 689//1 660//1 +f 660//1 689//1 176//1 +f 689//1 175//1 176//1 +f 234//1 690//1 661//1 +f 690//1 691//1 661//1 +f 661//1 691//1 662//1 +f 691//1 692//1 662//1 +f 662//1 692//1 663//1 +f 692//1 693//1 663//1 +f 663//1 693//1 664//1 +f 693//1 694//1 664//1 +f 664//1 694//1 665//1 +f 694//1 695//1 665//1 +f 665//1 695//1 666//1 +f 695//1 696//1 666//1 +f 666//1 696//1 667//1 +f 696//1 697//1 667//1 +f 667//1 697//1 668//1 +f 697//1 698//1 668//1 +f 668//1 698//1 669//1 +f 698//1 699//1 669//1 +f 669//1 699//1 670//1 +f 699//1 700//1 670//1 +f 670//1 700//1 671//1 +f 700//1 701//1 671//1 +f 671//1 701//1 672//1 +f 701//1 702//1 672//1 +f 672//1 702//1 673//1 +f 702//1 703//1 673//1 +f 673//1 703//1 674//1 +f 703//1 704//1 674//1 +f 674//1 704//1 675//1 +f 704//1 705//1 675//1 +f 675//1 705//1 676//1 +f 705//1 706//1 676//1 +f 676//1 706//1 677//1 +f 706//1 707//1 677//1 +f 677//1 707//1 678//1 +f 707//1 708//1 678//1 +f 678//1 708//1 679//1 +f 708//1 709//1 679//1 +f 679//1 709//1 680//1 +f 709//1 710//1 680//1 +f 680//1 710//1 681//1 +f 710//1 711//1 681//1 +f 681//1 711//1 682//1 +f 711//1 712//1 682//1 +f 682//1 712//1 683//1 +f 712//1 713//1 683//1 +f 683//1 713//1 684//1 +f 713//1 714//1 684//1 +f 684//1 714//1 685//1 +f 714//1 715//1 685//1 +f 685//1 715//1 686//1 +f 715//1 716//1 686//1 +f 686//1 716//1 687//1 +f 716//1 717//1 687//1 +f 687//1 717//1 688//1 +f 717//1 718//1 688//1 +f 688//1 718//1 689//1 +f 718//1 719//1 689//1 +f 689//1 719//1 175//1 +f 719//1 174//1 175//1 +f 235//1 720//1 690//1 +f 720//1 721//1 690//1 +f 690//1 721//1 691//1 +f 721//1 722//1 691//1 +f 691//1 722//1 692//1 +f 722//1 723//1 692//1 +f 692//1 723//1 693//1 +f 723//1 724//1 693//1 +f 693//1 724//1 694//1 +f 724//1 725//1 694//1 +f 694//1 725//1 695//1 +f 725//1 726//1 695//1 +f 695//1 726//1 696//1 +f 726//1 727//1 696//1 +f 696//1 727//1 697//1 +f 727//1 728//1 697//1 +f 697//1 728//1 698//1 +f 728//1 729//1 698//1 +f 698//1 729//1 699//1 +f 729//1 730//1 699//1 +f 699//1 730//1 700//1 +f 730//1 731//1 700//1 +f 700//1 731//1 701//1 +f 731//1 732//1 701//1 +f 701//1 732//1 702//1 +f 732//1 733//1 702//1 +f 702//1 733//1 703//1 +f 733//1 734//1 703//1 +f 703//1 734//1 704//1 +f 734//1 735//1 704//1 +f 704//1 735//1 705//1 +f 735//1 736//1 705//1 +f 705//1 736//1 706//1 +f 736//1 737//1 706//1 +f 706//1 737//1 707//1 +f 737//1 738//1 707//1 +f 707//1 738//1 708//1 +f 738//1 739//1 708//1 +f 708//1 739//1 709//1 +f 739//1 740//1 709//1 +f 709//1 740//1 710//1 +f 740//1 741//1 710//1 +f 710//1 741//1 711//1 +f 741//1 742//1 711//1 +f 711//1 742//1 712//1 +f 742//1 743//1 712//1 +f 712//1 743//1 713//1 +f 743//1 744//1 713//1 +f 713//1 744//1 714//1 +f 744//1 745//1 714//1 +f 714//1 745//1 715//1 +f 745//1 746//1 715//1 +f 715//1 746//1 716//1 +f 746//1 747//1 716//1 +f 716//1 747//1 717//1 +f 747//1 748//1 717//1 +f 717//1 748//1 718//1 +f 748//1 749//1 718//1 +f 718//1 749//1 719//1 +f 749//1 750//1 719//1 +f 719//1 750//1 174//1 +f 750//1 173//1 174//1 +f 236//1 751//1 720//1 +f 751//1 752//1 720//1 +f 720//1 752//1 721//1 +f 752//1 753//1 721//1 +f 721//1 753//1 722//1 +f 753//1 754//1 722//1 +f 722//1 754//1 723//1 +f 754//1 755//1 723//1 +f 723//1 755//1 724//1 +f 755//1 756//1 724//1 +f 724//1 756//1 725//1 +f 756//1 757//1 725//1 +f 725//1 757//1 726//1 +f 757//1 758//1 726//1 +f 726//1 758//1 727//1 +f 758//1 759//1 727//1 +f 727//1 759//1 728//1 +f 759//1 760//1 728//1 +f 728//1 760//1 729//1 +f 760//1 761//1 729//1 +f 729//1 761//1 730//1 +f 761//1 762//1 730//1 +f 730//1 762//1 731//1 +f 762//1 763//1 731//1 +f 731//1 763//1 732//1 +f 763//1 764//1 732//1 +f 732//1 764//1 733//1 +f 764//1 765//1 733//1 +f 733//1 765//1 734//1 +f 765//1 766//1 734//1 +f 734//1 766//1 735//1 +f 766//1 767//1 735//1 +f 735//1 767//1 736//1 +f 767//1 768//1 736//1 +f 736//1 768//1 737//1 +f 768//1 769//1 737//1 +f 737//1 769//1 738//1 +f 769//1 770//1 738//1 +f 738//1 770//1 739//1 +f 770//1 771//1 739//1 +f 739//1 771//1 740//1 +f 771//1 772//1 740//1 +f 740//1 772//1 741//1 +f 772//1 773//1 741//1 +f 741//1 773//1 742//1 +f 773//1 774//1 742//1 +f 742//1 774//1 743//1 +f 774//1 775//1 743//1 +f 743//1 775//1 744//1 +f 775//1 776//1 744//1 +f 744//1 776//1 745//1 +f 776//1 777//1 745//1 +f 745//1 777//1 746//1 +f 777//1 778//1 746//1 +f 746//1 778//1 747//1 +f 778//1 779//1 747//1 +f 747//1 779//1 748//1 +f 779//1 780//1 748//1 +f 748//1 780//1 749//1 +f 780//1 781//1 749//1 +f 749//1 781//1 750//1 +f 781//1 782//1 750//1 +f 750//1 782//1 173//1 +f 782//1 172//1 173//1 +f 237//1 783//1 751//1 +f 783//1 784//1 751//1 +f 751//1 784//1 752//1 +f 784//1 785//1 752//1 +f 752//1 785//1 753//1 +f 785//1 786//1 753//1 +f 753//1 786//1 754//1 +f 786//1 787//1 754//1 +f 754//1 787//1 755//1 +f 787//1 788//1 755//1 +f 755//1 788//1 756//1 +f 788//1 789//1 756//1 +f 756//1 789//1 757//1 +f 789//1 790//1 757//1 +f 757//1 790//1 758//1 +f 790//1 791//1 758//1 +f 758//1 791//1 759//1 +f 791//1 792//1 759//1 +f 759//1 792//1 760//1 +f 792//1 793//1 760//1 +f 760//1 793//1 761//1 +f 793//1 794//1 761//1 +f 761//1 794//1 762//1 +f 794//1 795//1 762//1 +f 762//1 795//1 763//1 +f 795//1 796//1 763//1 +f 763//1 796//1 764//1 +f 796//1 797//1 764//1 +f 764//1 797//1 765//1 +f 797//1 798//1 765//1 +f 765//1 798//1 766//1 +f 798//1 799//1 766//1 +f 766//1 799//1 767//1 +f 799//1 800//1 767//1 +f 767//1 800//1 768//1 +f 800//1 801//1 768//1 +f 768//1 801//1 769//1 +f 801//1 802//1 769//1 +f 769//1 802//1 770//1 +f 802//1 803//1 770//1 +f 770//1 803//1 771//1 +f 803//1 804//1 771//1 +f 771//1 804//1 772//1 +f 804//1 805//1 772//1 +f 772//1 805//1 773//1 +f 805//1 806//1 773//1 +f 773//1 806//1 774//1 +f 806//1 807//1 774//1 +f 774//1 807//1 775//1 +f 807//1 808//1 775//1 +f 775//1 808//1 776//1 +f 808//1 809//1 776//1 +f 776//1 809//1 777//1 +f 809//1 810//1 777//1 +f 777//1 810//1 778//1 +f 810//1 811//1 778//1 +f 778//1 811//1 779//1 +f 811//1 812//1 779//1 +f 779//1 812//1 780//1 +f 812//1 813//1 780//1 +f 780//1 813//1 781//1 +f 813//1 814//1 781//1 +f 781//1 814//1 782//1 +f 814//1 815//1 782//1 +f 782//1 815//1 172//1 +f 815//1 171//1 172//1 +f 238//1 816//1 783//1 +f 816//1 817//1 783//1 +f 783//1 817//1 784//1 +f 817//1 818//1 784//1 +f 784//1 818//1 785//1 +f 818//1 819//1 785//1 +f 785//1 819//1 786//1 +f 819//1 820//1 786//1 +f 786//1 820//1 787//1 +f 820//1 821//1 787//1 +f 787//1 821//1 788//1 +f 821//1 822//1 788//1 +f 788//1 822//1 789//1 +f 822//1 823//1 789//1 +f 789//1 823//1 790//1 +f 823//1 824//1 790//1 +f 790//1 824//1 791//1 +f 824//1 825//1 791//1 +f 791//1 825//1 792//1 +f 825//1 826//1 792//1 +f 792//1 826//1 793//1 +f 826//1 827//1 793//1 +f 793//1 827//1 794//1 +f 827//1 828//1 794//1 +f 794//1 828//1 795//1 +f 828//1 829//1 795//1 +f 795//1 829//1 796//1 +f 829//1 830//1 796//1 +f 796//1 830//1 797//1 +f 830//1 831//1 797//1 +f 797//1 831//1 798//1 +f 831//1 832//1 798//1 +f 798//1 832//1 799//1 +f 832//1 833//1 799//1 +f 799//1 833//1 800//1 +f 833//1 834//1 800//1 +f 800//1 834//1 801//1 +f 834//1 835//1 801//1 +f 801//1 835//1 802//1 +f 835//1 836//1 802//1 +f 802//1 836//1 803//1 +f 836//1 837//1 803//1 +f 803//1 837//1 804//1 +f 837//1 838//1 804//1 +f 804//1 838//1 805//1 +f 838//1 839//1 805//1 +f 805//1 839//1 806//1 +f 839//1 840//1 806//1 +f 806//1 840//1 807//1 +f 840//1 841//1 807//1 +f 807//1 841//1 808//1 +f 841//1 842//1 808//1 +f 808//1 842//1 809//1 +f 842//1 843//1 809//1 +f 809//1 843//1 810//1 +f 843//1 844//1 810//1 +f 810//1 844//1 811//1 +f 844//1 845//1 811//1 +f 811//1 845//1 812//1 +f 845//1 846//1 812//1 +f 812//1 846//1 813//1 +f 846//1 847//1 813//1 +f 813//1 847//1 814//1 +f 847//1 848//1 814//1 +f 814//1 848//1 815//1 +f 848//1 849//1 815//1 +f 815//1 849//1 171//1 +f 849//1 170//1 171//1 +f 239//1 850//1 816//1 +f 850//1 851//1 816//1 +f 816//1 851//1 817//1 +f 851//1 852//1 817//1 +f 817//1 852//1 818//1 +f 852//1 853//1 818//1 +f 818//1 853//1 819//1 +f 853//1 854//1 819//1 +f 819//1 854//1 820//1 +f 854//1 855//1 820//1 +f 820//1 855//1 821//1 +f 855//1 856//1 821//1 +f 821//1 856//1 822//1 +f 856//1 857//1 822//1 +f 822//1 857//1 823//1 +f 857//1 858//1 823//1 +f 823//1 858//1 824//1 +f 858//1 859//1 824//1 +f 824//1 859//1 825//1 +f 859//1 860//1 825//1 +f 825//1 860//1 826//1 +f 860//1 861//1 826//1 +f 826//1 861//1 827//1 +f 861//1 862//1 827//1 +f 827//1 862//1 828//1 +f 862//1 863//1 828//1 +f 828//1 863//1 829//1 +f 863//1 864//1 829//1 +f 829//1 864//1 830//1 +f 864//1 865//1 830//1 +f 830//1 865//1 831//1 +f 865//1 866//1 831//1 +f 831//1 866//1 832//1 +f 866//1 867//1 832//1 +f 832//1 867//1 833//1 +f 867//1 868//1 833//1 +f 833//1 868//1 834//1 +f 868//1 869//1 834//1 +f 834//1 869//1 835//1 +f 869//1 870//1 835//1 +f 835//1 870//1 836//1 +f 870//1 871//1 836//1 +f 836//1 871//1 837//1 +f 871//1 872//1 837//1 +f 837//1 872//1 838//1 +f 872//1 873//1 838//1 +f 838//1 873//1 839//1 +f 873//1 874//1 839//1 +f 839//1 874//1 840//1 +f 874//1 875//1 840//1 +f 840//1 875//1 841//1 +f 875//1 876//1 841//1 +f 841//1 876//1 842//1 +f 876//1 877//1 842//1 +f 842//1 877//1 843//1 +f 877//1 878//1 843//1 +f 843//1 878//1 844//1 +f 878//1 879//1 844//1 +f 844//1 879//1 845//1 +f 879//1 880//1 845//1 +f 845//1 880//1 846//1 +f 880//1 881//1 846//1 +f 846//1 881//1 847//1 +f 881//1 882//1 847//1 +f 847//1 882//1 848//1 +f 882//1 883//1 848//1 +f 848//1 883//1 849//1 +f 883//1 884//1 849//1 +f 849//1 884//1 170//1 +f 884//1 169//1 170//1 +f 240//1 885//1 850//1 +f 885//1 886//1 850//1 +f 850//1 886//1 851//1 +f 886//1 887//1 851//1 +f 851//1 887//1 852//1 +f 887//1 888//1 852//1 +f 852//1 888//1 853//1 +f 888//1 889//1 853//1 +f 853//1 889//1 854//1 +f 889//1 890//1 854//1 +f 854//1 890//1 855//1 +f 890//1 891//1 855//1 +f 855//1 891//1 856//1 +f 891//1 892//1 856//1 +f 856//1 892//1 857//1 +f 892//1 893//1 857//1 +f 857//1 893//1 858//1 +f 893//1 894//1 858//1 +f 858//1 894//1 859//1 +f 894//1 895//1 859//1 +f 859//1 895//1 860//1 +f 895//1 896//1 860//1 +f 860//1 896//1 861//1 +f 896//1 897//1 861//1 +f 861//1 897//1 862//1 +f 897//1 898//1 862//1 +f 862//1 898//1 863//1 +f 898//1 899//1 863//1 +f 863//1 899//1 864//1 +f 899//1 900//1 864//1 +f 864//1 900//1 865//1 +f 900//1 901//1 865//1 +f 865//1 901//1 866//1 +f 901//1 902//1 866//1 +f 866//1 902//1 867//1 +f 902//1 903//1 867//1 +f 867//1 903//1 868//1 +f 903//1 904//1 868//1 +f 868//1 904//1 869//1 +f 904//1 905//1 869//1 +f 869//1 905//1 870//1 +f 905//1 906//1 870//1 +f 870//1 906//1 871//1 +f 906//1 907//1 871//1 +f 871//1 907//1 872//1 +f 907//1 908//1 872//1 +f 872//1 908//1 873//1 +f 908//1 909//1 873//1 +f 873//1 909//1 874//1 +f 909//1 910//1 874//1 +f 874//1 910//1 875//1 +f 910//1 911//1 875//1 +f 875//1 911//1 876//1 +f 911//1 912//1 876//1 +f 876//1 912//1 877//1 +f 912//1 913//1 877//1 +f 877//1 913//1 878//1 +f 913//1 914//1 878//1 +f 878//1 914//1 879//1 +f 914//1 915//1 879//1 +f 879//1 915//1 880//1 +f 915//1 916//1 880//1 +f 880//1 916//1 881//1 +f 916//1 917//1 881//1 +f 881//1 917//1 882//1 +f 917//1 918//1 882//1 +f 882//1 918//1 883//1 +f 918//1 919//1 883//1 +f 883//1 919//1 884//1 +f 919//1 920//1 884//1 +f 884//1 920//1 169//1 +f 920//1 168//1 169//1 +f 241//1 921//1 885//1 +f 921//1 922//1 885//1 +f 885//1 922//1 886//1 +f 922//1 923//1 886//1 +f 886//1 923//1 887//1 +f 923//1 924//1 887//1 +f 887//1 924//1 888//1 +f 924//1 925//1 888//1 +f 888//1 925//1 889//1 +f 925//1 926//1 889//1 +f 889//1 926//1 890//1 +f 926//1 927//1 890//1 +f 890//1 927//1 891//1 +f 927//1 928//1 891//1 +f 891//1 928//1 892//1 +f 928//1 929//1 892//1 +f 892//1 929//1 893//1 +f 929//1 930//1 893//1 +f 893//1 930//1 894//1 +f 930//1 931//1 894//1 +f 894//1 931//1 895//1 +f 931//1 932//1 895//1 +f 895//1 932//1 896//1 +f 932//1 933//1 896//1 +f 896//1 933//1 897//1 +f 933//1 934//1 897//1 +f 897//1 934//1 898//1 +f 934//1 935//1 898//1 +f 898//1 935//1 899//1 +f 935//1 936//1 899//1 +f 899//1 936//1 900//1 +f 936//1 937//1 900//1 +f 900//1 937//1 901//1 +f 937//1 938//1 901//1 +f 901//1 938//1 902//1 +f 938//1 939//1 902//1 +f 902//1 939//1 903//1 +f 939//1 940//1 903//1 +f 903//1 940//1 904//1 +f 940//1 941//1 904//1 +f 904//1 941//1 905//1 +f 941//1 942//1 905//1 +f 905//1 942//1 906//1 +f 942//1 943//1 906//1 +f 906//1 943//1 907//1 +f 943//1 944//1 907//1 +f 907//1 944//1 908//1 +f 944//1 945//1 908//1 +f 908//1 945//1 909//1 +f 945//1 946//1 909//1 +f 909//1 946//1 910//1 +f 946//1 947//1 910//1 +f 910//1 947//1 911//1 +f 947//1 948//1 911//1 +f 911//1 948//1 912//1 +f 948//1 949//1 912//1 +f 912//1 949//1 913//1 +f 949//1 950//1 913//1 +f 913//1 950//1 914//1 +f 950//1 951//1 914//1 +f 914//1 951//1 915//1 +f 951//1 952//1 915//1 +f 915//1 952//1 916//1 +f 952//1 953//1 916//1 +f 916//1 953//1 917//1 +f 953//1 954//1 917//1 +f 917//1 954//1 918//1 +f 954//1 955//1 918//1 +f 918//1 955//1 919//1 +f 955//1 956//1 919//1 +f 919//1 956//1 920//1 +f 956//1 957//1 920//1 +f 920//1 957//1 168//1 +f 957//1 167//1 168//1 +f 242//1 958//1 921//1 +f 958//1 959//1 921//1 +f 921//1 959//1 922//1 +f 959//1 960//1 922//1 +f 922//1 960//1 923//1 +f 960//1 961//1 923//1 +f 923//1 961//1 924//1 +f 961//1 962//1 924//1 +f 924//1 962//1 925//1 +f 962//1 963//1 925//1 +f 925//1 963//1 926//1 +f 963//1 964//1 926//1 +f 926//1 964//1 927//1 +f 964//1 965//1 927//1 +f 927//1 965//1 928//1 +f 965//1 966//1 928//1 +f 928//1 966//1 929//1 +f 966//1 967//1 929//1 +f 929//1 967//1 930//1 +f 967//1 968//1 930//1 +f 930//1 968//1 931//1 +f 968//1 969//1 931//1 +f 931//1 969//1 932//1 +f 969//1 970//1 932//1 +f 932//1 970//1 933//1 +f 970//1 971//1 933//1 +f 933//1 971//1 934//1 +f 971//1 972//1 934//1 +f 934//1 972//1 935//1 +f 972//1 973//1 935//1 +f 935//1 973//1 936//1 +f 973//1 974//1 936//1 +f 936//1 974//1 937//1 +f 974//1 975//1 937//1 +f 937//1 975//1 938//1 +f 975//1 976//1 938//1 +f 938//1 976//1 939//1 +f 976//1 977//1 939//1 +f 939//1 977//1 940//1 +f 977//1 978//1 940//1 +f 940//1 978//1 941//1 +f 978//1 979//1 941//1 +f 941//1 979//1 942//1 +f 979//1 980//1 942//1 +f 942//1 980//1 943//1 +f 980//1 981//1 943//1 +f 943//1 981//1 944//1 +f 981//1 982//1 944//1 +f 944//1 982//1 945//1 +f 982//1 983//1 945//1 +f 945//1 983//1 946//1 +f 983//1 984//1 946//1 +f 946//1 984//1 947//1 +f 984//1 985//1 947//1 +f 947//1 985//1 948//1 +f 985//1 986//1 948//1 +f 948//1 986//1 949//1 +f 986//1 987//1 949//1 +f 949//1 987//1 950//1 +f 987//1 988//1 950//1 +f 950//1 988//1 951//1 +f 988//1 989//1 951//1 +f 951//1 989//1 952//1 +f 989//1 990//1 952//1 +f 952//1 990//1 953//1 +f 990//1 991//1 953//1 +f 953//1 991//1 954//1 +f 991//1 992//1 954//1 +f 954//1 992//1 955//1 +f 992//1 993//1 955//1 +f 955//1 993//1 956//1 +f 993//1 994//1 956//1 +f 956//1 994//1 957//1 +f 994//1 995//1 957//1 +f 957//1 995//1 167//1 +f 995//1 166//1 167//1 +f 243//1 996//1 958//1 +f 996//1 997//1 958//1 +f 958//1 997//1 959//1 +f 997//1 998//1 959//1 +f 959//1 998//1 960//1 +f 998//1 999//1 960//1 +f 960//1 999//1 961//1 +f 999//1 1000//1 961//1 +f 961//1 1000//1 962//1 +f 1000//1 1001//1 962//1 +f 962//1 1001//1 963//1 +f 1001//1 1002//1 963//1 +f 963//1 1002//1 964//1 +f 1002//1 1003//1 964//1 +f 964//1 1003//1 965//1 +f 1003//1 1004//1 965//1 +f 965//1 1004//1 966//1 +f 1004//1 1005//1 966//1 +f 966//1 1005//1 967//1 +f 1005//1 1006//1 967//1 +f 967//1 1006//1 968//1 +f 1006//1 1007//1 968//1 +f 968//1 1007//1 969//1 +f 1007//1 1008//1 969//1 +f 969//1 1008//1 970//1 +f 1008//1 1009//1 970//1 +f 970//1 1009//1 971//1 +f 1009//1 1010//1 971//1 +f 971//1 1010//1 972//1 +f 1010//1 1011//1 972//1 +f 972//1 1011//1 973//1 +f 1011//1 1012//1 973//1 +f 973//1 1012//1 974//1 +f 1012//1 1013//1 974//1 +f 974//1 1013//1 975//1 +f 1013//1 1014//1 975//1 +f 975//1 1014//1 976//1 +f 1014//1 1015//1 976//1 +f 976//1 1015//1 977//1 +f 1015//1 1016//1 977//1 +f 977//1 1016//1 978//1 +f 1016//1 1017//1 978//1 +f 978//1 1017//1 979//1 +f 1017//1 1018//1 979//1 +f 979//1 1018//1 980//1 +f 1018//1 1019//1 980//1 +f 980//1 1019//1 981//1 +f 1019//1 1020//1 981//1 +f 981//1 1020//1 982//1 +f 1020//1 1021//1 982//1 +f 982//1 1021//1 983//1 +f 1021//1 1022//1 983//1 +f 983//1 1022//1 984//1 +f 1022//1 1023//1 984//1 +f 984//1 1023//1 985//1 +f 1023//1 1024//1 985//1 +f 985//1 1024//1 986//1 +f 1024//1 1025//1 986//1 +f 986//1 1025//1 987//1 +f 1025//1 1026//1 987//1 +f 987//1 1026//1 988//1 +f 1026//1 1027//1 988//1 +f 988//1 1027//1 989//1 +f 1027//1 1028//1 989//1 +f 989//1 1028//1 990//1 +f 1028//1 1029//1 990//1 +f 990//1 1029//1 991//1 +f 1029//1 1030//1 991//1 +f 991//1 1030//1 992//1 +f 1030//1 1031//1 992//1 +f 992//1 1031//1 993//1 +f 1031//1 1032//1 993//1 +f 993//1 1032//1 994//1 +f 1032//1 1033//1 994//1 +f 994//1 1033//1 995//1 +f 1033//1 1034//1 995//1 +f 995//1 1034//1 166//1 +f 1034//1 165//1 166//1 +f 244//1 1035//1 996//1 +f 1035//1 1036//1 996//1 +f 996//1 1036//1 997//1 +f 1036//1 1037//1 997//1 +f 997//1 1037//1 998//1 +f 1037//1 1038//1 998//1 +f 998//1 1038//1 999//1 +f 1038//1 1039//1 999//1 +f 999//1 1039//1 1000//1 +f 1039//1 1040//1 1000//1 +f 1000//1 1040//1 1001//1 +f 1040//1 1041//1 1001//1 +f 1001//1 1041//1 1002//1 +f 1041//1 1042//1 1002//1 +f 1002//1 1042//1 1003//1 +f 1042//1 1043//1 1003//1 +f 1003//1 1043//1 1004//1 +f 1043//1 1044//1 1004//1 +f 1004//1 1044//1 1005//1 +f 1044//1 1045//1 1005//1 +f 1005//1 1045//1 1006//1 +f 1045//1 1046//1 1006//1 +f 1006//1 1046//1 1007//1 +f 1046//1 1047//1 1007//1 +f 1007//1 1047//1 1008//1 +f 1047//1 1048//1 1008//1 +f 1008//1 1048//1 1009//1 +f 1048//1 1049//1 1009//1 +f 1009//1 1049//1 1010//1 +f 1049//1 1050//1 1010//1 +f 1010//1 1050//1 1011//1 +f 1050//1 1051//1 1011//1 +f 1011//1 1051//1 1012//1 +f 1051//1 1052//1 1012//1 +f 1012//1 1052//1 1013//1 +f 1052//1 1053//1 1013//1 +f 1013//1 1053//1 1014//1 +f 1053//1 1054//1 1014//1 +f 1014//1 1054//1 1015//1 +f 1054//1 1055//1 1015//1 +f 1015//1 1055//1 1016//1 +f 1055//1 1056//1 1016//1 +f 1016//1 1056//1 1017//1 +f 1056//1 1057//1 1017//1 +f 1017//1 1057//1 1018//1 +f 1057//1 1058//1 1018//1 +f 1018//1 1058//1 1019//1 +f 1058//1 1059//1 1019//1 +f 1019//1 1059//1 1020//1 +f 1059//1 1060//1 1020//1 +f 1020//1 1060//1 1021//1 +f 1060//1 1061//1 1021//1 +f 1021//1 1061//1 1022//1 +f 1061//1 1062//1 1022//1 +f 1022//1 1062//1 1023//1 +f 1062//1 1063//1 1023//1 +f 1023//1 1063//1 1024//1 +f 1063//1 1064//1 1024//1 +f 1024//1 1064//1 1025//1 +f 1064//1 1065//1 1025//1 +f 1025//1 1065//1 1026//1 +f 1065//1 1066//1 1026//1 +f 1026//1 1066//1 1027//1 +f 1066//1 1067//1 1027//1 +f 1027//1 1067//1 1028//1 +f 1067//1 1068//1 1028//1 +f 1028//1 1068//1 1029//1 +f 1068//1 1069//1 1029//1 +f 1029//1 1069//1 1030//1 +f 1069//1 1070//1 1030//1 +f 1030//1 1070//1 1031//1 +f 1070//1 1071//1 1031//1 +f 1031//1 1071//1 1032//1 +f 1071//1 1072//1 1032//1 +f 1032//1 1072//1 1033//1 +f 1072//1 1073//1 1033//1 +f 1033//1 1073//1 1034//1 +f 1073//1 1074//1 1034//1 +f 1034//1 1074//1 165//1 +f 1074//1 164//1 165//1 +f 245//1 1075//1 1035//1 +f 1075//1 1076//1 1035//1 +f 1035//1 1076//1 1036//1 +f 1076//1 1077//1 1036//1 +f 1036//1 1077//1 1037//1 +f 1077//1 1078//1 1037//1 +f 1037//1 1078//1 1038//1 +f 1078//1 1079//1 1038//1 +f 1038//1 1079//1 1039//1 +f 1079//1 1080//1 1039//1 +f 1039//1 1080//1 1040//1 +f 1080//1 1081//1 1040//1 +f 1040//1 1081//1 1041//1 +f 1081//1 1082//1 1041//1 +f 1041//1 1082//1 1042//1 +f 1082//1 1083//1 1042//1 +f 1042//1 1083//1 1043//1 +f 1083//1 1084//1 1043//1 +f 1043//1 1084//1 1044//1 +f 1084//1 1085//1 1044//1 +f 1044//1 1085//1 1045//1 +f 1085//1 1086//1 1045//1 +f 1045//1 1086//1 1046//1 +f 1086//1 1087//1 1046//1 +f 1046//1 1087//1 1047//1 +f 1087//1 1088//1 1047//1 +f 1047//1 1088//1 1048//1 +f 1088//1 1089//1 1048//1 +f 1048//1 1089//1 1049//1 +f 1089//1 1090//1 1049//1 +f 1049//1 1090//1 1050//1 +f 1090//1 1091//1 1050//1 +f 1050//1 1091//1 1051//1 +f 1091//1 1092//1 1051//1 +f 1051//1 1092//1 1052//1 +f 1092//1 1093//1 1052//1 +f 1052//1 1093//1 1053//1 +f 1093//1 1094//1 1053//1 +f 1053//1 1094//1 1054//1 +f 1094//1 1095//1 1054//1 +f 1054//1 1095//1 1055//1 +f 1095//1 1096//1 1055//1 +f 1055//1 1096//1 1056//1 +f 1096//1 1097//1 1056//1 +f 1056//1 1097//1 1057//1 +f 1097//1 1098//1 1057//1 +f 1057//1 1098//1 1058//1 +f 1098//1 1099//1 1058//1 +f 1058//1 1099//1 1059//1 +f 1099//1 1100//1 1059//1 +f 1059//1 1100//1 1060//1 +f 1100//1 1101//1 1060//1 +f 1060//1 1101//1 1061//1 +f 1101//1 1102//1 1061//1 +f 1061//1 1102//1 1062//1 +f 1102//1 1103//1 1062//1 +f 1062//1 1103//1 1063//1 +f 1103//1 1104//1 1063//1 +f 1063//1 1104//1 1064//1 +f 1104//1 1105//1 1064//1 +f 1064//1 1105//1 1065//1 +f 1105//1 1106//1 1065//1 +f 1065//1 1106//1 1066//1 +f 1106//1 1107//1 1066//1 +f 1066//1 1107//1 1067//1 +f 1107//1 1108//1 1067//1 +f 1067//1 1108//1 1068//1 +f 1108//1 1109//1 1068//1 +f 1068//1 1109//1 1069//1 +f 1109//1 1110//1 1069//1 +f 1069//1 1110//1 1070//1 +f 1110//1 1111//1 1070//1 +f 1070//1 1111//1 1071//1 +f 1111//1 1112//1 1071//1 +f 1071//1 1112//1 1072//1 +f 1112//1 1113//1 1072//1 +f 1072//1 1113//1 1073//1 +f 1113//1 1114//1 1073//1 +f 1073//1 1114//1 1074//1 +f 1114//1 1115//1 1074//1 +f 1074//1 1115//1 164//1 +f 1115//1 163//1 164//1 +f 246//1 1116//1 1075//1 +f 1116//1 1117//1 1075//1 +f 1075//1 1117//1 1076//1 +f 1117//1 1118//1 1076//1 +f 1076//1 1118//1 1077//1 +f 1118//1 1119//1 1077//1 +f 1077//1 1119//1 1078//1 +f 1119//1 1120//1 1078//1 +f 1078//1 1120//1 1079//1 +f 1120//1 1121//1 1079//1 +f 1079//1 1121//1 1080//1 +f 1121//1 1122//1 1080//1 +f 1080//1 1122//1 1081//1 +f 1122//1 1123//1 1081//1 +f 1081//1 1123//1 1082//1 +f 1123//1 1124//1 1082//1 +f 1082//1 1124//1 1083//1 +f 1124//1 1125//1 1083//1 +f 1083//1 1125//1 1084//1 +f 1125//1 1126//1 1084//1 +f 1084//1 1126//1 1085//1 +f 1126//1 1127//1 1085//1 +f 1085//1 1127//1 1086//1 +f 1127//1 1128//1 1086//1 +f 1086//1 1128//1 1087//1 +f 1128//1 1129//1 1087//1 +f 1087//1 1129//1 1088//1 +f 1129//1 1130//1 1088//1 +f 1088//1 1130//1 1089//1 +f 1130//1 1131//1 1089//1 +f 1089//1 1131//1 1090//1 +f 1131//1 1132//1 1090//1 +f 1090//1 1132//1 1091//1 +f 1132//1 1133//1 1091//1 +f 1091//1 1133//1 1092//1 +f 1133//1 1134//1 1092//1 +f 1092//1 1134//1 1093//1 +f 1134//1 1135//1 1093//1 +f 1093//1 1135//1 1094//1 +f 1135//1 1136//1 1094//1 +f 1094//1 1136//1 1095//1 +f 1136//1 1137//1 1095//1 +f 1095//1 1137//1 1096//1 +f 1137//1 1138//1 1096//1 +f 1096//1 1138//1 1097//1 +f 1138//1 1139//1 1097//1 +f 1097//1 1139//1 1098//1 +f 1139//1 1140//1 1098//1 +f 1098//1 1140//1 1099//1 +f 1140//1 1141//1 1099//1 +f 1099//1 1141//1 1100//1 +f 1141//1 1142//1 1100//1 +f 1100//1 1142//1 1101//1 +f 1142//1 1143//1 1101//1 +f 1101//1 1143//1 1102//1 +f 1143//1 1144//1 1102//1 +f 1102//1 1144//1 1103//1 +f 1144//1 1145//1 1103//1 +f 1103//1 1145//1 1104//1 +f 1145//1 1146//1 1104//1 +f 1104//1 1146//1 1105//1 +f 1146//1 1147//1 1105//1 +f 1105//1 1147//1 1106//1 +f 1147//1 1148//1 1106//1 +f 1106//1 1148//1 1107//1 +f 1148//1 1149//1 1107//1 +f 1107//1 1149//1 1108//1 +f 1149//1 1150//1 1108//1 +f 1108//1 1150//1 1109//1 +f 1150//1 1151//1 1109//1 +f 1109//1 1151//1 1110//1 +f 1151//1 1152//1 1110//1 +f 1110//1 1152//1 1111//1 +f 1152//1 1153//1 1111//1 +f 1111//1 1153//1 1112//1 +f 1153//1 1154//1 1112//1 +f 1112//1 1154//1 1113//1 +f 1154//1 1155//1 1113//1 +f 1113//1 1155//1 1114//1 +f 1155//1 1156//1 1114//1 +f 1114//1 1156//1 1115//1 +f 1156//1 1157//1 1115//1 +f 1115//1 1157//1 163//1 +f 1157//1 162//1 163//1 +f 247//1 1158//1 1116//1 +f 1158//1 1159//1 1116//1 +f 1116//1 1159//1 1117//1 +f 1159//1 1160//1 1117//1 +f 1117//1 1160//1 1118//1 +f 1160//1 1161//1 1118//1 +f 1118//1 1161//1 1119//1 +f 1161//1 1162//1 1119//1 +f 1119//1 1162//1 1120//1 +f 1162//1 1163//1 1120//1 +f 1120//1 1163//1 1121//1 +f 1163//1 1164//1 1121//1 +f 1121//1 1164//1 1122//1 +f 1164//1 1165//1 1122//1 +f 1122//1 1165//1 1123//1 +f 1165//1 1166//1 1123//1 +f 1123//1 1166//1 1124//1 +f 1166//1 1167//1 1124//1 +f 1124//1 1167//1 1125//1 +f 1167//1 1168//1 1125//1 +f 1125//1 1168//1 1126//1 +f 1168//1 1169//1 1126//1 +f 1126//1 1169//1 1127//1 +f 1169//1 1170//1 1127//1 +f 1127//1 1170//1 1128//1 +f 1170//1 1171//1 1128//1 +f 1128//1 1171//1 1129//1 +f 1171//1 1172//1 1129//1 +f 1129//1 1172//1 1130//1 +f 1172//1 1173//1 1130//1 +f 1130//1 1173//1 1131//1 +f 1173//1 1174//1 1131//1 +f 1131//1 1174//1 1132//1 +f 1174//1 1175//1 1132//1 +f 1132//1 1175//1 1133//1 +f 1175//1 1176//1 1133//1 +f 1133//1 1176//1 1134//1 +f 1176//1 1177//1 1134//1 +f 1134//1 1177//1 1135//1 +f 1177//1 1178//1 1135//1 +f 1135//1 1178//1 1136//1 +f 1178//1 1179//1 1136//1 +f 1136//1 1179//1 1137//1 +f 1179//1 1180//1 1137//1 +f 1137//1 1180//1 1138//1 +f 1180//1 1181//1 1138//1 +f 1138//1 1181//1 1139//1 +f 1181//1 1182//1 1139//1 +f 1139//1 1182//1 1140//1 +f 1182//1 1183//1 1140//1 +f 1140//1 1183//1 1141//1 +f 1183//1 1184//1 1141//1 +f 1141//1 1184//1 1142//1 +f 1184//1 1185//1 1142//1 +f 1142//1 1185//1 1143//1 +f 1185//1 1186//1 1143//1 +f 1143//1 1186//1 1144//1 +f 1186//1 1187//1 1144//1 +f 1144//1 1187//1 1145//1 +f 1187//1 1188//1 1145//1 +f 1145//1 1188//1 1146//1 +f 1188//1 1189//1 1146//1 +f 1146//1 1189//1 1147//1 +f 1189//1 1190//1 1147//1 +f 1147//1 1190//1 1148//1 +f 1190//1 1191//1 1148//1 +f 1148//1 1191//1 1149//1 +f 1191//1 1192//1 1149//1 +f 1149//1 1192//1 1150//1 +f 1192//1 1193//1 1150//1 +f 1150//1 1193//1 1151//1 +f 1193//1 1194//1 1151//1 +f 1151//1 1194//1 1152//1 +f 1194//1 1195//1 1152//1 +f 1152//1 1195//1 1153//1 +f 1195//1 1196//1 1153//1 +f 1153//1 1196//1 1154//1 +f 1196//1 1197//1 1154//1 +f 1154//1 1197//1 1155//1 +f 1197//1 1198//1 1155//1 +f 1155//1 1198//1 1156//1 +f 1198//1 1199//1 1156//1 +f 1156//1 1199//1 1157//1 +f 1199//1 1200//1 1157//1 +f 1157//1 1200//1 162//1 +f 1200//1 161//1 162//1 +f 248//1 1201//1 1158//1 +f 1201//1 1202//1 1158//1 +f 1158//1 1202//1 1159//1 +f 1202//1 1203//1 1159//1 +f 1159//1 1203//1 1160//1 +f 1203//1 1204//1 1160//1 +f 1160//1 1204//1 1161//1 +f 1204//1 1205//1 1161//1 +f 1161//1 1205//1 1162//1 +f 1205//1 1206//1 1162//1 +f 1162//1 1206//1 1163//1 +f 1206//1 1207//1 1163//1 +f 1163//1 1207//1 1164//1 +f 1207//1 1208//1 1164//1 +f 1164//1 1208//1 1165//1 +f 1208//1 1209//1 1165//1 +f 1165//1 1209//1 1166//1 +f 1209//1 1210//1 1166//1 +f 1166//1 1210//1 1167//1 +f 1210//1 1211//1 1167//1 +f 1167//1 1211//1 1168//1 +f 1211//1 1212//1 1168//1 +f 1168//1 1212//1 1169//1 +f 1212//1 1213//1 1169//1 +f 1169//1 1213//1 1170//1 +f 1213//1 1214//1 1170//1 +f 1170//1 1214//1 1171//1 +f 1214//1 1215//1 1171//1 +f 1171//1 1215//1 1172//1 +f 1215//1 1216//1 1172//1 +f 1172//1 1216//1 1173//1 +f 1216//1 1217//1 1173//1 +f 1173//1 1217//1 1174//1 +f 1217//1 1218//1 1174//1 +f 1174//1 1218//1 1175//1 +f 1218//1 1219//1 1175//1 +f 1175//1 1219//1 1176//1 +f 1219//1 1220//1 1176//1 +f 1176//1 1220//1 1177//1 +f 1220//1 1221//1 1177//1 +f 1177//1 1221//1 1178//1 +f 1221//1 1222//1 1178//1 +f 1178//1 1222//1 1179//1 +f 1222//1 1223//1 1179//1 +f 1179//1 1223//1 1180//1 +f 1223//1 1224//1 1180//1 +f 1180//1 1224//1 1181//1 +f 1224//1 1225//1 1181//1 +f 1181//1 1225//1 1182//1 +f 1225//1 1226//1 1182//1 +f 1182//1 1226//1 1183//1 +f 1226//1 1227//1 1183//1 +f 1183//1 1227//1 1184//1 +f 1227//1 1228//1 1184//1 +f 1184//1 1228//1 1185//1 +f 1228//1 1229//1 1185//1 +f 1185//1 1229//1 1186//1 +f 1229//1 1230//1 1186//1 +f 1186//1 1230//1 1187//1 +f 1230//1 1231//1 1187//1 +f 1187//1 1231//1 1188//1 +f 1231//1 1232//1 1188//1 +f 1188//1 1232//1 1189//1 +f 1232//1 1233//1 1189//1 +f 1189//1 1233//1 1190//1 +f 1233//1 1234//1 1190//1 +f 1190//1 1234//1 1191//1 +f 1234//1 1235//1 1191//1 +f 1191//1 1235//1 1192//1 +f 1235//1 1236//1 1192//1 +f 1192//1 1236//1 1193//1 +f 1236//1 1237//1 1193//1 +f 1193//1 1237//1 1194//1 +f 1237//1 1238//1 1194//1 +f 1194//1 1238//1 1195//1 +f 1238//1 1239//1 1195//1 +f 1195//1 1239//1 1196//1 +f 1239//1 1240//1 1196//1 +f 1196//1 1240//1 1197//1 +f 1240//1 1241//1 1197//1 +f 1197//1 1241//1 1198//1 +f 1241//1 1242//1 1198//1 +f 1198//1 1242//1 1199//1 +f 1242//1 1243//1 1199//1 +f 1199//1 1243//1 1200//1 +f 1243//1 1244//1 1200//1 +f 1200//1 1244//1 161//1 +f 1244//1 160//1 161//1 +f 249//1 1245//1 1201//1 +f 1245//1 1246//1 1201//1 +f 1201//1 1246//1 1202//1 +f 1246//1 1247//1 1202//1 +f 1202//1 1247//1 1203//1 +f 1247//1 1248//1 1203//1 +f 1203//1 1248//1 1204//1 +f 1248//1 1249//1 1204//1 +f 1204//1 1249//1 1205//1 +f 1249//1 1250//1 1205//1 +f 1205//1 1250//1 1206//1 +f 1250//1 1251//1 1206//1 +f 1206//1 1251//1 1207//1 +f 1251//1 1252//1 1207//1 +f 1207//1 1252//1 1208//1 +f 1252//1 1253//1 1208//1 +f 1208//1 1253//1 1209//1 +f 1253//1 1254//1 1209//1 +f 1209//1 1254//1 1210//1 +f 1254//1 1255//1 1210//1 +f 1210//1 1255//1 1211//1 +f 1255//1 1256//1 1211//1 +f 1211//1 1256//1 1212//1 +f 1256//1 1257//1 1212//1 +f 1212//1 1257//1 1213//1 +f 1257//1 1258//1 1213//1 +f 1213//1 1258//1 1214//1 +f 1258//1 1259//1 1214//1 +f 1214//1 1259//1 1215//1 +f 1259//1 1260//1 1215//1 +f 1215//1 1260//1 1216//1 +f 1260//1 1261//1 1216//1 +f 1216//1 1261//1 1217//1 +f 1261//1 1262//1 1217//1 +f 1217//1 1262//1 1218//1 +f 1262//1 1263//1 1218//1 +f 1218//1 1263//1 1219//1 +f 1263//1 1264//1 1219//1 +f 1219//1 1264//1 1220//1 +f 1264//1 1265//1 1220//1 +f 1220//1 1265//1 1221//1 +f 1265//1 1266//1 1221//1 +f 1221//1 1266//1 1222//1 +f 1266//1 1267//1 1222//1 +f 1222//1 1267//1 1223//1 +f 1267//1 1268//1 1223//1 +f 1223//1 1268//1 1224//1 +f 1268//1 1269//1 1224//1 +f 1224//1 1269//1 1225//1 +f 1269//1 1270//1 1225//1 +f 1225//1 1270//1 1226//1 +f 1270//1 1271//1 1226//1 +f 1226//1 1271//1 1227//1 +f 1271//1 1272//1 1227//1 +f 1227//1 1272//1 1228//1 +f 1272//1 1273//1 1228//1 +f 1228//1 1273//1 1229//1 +f 1273//1 1274//1 1229//1 +f 1229//1 1274//1 1230//1 +f 1274//1 1275//1 1230//1 +f 1230//1 1275//1 1231//1 +f 1275//1 1276//1 1231//1 +f 1231//1 1276//1 1232//1 +f 1276//1 1277//1 1232//1 +f 1232//1 1277//1 1233//1 +f 1277//1 1278//1 1233//1 +f 1233//1 1278//1 1234//1 +f 1278//1 1279//1 1234//1 +f 1234//1 1279//1 1235//1 +f 1279//1 1280//1 1235//1 +f 1235//1 1280//1 1236//1 +f 1280//1 1281//1 1236//1 +f 1236//1 1281//1 1237//1 +f 1281//1 1282//1 1237//1 +f 1237//1 1282//1 1238//1 +f 1282//1 1283//1 1238//1 +f 1238//1 1283//1 1239//1 +f 1283//1 1284//1 1239//1 +f 1239//1 1284//1 1240//1 +f 1284//1 1285//1 1240//1 +f 1240//1 1285//1 1241//1 +f 1285//1 1286//1 1241//1 +f 1241//1 1286//1 1242//1 +f 1286//1 1287//1 1242//1 +f 1242//1 1287//1 1243//1 +f 1287//1 1288//1 1243//1 +f 1243//1 1288//1 1244//1 +f 1288//1 1289//1 1244//1 +f 1244//1 1289//1 160//1 +f 1289//1 159//1 160//1 +f 250//1 1290//1 1245//1 +f 1290//1 1291//1 1245//1 +f 1245//1 1291//1 1246//1 +f 1291//1 1292//1 1246//1 +f 1246//1 1292//1 1247//1 +f 1292//1 1293//1 1247//1 +f 1247//1 1293//1 1248//1 +f 1293//1 1294//1 1248//1 +f 1248//1 1294//1 1249//1 +f 1294//1 1295//1 1249//1 +f 1249//1 1295//1 1250//1 +f 1295//1 1296//1 1250//1 +f 1250//1 1296//1 1251//1 +f 1296//1 1297//1 1251//1 +f 1251//1 1297//1 1252//1 +f 1297//1 1298//1 1252//1 +f 1252//1 1298//1 1253//1 +f 1298//1 1299//1 1253//1 +f 1253//1 1299//1 1254//1 +f 1299//1 1300//1 1254//1 +f 1254//1 1300//1 1255//1 +f 1300//1 1301//1 1255//1 +f 1255//1 1301//1 1256//1 +f 1301//1 1302//1 1256//1 +f 1256//1 1302//1 1257//1 +f 1302//1 1303//1 1257//1 +f 1257//1 1303//1 1258//1 +f 1303//1 1304//1 1258//1 +f 1258//1 1304//1 1259//1 +f 1304//1 1305//1 1259//1 +f 1259//1 1305//1 1260//1 +f 1305//1 1306//1 1260//1 +f 1260//1 1306//1 1261//1 +f 1306//1 1307//1 1261//1 +f 1261//1 1307//1 1262//1 +f 1307//1 1308//1 1262//1 +f 1262//1 1308//1 1263//1 +f 1308//1 1309//1 1263//1 +f 1263//1 1309//1 1264//1 +f 1309//1 1310//1 1264//1 +f 1264//1 1310//1 1265//1 +f 1310//1 1311//1 1265//1 +f 1265//1 1311//1 1266//1 +f 1311//1 1312//1 1266//1 +f 1266//1 1312//1 1267//1 +f 1312//1 1313//1 1267//1 +f 1267//1 1313//1 1268//1 +f 1313//1 1314//1 1268//1 +f 1268//1 1314//1 1269//1 +f 1314//1 1315//1 1269//1 +f 1269//1 1315//1 1270//1 +f 1315//1 1316//1 1270//1 +f 1270//1 1316//1 1271//1 +f 1316//1 1317//1 1271//1 +f 1271//1 1317//1 1272//1 +f 1317//1 1318//1 1272//1 +f 1272//1 1318//1 1273//1 +f 1318//1 1319//1 1273//1 +f 1273//1 1319//1 1274//1 +f 1319//1 1320//1 1274//1 +f 1274//1 1320//1 1275//1 +f 1320//1 1321//1 1275//1 +f 1275//1 1321//1 1276//1 +f 1321//1 1322//1 1276//1 +f 1276//1 1322//1 1277//1 +f 1322//1 1323//1 1277//1 +f 1277//1 1323//1 1278//1 +f 1323//1 1324//1 1278//1 +f 1278//1 1324//1 1279//1 +f 1324//1 1325//1 1279//1 +f 1279//1 1325//1 1280//1 +f 1325//1 1326//1 1280//1 +f 1280//1 1326//1 1281//1 +f 1326//1 1327//1 1281//1 +f 1281//1 1327//1 1282//1 +f 1327//1 1328//1 1282//1 +f 1282//1 1328//1 1283//1 +f 1328//1 1329//1 1283//1 +f 1283//1 1329//1 1284//1 +f 1329//1 1330//1 1284//1 +f 1284//1 1330//1 1285//1 +f 1330//1 1331//1 1285//1 +f 1285//1 1331//1 1286//1 +f 1331//1 1332//1 1286//1 +f 1286//1 1332//1 1287//1 +f 1332//1 1333//1 1287//1 +f 1287//1 1333//1 1288//1 +f 1333//1 1334//1 1288//1 +f 1288//1 1334//1 1289//1 +f 1334//1 1335//1 1289//1 +f 1289//1 1335//1 159//1 +f 1335//1 158//1 159//1 +f 251//1 1336//1 1290//1 +f 1336//1 1337//1 1290//1 +f 1290//1 1337//1 1291//1 +f 1337//1 1338//1 1291//1 +f 1291//1 1338//1 1292//1 +f 1338//1 1339//1 1292//1 +f 1292//1 1339//1 1293//1 +f 1339//1 1340//1 1293//1 +f 1293//1 1340//1 1294//1 +f 1340//1 1341//1 1294//1 +f 1294//1 1341//1 1295//1 +f 1341//1 1342//1 1295//1 +f 1295//1 1342//1 1296//1 +f 1342//1 1343//1 1296//1 +f 1296//1 1343//1 1297//1 +f 1343//1 1344//1 1297//1 +f 1297//1 1344//1 1298//1 +f 1344//1 1345//1 1298//1 +f 1298//1 1345//1 1299//1 +f 1345//1 1346//1 1299//1 +f 1299//1 1346//1 1300//1 +f 1346//1 1347//1 1300//1 +f 1300//1 1347//1 1301//1 +f 1347//1 1348//1 1301//1 +f 1301//1 1348//1 1302//1 +f 1348//1 1349//1 1302//1 +f 1302//1 1349//1 1303//1 +f 1349//1 1350//1 1303//1 +f 1303//1 1350//1 1304//1 +f 1350//1 1351//1 1304//1 +f 1304//1 1351//1 1305//1 +f 1351//1 1352//1 1305//1 +f 1305//1 1352//1 1306//1 +f 1352//1 1353//1 1306//1 +f 1306//1 1353//1 1307//1 +f 1353//1 1354//1 1307//1 +f 1307//1 1354//1 1308//1 +f 1354//1 1355//1 1308//1 +f 1308//1 1355//1 1309//1 +f 1355//1 1356//1 1309//1 +f 1309//1 1356//1 1310//1 +f 1356//1 1357//1 1310//1 +f 1310//1 1357//1 1311//1 +f 1357//1 1358//1 1311//1 +f 1311//1 1358//1 1312//1 +f 1358//1 1359//1 1312//1 +f 1312//1 1359//1 1313//1 +f 1359//1 1360//1 1313//1 +f 1313//1 1360//1 1314//1 +f 1360//1 1361//1 1314//1 +f 1314//1 1361//1 1315//1 +f 1361//1 1362//1 1315//1 +f 1315//1 1362//1 1316//1 +f 1362//1 1363//1 1316//1 +f 1316//1 1363//1 1317//1 +f 1363//1 1364//1 1317//1 +f 1317//1 1364//1 1318//1 +f 1364//1 1365//1 1318//1 +f 1318//1 1365//1 1319//1 +f 1365//1 1366//1 1319//1 +f 1319//1 1366//1 1320//1 +f 1366//1 1367//1 1320//1 +f 1320//1 1367//1 1321//1 +f 1367//1 1368//1 1321//1 +f 1321//1 1368//1 1322//1 +f 1368//1 1369//1 1322//1 +f 1322//1 1369//1 1323//1 +f 1369//1 1370//1 1323//1 +f 1323//1 1370//1 1324//1 +f 1370//1 1371//1 1324//1 +f 1324//1 1371//1 1325//1 +f 1371//1 1372//1 1325//1 +f 1325//1 1372//1 1326//1 +f 1372//1 1373//1 1326//1 +f 1326//1 1373//1 1327//1 +f 1373//1 1374//1 1327//1 +f 1327//1 1374//1 1328//1 +f 1374//1 1375//1 1328//1 +f 1328//1 1375//1 1329//1 +f 1375//1 1376//1 1329//1 +f 1329//1 1376//1 1330//1 +f 1376//1 1377//1 1330//1 +f 1330//1 1377//1 1331//1 +f 1377//1 1378//1 1331//1 +f 1331//1 1378//1 1332//1 +f 1378//1 1379//1 1332//1 +f 1332//1 1379//1 1333//1 +f 1379//1 1380//1 1333//1 +f 1333//1 1380//1 1334//1 +f 1380//1 1381//1 1334//1 +f 1334//1 1381//1 1335//1 +f 1381//1 1382//1 1335//1 +f 1335//1 1382//1 158//1 +f 1382//1 157//1 158//1 +f 252//1 1383//1 1336//1 +f 1383//1 1384//1 1336//1 +f 1336//1 1384//1 1337//1 +f 1384//1 1385//1 1337//1 +f 1337//1 1385//1 1338//1 +f 1385//1 1386//1 1338//1 +f 1338//1 1386//1 1339//1 +f 1386//1 1387//1 1339//1 +f 1339//1 1387//1 1340//1 +f 1387//1 1388//1 1340//1 +f 1340//1 1388//1 1341//1 +f 1388//1 1389//1 1341//1 +f 1341//1 1389//1 1342//1 +f 1389//1 1390//1 1342//1 +f 1342//1 1390//1 1343//1 +f 1390//1 1391//1 1343//1 +f 1343//1 1391//1 1344//1 +f 1391//1 1392//1 1344//1 +f 1344//1 1392//1 1345//1 +f 1392//1 1393//1 1345//1 +f 1345//1 1393//1 1346//1 +f 1393//1 1394//1 1346//1 +f 1346//1 1394//1 1347//1 +f 1394//1 1395//1 1347//1 +f 1347//1 1395//1 1348//1 +f 1395//1 1396//1 1348//1 +f 1348//1 1396//1 1349//1 +f 1396//1 1397//1 1349//1 +f 1349//1 1397//1 1350//1 +f 1397//1 1398//1 1350//1 +f 1350//1 1398//1 1351//1 +f 1398//1 1399//1 1351//1 +f 1351//1 1399//1 1352//1 +f 1399//1 1400//1 1352//1 +f 1352//1 1400//1 1353//1 +f 1400//1 1401//1 1353//1 +f 1353//1 1401//1 1354//1 +f 1401//1 1402//1 1354//1 +f 1354//1 1402//1 1355//1 +f 1402//1 1403//1 1355//1 +f 1355//1 1403//1 1356//1 +f 1403//1 1404//1 1356//1 +f 1356//1 1404//1 1357//1 +f 1404//1 1405//1 1357//1 +f 1357//1 1405//1 1358//1 +f 1405//1 1406//1 1358//1 +f 1358//1 1406//1 1359//1 +f 1406//1 1407//1 1359//1 +f 1359//1 1407//1 1360//1 +f 1407//1 1408//1 1360//1 +f 1360//1 1408//1 1361//1 +f 1408//1 1409//1 1361//1 +f 1361//1 1409//1 1362//1 +f 1409//1 1410//1 1362//1 +f 1362//1 1410//1 1363//1 +f 1410//1 1411//1 1363//1 +f 1363//1 1411//1 1364//1 +f 1411//1 1412//1 1364//1 +f 1364//1 1412//1 1365//1 +f 1412//1 1413//1 1365//1 +f 1365//1 1413//1 1366//1 +f 1413//1 1414//1 1366//1 +f 1366//1 1414//1 1367//1 +f 1414//1 1415//1 1367//1 +f 1367//1 1415//1 1368//1 +f 1415//1 1416//1 1368//1 +f 1368//1 1416//1 1369//1 +f 1416//1 1417//1 1369//1 +f 1369//1 1417//1 1370//1 +f 1417//1 1418//1 1370//1 +f 1370//1 1418//1 1371//1 +f 1418//1 1419//1 1371//1 +f 1371//1 1419//1 1372//1 +f 1419//1 1420//1 1372//1 +f 1372//1 1420//1 1373//1 +f 1420//1 1421//1 1373//1 +f 1373//1 1421//1 1374//1 +f 1421//1 1422//1 1374//1 +f 1374//1 1422//1 1375//1 +f 1422//1 1423//1 1375//1 +f 1375//1 1423//1 1376//1 +f 1423//1 1424//1 1376//1 +f 1376//1 1424//1 1377//1 +f 1424//1 1425//1 1377//1 +f 1377//1 1425//1 1378//1 +f 1425//1 1426//1 1378//1 +f 1378//1 1426//1 1379//1 +f 1426//1 1427//1 1379//1 +f 1379//1 1427//1 1380//1 +f 1427//1 1428//1 1380//1 +f 1380//1 1428//1 1381//1 +f 1428//1 1429//1 1381//1 +f 1381//1 1429//1 1382//1 +f 1429//1 1430//1 1382//1 +f 1382//1 1430//1 157//1 +f 1430//1 156//1 157//1 +f 253//1 1431//1 1383//1 +f 1431//1 1432//1 1383//1 +f 1383//1 1432//1 1384//1 +f 1432//1 1433//1 1384//1 +f 1384//1 1433//1 1385//1 +f 1433//1 1434//1 1385//1 +f 1385//1 1434//1 1386//1 +f 1434//1 1435//1 1386//1 +f 1386//1 1435//1 1387//1 +f 1435//1 1436//1 1387//1 +f 1387//1 1436//1 1388//1 +f 1436//1 1437//1 1388//1 +f 1388//1 1437//1 1389//1 +f 1437//1 1438//1 1389//1 +f 1389//1 1438//1 1390//1 +f 1438//1 1439//1 1390//1 +f 1390//1 1439//1 1391//1 +f 1439//1 1440//1 1391//1 +f 1391//1 1440//1 1392//1 +f 1440//1 1441//1 1392//1 +f 1392//1 1441//1 1393//1 +f 1441//1 1442//1 1393//1 +f 1393//1 1442//1 1394//1 +f 1442//1 1443//1 1394//1 +f 1394//1 1443//1 1395//1 +f 1443//1 1444//1 1395//1 +f 1395//1 1444//1 1396//1 +f 1444//1 1445//1 1396//1 +f 1396//1 1445//1 1397//1 +f 1445//1 1446//1 1397//1 +f 1397//1 1446//1 1398//1 +f 1446//1 1447//1 1398//1 +f 1398//1 1447//1 1399//1 +f 1447//1 1448//1 1399//1 +f 1399//1 1448//1 1400//1 +f 1448//1 1449//1 1400//1 +f 1400//1 1449//1 1401//1 +f 1449//1 1450//1 1401//1 +f 1401//1 1450//1 1402//1 +f 1450//1 1451//1 1402//1 +f 1402//1 1451//1 1403//1 +f 1451//1 1452//1 1403//1 +f 1403//1 1452//1 1404//1 +f 1452//1 1453//1 1404//1 +f 1404//1 1453//1 1405//1 +f 1453//1 1454//1 1405//1 +f 1405//1 1454//1 1406//1 +f 1454//1 1455//1 1406//1 +f 1406//1 1455//1 1407//1 +f 1455//1 1456//1 1407//1 +f 1407//1 1456//1 1408//1 +f 1456//1 1457//1 1408//1 +f 1408//1 1457//1 1409//1 +f 1457//1 1458//1 1409//1 +f 1409//1 1458//1 1410//1 +f 1458//1 1459//1 1410//1 +f 1410//1 1459//1 1411//1 +f 1459//1 1460//1 1411//1 +f 1411//1 1460//1 1412//1 +f 1460//1 1461//1 1412//1 +f 1412//1 1461//1 1413//1 +f 1461//1 1462//1 1413//1 +f 1413//1 1462//1 1414//1 +f 1462//1 1463//1 1414//1 +f 1414//1 1463//1 1415//1 +f 1463//1 1464//1 1415//1 +f 1415//1 1464//1 1416//1 +f 1464//1 1465//1 1416//1 +f 1416//1 1465//1 1417//1 +f 1465//1 1466//1 1417//1 +f 1417//1 1466//1 1418//1 +f 1466//1 1467//1 1418//1 +f 1418//1 1467//1 1419//1 +f 1467//1 1468//1 1419//1 +f 1419//1 1468//1 1420//1 +f 1468//1 1469//1 1420//1 +f 1420//1 1469//1 1421//1 +f 1469//1 1470//1 1421//1 +f 1421//1 1470//1 1422//1 +f 1470//1 1471//1 1422//1 +f 1422//1 1471//1 1423//1 +f 1471//1 1472//1 1423//1 +f 1423//1 1472//1 1424//1 +f 1472//1 1473//1 1424//1 +f 1424//1 1473//1 1425//1 +f 1473//1 1474//1 1425//1 +f 1425//1 1474//1 1426//1 +f 1474//1 1475//1 1426//1 +f 1426//1 1475//1 1427//1 +f 1475//1 1476//1 1427//1 +f 1427//1 1476//1 1428//1 +f 1476//1 1477//1 1428//1 +f 1428//1 1477//1 1429//1 +f 1477//1 1478//1 1429//1 +f 1429//1 1478//1 1430//1 +f 1478//1 1479//1 1430//1 +f 1430//1 1479//1 156//1 +f 1479//1 155//1 156//1 +f 254//1 105//1 1431//1 +f 105//1 106//1 1431//1 +f 1431//1 106//1 1432//1 +f 106//1 107//1 1432//1 +f 1432//1 107//1 1433//1 +f 107//1 108//1 1433//1 +f 1433//1 108//1 1434//1 +f 108//1 109//1 1434//1 +f 1434//1 109//1 1435//1 +f 109//1 110//1 1435//1 +f 1435//1 110//1 1436//1 +f 110//1 111//1 1436//1 +f 1436//1 111//1 1437//1 +f 111//1 112//1 1437//1 +f 1437//1 112//1 1438//1 +f 112//1 113//1 1438//1 +f 1438//1 113//1 1439//1 +f 113//1 114//1 1439//1 +f 1439//1 114//1 1440//1 +f 114//1 115//1 1440//1 +f 1440//1 115//1 1441//1 +f 115//1 116//1 1441//1 +f 1441//1 116//1 1442//1 +f 116//1 117//1 1442//1 +f 1442//1 117//1 1443//1 +f 117//1 118//1 1443//1 +f 1443//1 118//1 1444//1 +f 118//1 119//1 1444//1 +f 1444//1 119//1 1445//1 +f 119//1 120//1 1445//1 +f 1445//1 120//1 1446//1 +f 120//1 121//1 1446//1 +f 1446//1 121//1 1447//1 +f 121//1 122//1 1447//1 +f 1447//1 122//1 1448//1 +f 122//1 123//1 1448//1 +f 1448//1 123//1 1449//1 +f 123//1 124//1 1449//1 +f 1449//1 124//1 1450//1 +f 124//1 125//1 1450//1 +f 1450//1 125//1 1451//1 +f 125//1 126//1 1451//1 +f 1451//1 126//1 1452//1 +f 126//1 127//1 1452//1 +f 1452//1 127//1 1453//1 +f 127//1 128//1 1453//1 +f 1453//1 128//1 1454//1 +f 128//1 129//1 1454//1 +f 1454//1 129//1 1455//1 +f 129//1 130//1 1455//1 +f 1455//1 130//1 1456//1 +f 130//1 131//1 1456//1 +f 1456//1 131//1 1457//1 +f 131//1 132//1 1457//1 +f 1457//1 132//1 1458//1 +f 132//1 133//1 1458//1 +f 1458//1 133//1 1459//1 +f 133//1 134//1 1459//1 +f 1459//1 134//1 1460//1 +f 134//1 135//1 1460//1 +f 1460//1 135//1 1461//1 +f 135//1 136//1 1461//1 +f 1461//1 136//1 1462//1 +f 136//1 137//1 1462//1 +f 1462//1 137//1 1463//1 +f 137//1 138//1 1463//1 +f 1463//1 138//1 1464//1 +f 138//1 139//1 1464//1 +f 1464//1 139//1 1465//1 +f 139//1 140//1 1465//1 +f 1465//1 140//1 1466//1 +f 140//1 141//1 1466//1 +f 1466//1 141//1 1467//1 +f 141//1 142//1 1467//1 +f 1467//1 142//1 1468//1 +f 142//1 143//1 1468//1 +f 1468//1 143//1 1469//1 +f 143//1 144//1 1469//1 +f 1469//1 144//1 1470//1 +f 144//1 145//1 1470//1 +f 1470//1 145//1 1471//1 +f 145//1 146//1 1471//1 +f 1471//1 146//1 1472//1 +f 146//1 147//1 1472//1 +f 1472//1 147//1 1473//1 +f 147//1 148//1 1473//1 +f 1473//1 148//1 1474//1 +f 148//1 149//1 1474//1 +f 1474//1 149//1 1475//1 +f 149//1 150//1 1475//1 +f 1475//1 150//1 1476//1 +f 150//1 151//1 1476//1 +f 1476//1 151//1 1477//1 +f 151//1 152//1 1477//1 +f 1477//1 152//1 1478//1 +f 152//1 153//1 1478//1 +f 1478//1 153//1 1479//1 +f 153//1 154//1 1479//1 +f 1479//1 154//1 155//1 +f 154//1 4//1 155//1 +f 55//1 54//1 1//1 +f 56//1 1480//1 55//1 +f 57//1 1481//1 56//1 +f 58//1 1483//1 57//1 +f 59//1 1486//1 58//1 +f 60//1 1490//1 59//1 +f 61//1 1495//1 60//1 +f 62//1 1501//1 61//1 +f 63//1 1508//1 62//1 +f 64//1 1516//1 63//1 +f 65//1 1525//1 64//1 +f 66//1 1535//1 65//1 +f 67//1 1546//1 66//1 +f 68//1 1558//1 67//1 +f 69//1 1571//1 68//1 +f 70//1 1585//1 69//1 +f 71//1 1600//1 70//1 +f 72//1 1616//1 71//1 +f 73//1 1633//1 72//1 +f 74//1 1651//1 73//1 +f 75//1 1670//1 74//1 +f 76//1 1690//1 75//1 +f 77//1 1711//1 76//1 +f 78//1 1733//1 77//1 +f 79//1 1756//1 78//1 +f 80//1 1780//1 79//1 +f 81//1 1805//1 80//1 +f 82//1 1831//1 81//1 +f 83//1 1858//1 82//1 +f 84//1 1886//1 83//1 +f 85//1 1915//1 84//1 +f 86//1 1945//1 85//1 +f 87//1 1976//1 86//1 +f 88//1 2008//1 87//1 +f 89//1 2041//1 88//1 +f 90//1 2075//1 89//1 +f 91//1 2110//1 90//1 +f 92//1 2146//1 91//1 +f 93//1 2183//1 92//1 +f 94//1 2221//1 93//1 +f 95//1 2260//1 94//1 +f 96//1 2300//1 95//1 +f 97//1 2341//1 96//1 +f 98//1 2383//1 97//1 +f 99//1 2426//1 98//1 +f 100//1 2470//1 99//1 +f 101//1 2515//1 100//1 +f 102//1 2561//1 101//1 +f 103//1 2608//1 102//1 +f 104//1 2656//1 103//1 +f 55//1 1480//1 54//1 +f 1480//1 53//1 54//1 +f 56//1 1481//1 1480//1 +f 1481//1 1482//1 1480//1 +f 1480//1 1482//1 53//1 +f 1482//1 52//1 53//1 +f 57//1 1483//1 1481//1 +f 1483//1 1484//1 1481//1 +f 1481//1 1484//1 1482//1 +f 1484//1 1485//1 1482//1 +f 1482//1 1485//1 52//1 +f 1485//1 51//1 52//1 +f 58//1 1486//1 1483//1 +f 1486//1 1487//1 1483//1 +f 1483//1 1487//1 1484//1 +f 1487//1 1488//1 1484//1 +f 1484//1 1488//1 1485//1 +f 1488//1 1489//1 1485//1 +f 1485//1 1489//1 51//1 +f 1489//1 50//1 51//1 +f 59//1 1490//1 1486//1 +f 1490//1 1491//1 1486//1 +f 1486//1 1491//1 1487//1 +f 1491//1 1492//1 1487//1 +f 1487//1 1492//1 1488//1 +f 1492//1 1493//1 1488//1 +f 1488//1 1493//1 1489//1 +f 1493//1 1494//1 1489//1 +f 1489//1 1494//1 50//1 +f 1494//1 49//1 50//1 +f 60//1 1495//1 1490//1 +f 1495//1 1496//1 1490//1 +f 1490//1 1496//1 1491//1 +f 1496//1 1497//1 1491//1 +f 1491//1 1497//1 1492//1 +f 1497//1 1498//1 1492//1 +f 1492//1 1498//1 1493//1 +f 1498//1 1499//1 1493//1 +f 1493//1 1499//1 1494//1 +f 1499//1 1500//1 1494//1 +f 1494//1 1500//1 49//1 +f 1500//1 48//1 49//1 +f 61//1 1501//1 1495//1 +f 1501//1 1502//1 1495//1 +f 1495//1 1502//1 1496//1 +f 1502//1 1503//1 1496//1 +f 1496//1 1503//1 1497//1 +f 1503//1 1504//1 1497//1 +f 1497//1 1504//1 1498//1 +f 1504//1 1505//1 1498//1 +f 1498//1 1505//1 1499//1 +f 1505//1 1506//1 1499//1 +f 1499//1 1506//1 1500//1 +f 1506//1 1507//1 1500//1 +f 1500//1 1507//1 48//1 +f 1507//1 47//1 48//1 +f 62//1 1508//1 1501//1 +f 1508//1 1509//1 1501//1 +f 1501//1 1509//1 1502//1 +f 1509//1 1510//1 1502//1 +f 1502//1 1510//1 1503//1 +f 1510//1 1511//1 1503//1 +f 1503//1 1511//1 1504//1 +f 1511//1 1512//1 1504//1 +f 1504//1 1512//1 1505//1 +f 1512//1 1513//1 1505//1 +f 1505//1 1513//1 1506//1 +f 1513//1 1514//1 1506//1 +f 1506//1 1514//1 1507//1 +f 1514//1 1515//1 1507//1 +f 1507//1 1515//1 47//1 +f 1515//1 46//1 47//1 +f 63//1 1516//1 1508//1 +f 1516//1 1517//1 1508//1 +f 1508//1 1517//1 1509//1 +f 1517//1 1518//1 1509//1 +f 1509//1 1518//1 1510//1 +f 1518//1 1519//1 1510//1 +f 1510//1 1519//1 1511//1 +f 1519//1 1520//1 1511//1 +f 1511//1 1520//1 1512//1 +f 1520//1 1521//1 1512//1 +f 1512//1 1521//1 1513//1 +f 1521//1 1522//1 1513//1 +f 1513//1 1522//1 1514//1 +f 1522//1 1523//1 1514//1 +f 1514//1 1523//1 1515//1 +f 1523//1 1524//1 1515//1 +f 1515//1 1524//1 46//1 +f 1524//1 45//1 46//1 +f 64//1 1525//1 1516//1 +f 1525//1 1526//1 1516//1 +f 1516//1 1526//1 1517//1 +f 1526//1 1527//1 1517//1 +f 1517//1 1527//1 1518//1 +f 1527//1 1528//1 1518//1 +f 1518//1 1528//1 1519//1 +f 1528//1 1529//1 1519//1 +f 1519//1 1529//1 1520//1 +f 1529//1 1530//1 1520//1 +f 1520//1 1530//1 1521//1 +f 1530//1 1531//1 1521//1 +f 1521//1 1531//1 1522//1 +f 1531//1 1532//1 1522//1 +f 1522//1 1532//1 1523//1 +f 1532//1 1533//1 1523//1 +f 1523//1 1533//1 1524//1 +f 1533//1 1534//1 1524//1 +f 1524//1 1534//1 45//1 +f 1534//1 44//1 45//1 +f 65//1 1535//1 1525//1 +f 1535//1 1536//1 1525//1 +f 1525//1 1536//1 1526//1 +f 1536//1 1537//1 1526//1 +f 1526//1 1537//1 1527//1 +f 1537//1 1538//1 1527//1 +f 1527//1 1538//1 1528//1 +f 1538//1 1539//1 1528//1 +f 1528//1 1539//1 1529//1 +f 1539//1 1540//1 1529//1 +f 1529//1 1540//1 1530//1 +f 1540//1 1541//1 1530//1 +f 1530//1 1541//1 1531//1 +f 1541//1 1542//1 1531//1 +f 1531//1 1542//1 1532//1 +f 1542//1 1543//1 1532//1 +f 1532//1 1543//1 1533//1 +f 1543//1 1544//1 1533//1 +f 1533//1 1544//1 1534//1 +f 1544//1 1545//1 1534//1 +f 1534//1 1545//1 44//1 +f 1545//1 43//1 44//1 +f 66//1 1546//1 1535//1 +f 1546//1 1547//1 1535//1 +f 1535//1 1547//1 1536//1 +f 1547//1 1548//1 1536//1 +f 1536//1 1548//1 1537//1 +f 1548//1 1549//1 1537//1 +f 1537//1 1549//1 1538//1 +f 1549//1 1550//1 1538//1 +f 1538//1 1550//1 1539//1 +f 1550//1 1551//1 1539//1 +f 1539//1 1551//1 1540//1 +f 1551//1 1552//1 1540//1 +f 1540//1 1552//1 1541//1 +f 1552//1 1553//1 1541//1 +f 1541//1 1553//1 1542//1 +f 1553//1 1554//1 1542//1 +f 1542//1 1554//1 1543//1 +f 1554//1 1555//1 1543//1 +f 1543//1 1555//1 1544//1 +f 1555//1 1556//1 1544//1 +f 1544//1 1556//1 1545//1 +f 1556//1 1557//1 1545//1 +f 1545//1 1557//1 43//1 +f 1557//1 42//1 43//1 +f 67//1 1558//1 1546//1 +f 1558//1 1559//1 1546//1 +f 1546//1 1559//1 1547//1 +f 1559//1 1560//1 1547//1 +f 1547//1 1560//1 1548//1 +f 1560//1 1561//1 1548//1 +f 1548//1 1561//1 1549//1 +f 1561//1 1562//1 1549//1 +f 1549//1 1562//1 1550//1 +f 1562//1 1563//1 1550//1 +f 1550//1 1563//1 1551//1 +f 1563//1 1564//1 1551//1 +f 1551//1 1564//1 1552//1 +f 1564//1 1565//1 1552//1 +f 1552//1 1565//1 1553//1 +f 1565//1 1566//1 1553//1 +f 1553//1 1566//1 1554//1 +f 1566//1 1567//1 1554//1 +f 1554//1 1567//1 1555//1 +f 1567//1 1568//1 1555//1 +f 1555//1 1568//1 1556//1 +f 1568//1 1569//1 1556//1 +f 1556//1 1569//1 1557//1 +f 1569//1 1570//1 1557//1 +f 1557//1 1570//1 42//1 +f 1570//1 41//1 42//1 +f 68//1 1571//1 1558//1 +f 1571//1 1572//1 1558//1 +f 1558//1 1572//1 1559//1 +f 1572//1 1573//1 1559//1 +f 1559//1 1573//1 1560//1 +f 1573//1 1574//1 1560//1 +f 1560//1 1574//1 1561//1 +f 1574//1 1575//1 1561//1 +f 1561//1 1575//1 1562//1 +f 1575//1 1576//1 1562//1 +f 1562//1 1576//1 1563//1 +f 1576//1 1577//1 1563//1 +f 1563//1 1577//1 1564//1 +f 1577//1 1578//1 1564//1 +f 1564//1 1578//1 1565//1 +f 1578//1 1579//1 1565//1 +f 1565//1 1579//1 1566//1 +f 1579//1 1580//1 1566//1 +f 1566//1 1580//1 1567//1 +f 1580//1 1581//1 1567//1 +f 1567//1 1581//1 1568//1 +f 1581//1 1582//1 1568//1 +f 1568//1 1582//1 1569//1 +f 1582//1 1583//1 1569//1 +f 1569//1 1583//1 1570//1 +f 1583//1 1584//1 1570//1 +f 1570//1 1584//1 41//1 +f 1584//1 40//1 41//1 +f 69//1 1585//1 1571//1 +f 1585//1 1586//1 1571//1 +f 1571//1 1586//1 1572//1 +f 1586//1 1587//1 1572//1 +f 1572//1 1587//1 1573//1 +f 1587//1 1588//1 1573//1 +f 1573//1 1588//1 1574//1 +f 1588//1 1589//1 1574//1 +f 1574//1 1589//1 1575//1 +f 1589//1 1590//1 1575//1 +f 1575//1 1590//1 1576//1 +f 1590//1 1591//1 1576//1 +f 1576//1 1591//1 1577//1 +f 1591//1 1592//1 1577//1 +f 1577//1 1592//1 1578//1 +f 1592//1 1593//1 1578//1 +f 1578//1 1593//1 1579//1 +f 1593//1 1594//1 1579//1 +f 1579//1 1594//1 1580//1 +f 1594//1 1595//1 1580//1 +f 1580//1 1595//1 1581//1 +f 1595//1 1596//1 1581//1 +f 1581//1 1596//1 1582//1 +f 1596//1 1597//1 1582//1 +f 1582//1 1597//1 1583//1 +f 1597//1 1598//1 1583//1 +f 1583//1 1598//1 1584//1 +f 1598//1 1599//1 1584//1 +f 1584//1 1599//1 40//1 +f 1599//1 39//1 40//1 +f 70//1 1600//1 1585//1 +f 1600//1 1601//1 1585//1 +f 1585//1 1601//1 1586//1 +f 1601//1 1602//1 1586//1 +f 1586//1 1602//1 1587//1 +f 1602//1 1603//1 1587//1 +f 1587//1 1603//1 1588//1 +f 1603//1 1604//1 1588//1 +f 1588//1 1604//1 1589//1 +f 1604//1 1605//1 1589//1 +f 1589//1 1605//1 1590//1 +f 1605//1 1606//1 1590//1 +f 1590//1 1606//1 1591//1 +f 1606//1 1607//1 1591//1 +f 1591//1 1607//1 1592//1 +f 1607//1 1608//1 1592//1 +f 1592//1 1608//1 1593//1 +f 1608//1 1609//1 1593//1 +f 1593//1 1609//1 1594//1 +f 1609//1 1610//1 1594//1 +f 1594//1 1610//1 1595//1 +f 1610//1 1611//1 1595//1 +f 1595//1 1611//1 1596//1 +f 1611//1 1612//1 1596//1 +f 1596//1 1612//1 1597//1 +f 1612//1 1613//1 1597//1 +f 1597//1 1613//1 1598//1 +f 1613//1 1614//1 1598//1 +f 1598//1 1614//1 1599//1 +f 1614//1 1615//1 1599//1 +f 1599//1 1615//1 39//1 +f 1615//1 38//1 39//1 +f 71//1 1616//1 1600//1 +f 1616//1 1617//1 1600//1 +f 1600//1 1617//1 1601//1 +f 1617//1 1618//1 1601//1 +f 1601//1 1618//1 1602//1 +f 1618//1 1619//1 1602//1 +f 1602//1 1619//1 1603//1 +f 1619//1 1620//1 1603//1 +f 1603//1 1620//1 1604//1 +f 1620//1 1621//1 1604//1 +f 1604//1 1621//1 1605//1 +f 1621//1 1622//1 1605//1 +f 1605//1 1622//1 1606//1 +f 1622//1 1623//1 1606//1 +f 1606//1 1623//1 1607//1 +f 1623//1 1624//1 1607//1 +f 1607//1 1624//1 1608//1 +f 1624//1 1625//1 1608//1 +f 1608//1 1625//1 1609//1 +f 1625//1 1626//1 1609//1 +f 1609//1 1626//1 1610//1 +f 1626//1 1627//1 1610//1 +f 1610//1 1627//1 1611//1 +f 1627//1 1628//1 1611//1 +f 1611//1 1628//1 1612//1 +f 1628//1 1629//1 1612//1 +f 1612//1 1629//1 1613//1 +f 1629//1 1630//1 1613//1 +f 1613//1 1630//1 1614//1 +f 1630//1 1631//1 1614//1 +f 1614//1 1631//1 1615//1 +f 1631//1 1632//1 1615//1 +f 1615//1 1632//1 38//1 +f 1632//1 37//1 38//1 +f 72//1 1633//1 1616//1 +f 1633//1 1634//1 1616//1 +f 1616//1 1634//1 1617//1 +f 1634//1 1635//1 1617//1 +f 1617//1 1635//1 1618//1 +f 1635//1 1636//1 1618//1 +f 1618//1 1636//1 1619//1 +f 1636//1 1637//1 1619//1 +f 1619//1 1637//1 1620//1 +f 1637//1 1638//1 1620//1 +f 1620//1 1638//1 1621//1 +f 1638//1 1639//1 1621//1 +f 1621//1 1639//1 1622//1 +f 1639//1 1640//1 1622//1 +f 1622//1 1640//1 1623//1 +f 1640//1 1641//1 1623//1 +f 1623//1 1641//1 1624//1 +f 1641//1 1642//1 1624//1 +f 1624//1 1642//1 1625//1 +f 1642//1 1643//1 1625//1 +f 1625//1 1643//1 1626//1 +f 1643//1 1644//1 1626//1 +f 1626//1 1644//1 1627//1 +f 1644//1 1645//1 1627//1 +f 1627//1 1645//1 1628//1 +f 1645//1 1646//1 1628//1 +f 1628//1 1646//1 1629//1 +f 1646//1 1647//1 1629//1 +f 1629//1 1647//1 1630//1 +f 1647//1 1648//1 1630//1 +f 1630//1 1648//1 1631//1 +f 1648//1 1649//1 1631//1 +f 1631//1 1649//1 1632//1 +f 1649//1 1650//1 1632//1 +f 1632//1 1650//1 37//1 +f 1650//1 36//1 37//1 +f 73//1 1651//1 1633//1 +f 1651//1 1652//1 1633//1 +f 1633//1 1652//1 1634//1 +f 1652//1 1653//1 1634//1 +f 1634//1 1653//1 1635//1 +f 1653//1 1654//1 1635//1 +f 1635//1 1654//1 1636//1 +f 1654//1 1655//1 1636//1 +f 1636//1 1655//1 1637//1 +f 1655//1 1656//1 1637//1 +f 1637//1 1656//1 1638//1 +f 1656//1 1657//1 1638//1 +f 1638//1 1657//1 1639//1 +f 1657//1 1658//1 1639//1 +f 1639//1 1658//1 1640//1 +f 1658//1 1659//1 1640//1 +f 1640//1 1659//1 1641//1 +f 1659//1 1660//1 1641//1 +f 1641//1 1660//1 1642//1 +f 1660//1 1661//1 1642//1 +f 1642//1 1661//1 1643//1 +f 1661//1 1662//1 1643//1 +f 1643//1 1662//1 1644//1 +f 1662//1 1663//1 1644//1 +f 1644//1 1663//1 1645//1 +f 1663//1 1664//1 1645//1 +f 1645//1 1664//1 1646//1 +f 1664//1 1665//1 1646//1 +f 1646//1 1665//1 1647//1 +f 1665//1 1666//1 1647//1 +f 1647//1 1666//1 1648//1 +f 1666//1 1667//1 1648//1 +f 1648//1 1667//1 1649//1 +f 1667//1 1668//1 1649//1 +f 1649//1 1668//1 1650//1 +f 1668//1 1669//1 1650//1 +f 1650//1 1669//1 36//1 +f 1669//1 35//1 36//1 +f 74//1 1670//1 1651//1 +f 1670//1 1671//1 1651//1 +f 1651//1 1671//1 1652//1 +f 1671//1 1672//1 1652//1 +f 1652//1 1672//1 1653//1 +f 1672//1 1673//1 1653//1 +f 1653//1 1673//1 1654//1 +f 1673//1 1674//1 1654//1 +f 1654//1 1674//1 1655//1 +f 1674//1 1675//1 1655//1 +f 1655//1 1675//1 1656//1 +f 1675//1 1676//1 1656//1 +f 1656//1 1676//1 1657//1 +f 1676//1 1677//1 1657//1 +f 1657//1 1677//1 1658//1 +f 1677//1 1678//1 1658//1 +f 1658//1 1678//1 1659//1 +f 1678//1 1679//1 1659//1 +f 1659//1 1679//1 1660//1 +f 1679//1 1680//1 1660//1 +f 1660//1 1680//1 1661//1 +f 1680//1 1681//1 1661//1 +f 1661//1 1681//1 1662//1 +f 1681//1 1682//1 1662//1 +f 1662//1 1682//1 1663//1 +f 1682//1 1683//1 1663//1 +f 1663//1 1683//1 1664//1 +f 1683//1 1684//1 1664//1 +f 1664//1 1684//1 1665//1 +f 1684//1 1685//1 1665//1 +f 1665//1 1685//1 1666//1 +f 1685//1 1686//1 1666//1 +f 1666//1 1686//1 1667//1 +f 1686//1 1687//1 1667//1 +f 1667//1 1687//1 1668//1 +f 1687//1 1688//1 1668//1 +f 1668//1 1688//1 1669//1 +f 1688//1 1689//1 1669//1 +f 1669//1 1689//1 35//1 +f 1689//1 34//1 35//1 +f 75//1 1690//1 1670//1 +f 1690//1 1691//1 1670//1 +f 1670//1 1691//1 1671//1 +f 1691//1 1692//1 1671//1 +f 1671//1 1692//1 1672//1 +f 1692//1 1693//1 1672//1 +f 1672//1 1693//1 1673//1 +f 1693//1 1694//1 1673//1 +f 1673//1 1694//1 1674//1 +f 1694//1 1695//1 1674//1 +f 1674//1 1695//1 1675//1 +f 1695//1 1696//1 1675//1 +f 1675//1 1696//1 1676//1 +f 1696//1 1697//1 1676//1 +f 1676//1 1697//1 1677//1 +f 1697//1 1698//1 1677//1 +f 1677//1 1698//1 1678//1 +f 1698//1 1699//1 1678//1 +f 1678//1 1699//1 1679//1 +f 1699//1 1700//1 1679//1 +f 1679//1 1700//1 1680//1 +f 1700//1 1701//1 1680//1 +f 1680//1 1701//1 1681//1 +f 1701//1 1702//1 1681//1 +f 1681//1 1702//1 1682//1 +f 1702//1 1703//1 1682//1 +f 1682//1 1703//1 1683//1 +f 1703//1 1704//1 1683//1 +f 1683//1 1704//1 1684//1 +f 1704//1 1705//1 1684//1 +f 1684//1 1705//1 1685//1 +f 1705//1 1706//1 1685//1 +f 1685//1 1706//1 1686//1 +f 1706//1 1707//1 1686//1 +f 1686//1 1707//1 1687//1 +f 1707//1 1708//1 1687//1 +f 1687//1 1708//1 1688//1 +f 1708//1 1709//1 1688//1 +f 1688//1 1709//1 1689//1 +f 1709//1 1710//1 1689//1 +f 1689//1 1710//1 34//1 +f 1710//1 33//1 34//1 +f 76//1 1711//1 1690//1 +f 1711//1 1712//1 1690//1 +f 1690//1 1712//1 1691//1 +f 1712//1 1713//1 1691//1 +f 1691//1 1713//1 1692//1 +f 1713//1 1714//1 1692//1 +f 1692//1 1714//1 1693//1 +f 1714//1 1715//1 1693//1 +f 1693//1 1715//1 1694//1 +f 1715//1 1716//1 1694//1 +f 1694//1 1716//1 1695//1 +f 1716//1 1717//1 1695//1 +f 1695//1 1717//1 1696//1 +f 1717//1 1718//1 1696//1 +f 1696//1 1718//1 1697//1 +f 1718//1 1719//1 1697//1 +f 1697//1 1719//1 1698//1 +f 1719//1 1720//1 1698//1 +f 1698//1 1720//1 1699//1 +f 1720//1 1721//1 1699//1 +f 1699//1 1721//1 1700//1 +f 1721//1 1722//1 1700//1 +f 1700//1 1722//1 1701//1 +f 1722//1 1723//1 1701//1 +f 1701//1 1723//1 1702//1 +f 1723//1 1724//1 1702//1 +f 1702//1 1724//1 1703//1 +f 1724//1 1725//1 1703//1 +f 1703//1 1725//1 1704//1 +f 1725//1 1726//1 1704//1 +f 1704//1 1726//1 1705//1 +f 1726//1 1727//1 1705//1 +f 1705//1 1727//1 1706//1 +f 1727//1 1728//1 1706//1 +f 1706//1 1728//1 1707//1 +f 1728//1 1729//1 1707//1 +f 1707//1 1729//1 1708//1 +f 1729//1 1730//1 1708//1 +f 1708//1 1730//1 1709//1 +f 1730//1 1731//1 1709//1 +f 1709//1 1731//1 1710//1 +f 1731//1 1732//1 1710//1 +f 1710//1 1732//1 33//1 +f 1732//1 32//1 33//1 +f 77//1 1733//1 1711//1 +f 1733//1 1734//1 1711//1 +f 1711//1 1734//1 1712//1 +f 1734//1 1735//1 1712//1 +f 1712//1 1735//1 1713//1 +f 1735//1 1736//1 1713//1 +f 1713//1 1736//1 1714//1 +f 1736//1 1737//1 1714//1 +f 1714//1 1737//1 1715//1 +f 1737//1 1738//1 1715//1 +f 1715//1 1738//1 1716//1 +f 1738//1 1739//1 1716//1 +f 1716//1 1739//1 1717//1 +f 1739//1 1740//1 1717//1 +f 1717//1 1740//1 1718//1 +f 1740//1 1741//1 1718//1 +f 1718//1 1741//1 1719//1 +f 1741//1 1742//1 1719//1 +f 1719//1 1742//1 1720//1 +f 1742//1 1743//1 1720//1 +f 1720//1 1743//1 1721//1 +f 1743//1 1744//1 1721//1 +f 1721//1 1744//1 1722//1 +f 1744//1 1745//1 1722//1 +f 1722//1 1745//1 1723//1 +f 1745//1 1746//1 1723//1 +f 1723//1 1746//1 1724//1 +f 1746//1 1747//1 1724//1 +f 1724//1 1747//1 1725//1 +f 1747//1 1748//1 1725//1 +f 1725//1 1748//1 1726//1 +f 1748//1 1749//1 1726//1 +f 1726//1 1749//1 1727//1 +f 1749//1 1750//1 1727//1 +f 1727//1 1750//1 1728//1 +f 1750//1 1751//1 1728//1 +f 1728//1 1751//1 1729//1 +f 1751//1 1752//1 1729//1 +f 1729//1 1752//1 1730//1 +f 1752//1 1753//1 1730//1 +f 1730//1 1753//1 1731//1 +f 1753//1 1754//1 1731//1 +f 1731//1 1754//1 1732//1 +f 1754//1 1755//1 1732//1 +f 1732//1 1755//1 32//1 +f 1755//1 31//1 32//1 +f 78//1 1756//1 1733//1 +f 1756//1 1757//1 1733//1 +f 1733//1 1757//1 1734//1 +f 1757//1 1758//1 1734//1 +f 1734//1 1758//1 1735//1 +f 1758//1 1759//1 1735//1 +f 1735//1 1759//1 1736//1 +f 1759//1 1760//1 1736//1 +f 1736//1 1760//1 1737//1 +f 1760//1 1761//1 1737//1 +f 1737//1 1761//1 1738//1 +f 1761//1 1762//1 1738//1 +f 1738//1 1762//1 1739//1 +f 1762//1 1763//1 1739//1 +f 1739//1 1763//1 1740//1 +f 1763//1 1764//1 1740//1 +f 1740//1 1764//1 1741//1 +f 1764//1 1765//1 1741//1 +f 1741//1 1765//1 1742//1 +f 1765//1 1766//1 1742//1 +f 1742//1 1766//1 1743//1 +f 1766//1 1767//1 1743//1 +f 1743//1 1767//1 1744//1 +f 1767//1 1768//1 1744//1 +f 1744//1 1768//1 1745//1 +f 1768//1 1769//1 1745//1 +f 1745//1 1769//1 1746//1 +f 1769//1 1770//1 1746//1 +f 1746//1 1770//1 1747//1 +f 1770//1 1771//1 1747//1 +f 1747//1 1771//1 1748//1 +f 1771//1 1772//1 1748//1 +f 1748//1 1772//1 1749//1 +f 1772//1 1773//1 1749//1 +f 1749//1 1773//1 1750//1 +f 1773//1 1774//1 1750//1 +f 1750//1 1774//1 1751//1 +f 1774//1 1775//1 1751//1 +f 1751//1 1775//1 1752//1 +f 1775//1 1776//1 1752//1 +f 1752//1 1776//1 1753//1 +f 1776//1 1777//1 1753//1 +f 1753//1 1777//1 1754//1 +f 1777//1 1778//1 1754//1 +f 1754//1 1778//1 1755//1 +f 1778//1 1779//1 1755//1 +f 1755//1 1779//1 31//1 +f 1779//1 30//1 31//1 +f 79//1 1780//1 1756//1 +f 1780//1 1781//1 1756//1 +f 1756//1 1781//1 1757//1 +f 1781//1 1782//1 1757//1 +f 1757//1 1782//1 1758//1 +f 1782//1 1783//1 1758//1 +f 1758//1 1783//1 1759//1 +f 1783//1 1784//1 1759//1 +f 1759//1 1784//1 1760//1 +f 1784//1 1785//1 1760//1 +f 1760//1 1785//1 1761//1 +f 1785//1 1786//1 1761//1 +f 1761//1 1786//1 1762//1 +f 1786//1 1787//1 1762//1 +f 1762//1 1787//1 1763//1 +f 1787//1 1788//1 1763//1 +f 1763//1 1788//1 1764//1 +f 1788//1 1789//1 1764//1 +f 1764//1 1789//1 1765//1 +f 1789//1 1790//1 1765//1 +f 1765//1 1790//1 1766//1 +f 1790//1 1791//1 1766//1 +f 1766//1 1791//1 1767//1 +f 1791//1 1792//1 1767//1 +f 1767//1 1792//1 1768//1 +f 1792//1 1793//1 1768//1 +f 1768//1 1793//1 1769//1 +f 1793//1 1794//1 1769//1 +f 1769//1 1794//1 1770//1 +f 1794//1 1795//1 1770//1 +f 1770//1 1795//1 1771//1 +f 1795//1 1796//1 1771//1 +f 1771//1 1796//1 1772//1 +f 1796//1 1797//1 1772//1 +f 1772//1 1797//1 1773//1 +f 1797//1 1798//1 1773//1 +f 1773//1 1798//1 1774//1 +f 1798//1 1799//1 1774//1 +f 1774//1 1799//1 1775//1 +f 1799//1 1800//1 1775//1 +f 1775//1 1800//1 1776//1 +f 1800//1 1801//1 1776//1 +f 1776//1 1801//1 1777//1 +f 1801//1 1802//1 1777//1 +f 1777//1 1802//1 1778//1 +f 1802//1 1803//1 1778//1 +f 1778//1 1803//1 1779//1 +f 1803//1 1804//1 1779//1 +f 1779//1 1804//1 30//1 +f 1804//1 29//1 30//1 +f 80//1 1805//1 1780//1 +f 1805//1 1806//1 1780//1 +f 1780//1 1806//1 1781//1 +f 1806//1 1807//1 1781//1 +f 1781//1 1807//1 1782//1 +f 1807//1 1808//1 1782//1 +f 1782//1 1808//1 1783//1 +f 1808//1 1809//1 1783//1 +f 1783//1 1809//1 1784//1 +f 1809//1 1810//1 1784//1 +f 1784//1 1810//1 1785//1 +f 1810//1 1811//1 1785//1 +f 1785//1 1811//1 1786//1 +f 1811//1 1812//1 1786//1 +f 1786//1 1812//1 1787//1 +f 1812//1 1813//1 1787//1 +f 1787//1 1813//1 1788//1 +f 1813//1 1814//1 1788//1 +f 1788//1 1814//1 1789//1 +f 1814//1 1815//1 1789//1 +f 1789//1 1815//1 1790//1 +f 1815//1 1816//1 1790//1 +f 1790//1 1816//1 1791//1 +f 1816//1 1817//1 1791//1 +f 1791//1 1817//1 1792//1 +f 1817//1 1818//1 1792//1 +f 1792//1 1818//1 1793//1 +f 1818//1 1819//1 1793//1 +f 1793//1 1819//1 1794//1 +f 1819//1 1820//1 1794//1 +f 1794//1 1820//1 1795//1 +f 1820//1 1821//1 1795//1 +f 1795//1 1821//1 1796//1 +f 1821//1 1822//1 1796//1 +f 1796//1 1822//1 1797//1 +f 1822//1 1823//1 1797//1 +f 1797//1 1823//1 1798//1 +f 1823//1 1824//1 1798//1 +f 1798//1 1824//1 1799//1 +f 1824//1 1825//1 1799//1 +f 1799//1 1825//1 1800//1 +f 1825//1 1826//1 1800//1 +f 1800//1 1826//1 1801//1 +f 1826//1 1827//1 1801//1 +f 1801//1 1827//1 1802//1 +f 1827//1 1828//1 1802//1 +f 1802//1 1828//1 1803//1 +f 1828//1 1829//1 1803//1 +f 1803//1 1829//1 1804//1 +f 1829//1 1830//1 1804//1 +f 1804//1 1830//1 29//1 +f 1830//1 28//1 29//1 +f 81//1 1831//1 1805//1 +f 1831//1 1832//1 1805//1 +f 1805//1 1832//1 1806//1 +f 1832//1 1833//1 1806//1 +f 1806//1 1833//1 1807//1 +f 1833//1 1834//1 1807//1 +f 1807//1 1834//1 1808//1 +f 1834//1 1835//1 1808//1 +f 1808//1 1835//1 1809//1 +f 1835//1 1836//1 1809//1 +f 1809//1 1836//1 1810//1 +f 1836//1 1837//1 1810//1 +f 1810//1 1837//1 1811//1 +f 1837//1 1838//1 1811//1 +f 1811//1 1838//1 1812//1 +f 1838//1 1839//1 1812//1 +f 1812//1 1839//1 1813//1 +f 1839//1 1840//1 1813//1 +f 1813//1 1840//1 1814//1 +f 1840//1 1841//1 1814//1 +f 1814//1 1841//1 1815//1 +f 1841//1 1842//1 1815//1 +f 1815//1 1842//1 1816//1 +f 1842//1 1843//1 1816//1 +f 1816//1 1843//1 1817//1 +f 1843//1 1844//1 1817//1 +f 1817//1 1844//1 1818//1 +f 1844//1 1845//1 1818//1 +f 1818//1 1845//1 1819//1 +f 1845//1 1846//1 1819//1 +f 1819//1 1846//1 1820//1 +f 1846//1 1847//1 1820//1 +f 1820//1 1847//1 1821//1 +f 1847//1 1848//1 1821//1 +f 1821//1 1848//1 1822//1 +f 1848//1 1849//1 1822//1 +f 1822//1 1849//1 1823//1 +f 1849//1 1850//1 1823//1 +f 1823//1 1850//1 1824//1 +f 1850//1 1851//1 1824//1 +f 1824//1 1851//1 1825//1 +f 1851//1 1852//1 1825//1 +f 1825//1 1852//1 1826//1 +f 1852//1 1853//1 1826//1 +f 1826//1 1853//1 1827//1 +f 1853//1 1854//1 1827//1 +f 1827//1 1854//1 1828//1 +f 1854//1 1855//1 1828//1 +f 1828//1 1855//1 1829//1 +f 1855//1 1856//1 1829//1 +f 1829//1 1856//1 1830//1 +f 1856//1 1857//1 1830//1 +f 1830//1 1857//1 28//1 +f 1857//1 27//1 28//1 +f 82//1 1858//1 1831//1 +f 1858//1 1859//1 1831//1 +f 1831//1 1859//1 1832//1 +f 1859//1 1860//1 1832//1 +f 1832//1 1860//1 1833//1 +f 1860//1 1861//1 1833//1 +f 1833//1 1861//1 1834//1 +f 1861//1 1862//1 1834//1 +f 1834//1 1862//1 1835//1 +f 1862//1 1863//1 1835//1 +f 1835//1 1863//1 1836//1 +f 1863//1 1864//1 1836//1 +f 1836//1 1864//1 1837//1 +f 1864//1 1865//1 1837//1 +f 1837//1 1865//1 1838//1 +f 1865//1 1866//1 1838//1 +f 1838//1 1866//1 1839//1 +f 1866//1 1867//1 1839//1 +f 1839//1 1867//1 1840//1 +f 1867//1 1868//1 1840//1 +f 1840//1 1868//1 1841//1 +f 1868//1 1869//1 1841//1 +f 1841//1 1869//1 1842//1 +f 1869//1 1870//1 1842//1 +f 1842//1 1870//1 1843//1 +f 1870//1 1871//1 1843//1 +f 1843//1 1871//1 1844//1 +f 1871//1 1872//1 1844//1 +f 1844//1 1872//1 1845//1 +f 1872//1 1873//1 1845//1 +f 1845//1 1873//1 1846//1 +f 1873//1 1874//1 1846//1 +f 1846//1 1874//1 1847//1 +f 1874//1 1875//1 1847//1 +f 1847//1 1875//1 1848//1 +f 1875//1 1876//1 1848//1 +f 1848//1 1876//1 1849//1 +f 1876//1 1877//1 1849//1 +f 1849//1 1877//1 1850//1 +f 1877//1 1878//1 1850//1 +f 1850//1 1878//1 1851//1 +f 1878//1 1879//1 1851//1 +f 1851//1 1879//1 1852//1 +f 1879//1 1880//1 1852//1 +f 1852//1 1880//1 1853//1 +f 1880//1 1881//1 1853//1 +f 1853//1 1881//1 1854//1 +f 1881//1 1882//1 1854//1 +f 1854//1 1882//1 1855//1 +f 1882//1 1883//1 1855//1 +f 1855//1 1883//1 1856//1 +f 1883//1 1884//1 1856//1 +f 1856//1 1884//1 1857//1 +f 1884//1 1885//1 1857//1 +f 1857//1 1885//1 27//1 +f 1885//1 26//1 27//1 +f 83//1 1886//1 1858//1 +f 1886//1 1887//1 1858//1 +f 1858//1 1887//1 1859//1 +f 1887//1 1888//1 1859//1 +f 1859//1 1888//1 1860//1 +f 1888//1 1889//1 1860//1 +f 1860//1 1889//1 1861//1 +f 1889//1 1890//1 1861//1 +f 1861//1 1890//1 1862//1 +f 1890//1 1891//1 1862//1 +f 1862//1 1891//1 1863//1 +f 1891//1 1892//1 1863//1 +f 1863//1 1892//1 1864//1 +f 1892//1 1893//1 1864//1 +f 1864//1 1893//1 1865//1 +f 1893//1 1894//1 1865//1 +f 1865//1 1894//1 1866//1 +f 1894//1 1895//1 1866//1 +f 1866//1 1895//1 1867//1 +f 1895//1 1896//1 1867//1 +f 1867//1 1896//1 1868//1 +f 1896//1 1897//1 1868//1 +f 1868//1 1897//1 1869//1 +f 1897//1 1898//1 1869//1 +f 1869//1 1898//1 1870//1 +f 1898//1 1899//1 1870//1 +f 1870//1 1899//1 1871//1 +f 1899//1 1900//1 1871//1 +f 1871//1 1900//1 1872//1 +f 1900//1 1901//1 1872//1 +f 1872//1 1901//1 1873//1 +f 1901//1 1902//1 1873//1 +f 1873//1 1902//1 1874//1 +f 1902//1 1903//1 1874//1 +f 1874//1 1903//1 1875//1 +f 1903//1 1904//1 1875//1 +f 1875//1 1904//1 1876//1 +f 1904//1 1905//1 1876//1 +f 1876//1 1905//1 1877//1 +f 1905//1 1906//1 1877//1 +f 1877//1 1906//1 1878//1 +f 1906//1 1907//1 1878//1 +f 1878//1 1907//1 1879//1 +f 1907//1 1908//1 1879//1 +f 1879//1 1908//1 1880//1 +f 1908//1 1909//1 1880//1 +f 1880//1 1909//1 1881//1 +f 1909//1 1910//1 1881//1 +f 1881//1 1910//1 1882//1 +f 1910//1 1911//1 1882//1 +f 1882//1 1911//1 1883//1 +f 1911//1 1912//1 1883//1 +f 1883//1 1912//1 1884//1 +f 1912//1 1913//1 1884//1 +f 1884//1 1913//1 1885//1 +f 1913//1 1914//1 1885//1 +f 1885//1 1914//1 26//1 +f 1914//1 25//1 26//1 +f 84//1 1915//1 1886//1 +f 1915//1 1916//1 1886//1 +f 1886//1 1916//1 1887//1 +f 1916//1 1917//1 1887//1 +f 1887//1 1917//1 1888//1 +f 1917//1 1918//1 1888//1 +f 1888//1 1918//1 1889//1 +f 1918//1 1919//1 1889//1 +f 1889//1 1919//1 1890//1 +f 1919//1 1920//1 1890//1 +f 1890//1 1920//1 1891//1 +f 1920//1 1921//1 1891//1 +f 1891//1 1921//1 1892//1 +f 1921//1 1922//1 1892//1 +f 1892//1 1922//1 1893//1 +f 1922//1 1923//1 1893//1 +f 1893//1 1923//1 1894//1 +f 1923//1 1924//1 1894//1 +f 1894//1 1924//1 1895//1 +f 1924//1 1925//1 1895//1 +f 1895//1 1925//1 1896//1 +f 1925//1 1926//1 1896//1 +f 1896//1 1926//1 1897//1 +f 1926//1 1927//1 1897//1 +f 1897//1 1927//1 1898//1 +f 1927//1 1928//1 1898//1 +f 1898//1 1928//1 1899//1 +f 1928//1 1929//1 1899//1 +f 1899//1 1929//1 1900//1 +f 1929//1 1930//1 1900//1 +f 1900//1 1930//1 1901//1 +f 1930//1 1931//1 1901//1 +f 1901//1 1931//1 1902//1 +f 1931//1 1932//1 1902//1 +f 1902//1 1932//1 1903//1 +f 1932//1 1933//1 1903//1 +f 1903//1 1933//1 1904//1 +f 1933//1 1934//1 1904//1 +f 1904//1 1934//1 1905//1 +f 1934//1 1935//1 1905//1 +f 1905//1 1935//1 1906//1 +f 1935//1 1936//1 1906//1 +f 1906//1 1936//1 1907//1 +f 1936//1 1937//1 1907//1 +f 1907//1 1937//1 1908//1 +f 1937//1 1938//1 1908//1 +f 1908//1 1938//1 1909//1 +f 1938//1 1939//1 1909//1 +f 1909//1 1939//1 1910//1 +f 1939//1 1940//1 1910//1 +f 1910//1 1940//1 1911//1 +f 1940//1 1941//1 1911//1 +f 1911//1 1941//1 1912//1 +f 1941//1 1942//1 1912//1 +f 1912//1 1942//1 1913//1 +f 1942//1 1943//1 1913//1 +f 1913//1 1943//1 1914//1 +f 1943//1 1944//1 1914//1 +f 1914//1 1944//1 25//1 +f 1944//1 24//1 25//1 +f 85//1 1945//1 1915//1 +f 1945//1 1946//1 1915//1 +f 1915//1 1946//1 1916//1 +f 1946//1 1947//1 1916//1 +f 1916//1 1947//1 1917//1 +f 1947//1 1948//1 1917//1 +f 1917//1 1948//1 1918//1 +f 1948//1 1949//1 1918//1 +f 1918//1 1949//1 1919//1 +f 1949//1 1950//1 1919//1 +f 1919//1 1950//1 1920//1 +f 1950//1 1951//1 1920//1 +f 1920//1 1951//1 1921//1 +f 1951//1 1952//1 1921//1 +f 1921//1 1952//1 1922//1 +f 1952//1 1953//1 1922//1 +f 1922//1 1953//1 1923//1 +f 1953//1 1954//1 1923//1 +f 1923//1 1954//1 1924//1 +f 1954//1 1955//1 1924//1 +f 1924//1 1955//1 1925//1 +f 1955//1 1956//1 1925//1 +f 1925//1 1956//1 1926//1 +f 1956//1 1957//1 1926//1 +f 1926//1 1957//1 1927//1 +f 1957//1 1958//1 1927//1 +f 1927//1 1958//1 1928//1 +f 1958//1 1959//1 1928//1 +f 1928//1 1959//1 1929//1 +f 1959//1 1960//1 1929//1 +f 1929//1 1960//1 1930//1 +f 1960//1 1961//1 1930//1 +f 1930//1 1961//1 1931//1 +f 1961//1 1962//1 1931//1 +f 1931//1 1962//1 1932//1 +f 1962//1 1963//1 1932//1 +f 1932//1 1963//1 1933//1 +f 1963//1 1964//1 1933//1 +f 1933//1 1964//1 1934//1 +f 1964//1 1965//1 1934//1 +f 1934//1 1965//1 1935//1 +f 1965//1 1966//1 1935//1 +f 1935//1 1966//1 1936//1 +f 1966//1 1967//1 1936//1 +f 1936//1 1967//1 1937//1 +f 1967//1 1968//1 1937//1 +f 1937//1 1968//1 1938//1 +f 1968//1 1969//1 1938//1 +f 1938//1 1969//1 1939//1 +f 1969//1 1970//1 1939//1 +f 1939//1 1970//1 1940//1 +f 1970//1 1971//1 1940//1 +f 1940//1 1971//1 1941//1 +f 1971//1 1972//1 1941//1 +f 1941//1 1972//1 1942//1 +f 1972//1 1973//1 1942//1 +f 1942//1 1973//1 1943//1 +f 1973//1 1974//1 1943//1 +f 1943//1 1974//1 1944//1 +f 1974//1 1975//1 1944//1 +f 1944//1 1975//1 24//1 +f 1975//1 23//1 24//1 +f 86//1 1976//1 1945//1 +f 1976//1 1977//1 1945//1 +f 1945//1 1977//1 1946//1 +f 1977//1 1978//1 1946//1 +f 1946//1 1978//1 1947//1 +f 1978//1 1979//1 1947//1 +f 1947//1 1979//1 1948//1 +f 1979//1 1980//1 1948//1 +f 1948//1 1980//1 1949//1 +f 1980//1 1981//1 1949//1 +f 1949//1 1981//1 1950//1 +f 1981//1 1982//1 1950//1 +f 1950//1 1982//1 1951//1 +f 1982//1 1983//1 1951//1 +f 1951//1 1983//1 1952//1 +f 1983//1 1984//1 1952//1 +f 1952//1 1984//1 1953//1 +f 1984//1 1985//1 1953//1 +f 1953//1 1985//1 1954//1 +f 1985//1 1986//1 1954//1 +f 1954//1 1986//1 1955//1 +f 1986//1 1987//1 1955//1 +f 1955//1 1987//1 1956//1 +f 1987//1 1988//1 1956//1 +f 1956//1 1988//1 1957//1 +f 1988//1 1989//1 1957//1 +f 1957//1 1989//1 1958//1 +f 1989//1 1990//1 1958//1 +f 1958//1 1990//1 1959//1 +f 1990//1 1991//1 1959//1 +f 1959//1 1991//1 1960//1 +f 1991//1 1992//1 1960//1 +f 1960//1 1992//1 1961//1 +f 1992//1 1993//1 1961//1 +f 1961//1 1993//1 1962//1 +f 1993//1 1994//1 1962//1 +f 1962//1 1994//1 1963//1 +f 1994//1 1995//1 1963//1 +f 1963//1 1995//1 1964//1 +f 1995//1 1996//1 1964//1 +f 1964//1 1996//1 1965//1 +f 1996//1 1997//1 1965//1 +f 1965//1 1997//1 1966//1 +f 1997//1 1998//1 1966//1 +f 1966//1 1998//1 1967//1 +f 1998//1 1999//1 1967//1 +f 1967//1 1999//1 1968//1 +f 1999//1 2000//1 1968//1 +f 1968//1 2000//1 1969//1 +f 2000//1 2001//1 1969//1 +f 1969//1 2001//1 1970//1 +f 2001//1 2002//1 1970//1 +f 1970//1 2002//1 1971//1 +f 2002//1 2003//1 1971//1 +f 1971//1 2003//1 1972//1 +f 2003//1 2004//1 1972//1 +f 1972//1 2004//1 1973//1 +f 2004//1 2005//1 1973//1 +f 1973//1 2005//1 1974//1 +f 2005//1 2006//1 1974//1 +f 1974//1 2006//1 1975//1 +f 2006//1 2007//1 1975//1 +f 1975//1 2007//1 23//1 +f 2007//1 22//1 23//1 +f 87//1 2008//1 1976//1 +f 2008//1 2009//1 1976//1 +f 1976//1 2009//1 1977//1 +f 2009//1 2010//1 1977//1 +f 1977//1 2010//1 1978//1 +f 2010//1 2011//1 1978//1 +f 1978//1 2011//1 1979//1 +f 2011//1 2012//1 1979//1 +f 1979//1 2012//1 1980//1 +f 2012//1 2013//1 1980//1 +f 1980//1 2013//1 1981//1 +f 2013//1 2014//1 1981//1 +f 1981//1 2014//1 1982//1 +f 2014//1 2015//1 1982//1 +f 1982//1 2015//1 1983//1 +f 2015//1 2016//1 1983//1 +f 1983//1 2016//1 1984//1 +f 2016//1 2017//1 1984//1 +f 1984//1 2017//1 1985//1 +f 2017//1 2018//1 1985//1 +f 1985//1 2018//1 1986//1 +f 2018//1 2019//1 1986//1 +f 1986//1 2019//1 1987//1 +f 2019//1 2020//1 1987//1 +f 1987//1 2020//1 1988//1 +f 2020//1 2021//1 1988//1 +f 1988//1 2021//1 1989//1 +f 2021//1 2022//1 1989//1 +f 1989//1 2022//1 1990//1 +f 2022//1 2023//1 1990//1 +f 1990//1 2023//1 1991//1 +f 2023//1 2024//1 1991//1 +f 1991//1 2024//1 1992//1 +f 2024//1 2025//1 1992//1 +f 1992//1 2025//1 1993//1 +f 2025//1 2026//1 1993//1 +f 1993//1 2026//1 1994//1 +f 2026//1 2027//1 1994//1 +f 1994//1 2027//1 1995//1 +f 2027//1 2028//1 1995//1 +f 1995//1 2028//1 1996//1 +f 2028//1 2029//1 1996//1 +f 1996//1 2029//1 1997//1 +f 2029//1 2030//1 1997//1 +f 1997//1 2030//1 1998//1 +f 2030//1 2031//1 1998//1 +f 1998//1 2031//1 1999//1 +f 2031//1 2032//1 1999//1 +f 1999//1 2032//1 2000//1 +f 2032//1 2033//1 2000//1 +f 2000//1 2033//1 2001//1 +f 2033//1 2034//1 2001//1 +f 2001//1 2034//1 2002//1 +f 2034//1 2035//1 2002//1 +f 2002//1 2035//1 2003//1 +f 2035//1 2036//1 2003//1 +f 2003//1 2036//1 2004//1 +f 2036//1 2037//1 2004//1 +f 2004//1 2037//1 2005//1 +f 2037//1 2038//1 2005//1 +f 2005//1 2038//1 2006//1 +f 2038//1 2039//1 2006//1 +f 2006//1 2039//1 2007//1 +f 2039//1 2040//1 2007//1 +f 2007//1 2040//1 22//1 +f 2040//1 21//1 22//1 +f 88//1 2041//1 2008//1 +f 2041//1 2042//1 2008//1 +f 2008//1 2042//1 2009//1 +f 2042//1 2043//1 2009//1 +f 2009//1 2043//1 2010//1 +f 2043//1 2044//1 2010//1 +f 2010//1 2044//1 2011//1 +f 2044//1 2045//1 2011//1 +f 2011//1 2045//1 2012//1 +f 2045//1 2046//1 2012//1 +f 2012//1 2046//1 2013//1 +f 2046//1 2047//1 2013//1 +f 2013//1 2047//1 2014//1 +f 2047//1 2048//1 2014//1 +f 2014//1 2048//1 2015//1 +f 2048//1 2049//1 2015//1 +f 2015//1 2049//1 2016//1 +f 2049//1 2050//1 2016//1 +f 2016//1 2050//1 2017//1 +f 2050//1 2051//1 2017//1 +f 2017//1 2051//1 2018//1 +f 2051//1 2052//1 2018//1 +f 2018//1 2052//1 2019//1 +f 2052//1 2053//1 2019//1 +f 2019//1 2053//1 2020//1 +f 2053//1 2054//1 2020//1 +f 2020//1 2054//1 2021//1 +f 2054//1 2055//1 2021//1 +f 2021//1 2055//1 2022//1 +f 2055//1 2056//1 2022//1 +f 2022//1 2056//1 2023//1 +f 2056//1 2057//1 2023//1 +f 2023//1 2057//1 2024//1 +f 2057//1 2058//1 2024//1 +f 2024//1 2058//1 2025//1 +f 2058//1 2059//1 2025//1 +f 2025//1 2059//1 2026//1 +f 2059//1 2060//1 2026//1 +f 2026//1 2060//1 2027//1 +f 2060//1 2061//1 2027//1 +f 2027//1 2061//1 2028//1 +f 2061//1 2062//1 2028//1 +f 2028//1 2062//1 2029//1 +f 2062//1 2063//1 2029//1 +f 2029//1 2063//1 2030//1 +f 2063//1 2064//1 2030//1 +f 2030//1 2064//1 2031//1 +f 2064//1 2065//1 2031//1 +f 2031//1 2065//1 2032//1 +f 2065//1 2066//1 2032//1 +f 2032//1 2066//1 2033//1 +f 2066//1 2067//1 2033//1 +f 2033//1 2067//1 2034//1 +f 2067//1 2068//1 2034//1 +f 2034//1 2068//1 2035//1 +f 2068//1 2069//1 2035//1 +f 2035//1 2069//1 2036//1 +f 2069//1 2070//1 2036//1 +f 2036//1 2070//1 2037//1 +f 2070//1 2071//1 2037//1 +f 2037//1 2071//1 2038//1 +f 2071//1 2072//1 2038//1 +f 2038//1 2072//1 2039//1 +f 2072//1 2073//1 2039//1 +f 2039//1 2073//1 2040//1 +f 2073//1 2074//1 2040//1 +f 2040//1 2074//1 21//1 +f 2074//1 20//1 21//1 +f 89//1 2075//1 2041//1 +f 2075//1 2076//1 2041//1 +f 2041//1 2076//1 2042//1 +f 2076//1 2077//1 2042//1 +f 2042//1 2077//1 2043//1 +f 2077//1 2078//1 2043//1 +f 2043//1 2078//1 2044//1 +f 2078//1 2079//1 2044//1 +f 2044//1 2079//1 2045//1 +f 2079//1 2080//1 2045//1 +f 2045//1 2080//1 2046//1 +f 2080//1 2081//1 2046//1 +f 2046//1 2081//1 2047//1 +f 2081//1 2082//1 2047//1 +f 2047//1 2082//1 2048//1 +f 2082//1 2083//1 2048//1 +f 2048//1 2083//1 2049//1 +f 2083//1 2084//1 2049//1 +f 2049//1 2084//1 2050//1 +f 2084//1 2085//1 2050//1 +f 2050//1 2085//1 2051//1 +f 2085//1 2086//1 2051//1 +f 2051//1 2086//1 2052//1 +f 2086//1 2087//1 2052//1 +f 2052//1 2087//1 2053//1 +f 2087//1 2088//1 2053//1 +f 2053//1 2088//1 2054//1 +f 2088//1 2089//1 2054//1 +f 2054//1 2089//1 2055//1 +f 2089//1 2090//1 2055//1 +f 2055//1 2090//1 2056//1 +f 2090//1 2091//1 2056//1 +f 2056//1 2091//1 2057//1 +f 2091//1 2092//1 2057//1 +f 2057//1 2092//1 2058//1 +f 2092//1 2093//1 2058//1 +f 2058//1 2093//1 2059//1 +f 2093//1 2094//1 2059//1 +f 2059//1 2094//1 2060//1 +f 2094//1 2095//1 2060//1 +f 2060//1 2095//1 2061//1 +f 2095//1 2096//1 2061//1 +f 2061//1 2096//1 2062//1 +f 2096//1 2097//1 2062//1 +f 2062//1 2097//1 2063//1 +f 2097//1 2098//1 2063//1 +f 2063//1 2098//1 2064//1 +f 2098//1 2099//1 2064//1 +f 2064//1 2099//1 2065//1 +f 2099//1 2100//1 2065//1 +f 2065//1 2100//1 2066//1 +f 2100//1 2101//1 2066//1 +f 2066//1 2101//1 2067//1 +f 2101//1 2102//1 2067//1 +f 2067//1 2102//1 2068//1 +f 2102//1 2103//1 2068//1 +f 2068//1 2103//1 2069//1 +f 2103//1 2104//1 2069//1 +f 2069//1 2104//1 2070//1 +f 2104//1 2105//1 2070//1 +f 2070//1 2105//1 2071//1 +f 2105//1 2106//1 2071//1 +f 2071//1 2106//1 2072//1 +f 2106//1 2107//1 2072//1 +f 2072//1 2107//1 2073//1 +f 2107//1 2108//1 2073//1 +f 2073//1 2108//1 2074//1 +f 2108//1 2109//1 2074//1 +f 2074//1 2109//1 20//1 +f 2109//1 19//1 20//1 +f 90//1 2110//1 2075//1 +f 2110//1 2111//1 2075//1 +f 2075//1 2111//1 2076//1 +f 2111//1 2112//1 2076//1 +f 2076//1 2112//1 2077//1 +f 2112//1 2113//1 2077//1 +f 2077//1 2113//1 2078//1 +f 2113//1 2114//1 2078//1 +f 2078//1 2114//1 2079//1 +f 2114//1 2115//1 2079//1 +f 2079//1 2115//1 2080//1 +f 2115//1 2116//1 2080//1 +f 2080//1 2116//1 2081//1 +f 2116//1 2117//1 2081//1 +f 2081//1 2117//1 2082//1 +f 2117//1 2118//1 2082//1 +f 2082//1 2118//1 2083//1 +f 2118//1 2119//1 2083//1 +f 2083//1 2119//1 2084//1 +f 2119//1 2120//1 2084//1 +f 2084//1 2120//1 2085//1 +f 2120//1 2121//1 2085//1 +f 2085//1 2121//1 2086//1 +f 2121//1 2122//1 2086//1 +f 2086//1 2122//1 2087//1 +f 2122//1 2123//1 2087//1 +f 2087//1 2123//1 2088//1 +f 2123//1 2124//1 2088//1 +f 2088//1 2124//1 2089//1 +f 2124//1 2125//1 2089//1 +f 2089//1 2125//1 2090//1 +f 2125//1 2126//1 2090//1 +f 2090//1 2126//1 2091//1 +f 2126//1 2127//1 2091//1 +f 2091//1 2127//1 2092//1 +f 2127//1 2128//1 2092//1 +f 2092//1 2128//1 2093//1 +f 2128//1 2129//1 2093//1 +f 2093//1 2129//1 2094//1 +f 2129//1 2130//1 2094//1 +f 2094//1 2130//1 2095//1 +f 2130//1 2131//1 2095//1 +f 2095//1 2131//1 2096//1 +f 2131//1 2132//1 2096//1 +f 2096//1 2132//1 2097//1 +f 2132//1 2133//1 2097//1 +f 2097//1 2133//1 2098//1 +f 2133//1 2134//1 2098//1 +f 2098//1 2134//1 2099//1 +f 2134//1 2135//1 2099//1 +f 2099//1 2135//1 2100//1 +f 2135//1 2136//1 2100//1 +f 2100//1 2136//1 2101//1 +f 2136//1 2137//1 2101//1 +f 2101//1 2137//1 2102//1 +f 2137//1 2138//1 2102//1 +f 2102//1 2138//1 2103//1 +f 2138//1 2139//1 2103//1 +f 2103//1 2139//1 2104//1 +f 2139//1 2140//1 2104//1 +f 2104//1 2140//1 2105//1 +f 2140//1 2141//1 2105//1 +f 2105//1 2141//1 2106//1 +f 2141//1 2142//1 2106//1 +f 2106//1 2142//1 2107//1 +f 2142//1 2143//1 2107//1 +f 2107//1 2143//1 2108//1 +f 2143//1 2144//1 2108//1 +f 2108//1 2144//1 2109//1 +f 2144//1 2145//1 2109//1 +f 2109//1 2145//1 19//1 +f 2145//1 18//1 19//1 +f 91//1 2146//1 2110//1 +f 2146//1 2147//1 2110//1 +f 2110//1 2147//1 2111//1 +f 2147//1 2148//1 2111//1 +f 2111//1 2148//1 2112//1 +f 2148//1 2149//1 2112//1 +f 2112//1 2149//1 2113//1 +f 2149//1 2150//1 2113//1 +f 2113//1 2150//1 2114//1 +f 2150//1 2151//1 2114//1 +f 2114//1 2151//1 2115//1 +f 2151//1 2152//1 2115//1 +f 2115//1 2152//1 2116//1 +f 2152//1 2153//1 2116//1 +f 2116//1 2153//1 2117//1 +f 2153//1 2154//1 2117//1 +f 2117//1 2154//1 2118//1 +f 2154//1 2155//1 2118//1 +f 2118//1 2155//1 2119//1 +f 2155//1 2156//1 2119//1 +f 2119//1 2156//1 2120//1 +f 2156//1 2157//1 2120//1 +f 2120//1 2157//1 2121//1 +f 2157//1 2158//1 2121//1 +f 2121//1 2158//1 2122//1 +f 2158//1 2159//1 2122//1 +f 2122//1 2159//1 2123//1 +f 2159//1 2160//1 2123//1 +f 2123//1 2160//1 2124//1 +f 2160//1 2161//1 2124//1 +f 2124//1 2161//1 2125//1 +f 2161//1 2162//1 2125//1 +f 2125//1 2162//1 2126//1 +f 2162//1 2163//1 2126//1 +f 2126//1 2163//1 2127//1 +f 2163//1 2164//1 2127//1 +f 2127//1 2164//1 2128//1 +f 2164//1 2165//1 2128//1 +f 2128//1 2165//1 2129//1 +f 2165//1 2166//1 2129//1 +f 2129//1 2166//1 2130//1 +f 2166//1 2167//1 2130//1 +f 2130//1 2167//1 2131//1 +f 2167//1 2168//1 2131//1 +f 2131//1 2168//1 2132//1 +f 2168//1 2169//1 2132//1 +f 2132//1 2169//1 2133//1 +f 2169//1 2170//1 2133//1 +f 2133//1 2170//1 2134//1 +f 2170//1 2171//1 2134//1 +f 2134//1 2171//1 2135//1 +f 2171//1 2172//1 2135//1 +f 2135//1 2172//1 2136//1 +f 2172//1 2173//1 2136//1 +f 2136//1 2173//1 2137//1 +f 2173//1 2174//1 2137//1 +f 2137//1 2174//1 2138//1 +f 2174//1 2175//1 2138//1 +f 2138//1 2175//1 2139//1 +f 2175//1 2176//1 2139//1 +f 2139//1 2176//1 2140//1 +f 2176//1 2177//1 2140//1 +f 2140//1 2177//1 2141//1 +f 2177//1 2178//1 2141//1 +f 2141//1 2178//1 2142//1 +f 2178//1 2179//1 2142//1 +f 2142//1 2179//1 2143//1 +f 2179//1 2180//1 2143//1 +f 2143//1 2180//1 2144//1 +f 2180//1 2181//1 2144//1 +f 2144//1 2181//1 2145//1 +f 2181//1 2182//1 2145//1 +f 2145//1 2182//1 18//1 +f 2182//1 17//1 18//1 +f 92//1 2183//1 2146//1 +f 2183//1 2184//1 2146//1 +f 2146//1 2184//1 2147//1 +f 2184//1 2185//1 2147//1 +f 2147//1 2185//1 2148//1 +f 2185//1 2186//1 2148//1 +f 2148//1 2186//1 2149//1 +f 2186//1 2187//1 2149//1 +f 2149//1 2187//1 2150//1 +f 2187//1 2188//1 2150//1 +f 2150//1 2188//1 2151//1 +f 2188//1 2189//1 2151//1 +f 2151//1 2189//1 2152//1 +f 2189//1 2190//1 2152//1 +f 2152//1 2190//1 2153//1 +f 2190//1 2191//1 2153//1 +f 2153//1 2191//1 2154//1 +f 2191//1 2192//1 2154//1 +f 2154//1 2192//1 2155//1 +f 2192//1 2193//1 2155//1 +f 2155//1 2193//1 2156//1 +f 2193//1 2194//1 2156//1 +f 2156//1 2194//1 2157//1 +f 2194//1 2195//1 2157//1 +f 2157//1 2195//1 2158//1 +f 2195//1 2196//1 2158//1 +f 2158//1 2196//1 2159//1 +f 2196//1 2197//1 2159//1 +f 2159//1 2197//1 2160//1 +f 2197//1 2198//1 2160//1 +f 2160//1 2198//1 2161//1 +f 2198//1 2199//1 2161//1 +f 2161//1 2199//1 2162//1 +f 2199//1 2200//1 2162//1 +f 2162//1 2200//1 2163//1 +f 2200//1 2201//1 2163//1 +f 2163//1 2201//1 2164//1 +f 2201//1 2202//1 2164//1 +f 2164//1 2202//1 2165//1 +f 2202//1 2203//1 2165//1 +f 2165//1 2203//1 2166//1 +f 2203//1 2204//1 2166//1 +f 2166//1 2204//1 2167//1 +f 2204//1 2205//1 2167//1 +f 2167//1 2205//1 2168//1 +f 2205//1 2206//1 2168//1 +f 2168//1 2206//1 2169//1 +f 2206//1 2207//1 2169//1 +f 2169//1 2207//1 2170//1 +f 2207//1 2208//1 2170//1 +f 2170//1 2208//1 2171//1 +f 2208//1 2209//1 2171//1 +f 2171//1 2209//1 2172//1 +f 2209//1 2210//1 2172//1 +f 2172//1 2210//1 2173//1 +f 2210//1 2211//1 2173//1 +f 2173//1 2211//1 2174//1 +f 2211//1 2212//1 2174//1 +f 2174//1 2212//1 2175//1 +f 2212//1 2213//1 2175//1 +f 2175//1 2213//1 2176//1 +f 2213//1 2214//1 2176//1 +f 2176//1 2214//1 2177//1 +f 2214//1 2215//1 2177//1 +f 2177//1 2215//1 2178//1 +f 2215//1 2216//1 2178//1 +f 2178//1 2216//1 2179//1 +f 2216//1 2217//1 2179//1 +f 2179//1 2217//1 2180//1 +f 2217//1 2218//1 2180//1 +f 2180//1 2218//1 2181//1 +f 2218//1 2219//1 2181//1 +f 2181//1 2219//1 2182//1 +f 2219//1 2220//1 2182//1 +f 2182//1 2220//1 17//1 +f 2220//1 16//1 17//1 +f 93//1 2221//1 2183//1 +f 2221//1 2222//1 2183//1 +f 2183//1 2222//1 2184//1 +f 2222//1 2223//1 2184//1 +f 2184//1 2223//1 2185//1 +f 2223//1 2224//1 2185//1 +f 2185//1 2224//1 2186//1 +f 2224//1 2225//1 2186//1 +f 2186//1 2225//1 2187//1 +f 2225//1 2226//1 2187//1 +f 2187//1 2226//1 2188//1 +f 2226//1 2227//1 2188//1 +f 2188//1 2227//1 2189//1 +f 2227//1 2228//1 2189//1 +f 2189//1 2228//1 2190//1 +f 2228//1 2229//1 2190//1 +f 2190//1 2229//1 2191//1 +f 2229//1 2230//1 2191//1 +f 2191//1 2230//1 2192//1 +f 2230//1 2231//1 2192//1 +f 2192//1 2231//1 2193//1 +f 2231//1 2232//1 2193//1 +f 2193//1 2232//1 2194//1 +f 2232//1 2233//1 2194//1 +f 2194//1 2233//1 2195//1 +f 2233//1 2234//1 2195//1 +f 2195//1 2234//1 2196//1 +f 2234//1 2235//1 2196//1 +f 2196//1 2235//1 2197//1 +f 2235//1 2236//1 2197//1 +f 2197//1 2236//1 2198//1 +f 2236//1 2237//1 2198//1 +f 2198//1 2237//1 2199//1 +f 2237//1 2238//1 2199//1 +f 2199//1 2238//1 2200//1 +f 2238//1 2239//1 2200//1 +f 2200//1 2239//1 2201//1 +f 2239//1 2240//1 2201//1 +f 2201//1 2240//1 2202//1 +f 2240//1 2241//1 2202//1 +f 2202//1 2241//1 2203//1 +f 2241//1 2242//1 2203//1 +f 2203//1 2242//1 2204//1 +f 2242//1 2243//1 2204//1 +f 2204//1 2243//1 2205//1 +f 2243//1 2244//1 2205//1 +f 2205//1 2244//1 2206//1 +f 2244//1 2245//1 2206//1 +f 2206//1 2245//1 2207//1 +f 2245//1 2246//1 2207//1 +f 2207//1 2246//1 2208//1 +f 2246//1 2247//1 2208//1 +f 2208//1 2247//1 2209//1 +f 2247//1 2248//1 2209//1 +f 2209//1 2248//1 2210//1 +f 2248//1 2249//1 2210//1 +f 2210//1 2249//1 2211//1 +f 2249//1 2250//1 2211//1 +f 2211//1 2250//1 2212//1 +f 2250//1 2251//1 2212//1 +f 2212//1 2251//1 2213//1 +f 2251//1 2252//1 2213//1 +f 2213//1 2252//1 2214//1 +f 2252//1 2253//1 2214//1 +f 2214//1 2253//1 2215//1 +f 2253//1 2254//1 2215//1 +f 2215//1 2254//1 2216//1 +f 2254//1 2255//1 2216//1 +f 2216//1 2255//1 2217//1 +f 2255//1 2256//1 2217//1 +f 2217//1 2256//1 2218//1 +f 2256//1 2257//1 2218//1 +f 2218//1 2257//1 2219//1 +f 2257//1 2258//1 2219//1 +f 2219//1 2258//1 2220//1 +f 2258//1 2259//1 2220//1 +f 2220//1 2259//1 16//1 +f 2259//1 15//1 16//1 +f 94//1 2260//1 2221//1 +f 2260//1 2261//1 2221//1 +f 2221//1 2261//1 2222//1 +f 2261//1 2262//1 2222//1 +f 2222//1 2262//1 2223//1 +f 2262//1 2263//1 2223//1 +f 2223//1 2263//1 2224//1 +f 2263//1 2264//1 2224//1 +f 2224//1 2264//1 2225//1 +f 2264//1 2265//1 2225//1 +f 2225//1 2265//1 2226//1 +f 2265//1 2266//1 2226//1 +f 2226//1 2266//1 2227//1 +f 2266//1 2267//1 2227//1 +f 2227//1 2267//1 2228//1 +f 2267//1 2268//1 2228//1 +f 2228//1 2268//1 2229//1 +f 2268//1 2269//1 2229//1 +f 2229//1 2269//1 2230//1 +f 2269//1 2270//1 2230//1 +f 2230//1 2270//1 2231//1 +f 2270//1 2271//1 2231//1 +f 2231//1 2271//1 2232//1 +f 2271//1 2272//1 2232//1 +f 2232//1 2272//1 2233//1 +f 2272//1 2273//1 2233//1 +f 2233//1 2273//1 2234//1 +f 2273//1 2274//1 2234//1 +f 2234//1 2274//1 2235//1 +f 2274//1 2275//1 2235//1 +f 2235//1 2275//1 2236//1 +f 2275//1 2276//1 2236//1 +f 2236//1 2276//1 2237//1 +f 2276//1 2277//1 2237//1 +f 2237//1 2277//1 2238//1 +f 2277//1 2278//1 2238//1 +f 2238//1 2278//1 2239//1 +f 2278//1 2279//1 2239//1 +f 2239//1 2279//1 2240//1 +f 2279//1 2280//1 2240//1 +f 2240//1 2280//1 2241//1 +f 2280//1 2281//1 2241//1 +f 2241//1 2281//1 2242//1 +f 2281//1 2282//1 2242//1 +f 2242//1 2282//1 2243//1 +f 2282//1 2283//1 2243//1 +f 2243//1 2283//1 2244//1 +f 2283//1 2284//1 2244//1 +f 2244//1 2284//1 2245//1 +f 2284//1 2285//1 2245//1 +f 2245//1 2285//1 2246//1 +f 2285//1 2286//1 2246//1 +f 2246//1 2286//1 2247//1 +f 2286//1 2287//1 2247//1 +f 2247//1 2287//1 2248//1 +f 2287//1 2288//1 2248//1 +f 2248//1 2288//1 2249//1 +f 2288//1 2289//1 2249//1 +f 2249//1 2289//1 2250//1 +f 2289//1 2290//1 2250//1 +f 2250//1 2290//1 2251//1 +f 2290//1 2291//1 2251//1 +f 2251//1 2291//1 2252//1 +f 2291//1 2292//1 2252//1 +f 2252//1 2292//1 2253//1 +f 2292//1 2293//1 2253//1 +f 2253//1 2293//1 2254//1 +f 2293//1 2294//1 2254//1 +f 2254//1 2294//1 2255//1 +f 2294//1 2295//1 2255//1 +f 2255//1 2295//1 2256//1 +f 2295//1 2296//1 2256//1 +f 2256//1 2296//1 2257//1 +f 2296//1 2297//1 2257//1 +f 2257//1 2297//1 2258//1 +f 2297//1 2298//1 2258//1 +f 2258//1 2298//1 2259//1 +f 2298//1 2299//1 2259//1 +f 2259//1 2299//1 15//1 +f 2299//1 14//1 15//1 +f 95//1 2300//1 2260//1 +f 2300//1 2301//1 2260//1 +f 2260//1 2301//1 2261//1 +f 2301//1 2302//1 2261//1 +f 2261//1 2302//1 2262//1 +f 2302//1 2303//1 2262//1 +f 2262//1 2303//1 2263//1 +f 2303//1 2304//1 2263//1 +f 2263//1 2304//1 2264//1 +f 2304//1 2305//1 2264//1 +f 2264//1 2305//1 2265//1 +f 2305//1 2306//1 2265//1 +f 2265//1 2306//1 2266//1 +f 2306//1 2307//1 2266//1 +f 2266//1 2307//1 2267//1 +f 2307//1 2308//1 2267//1 +f 2267//1 2308//1 2268//1 +f 2308//1 2309//1 2268//1 +f 2268//1 2309//1 2269//1 +f 2309//1 2310//1 2269//1 +f 2269//1 2310//1 2270//1 +f 2310//1 2311//1 2270//1 +f 2270//1 2311//1 2271//1 +f 2311//1 2312//1 2271//1 +f 2271//1 2312//1 2272//1 +f 2312//1 2313//1 2272//1 +f 2272//1 2313//1 2273//1 +f 2313//1 2314//1 2273//1 +f 2273//1 2314//1 2274//1 +f 2314//1 2315//1 2274//1 +f 2274//1 2315//1 2275//1 +f 2315//1 2316//1 2275//1 +f 2275//1 2316//1 2276//1 +f 2316//1 2317//1 2276//1 +f 2276//1 2317//1 2277//1 +f 2317//1 2318//1 2277//1 +f 2277//1 2318//1 2278//1 +f 2318//1 2319//1 2278//1 +f 2278//1 2319//1 2279//1 +f 2319//1 2320//1 2279//1 +f 2279//1 2320//1 2280//1 +f 2320//1 2321//1 2280//1 +f 2280//1 2321//1 2281//1 +f 2321//1 2322//1 2281//1 +f 2281//1 2322//1 2282//1 +f 2322//1 2323//1 2282//1 +f 2282//1 2323//1 2283//1 +f 2323//1 2324//1 2283//1 +f 2283//1 2324//1 2284//1 +f 2324//1 2325//1 2284//1 +f 2284//1 2325//1 2285//1 +f 2325//1 2326//1 2285//1 +f 2285//1 2326//1 2286//1 +f 2326//1 2327//1 2286//1 +f 2286//1 2327//1 2287//1 +f 2327//1 2328//1 2287//1 +f 2287//1 2328//1 2288//1 +f 2328//1 2329//1 2288//1 +f 2288//1 2329//1 2289//1 +f 2329//1 2330//1 2289//1 +f 2289//1 2330//1 2290//1 +f 2330//1 2331//1 2290//1 +f 2290//1 2331//1 2291//1 +f 2331//1 2332//1 2291//1 +f 2291//1 2332//1 2292//1 +f 2332//1 2333//1 2292//1 +f 2292//1 2333//1 2293//1 +f 2333//1 2334//1 2293//1 +f 2293//1 2334//1 2294//1 +f 2334//1 2335//1 2294//1 +f 2294//1 2335//1 2295//1 +f 2335//1 2336//1 2295//1 +f 2295//1 2336//1 2296//1 +f 2336//1 2337//1 2296//1 +f 2296//1 2337//1 2297//1 +f 2337//1 2338//1 2297//1 +f 2297//1 2338//1 2298//1 +f 2338//1 2339//1 2298//1 +f 2298//1 2339//1 2299//1 +f 2339//1 2340//1 2299//1 +f 2299//1 2340//1 14//1 +f 2340//1 13//1 14//1 +f 96//1 2341//1 2300//1 +f 2341//1 2342//1 2300//1 +f 2300//1 2342//1 2301//1 +f 2342//1 2343//1 2301//1 +f 2301//1 2343//1 2302//1 +f 2343//1 2344//1 2302//1 +f 2302//1 2344//1 2303//1 +f 2344//1 2345//1 2303//1 +f 2303//1 2345//1 2304//1 +f 2345//1 2346//1 2304//1 +f 2304//1 2346//1 2305//1 +f 2346//1 2347//1 2305//1 +f 2305//1 2347//1 2306//1 +f 2347//1 2348//1 2306//1 +f 2306//1 2348//1 2307//1 +f 2348//1 2349//1 2307//1 +f 2307//1 2349//1 2308//1 +f 2349//1 2350//1 2308//1 +f 2308//1 2350//1 2309//1 +f 2350//1 2351//1 2309//1 +f 2309//1 2351//1 2310//1 +f 2351//1 2352//1 2310//1 +f 2310//1 2352//1 2311//1 +f 2352//1 2353//1 2311//1 +f 2311//1 2353//1 2312//1 +f 2353//1 2354//1 2312//1 +f 2312//1 2354//1 2313//1 +f 2354//1 2355//1 2313//1 +f 2313//1 2355//1 2314//1 +f 2355//1 2356//1 2314//1 +f 2314//1 2356//1 2315//1 +f 2356//1 2357//1 2315//1 +f 2315//1 2357//1 2316//1 +f 2357//1 2358//1 2316//1 +f 2316//1 2358//1 2317//1 +f 2358//1 2359//1 2317//1 +f 2317//1 2359//1 2318//1 +f 2359//1 2360//1 2318//1 +f 2318//1 2360//1 2319//1 +f 2360//1 2361//1 2319//1 +f 2319//1 2361//1 2320//1 +f 2361//1 2362//1 2320//1 +f 2320//1 2362//1 2321//1 +f 2362//1 2363//1 2321//1 +f 2321//1 2363//1 2322//1 +f 2363//1 2364//1 2322//1 +f 2322//1 2364//1 2323//1 +f 2364//1 2365//1 2323//1 +f 2323//1 2365//1 2324//1 +f 2365//1 2366//1 2324//1 +f 2324//1 2366//1 2325//1 +f 2366//1 2367//1 2325//1 +f 2325//1 2367//1 2326//1 +f 2367//1 2368//1 2326//1 +f 2326//1 2368//1 2327//1 +f 2368//1 2369//1 2327//1 +f 2327//1 2369//1 2328//1 +f 2369//1 2370//1 2328//1 +f 2328//1 2370//1 2329//1 +f 2370//1 2371//1 2329//1 +f 2329//1 2371//1 2330//1 +f 2371//1 2372//1 2330//1 +f 2330//1 2372//1 2331//1 +f 2372//1 2373//1 2331//1 +f 2331//1 2373//1 2332//1 +f 2373//1 2374//1 2332//1 +f 2332//1 2374//1 2333//1 +f 2374//1 2375//1 2333//1 +f 2333//1 2375//1 2334//1 +f 2375//1 2376//1 2334//1 +f 2334//1 2376//1 2335//1 +f 2376//1 2377//1 2335//1 +f 2335//1 2377//1 2336//1 +f 2377//1 2378//1 2336//1 +f 2336//1 2378//1 2337//1 +f 2378//1 2379//1 2337//1 +f 2337//1 2379//1 2338//1 +f 2379//1 2380//1 2338//1 +f 2338//1 2380//1 2339//1 +f 2380//1 2381//1 2339//1 +f 2339//1 2381//1 2340//1 +f 2381//1 2382//1 2340//1 +f 2340//1 2382//1 13//1 +f 2382//1 12//1 13//1 +f 97//1 2383//1 2341//1 +f 2383//1 2384//1 2341//1 +f 2341//1 2384//1 2342//1 +f 2384//1 2385//1 2342//1 +f 2342//1 2385//1 2343//1 +f 2385//1 2386//1 2343//1 +f 2343//1 2386//1 2344//1 +f 2386//1 2387//1 2344//1 +f 2344//1 2387//1 2345//1 +f 2387//1 2388//1 2345//1 +f 2345//1 2388//1 2346//1 +f 2388//1 2389//1 2346//1 +f 2346//1 2389//1 2347//1 +f 2389//1 2390//1 2347//1 +f 2347//1 2390//1 2348//1 +f 2390//1 2391//1 2348//1 +f 2348//1 2391//1 2349//1 +f 2391//1 2392//1 2349//1 +f 2349//1 2392//1 2350//1 +f 2392//1 2393//1 2350//1 +f 2350//1 2393//1 2351//1 +f 2393//1 2394//1 2351//1 +f 2351//1 2394//1 2352//1 +f 2394//1 2395//1 2352//1 +f 2352//1 2395//1 2353//1 +f 2395//1 2396//1 2353//1 +f 2353//1 2396//1 2354//1 +f 2396//1 2397//1 2354//1 +f 2354//1 2397//1 2355//1 +f 2397//1 2398//1 2355//1 +f 2355//1 2398//1 2356//1 +f 2398//1 2399//1 2356//1 +f 2356//1 2399//1 2357//1 +f 2399//1 2400//1 2357//1 +f 2357//1 2400//1 2358//1 +f 2400//1 2401//1 2358//1 +f 2358//1 2401//1 2359//1 +f 2401//1 2402//1 2359//1 +f 2359//1 2402//1 2360//1 +f 2402//1 2403//1 2360//1 +f 2360//1 2403//1 2361//1 +f 2403//1 2404//1 2361//1 +f 2361//1 2404//1 2362//1 +f 2404//1 2405//1 2362//1 +f 2362//1 2405//1 2363//1 +f 2405//1 2406//1 2363//1 +f 2363//1 2406//1 2364//1 +f 2406//1 2407//1 2364//1 +f 2364//1 2407//1 2365//1 +f 2407//1 2408//1 2365//1 +f 2365//1 2408//1 2366//1 +f 2408//1 2409//1 2366//1 +f 2366//1 2409//1 2367//1 +f 2409//1 2410//1 2367//1 +f 2367//1 2410//1 2368//1 +f 2410//1 2411//1 2368//1 +f 2368//1 2411//1 2369//1 +f 2411//1 2412//1 2369//1 +f 2369//1 2412//1 2370//1 +f 2412//1 2413//1 2370//1 +f 2370//1 2413//1 2371//1 +f 2413//1 2414//1 2371//1 +f 2371//1 2414//1 2372//1 +f 2414//1 2415//1 2372//1 +f 2372//1 2415//1 2373//1 +f 2415//1 2416//1 2373//1 +f 2373//1 2416//1 2374//1 +f 2416//1 2417//1 2374//1 +f 2374//1 2417//1 2375//1 +f 2417//1 2418//1 2375//1 +f 2375//1 2418//1 2376//1 +f 2418//1 2419//1 2376//1 +f 2376//1 2419//1 2377//1 +f 2419//1 2420//1 2377//1 +f 2377//1 2420//1 2378//1 +f 2420//1 2421//1 2378//1 +f 2378//1 2421//1 2379//1 +f 2421//1 2422//1 2379//1 +f 2379//1 2422//1 2380//1 +f 2422//1 2423//1 2380//1 +f 2380//1 2423//1 2381//1 +f 2423//1 2424//1 2381//1 +f 2381//1 2424//1 2382//1 +f 2424//1 2425//1 2382//1 +f 2382//1 2425//1 12//1 +f 2425//1 11//1 12//1 +f 98//1 2426//1 2383//1 +f 2426//1 2427//1 2383//1 +f 2383//1 2427//1 2384//1 +f 2427//1 2428//1 2384//1 +f 2384//1 2428//1 2385//1 +f 2428//1 2429//1 2385//1 +f 2385//1 2429//1 2386//1 +f 2429//1 2430//1 2386//1 +f 2386//1 2430//1 2387//1 +f 2430//1 2431//1 2387//1 +f 2387//1 2431//1 2388//1 +f 2431//1 2432//1 2388//1 +f 2388//1 2432//1 2389//1 +f 2432//1 2433//1 2389//1 +f 2389//1 2433//1 2390//1 +f 2433//1 2434//1 2390//1 +f 2390//1 2434//1 2391//1 +f 2434//1 2435//1 2391//1 +f 2391//1 2435//1 2392//1 +f 2435//1 2436//1 2392//1 +f 2392//1 2436//1 2393//1 +f 2436//1 2437//1 2393//1 +f 2393//1 2437//1 2394//1 +f 2437//1 2438//1 2394//1 +f 2394//1 2438//1 2395//1 +f 2438//1 2439//1 2395//1 +f 2395//1 2439//1 2396//1 +f 2439//1 2440//1 2396//1 +f 2396//1 2440//1 2397//1 +f 2440//1 2441//1 2397//1 +f 2397//1 2441//1 2398//1 +f 2441//1 2442//1 2398//1 +f 2398//1 2442//1 2399//1 +f 2442//1 2443//1 2399//1 +f 2399//1 2443//1 2400//1 +f 2443//1 2444//1 2400//1 +f 2400//1 2444//1 2401//1 +f 2444//1 2445//1 2401//1 +f 2401//1 2445//1 2402//1 +f 2445//1 2446//1 2402//1 +f 2402//1 2446//1 2403//1 +f 2446//1 2447//1 2403//1 +f 2403//1 2447//1 2404//1 +f 2447//1 2448//1 2404//1 +f 2404//1 2448//1 2405//1 +f 2448//1 2449//1 2405//1 +f 2405//1 2449//1 2406//1 +f 2449//1 2450//1 2406//1 +f 2406//1 2450//1 2407//1 +f 2450//1 2451//1 2407//1 +f 2407//1 2451//1 2408//1 +f 2451//1 2452//1 2408//1 +f 2408//1 2452//1 2409//1 +f 2452//1 2453//1 2409//1 +f 2409//1 2453//1 2410//1 +f 2453//1 2454//1 2410//1 +f 2410//1 2454//1 2411//1 +f 2454//1 2455//1 2411//1 +f 2411//1 2455//1 2412//1 +f 2455//1 2456//1 2412//1 +f 2412//1 2456//1 2413//1 +f 2456//1 2457//1 2413//1 +f 2413//1 2457//1 2414//1 +f 2457//1 2458//1 2414//1 +f 2414//1 2458//1 2415//1 +f 2458//1 2459//1 2415//1 +f 2415//1 2459//1 2416//1 +f 2459//1 2460//1 2416//1 +f 2416//1 2460//1 2417//1 +f 2460//1 2461//1 2417//1 +f 2417//1 2461//1 2418//1 +f 2461//1 2462//1 2418//1 +f 2418//1 2462//1 2419//1 +f 2462//1 2463//1 2419//1 +f 2419//1 2463//1 2420//1 +f 2463//1 2464//1 2420//1 +f 2420//1 2464//1 2421//1 +f 2464//1 2465//1 2421//1 +f 2421//1 2465//1 2422//1 +f 2465//1 2466//1 2422//1 +f 2422//1 2466//1 2423//1 +f 2466//1 2467//1 2423//1 +f 2423//1 2467//1 2424//1 +f 2467//1 2468//1 2424//1 +f 2424//1 2468//1 2425//1 +f 2468//1 2469//1 2425//1 +f 2425//1 2469//1 11//1 +f 2469//1 10//1 11//1 +f 99//1 2470//1 2426//1 +f 2470//1 2471//1 2426//1 +f 2426//1 2471//1 2427//1 +f 2471//1 2472//1 2427//1 +f 2427//1 2472//1 2428//1 +f 2472//1 2473//1 2428//1 +f 2428//1 2473//1 2429//1 +f 2473//1 2474//1 2429//1 +f 2429//1 2474//1 2430//1 +f 2474//1 2475//1 2430//1 +f 2430//1 2475//1 2431//1 +f 2475//1 2476//1 2431//1 +f 2431//1 2476//1 2432//1 +f 2476//1 2477//1 2432//1 +f 2432//1 2477//1 2433//1 +f 2477//1 2478//1 2433//1 +f 2433//1 2478//1 2434//1 +f 2478//1 2479//1 2434//1 +f 2434//1 2479//1 2435//1 +f 2479//1 2480//1 2435//1 +f 2435//1 2480//1 2436//1 +f 2480//1 2481//1 2436//1 +f 2436//1 2481//1 2437//1 +f 2481//1 2482//1 2437//1 +f 2437//1 2482//1 2438//1 +f 2482//1 2483//1 2438//1 +f 2438//1 2483//1 2439//1 +f 2483//1 2484//1 2439//1 +f 2439//1 2484//1 2440//1 +f 2484//1 2485//1 2440//1 +f 2440//1 2485//1 2441//1 +f 2485//1 2486//1 2441//1 +f 2441//1 2486//1 2442//1 +f 2486//1 2487//1 2442//1 +f 2442//1 2487//1 2443//1 +f 2487//1 2488//1 2443//1 +f 2443//1 2488//1 2444//1 +f 2488//1 2489//1 2444//1 +f 2444//1 2489//1 2445//1 +f 2489//1 2490//1 2445//1 +f 2445//1 2490//1 2446//1 +f 2490//1 2491//1 2446//1 +f 2446//1 2491//1 2447//1 +f 2491//1 2492//1 2447//1 +f 2447//1 2492//1 2448//1 +f 2492//1 2493//1 2448//1 +f 2448//1 2493//1 2449//1 +f 2493//1 2494//1 2449//1 +f 2449//1 2494//1 2450//1 +f 2494//1 2495//1 2450//1 +f 2450//1 2495//1 2451//1 +f 2495//1 2496//1 2451//1 +f 2451//1 2496//1 2452//1 +f 2496//1 2497//1 2452//1 +f 2452//1 2497//1 2453//1 +f 2497//1 2498//1 2453//1 +f 2453//1 2498//1 2454//1 +f 2498//1 2499//1 2454//1 +f 2454//1 2499//1 2455//1 +f 2499//1 2500//1 2455//1 +f 2455//1 2500//1 2456//1 +f 2500//1 2501//1 2456//1 +f 2456//1 2501//1 2457//1 +f 2501//1 2502//1 2457//1 +f 2457//1 2502//1 2458//1 +f 2502//1 2503//1 2458//1 +f 2458//1 2503//1 2459//1 +f 2503//1 2504//1 2459//1 +f 2459//1 2504//1 2460//1 +f 2504//1 2505//1 2460//1 +f 2460//1 2505//1 2461//1 +f 2505//1 2506//1 2461//1 +f 2461//1 2506//1 2462//1 +f 2506//1 2507//1 2462//1 +f 2462//1 2507//1 2463//1 +f 2507//1 2508//1 2463//1 +f 2463//1 2508//1 2464//1 +f 2508//1 2509//1 2464//1 +f 2464//1 2509//1 2465//1 +f 2509//1 2510//1 2465//1 +f 2465//1 2510//1 2466//1 +f 2510//1 2511//1 2466//1 +f 2466//1 2511//1 2467//1 +f 2511//1 2512//1 2467//1 +f 2467//1 2512//1 2468//1 +f 2512//1 2513//1 2468//1 +f 2468//1 2513//1 2469//1 +f 2513//1 2514//1 2469//1 +f 2469//1 2514//1 10//1 +f 2514//1 9//1 10//1 +f 100//1 2515//1 2470//1 +f 2515//1 2516//1 2470//1 +f 2470//1 2516//1 2471//1 +f 2516//1 2517//1 2471//1 +f 2471//1 2517//1 2472//1 +f 2517//1 2518//1 2472//1 +f 2472//1 2518//1 2473//1 +f 2518//1 2519//1 2473//1 +f 2473//1 2519//1 2474//1 +f 2519//1 2520//1 2474//1 +f 2474//1 2520//1 2475//1 +f 2520//1 2521//1 2475//1 +f 2475//1 2521//1 2476//1 +f 2521//1 2522//1 2476//1 +f 2476//1 2522//1 2477//1 +f 2522//1 2523//1 2477//1 +f 2477//1 2523//1 2478//1 +f 2523//1 2524//1 2478//1 +f 2478//1 2524//1 2479//1 +f 2524//1 2525//1 2479//1 +f 2479//1 2525//1 2480//1 +f 2525//1 2526//1 2480//1 +f 2480//1 2526//1 2481//1 +f 2526//1 2527//1 2481//1 +f 2481//1 2527//1 2482//1 +f 2527//1 2528//1 2482//1 +f 2482//1 2528//1 2483//1 +f 2528//1 2529//1 2483//1 +f 2483//1 2529//1 2484//1 +f 2529//1 2530//1 2484//1 +f 2484//1 2530//1 2485//1 +f 2530//1 2531//1 2485//1 +f 2485//1 2531//1 2486//1 +f 2531//1 2532//1 2486//1 +f 2486//1 2532//1 2487//1 +f 2532//1 2533//1 2487//1 +f 2487//1 2533//1 2488//1 +f 2533//1 2534//1 2488//1 +f 2488//1 2534//1 2489//1 +f 2534//1 2535//1 2489//1 +f 2489//1 2535//1 2490//1 +f 2535//1 2536//1 2490//1 +f 2490//1 2536//1 2491//1 +f 2536//1 2537//1 2491//1 +f 2491//1 2537//1 2492//1 +f 2537//1 2538//1 2492//1 +f 2492//1 2538//1 2493//1 +f 2538//1 2539//1 2493//1 +f 2493//1 2539//1 2494//1 +f 2539//1 2540//1 2494//1 +f 2494//1 2540//1 2495//1 +f 2540//1 2541//1 2495//1 +f 2495//1 2541//1 2496//1 +f 2541//1 2542//1 2496//1 +f 2496//1 2542//1 2497//1 +f 2542//1 2543//1 2497//1 +f 2497//1 2543//1 2498//1 +f 2543//1 2544//1 2498//1 +f 2498//1 2544//1 2499//1 +f 2544//1 2545//1 2499//1 +f 2499//1 2545//1 2500//1 +f 2545//1 2546//1 2500//1 +f 2500//1 2546//1 2501//1 +f 2546//1 2547//1 2501//1 +f 2501//1 2547//1 2502//1 +f 2547//1 2548//1 2502//1 +f 2502//1 2548//1 2503//1 +f 2548//1 2549//1 2503//1 +f 2503//1 2549//1 2504//1 +f 2549//1 2550//1 2504//1 +f 2504//1 2550//1 2505//1 +f 2550//1 2551//1 2505//1 +f 2505//1 2551//1 2506//1 +f 2551//1 2552//1 2506//1 +f 2506//1 2552//1 2507//1 +f 2552//1 2553//1 2507//1 +f 2507//1 2553//1 2508//1 +f 2553//1 2554//1 2508//1 +f 2508//1 2554//1 2509//1 +f 2554//1 2555//1 2509//1 +f 2509//1 2555//1 2510//1 +f 2555//1 2556//1 2510//1 +f 2510//1 2556//1 2511//1 +f 2556//1 2557//1 2511//1 +f 2511//1 2557//1 2512//1 +f 2557//1 2558//1 2512//1 +f 2512//1 2558//1 2513//1 +f 2558//1 2559//1 2513//1 +f 2513//1 2559//1 2514//1 +f 2559//1 2560//1 2514//1 +f 2514//1 2560//1 9//1 +f 2560//1 8//1 9//1 +f 101//1 2561//1 2515//1 +f 2561//1 2562//1 2515//1 +f 2515//1 2562//1 2516//1 +f 2562//1 2563//1 2516//1 +f 2516//1 2563//1 2517//1 +f 2563//1 2564//1 2517//1 +f 2517//1 2564//1 2518//1 +f 2564//1 2565//1 2518//1 +f 2518//1 2565//1 2519//1 +f 2565//1 2566//1 2519//1 +f 2519//1 2566//1 2520//1 +f 2566//1 2567//1 2520//1 +f 2520//1 2567//1 2521//1 +f 2567//1 2568//1 2521//1 +f 2521//1 2568//1 2522//1 +f 2568//1 2569//1 2522//1 +f 2522//1 2569//1 2523//1 +f 2569//1 2570//1 2523//1 +f 2523//1 2570//1 2524//1 +f 2570//1 2571//1 2524//1 +f 2524//1 2571//1 2525//1 +f 2571//1 2572//1 2525//1 +f 2525//1 2572//1 2526//1 +f 2572//1 2573//1 2526//1 +f 2526//1 2573//1 2527//1 +f 2573//1 2574//1 2527//1 +f 2527//1 2574//1 2528//1 +f 2574//1 2575//1 2528//1 +f 2528//1 2575//1 2529//1 +f 2575//1 2576//1 2529//1 +f 2529//1 2576//1 2530//1 +f 2576//1 2577//1 2530//1 +f 2530//1 2577//1 2531//1 +f 2577//1 2578//1 2531//1 +f 2531//1 2578//1 2532//1 +f 2578//1 2579//1 2532//1 +f 2532//1 2579//1 2533//1 +f 2579//1 2580//1 2533//1 +f 2533//1 2580//1 2534//1 +f 2580//1 2581//1 2534//1 +f 2534//1 2581//1 2535//1 +f 2581//1 2582//1 2535//1 +f 2535//1 2582//1 2536//1 +f 2582//1 2583//1 2536//1 +f 2536//1 2583//1 2537//1 +f 2583//1 2584//1 2537//1 +f 2537//1 2584//1 2538//1 +f 2584//1 2585//1 2538//1 +f 2538//1 2585//1 2539//1 +f 2585//1 2586//1 2539//1 +f 2539//1 2586//1 2540//1 +f 2586//1 2587//1 2540//1 +f 2540//1 2587//1 2541//1 +f 2587//1 2588//1 2541//1 +f 2541//1 2588//1 2542//1 +f 2588//1 2589//1 2542//1 +f 2542//1 2589//1 2543//1 +f 2589//1 2590//1 2543//1 +f 2543//1 2590//1 2544//1 +f 2590//1 2591//1 2544//1 +f 2544//1 2591//1 2545//1 +f 2591//1 2592//1 2545//1 +f 2545//1 2592//1 2546//1 +f 2592//1 2593//1 2546//1 +f 2546//1 2593//1 2547//1 +f 2593//1 2594//1 2547//1 +f 2547//1 2594//1 2548//1 +f 2594//1 2595//1 2548//1 +f 2548//1 2595//1 2549//1 +f 2595//1 2596//1 2549//1 +f 2549//1 2596//1 2550//1 +f 2596//1 2597//1 2550//1 +f 2550//1 2597//1 2551//1 +f 2597//1 2598//1 2551//1 +f 2551//1 2598//1 2552//1 +f 2598//1 2599//1 2552//1 +f 2552//1 2599//1 2553//1 +f 2599//1 2600//1 2553//1 +f 2553//1 2600//1 2554//1 +f 2600//1 2601//1 2554//1 +f 2554//1 2601//1 2555//1 +f 2601//1 2602//1 2555//1 +f 2555//1 2602//1 2556//1 +f 2602//1 2603//1 2556//1 +f 2556//1 2603//1 2557//1 +f 2603//1 2604//1 2557//1 +f 2557//1 2604//1 2558//1 +f 2604//1 2605//1 2558//1 +f 2558//1 2605//1 2559//1 +f 2605//1 2606//1 2559//1 +f 2559//1 2606//1 2560//1 +f 2606//1 2607//1 2560//1 +f 2560//1 2607//1 8//1 +f 2607//1 7//1 8//1 +f 102//1 2608//1 2561//1 +f 2608//1 2609//1 2561//1 +f 2561//1 2609//1 2562//1 +f 2609//1 2610//1 2562//1 +f 2562//1 2610//1 2563//1 +f 2610//1 2611//1 2563//1 +f 2563//1 2611//1 2564//1 +f 2611//1 2612//1 2564//1 +f 2564//1 2612//1 2565//1 +f 2612//1 2613//1 2565//1 +f 2565//1 2613//1 2566//1 +f 2613//1 2614//1 2566//1 +f 2566//1 2614//1 2567//1 +f 2614//1 2615//1 2567//1 +f 2567//1 2615//1 2568//1 +f 2615//1 2616//1 2568//1 +f 2568//1 2616//1 2569//1 +f 2616//1 2617//1 2569//1 +f 2569//1 2617//1 2570//1 +f 2617//1 2618//1 2570//1 +f 2570//1 2618//1 2571//1 +f 2618//1 2619//1 2571//1 +f 2571//1 2619//1 2572//1 +f 2619//1 2620//1 2572//1 +f 2572//1 2620//1 2573//1 +f 2620//1 2621//1 2573//1 +f 2573//1 2621//1 2574//1 +f 2621//1 2622//1 2574//1 +f 2574//1 2622//1 2575//1 +f 2622//1 2623//1 2575//1 +f 2575//1 2623//1 2576//1 +f 2623//1 2624//1 2576//1 +f 2576//1 2624//1 2577//1 +f 2624//1 2625//1 2577//1 +f 2577//1 2625//1 2578//1 +f 2625//1 2626//1 2578//1 +f 2578//1 2626//1 2579//1 +f 2626//1 2627//1 2579//1 +f 2579//1 2627//1 2580//1 +f 2627//1 2628//1 2580//1 +f 2580//1 2628//1 2581//1 +f 2628//1 2629//1 2581//1 +f 2581//1 2629//1 2582//1 +f 2629//1 2630//1 2582//1 +f 2582//1 2630//1 2583//1 +f 2630//1 2631//1 2583//1 +f 2583//1 2631//1 2584//1 +f 2631//1 2632//1 2584//1 +f 2584//1 2632//1 2585//1 +f 2632//1 2633//1 2585//1 +f 2585//1 2633//1 2586//1 +f 2633//1 2634//1 2586//1 +f 2586//1 2634//1 2587//1 +f 2634//1 2635//1 2587//1 +f 2587//1 2635//1 2588//1 +f 2635//1 2636//1 2588//1 +f 2588//1 2636//1 2589//1 +f 2636//1 2637//1 2589//1 +f 2589//1 2637//1 2590//1 +f 2637//1 2638//1 2590//1 +f 2590//1 2638//1 2591//1 +f 2638//1 2639//1 2591//1 +f 2591//1 2639//1 2592//1 +f 2639//1 2640//1 2592//1 +f 2592//1 2640//1 2593//1 +f 2640//1 2641//1 2593//1 +f 2593//1 2641//1 2594//1 +f 2641//1 2642//1 2594//1 +f 2594//1 2642//1 2595//1 +f 2642//1 2643//1 2595//1 +f 2595//1 2643//1 2596//1 +f 2643//1 2644//1 2596//1 +f 2596//1 2644//1 2597//1 +f 2644//1 2645//1 2597//1 +f 2597//1 2645//1 2598//1 +f 2645//1 2646//1 2598//1 +f 2598//1 2646//1 2599//1 +f 2646//1 2647//1 2599//1 +f 2599//1 2647//1 2600//1 +f 2647//1 2648//1 2600//1 +f 2600//1 2648//1 2601//1 +f 2648//1 2649//1 2601//1 +f 2601//1 2649//1 2602//1 +f 2649//1 2650//1 2602//1 +f 2602//1 2650//1 2603//1 +f 2650//1 2651//1 2603//1 +f 2603//1 2651//1 2604//1 +f 2651//1 2652//1 2604//1 +f 2604//1 2652//1 2605//1 +f 2652//1 2653//1 2605//1 +f 2605//1 2653//1 2606//1 +f 2653//1 2654//1 2606//1 +f 2606//1 2654//1 2607//1 +f 2654//1 2655//1 2607//1 +f 2607//1 2655//1 7//1 +f 2655//1 6//1 7//1 +f 103//1 2656//1 2608//1 +f 2656//1 2657//1 2608//1 +f 2608//1 2657//1 2609//1 +f 2657//1 2658//1 2609//1 +f 2609//1 2658//1 2610//1 +f 2658//1 2659//1 2610//1 +f 2610//1 2659//1 2611//1 +f 2659//1 2660//1 2611//1 +f 2611//1 2660//1 2612//1 +f 2660//1 2661//1 2612//1 +f 2612//1 2661//1 2613//1 +f 2661//1 2662//1 2613//1 +f 2613//1 2662//1 2614//1 +f 2662//1 2663//1 2614//1 +f 2614//1 2663//1 2615//1 +f 2663//1 2664//1 2615//1 +f 2615//1 2664//1 2616//1 +f 2664//1 2665//1 2616//1 +f 2616//1 2665//1 2617//1 +f 2665//1 2666//1 2617//1 +f 2617//1 2666//1 2618//1 +f 2666//1 2667//1 2618//1 +f 2618//1 2667//1 2619//1 +f 2667//1 2668//1 2619//1 +f 2619//1 2668//1 2620//1 +f 2668//1 2669//1 2620//1 +f 2620//1 2669//1 2621//1 +f 2669//1 2670//1 2621//1 +f 2621//1 2670//1 2622//1 +f 2670//1 2671//1 2622//1 +f 2622//1 2671//1 2623//1 +f 2671//1 2672//1 2623//1 +f 2623//1 2672//1 2624//1 +f 2672//1 2673//1 2624//1 +f 2624//1 2673//1 2625//1 +f 2673//1 2674//1 2625//1 +f 2625//1 2674//1 2626//1 +f 2674//1 2675//1 2626//1 +f 2626//1 2675//1 2627//1 +f 2675//1 2676//1 2627//1 +f 2627//1 2676//1 2628//1 +f 2676//1 2677//1 2628//1 +f 2628//1 2677//1 2629//1 +f 2677//1 2678//1 2629//1 +f 2629//1 2678//1 2630//1 +f 2678//1 2679//1 2630//1 +f 2630//1 2679//1 2631//1 +f 2679//1 2680//1 2631//1 +f 2631//1 2680//1 2632//1 +f 2680//1 2681//1 2632//1 +f 2632//1 2681//1 2633//1 +f 2681//1 2682//1 2633//1 +f 2633//1 2682//1 2634//1 +f 2682//1 2683//1 2634//1 +f 2634//1 2683//1 2635//1 +f 2683//1 2684//1 2635//1 +f 2635//1 2684//1 2636//1 +f 2684//1 2685//1 2636//1 +f 2636//1 2685//1 2637//1 +f 2685//1 2686//1 2637//1 +f 2637//1 2686//1 2638//1 +f 2686//1 2687//1 2638//1 +f 2638//1 2687//1 2639//1 +f 2687//1 2688//1 2639//1 +f 2639//1 2688//1 2640//1 +f 2688//1 2689//1 2640//1 +f 2640//1 2689//1 2641//1 +f 2689//1 2690//1 2641//1 +f 2641//1 2690//1 2642//1 +f 2690//1 2691//1 2642//1 +f 2642//1 2691//1 2643//1 +f 2691//1 2692//1 2643//1 +f 2643//1 2692//1 2644//1 +f 2692//1 2693//1 2644//1 +f 2644//1 2693//1 2645//1 +f 2693//1 2694//1 2645//1 +f 2645//1 2694//1 2646//1 +f 2694//1 2695//1 2646//1 +f 2646//1 2695//1 2647//1 +f 2695//1 2696//1 2647//1 +f 2647//1 2696//1 2648//1 +f 2696//1 2697//1 2648//1 +f 2648//1 2697//1 2649//1 +f 2697//1 2698//1 2649//1 +f 2649//1 2698//1 2650//1 +f 2698//1 2699//1 2650//1 +f 2650//1 2699//1 2651//1 +f 2699//1 2700//1 2651//1 +f 2651//1 2700//1 2652//1 +f 2700//1 2701//1 2652//1 +f 2652//1 2701//1 2653//1 +f 2701//1 2702//1 2653//1 +f 2653//1 2702//1 2654//1 +f 2702//1 2703//1 2654//1 +f 2654//1 2703//1 2655//1 +f 2703//1 2704//1 2655//1 +f 2655//1 2704//1 6//1 +f 2704//1 5//1 6//1 +f 104//1 254//1 2656//1 +f 254//1 253//1 2656//1 +f 2656//1 253//1 2657//1 +f 253//1 252//1 2657//1 +f 2657//1 252//1 2658//1 +f 252//1 251//1 2658//1 +f 2658//1 251//1 2659//1 +f 251//1 250//1 2659//1 +f 2659//1 250//1 2660//1 +f 250//1 249//1 2660//1 +f 2660//1 249//1 2661//1 +f 249//1 248//1 2661//1 +f 2661//1 248//1 2662//1 +f 248//1 247//1 2662//1 +f 2662//1 247//1 2663//1 +f 247//1 246//1 2663//1 +f 2663//1 246//1 2664//1 +f 246//1 245//1 2664//1 +f 2664//1 245//1 2665//1 +f 245//1 244//1 2665//1 +f 2665//1 244//1 2666//1 +f 244//1 243//1 2666//1 +f 2666//1 243//1 2667//1 +f 243//1 242//1 2667//1 +f 2667//1 242//1 2668//1 +f 242//1 241//1 2668//1 +f 2668//1 241//1 2669//1 +f 241//1 240//1 2669//1 +f 2669//1 240//1 2670//1 +f 240//1 239//1 2670//1 +f 2670//1 239//1 2671//1 +f 239//1 238//1 2671//1 +f 2671//1 238//1 2672//1 +f 238//1 237//1 2672//1 +f 2672//1 237//1 2673//1 +f 237//1 236//1 2673//1 +f 2673//1 236//1 2674//1 +f 236//1 235//1 2674//1 +f 2674//1 235//1 2675//1 +f 235//1 234//1 2675//1 +f 2675//1 234//1 2676//1 +f 234//1 233//1 2676//1 +f 2676//1 233//1 2677//1 +f 233//1 232//1 2677//1 +f 2677//1 232//1 2678//1 +f 232//1 231//1 2678//1 +f 2678//1 231//1 2679//1 +f 231//1 230//1 2679//1 +f 2679//1 230//1 2680//1 +f 230//1 229//1 2680//1 +f 2680//1 229//1 2681//1 +f 229//1 228//1 2681//1 +f 2681//1 228//1 2682//1 +f 228//1 227//1 2682//1 +f 2682//1 227//1 2683//1 +f 227//1 226//1 2683//1 +f 2683//1 226//1 2684//1 +f 226//1 225//1 2684//1 +f 2684//1 225//1 2685//1 +f 225//1 224//1 2685//1 +f 2685//1 224//1 2686//1 +f 224//1 223//1 2686//1 +f 2686//1 223//1 2687//1 +f 223//1 222//1 2687//1 +f 2687//1 222//1 2688//1 +f 222//1 221//1 2688//1 +f 2688//1 221//1 2689//1 +f 221//1 220//1 2689//1 +f 2689//1 220//1 2690//1 +f 220//1 219//1 2690//1 +f 2690//1 219//1 2691//1 +f 219//1 218//1 2691//1 +f 2691//1 218//1 2692//1 +f 218//1 217//1 2692//1 +f 2692//1 217//1 2693//1 +f 217//1 216//1 2693//1 +f 2693//1 216//1 2694//1 +f 216//1 215//1 2694//1 +f 2694//1 215//1 2695//1 +f 215//1 214//1 2695//1 +f 2695//1 214//1 2696//1 +f 214//1 213//1 2696//1 +f 2696//1 213//1 2697//1 +f 213//1 212//1 2697//1 +f 2697//1 212//1 2698//1 +f 212//1 211//1 2698//1 +f 2698//1 211//1 2699//1 +f 211//1 210//1 2699//1 +f 2699//1 210//1 2700//1 +f 210//1 209//1 2700//1 +f 2700//1 209//1 2701//1 +f 209//1 208//1 2701//1 +f 2701//1 208//1 2702//1 +f 208//1 207//1 2702//1 +f 2702//1 207//1 2703//1 +f 207//1 206//1 2703//1 +f 2703//1 206//1 2704//1 +f 206//1 205//1 2704//1 +f 2704//1 205//1 5//1 +f 205//1 3//1 5//1 diff --git a/data/torus/torus.mtl b/data/torus/torus.mtl new file mode 100644 index 000000000..70d3ba1da --- /dev/null +++ b/data/torus/torus.mtl @@ -0,0 +1,10 @@ +# Blender MTL File: 'None' +# Material Count: 1 + +newmtl None +Ns 0 +Ka 0.000000 0.000000 0.000000 +Kd 0.8 0.8 0.8 +Ks 0.8 0.8 0.8 +d 1 +illum 2 diff --git a/data/torus/torus.obj b/data/torus/torus.obj new file mode 100644 index 000000000..4aafd8fce --- /dev/null +++ b/data/torus/torus.obj @@ -0,0 +1,1446 @@ +# Blender v2.77 (sub 0) OBJ File: '' +# www.blender.org +mtllib torus.mtl +o Torus +v 1.269537 0.006289 0.009606 +v 1.236043 0.131289 0.009606 +v 1.144537 0.222796 0.009606 +v 1.019537 0.256289 0.009606 +v 0.894537 0.222796 0.009606 +v 0.803031 0.131289 0.009606 +v 0.769537 0.006289 0.009606 +v 0.803031 -0.118711 0.009606 +v 0.894537 -0.210217 0.009606 +v 1.019537 -0.243711 0.009606 +v 1.144537 -0.210217 0.009606 +v 1.236043 -0.118711 0.009606 +v 1.258843 0.006289 -0.153552 +v 1.225636 0.131289 -0.149180 +v 1.134912 0.222796 -0.137236 +v 1.010982 0.256289 -0.120920 +v 0.887051 0.222796 -0.104605 +v 0.796328 0.131289 -0.092661 +v 0.763121 0.006289 -0.088289 +v 0.796328 -0.118711 -0.092661 +v 0.887051 -0.210217 -0.104605 +v 1.010982 -0.243711 -0.120920 +v 1.134912 -0.210217 -0.137236 +v 1.225636 -0.118711 -0.149180 +v 1.226944 0.006289 -0.313918 +v 1.194592 0.131289 -0.305249 +v 1.106204 0.222796 -0.281566 +v 0.985463 0.256289 -0.249213 +v 0.864722 0.222796 -0.216861 +v 0.776334 0.131289 -0.193177 +v 0.743981 0.006289 -0.184509 +v 0.776334 -0.118711 -0.193177 +v 0.864722 -0.210217 -0.216861 +v 0.985463 -0.243711 -0.249213 +v 1.106204 -0.210217 -0.281566 +v 1.194592 -0.118711 -0.305249 +v 1.174387 0.006289 -0.468749 +v 1.143442 0.131289 -0.455931 +v 1.058902 0.222796 -0.420913 +v 0.943417 0.256289 -0.373078 +v 0.827932 0.222796 -0.325242 +v 0.743391 0.131289 -0.290224 +v 0.712447 0.006289 -0.277407 +v 0.743391 -0.118711 -0.290224 +v 0.827932 -0.210217 -0.325242 +v 0.943417 -0.243711 -0.373078 +v 1.058902 -0.210217 -0.420913 +v 1.143442 -0.118711 -0.455931 +v 1.102069 0.006289 -0.615394 +v 1.073062 0.131289 -0.598648 +v 0.993815 0.222796 -0.552894 +v 0.885562 0.256289 -0.490394 +v 0.777309 0.222796 -0.427894 +v 0.698062 0.131289 -0.382141 +v 0.669056 0.006289 -0.365394 +v 0.698062 -0.118711 -0.382141 +v 0.777309 -0.210217 -0.427894 +v 0.885562 -0.243711 -0.490394 +v 0.993815 -0.210217 -0.552894 +v 1.073062 -0.118711 -0.598648 +v 1.011229 0.006289 -0.751346 +v 0.984656 0.131289 -0.730956 +v 0.912059 0.222796 -0.675251 +v 0.812890 0.256289 -0.599156 +v 0.713721 0.222796 -0.523061 +v 0.641124 0.131289 -0.467355 +v 0.614552 0.006289 -0.446965 +v 0.641124 -0.118711 -0.467355 +v 0.713721 -0.210217 -0.523061 +v 0.812890 -0.243711 -0.599156 +v 0.912059 -0.210217 -0.675251 +v 0.984656 -0.118711 -0.730956 +v 0.903420 0.006289 -0.874278 +v 0.879737 0.131289 -0.850594 +v 0.815032 0.222796 -0.785889 +v 0.726644 0.256289 -0.697501 +v 0.638255 0.222796 -0.609113 +v 0.573551 0.131289 -0.544408 +v 0.549867 0.006289 -0.520724 +v 0.573551 -0.118711 -0.544408 +v 0.638255 -0.210217 -0.609113 +v 0.726644 -0.243711 -0.697501 +v 0.815032 -0.210217 -0.785889 +v 0.879737 -0.118711 -0.850594 +v 0.780489 0.006289 -0.982086 +v 0.760099 0.131289 -0.955514 +v 0.704394 0.222796 -0.882917 +v 0.628298 0.256289 -0.783747 +v 0.552203 0.222796 -0.684578 +v 0.496498 0.131289 -0.611982 +v 0.476108 0.006289 -0.585409 +v 0.496498 -0.118711 -0.611982 +v 0.552203 -0.210217 -0.684578 +v 0.628298 -0.243711 -0.783747 +v 0.704394 -0.210217 -0.882917 +v 0.760099 -0.118711 -0.955514 +v 0.644537 0.006289 -1.072926 +v 0.627790 0.131289 -1.043920 +v 0.582037 0.222796 -0.964673 +v 0.519537 0.256289 -0.856420 +v 0.457037 0.222796 -0.748167 +v 0.411284 0.131289 -0.668920 +v 0.394537 0.006289 -0.639913 +v 0.411284 -0.118711 -0.668920 +v 0.457037 -0.210217 -0.748167 +v 0.519537 -0.243711 -0.856420 +v 0.582037 -0.210217 -0.964673 +v 0.627790 -0.118711 -1.043920 +v 0.497891 0.006289 -1.145244 +v 0.485074 0.131289 -1.114299 +v 0.450056 0.222796 -1.029759 +v 0.402221 0.256289 -0.914274 +v 0.354385 0.222796 -0.798789 +v 0.319367 0.131289 -0.714248 +v 0.306550 0.006289 -0.683304 +v 0.319367 -0.118711 -0.714248 +v 0.354385 -0.210217 -0.798789 +v 0.402221 -0.243711 -0.914274 +v 0.450056 -0.210217 -1.029759 +v 0.485074 -0.118711 -1.114299 +v 0.343061 0.006289 -1.197802 +v 0.334392 0.131289 -1.165449 +v 0.310708 0.222796 -1.077061 +v 0.278356 0.256289 -0.956320 +v 0.246004 0.222796 -0.835579 +v 0.222320 0.131289 -0.747191 +v 0.213651 0.006289 -0.714839 +v 0.222320 -0.118711 -0.747191 +v 0.246004 -0.210217 -0.835579 +v 0.278356 -0.243711 -0.956320 +v 0.310708 -0.210217 -1.077061 +v 0.334392 -0.118711 -1.165449 +v 0.182694 0.006289 -1.229700 +v 0.178323 0.131289 -1.196493 +v 0.166379 0.222796 -1.105770 +v 0.150063 0.256289 -0.981839 +v 0.133747 0.222796 -0.857909 +v 0.121803 0.131289 -0.767185 +v 0.117431 0.006289 -0.733978 +v 0.121803 -0.118711 -0.767185 +v 0.133747 -0.210217 -0.857909 +v 0.150063 -0.243711 -0.981839 +v 0.166379 -0.210217 -1.105770 +v 0.178323 -0.118711 -1.196493 +v 0.019537 0.006289 -1.240394 +v 0.019537 0.131289 -1.206901 +v 0.019537 0.222796 -1.115394 +v 0.019537 0.256289 -0.990394 +v 0.019537 0.222796 -0.865394 +v 0.019537 0.131289 -0.773888 +v 0.019537 0.006289 -0.740394 +v 0.019537 -0.118711 -0.773888 +v 0.019537 -0.210217 -0.865394 +v 0.019537 -0.243711 -0.990394 +v 0.019537 -0.210217 -1.115394 +v 0.019537 -0.118711 -1.206901 +v -0.143621 0.006289 -1.229700 +v -0.139249 0.131289 -1.196493 +v -0.127305 0.222796 -1.105770 +v -0.110989 0.256289 -0.981839 +v -0.094674 0.222796 -0.857909 +v -0.082730 0.131289 -0.767185 +v -0.078358 0.006289 -0.733978 +v -0.082730 -0.118711 -0.767185 +v -0.094674 -0.210217 -0.857909 +v -0.110989 -0.243711 -0.981839 +v -0.127305 -0.210217 -1.105770 +v -0.139249 -0.118711 -1.196493 +v -0.303987 0.006289 -1.197802 +v -0.295318 0.131289 -1.165449 +v -0.271634 0.222796 -1.077061 +v -0.239282 0.256289 -0.956320 +v -0.206930 0.222796 -0.835580 +v -0.183246 0.131289 -0.747191 +v -0.174577 0.006289 -0.714839 +v -0.183246 -0.118711 -0.747191 +v -0.206930 -0.210217 -0.835580 +v -0.239282 -0.243711 -0.956320 +v -0.271634 -0.210217 -1.077061 +v -0.295318 -0.118711 -1.165449 +v -0.458818 0.006289 -1.145244 +v -0.446000 0.131289 -1.114300 +v -0.410982 0.222796 -1.029759 +v -0.363147 0.256289 -0.914274 +v -0.315311 0.222796 -0.798789 +v -0.280293 0.131289 -0.714248 +v -0.267476 0.006289 -0.683304 +v -0.280293 -0.118711 -0.714248 +v -0.315311 -0.210217 -0.798789 +v -0.363147 -0.243711 -0.914274 +v -0.410982 -0.210217 -1.029759 +v -0.446000 -0.118711 -1.114300 +v -0.605463 0.006289 -1.072926 +v -0.588716 0.131289 -1.043920 +v -0.542963 0.222796 -0.964673 +v -0.480463 0.256289 -0.856420 +v -0.417963 0.222796 -0.748167 +v -0.372210 0.131289 -0.668920 +v -0.355463 0.006289 -0.639913 +v -0.372210 -0.118711 -0.668920 +v -0.417963 -0.210217 -0.748167 +v -0.480463 -0.243711 -0.856420 +v -0.542963 -0.210217 -0.964673 +v -0.588716 -0.118711 -1.043920 +v -0.741415 0.006289 -0.982086 +v -0.721025 0.131289 -0.955514 +v -0.665320 0.222796 -0.882917 +v -0.589225 0.256289 -0.783748 +v -0.513129 0.222796 -0.684578 +v -0.457424 0.131289 -0.611982 +v -0.437034 0.006289 -0.585409 +v -0.457424 -0.118711 -0.611982 +v -0.513129 -0.210217 -0.684578 +v -0.589225 -0.243711 -0.783748 +v -0.665320 -0.210217 -0.882917 +v -0.721025 -0.118711 -0.955514 +v -0.864347 0.006289 -0.874277 +v -0.840663 0.131289 -0.850594 +v -0.775958 0.222796 -0.785889 +v -0.687570 0.256289 -0.697501 +v -0.599182 0.222796 -0.609113 +v -0.534477 0.131289 -0.544408 +v -0.510793 0.006289 -0.520724 +v -0.534477 -0.118711 -0.544408 +v -0.599182 -0.210217 -0.609113 +v -0.687570 -0.243711 -0.697501 +v -0.775958 -0.210217 -0.785889 +v -0.840663 -0.118711 -0.850594 +v -0.972155 0.006289 -0.751346 +v -0.945583 0.131289 -0.730956 +v -0.872986 0.222796 -0.675251 +v -0.773816 0.256289 -0.599156 +v -0.674647 0.222796 -0.523061 +v -0.602050 0.131289 -0.467355 +v -0.575478 0.006289 -0.446965 +v -0.602050 -0.118711 -0.467355 +v -0.674647 -0.210217 -0.523061 +v -0.773816 -0.243711 -0.599156 +v -0.872986 -0.210217 -0.675251 +v -0.945583 -0.118711 -0.730956 +v -1.062995 0.006289 -0.615395 +v -1.033988 0.131289 -0.598648 +v -0.954742 0.222796 -0.552895 +v -0.846488 0.256289 -0.490395 +v -0.738235 0.222796 -0.427895 +v -0.658988 0.131289 -0.382141 +v -0.629982 0.006289 -0.365395 +v -0.658988 -0.118711 -0.382141 +v -0.738235 -0.210217 -0.427895 +v -0.846488 -0.243711 -0.490395 +v -0.954742 -0.210217 -0.552895 +v -1.033988 -0.118711 -0.598648 +v -1.135312 0.006289 -0.468749 +v -1.104368 0.131289 -0.455931 +v -1.019827 0.222796 -0.420913 +v -0.904343 0.256289 -0.373078 +v -0.788858 0.222796 -0.325242 +v -0.704317 0.131289 -0.290224 +v -0.673373 0.006289 -0.277407 +v -0.704317 -0.118711 -0.290224 +v -0.788858 -0.210217 -0.325242 +v -0.904343 -0.243711 -0.373078 +v -1.019827 -0.210217 -0.420913 +v -1.104368 -0.118711 -0.455931 +v -1.187871 0.006289 -0.313918 +v -1.155518 0.131289 -0.305249 +v -1.067130 0.222796 -0.281566 +v -0.946389 0.256289 -0.249213 +v -0.825648 0.222796 -0.216861 +v -0.737260 0.131289 -0.193177 +v -0.704908 0.006289 -0.184508 +v -0.737260 -0.118711 -0.193177 +v -0.825648 -0.210217 -0.216861 +v -0.946389 -0.243711 -0.249213 +v -1.067130 -0.210217 -0.281566 +v -1.155518 -0.118711 -0.305249 +v -1.219769 0.006289 -0.153552 +v -1.186562 0.131289 -0.149180 +v -1.095839 0.222796 -0.137236 +v -0.971908 0.256289 -0.120921 +v -0.847977 0.222796 -0.104605 +v -0.757254 0.131289 -0.092661 +v -0.724047 0.006289 -0.088289 +v -0.757254 -0.118711 -0.092661 +v -0.847977 -0.210217 -0.104605 +v -0.971908 -0.243711 -0.120921 +v -1.095839 -0.210217 -0.137236 +v -1.186562 -0.118711 -0.149180 +v -1.230463 0.006289 0.009606 +v -1.196970 0.131289 0.009606 +v -1.105463 0.222796 0.009606 +v -0.980463 0.256289 0.009606 +v -0.855463 0.222796 0.009606 +v -0.763957 0.131289 0.009606 +v -0.730463 0.006289 0.009606 +v -0.763957 -0.118711 0.009606 +v -0.855463 -0.210217 0.009606 +v -0.980463 -0.243711 0.009606 +v -1.105463 -0.210217 0.009606 +v -1.196970 -0.118711 0.009606 +v -1.219769 0.006289 0.172764 +v -1.186562 0.131289 0.168392 +v -1.095839 0.222796 0.156448 +v -0.971908 0.256289 0.140132 +v -0.847977 0.222796 0.123816 +v -0.757254 0.131289 0.111872 +v -0.724047 0.006289 0.107500 +v -0.757254 -0.118711 0.111872 +v -0.847977 -0.210217 0.123816 +v -0.971908 -0.243711 0.140132 +v -1.095839 -0.210217 0.156448 +v -1.186562 -0.118711 0.168392 +v -1.187871 0.006289 0.333129 +v -1.155518 0.131289 0.324461 +v -1.067130 0.222796 0.300777 +v -0.946389 0.256289 0.268425 +v -0.825648 0.222796 0.236072 +v -0.737260 0.131289 0.212389 +v -0.704908 0.006289 0.203720 +v -0.737260 -0.118711 0.212389 +v -0.825648 -0.210217 0.236072 +v -0.946389 -0.243711 0.268425 +v -1.067130 -0.210217 0.300777 +v -1.155518 -0.118711 0.324461 +v -1.135313 0.006289 0.487960 +v -1.104369 0.131289 0.475142 +v -1.019828 0.222796 0.440124 +v -0.904343 0.256289 0.392289 +v -0.788858 0.222796 0.344453 +v -0.704317 0.131289 0.309435 +v -0.673373 0.006289 0.296618 +v -0.704317 -0.118711 0.309435 +v -0.788858 -0.210217 0.344453 +v -0.904343 -0.243711 0.392289 +v -1.019828 -0.210217 0.440124 +v -1.104369 -0.118711 0.475142 +v -1.062995 0.006289 0.634606 +v -1.033989 0.131289 0.617859 +v -0.954742 0.222796 0.572106 +v -0.846489 0.256289 0.509606 +v -0.738235 0.222796 0.447106 +v -0.658989 0.131289 0.401352 +v -0.629982 0.006289 0.384606 +v -0.658989 -0.118711 0.401352 +v -0.738235 -0.210217 0.447106 +v -0.846489 -0.243711 0.509606 +v -0.954742 -0.210217 0.572106 +v -1.033989 -0.118711 0.617859 +v -0.972155 0.006289 0.770558 +v -0.945583 0.131289 0.750168 +v -0.872986 0.222796 0.694462 +v -0.773816 0.256289 0.618367 +v -0.674647 0.222796 0.542272 +v -0.602050 0.131289 0.486566 +v -0.575478 0.006289 0.466177 +v -0.602050 -0.118711 0.486566 +v -0.674647 -0.210217 0.542272 +v -0.773816 -0.243711 0.618367 +v -0.872986 -0.210217 0.694462 +v -0.945583 -0.118711 0.750168 +v -0.864347 0.006289 0.893489 +v -0.840663 0.131289 0.869805 +v -0.775958 0.222796 0.805101 +v -0.687570 0.256289 0.716712 +v -0.599182 0.222796 0.628324 +v -0.534477 0.131289 0.563619 +v -0.510793 0.006289 0.539936 +v -0.534477 -0.118711 0.563619 +v -0.599182 -0.210217 0.628324 +v -0.687570 -0.243711 0.716712 +v -0.775958 -0.210217 0.805101 +v -0.840663 -0.118711 0.869805 +v -0.741416 0.006289 1.001297 +v -0.721026 0.131289 0.974725 +v -0.665320 0.222796 0.902128 +v -0.589225 0.256289 0.802959 +v -0.513130 0.222796 0.703790 +v -0.457424 0.131289 0.631193 +v -0.437034 0.006289 0.604621 +v -0.457424 -0.118711 0.631193 +v -0.513130 -0.210217 0.703790 +v -0.589225 -0.243711 0.802959 +v -0.665320 -0.210217 0.902128 +v -0.721026 -0.118711 0.974725 +v -0.605463 0.006289 1.092138 +v -0.588716 0.131289 1.063131 +v -0.542963 0.222796 0.983884 +v -0.480463 0.256289 0.875631 +v -0.417963 0.222796 0.767378 +v -0.372210 0.131289 0.688131 +v -0.355463 0.006289 0.659125 +v -0.372210 -0.118711 0.688131 +v -0.417963 -0.210217 0.767378 +v -0.480463 -0.243711 0.875631 +v -0.542963 -0.210217 0.983884 +v -0.588716 -0.118711 1.063131 +v -0.458818 0.006289 1.164455 +v -0.446000 0.131289 1.133511 +v -0.410982 0.222796 1.048970 +v -0.363147 0.256289 0.933485 +v -0.315311 0.222796 0.818000 +v -0.280293 0.131289 0.733459 +v -0.267476 0.006289 0.702515 +v -0.280293 -0.118711 0.733459 +v -0.315311 -0.210217 0.818000 +v -0.363147 -0.243711 0.933485 +v -0.410982 -0.210217 1.048970 +v -0.446000 -0.118711 1.133511 +v -0.303987 0.006289 1.217013 +v -0.295318 0.131289 1.184660 +v -0.271635 0.222796 1.096272 +v -0.239282 0.256289 0.975531 +v -0.206930 0.222796 0.854791 +v -0.183246 0.131289 0.766402 +v -0.174578 0.006289 0.734050 +v -0.183246 -0.118711 0.766402 +v -0.206930 -0.210217 0.854791 +v -0.239282 -0.243711 0.975531 +v -0.271635 -0.210217 1.096272 +v -0.295318 -0.118711 1.184660 +v -0.143622 0.006289 1.248912 +v -0.139250 0.131289 1.215704 +v -0.127306 0.222796 1.124981 +v -0.110990 0.256289 1.001050 +v -0.094674 0.222796 0.877120 +v -0.082730 0.131289 0.786396 +v -0.078358 0.006289 0.753189 +v -0.082730 -0.118711 0.786396 +v -0.094674 -0.210217 0.877120 +v -0.110990 -0.243711 1.001050 +v -0.127306 -0.210217 1.124981 +v -0.139250 -0.118711 1.215704 +v 0.019537 0.006289 1.259606 +v 0.019537 0.131289 1.226112 +v 0.019537 0.222796 1.134606 +v 0.019537 0.256289 1.009606 +v 0.019537 0.222796 0.884606 +v 0.019537 0.131289 0.793099 +v 0.019537 0.006289 0.759606 +v 0.019537 -0.118711 0.793099 +v 0.019537 -0.210217 0.884606 +v 0.019537 -0.243711 1.009606 +v 0.019537 -0.210217 1.134606 +v 0.019537 -0.118711 1.226112 +v 0.182694 0.006289 1.248912 +v 0.178323 0.131289 1.215705 +v 0.166379 0.222796 1.124981 +v 0.150063 0.256289 1.001051 +v 0.133747 0.222796 0.877120 +v 0.121803 0.131289 0.786396 +v 0.117431 0.006289 0.753189 +v 0.121803 -0.118711 0.786396 +v 0.133747 -0.210217 0.877120 +v 0.150063 -0.243711 1.001051 +v 0.166379 -0.210217 1.124981 +v 0.178323 -0.118711 1.215705 +v 0.343060 0.006289 1.217013 +v 0.334391 0.131289 1.184661 +v 0.310708 0.222796 1.096272 +v 0.278356 0.256289 0.975532 +v 0.246003 0.222796 0.854791 +v 0.222320 0.131289 0.766403 +v 0.213651 0.006289 0.734050 +v 0.222320 -0.118711 0.766403 +v 0.246003 -0.210217 0.854791 +v 0.278356 -0.243711 0.975532 +v 0.310708 -0.210217 1.096272 +v 0.334391 -0.118711 1.184661 +v 0.497891 0.006289 1.164455 +v 0.485074 0.131289 1.133511 +v 0.450056 0.222796 1.048970 +v 0.402221 0.256289 0.933485 +v 0.354385 0.222796 0.818000 +v 0.319367 0.131289 0.733459 +v 0.306550 0.006289 0.702515 +v 0.319367 -0.118711 0.733459 +v 0.354385 -0.210217 0.818000 +v 0.402221 -0.243711 0.933485 +v 0.450056 -0.210217 1.048970 +v 0.485074 -0.118711 1.133511 +v 0.644537 0.006289 1.092137 +v 0.627790 0.131289 1.063131 +v 0.582037 0.222796 0.983884 +v 0.519537 0.256289 0.875631 +v 0.457037 0.222796 0.767378 +v 0.411284 0.131289 0.688131 +v 0.394537 0.006289 0.659125 +v 0.411284 -0.118711 0.688131 +v 0.457037 -0.210217 0.767378 +v 0.519537 -0.243711 0.875631 +v 0.582037 -0.210217 0.983884 +v 0.627790 -0.118711 1.063131 +v 0.780488 0.006289 1.001298 +v 0.760099 0.131289 0.974725 +v 0.704393 0.222796 0.902128 +v 0.628298 0.256289 0.802959 +v 0.552203 0.222796 0.703790 +v 0.496497 0.131289 0.631193 +v 0.476108 0.006289 0.604621 +v 0.496497 -0.118711 0.631193 +v 0.552203 -0.210217 0.703790 +v 0.628298 -0.243711 0.802959 +v 0.704393 -0.210217 0.902128 +v 0.760099 -0.118711 0.974725 +v 0.903420 0.006289 0.893490 +v 0.879736 0.131289 0.869806 +v 0.815032 0.222796 0.805101 +v 0.726643 0.256289 0.716713 +v 0.638255 0.222796 0.628325 +v 0.573550 0.131289 0.563620 +v 0.549867 0.006289 0.539936 +v 0.573550 -0.118711 0.563620 +v 0.638255 -0.210217 0.628325 +v 0.726643 -0.243711 0.716713 +v 0.815032 -0.210217 0.805101 +v 0.879736 -0.118711 0.869806 +v 1.011229 0.006289 0.770557 +v 0.984656 0.131289 0.750168 +v 0.912059 0.222796 0.694462 +v 0.812890 0.256289 0.618367 +v 0.713721 0.222796 0.542272 +v 0.641124 0.131289 0.486566 +v 0.614552 0.006289 0.466177 +v 0.641124 -0.118711 0.486566 +v 0.713721 -0.210217 0.542272 +v 0.812890 -0.243711 0.618367 +v 0.912059 -0.210217 0.694462 +v 0.984656 -0.118711 0.750168 +v 1.102069 0.006289 0.634606 +v 1.073062 0.131289 0.617859 +v 0.993815 0.222796 0.572106 +v 0.885562 0.256289 0.509606 +v 0.777309 0.222796 0.447106 +v 0.698062 0.131289 0.401353 +v 0.669056 0.006289 0.384606 +v 0.698062 -0.118711 0.401353 +v 0.777309 -0.210217 0.447106 +v 0.885562 -0.243711 0.509606 +v 0.993815 -0.210217 0.572106 +v 1.073062 -0.118711 0.617859 +v 1.174386 0.006289 0.487960 +v 1.143442 0.131289 0.475143 +v 1.058901 0.222796 0.440125 +v 0.943416 0.256289 0.392290 +v 0.827931 0.222796 0.344454 +v 0.743391 0.131289 0.309436 +v 0.712446 0.006289 0.296619 +v 0.743391 -0.118711 0.309436 +v 0.827931 -0.210217 0.344454 +v 0.943416 -0.243711 0.392290 +v 1.058901 -0.210217 0.440125 +v 1.143442 -0.118711 0.475143 +v 1.226944 0.006289 0.333129 +v 1.194592 0.131289 0.324460 +v 1.106204 0.222796 0.300777 +v 0.985463 0.256289 0.268424 +v 0.864722 0.222796 0.236072 +v 0.776334 0.131289 0.212389 +v 0.743981 0.006289 0.203720 +v 0.776334 -0.118711 0.212389 +v 0.864722 -0.210217 0.236072 +v 0.985463 -0.243711 0.268424 +v 1.106204 -0.210217 0.300777 +v 1.194592 -0.118711 0.324460 +v 1.258843 0.006289 0.172763 +v 1.225636 0.131289 0.168392 +v 1.134912 0.222796 0.156448 +v 1.010982 0.256289 0.140132 +v 0.887051 0.222796 0.123816 +v 0.796328 0.131289 0.111872 +v 0.763121 0.006289 0.107500 +v 0.796328 -0.118711 0.111872 +v 0.887051 -0.210217 0.123816 +v 1.010982 -0.243711 0.140132 +v 1.134912 -0.210217 0.156448 +v 1.225636 -0.118711 0.168392 +vn 0.9640 0.2583 -0.0632 +vn 0.7063 0.7063 -0.0463 +vn 0.2588 0.9658 -0.0170 +vn -0.2588 0.9658 0.0170 +vn -0.7063 0.7063 0.0463 +vn -0.9640 0.2583 0.0632 +vn -0.9640 -0.2583 0.0632 +vn -0.7063 -0.7063 0.0463 +vn -0.2588 -0.9658 0.0170 +vn 0.2588 -0.9658 -0.0170 +vn 0.7063 -0.7063 -0.0463 +vn 0.9640 -0.2583 -0.0632 +vn 0.9475 0.2583 -0.1885 +vn 0.6943 0.7063 -0.1381 +vn 0.2544 0.9658 -0.0506 +vn -0.2544 0.9658 0.0506 +vn -0.6943 0.7063 0.1381 +vn -0.9475 0.2583 0.1885 +vn -0.9475 -0.2583 0.1885 +vn -0.6943 -0.7063 0.1381 +vn -0.2544 -0.9658 0.0506 +vn 0.2544 -0.9658 -0.0506 +vn 0.6943 -0.7063 -0.1381 +vn 0.9475 -0.2583 -0.1885 +vn 0.9148 0.2583 -0.3105 +vn 0.6703 0.7063 -0.2275 +vn 0.2456 0.9658 -0.0834 +vn -0.2456 0.9658 0.0834 +vn -0.6703 0.7063 0.2275 +vn -0.9148 0.2583 0.3105 +vn -0.9148 -0.2583 0.3105 +vn -0.6703 -0.7063 0.2275 +vn -0.2456 -0.9658 0.0834 +vn 0.2456 -0.9658 -0.0834 +vn 0.6703 -0.7063 -0.2275 +vn 0.9148 -0.2583 -0.3105 +vn 0.8664 0.2583 -0.4273 +vn 0.6349 0.7063 -0.3131 +vn 0.2326 0.9658 -0.1147 +vn -0.2326 0.9658 0.1147 +vn -0.6349 0.7063 0.3131 +vn -0.8664 0.2583 0.4273 +vn -0.8664 -0.2583 0.4273 +vn -0.6349 -0.7063 0.3131 +vn -0.2326 -0.9658 0.1147 +vn 0.2326 -0.9658 -0.1147 +vn 0.6349 -0.7063 -0.3131 +vn 0.8664 -0.2583 -0.4273 +vn 0.8033 0.2583 -0.5367 +vn 0.5886 0.7063 -0.3933 +vn 0.2156 0.9658 -0.1441 +vn -0.2156 0.9658 0.1441 +vn -0.5886 0.7063 0.3933 +vn -0.8033 0.2583 0.5367 +vn -0.8033 -0.2583 0.5367 +vn -0.5886 -0.7063 0.3933 +vn -0.2156 -0.9658 0.1441 +vn 0.2156 -0.9658 -0.1441 +vn 0.5886 -0.7063 -0.3933 +vn 0.8033 -0.2583 -0.5367 +vn 0.7263 0.2583 -0.6370 +vn 0.5322 0.7063 -0.4667 +vn 0.1950 0.9658 -0.1710 +vn -0.1950 0.9658 0.1710 +vn -0.5322 0.7063 0.4667 +vn -0.7263 0.2583 0.6370 +vn -0.7263 -0.2583 0.6370 +vn -0.5322 -0.7063 0.4667 +vn -0.1950 -0.9658 0.1710 +vn 0.1950 -0.9658 -0.1710 +vn 0.5322 -0.7063 -0.4667 +vn 0.7263 -0.2583 -0.6370 +vn 0.6370 0.2583 -0.7263 +vn 0.4667 0.7063 -0.5322 +vn 0.1710 0.9658 -0.1950 +vn -0.1710 0.9658 0.1950 +vn -0.4667 0.7063 0.5322 +vn -0.6370 0.2583 0.7263 +vn -0.6370 -0.2583 0.7263 +vn -0.4667 -0.7063 0.5322 +vn -0.1710 -0.9658 0.1950 +vn 0.1710 -0.9658 -0.1950 +vn 0.4667 -0.7063 -0.5322 +vn 0.6370 -0.2583 -0.7263 +vn 0.5367 0.2583 -0.8033 +vn 0.3933 0.7063 -0.5886 +vn 0.1441 0.9658 -0.2156 +vn -0.1441 0.9658 0.2156 +vn -0.3933 0.7063 0.5886 +vn -0.5367 0.2583 0.8033 +vn -0.5367 -0.2583 0.8033 +vn -0.3933 -0.7063 0.5886 +vn -0.1441 -0.9658 0.2156 +vn 0.1441 -0.9658 -0.2156 +vn 0.3933 -0.7063 -0.5886 +vn 0.5367 -0.2583 -0.8033 +vn 0.4273 0.2583 -0.8664 +vn 0.3131 0.7063 -0.6349 +vn 0.1147 0.9658 -0.2326 +vn -0.1147 0.9658 0.2326 +vn -0.3131 0.7063 0.6349 +vn -0.4273 0.2583 0.8664 +vn -0.4273 -0.2583 0.8664 +vn -0.3131 -0.7063 0.6349 +vn -0.1147 -0.9658 0.2326 +vn 0.1147 -0.9658 -0.2326 +vn 0.3131 -0.7063 -0.6349 +vn 0.4273 -0.2583 -0.8664 +vn 0.3105 0.2583 -0.9148 +vn 0.2275 0.7063 -0.6703 +vn 0.0834 0.9658 -0.2456 +vn -0.0834 0.9658 0.2456 +vn -0.2275 0.7063 0.6703 +vn -0.3105 0.2583 0.9148 +vn -0.3105 -0.2583 0.9148 +vn -0.2275 -0.7063 0.6703 +vn -0.0834 -0.9658 0.2456 +vn 0.0834 -0.9658 -0.2456 +vn 0.2275 -0.7063 -0.6703 +vn 0.3105 -0.2583 -0.9148 +vn 0.1885 0.2583 -0.9475 +vn 0.1381 0.7063 -0.6943 +vn 0.0506 0.9658 -0.2544 +vn -0.0506 0.9658 0.2544 +vn -0.1381 0.7063 0.6943 +vn -0.1885 0.2583 0.9475 +vn -0.1885 -0.2583 0.9475 +vn -0.1381 -0.7063 0.6943 +vn -0.0506 -0.9658 0.2544 +vn 0.0506 -0.9658 -0.2544 +vn 0.1381 -0.7063 -0.6943 +vn 0.1885 -0.2583 -0.9475 +vn 0.0632 0.2583 -0.9640 +vn 0.0463 0.7063 -0.7063 +vn 0.0170 0.9658 -0.2588 +vn -0.0170 0.9658 0.2588 +vn -0.0463 0.7063 0.7063 +vn -0.0632 0.2583 0.9640 +vn -0.0632 -0.2583 0.9640 +vn -0.0463 -0.7063 0.7063 +vn -0.0170 -0.9658 0.2588 +vn 0.0170 -0.9658 -0.2588 +vn 0.0463 -0.7063 -0.7063 +vn 0.0632 -0.2583 -0.9640 +vn -0.0632 0.2583 -0.9640 +vn -0.0463 0.7063 -0.7063 +vn -0.0170 0.9658 -0.2588 +vn 0.0170 0.9658 0.2588 +vn 0.0463 0.7063 0.7063 +vn 0.0632 0.2583 0.9640 +vn 0.0632 -0.2583 0.9640 +vn 0.0463 -0.7063 0.7063 +vn 0.0170 -0.9658 0.2588 +vn -0.0170 -0.9658 -0.2588 +vn -0.0463 -0.7063 -0.7063 +vn -0.0632 -0.2583 -0.9640 +vn -0.1885 0.2583 -0.9475 +vn -0.1381 0.7063 -0.6943 +vn -0.0506 0.9658 -0.2544 +vn 0.0506 0.9658 0.2544 +vn 0.1381 0.7063 0.6943 +vn 0.1885 0.2583 0.9475 +vn 0.1885 -0.2583 0.9475 +vn 0.1381 -0.7063 0.6943 +vn 0.0506 -0.9658 0.2544 +vn -0.0506 -0.9658 -0.2544 +vn -0.1381 -0.7063 -0.6943 +vn -0.1885 -0.2583 -0.9475 +vn -0.3105 0.2583 -0.9148 +vn -0.2275 0.7063 -0.6703 +vn -0.0834 0.9658 -0.2456 +vn 0.0834 0.9658 0.2456 +vn 0.2275 0.7063 0.6703 +vn 0.3105 0.2583 0.9148 +vn 0.3105 -0.2583 0.9148 +vn 0.2275 -0.7063 0.6703 +vn 0.0834 -0.9658 0.2456 +vn -0.0834 -0.9658 -0.2456 +vn -0.2275 -0.7063 -0.6703 +vn -0.3105 -0.2583 -0.9148 +vn -0.4273 0.2583 -0.8664 +vn -0.3131 0.7063 -0.6349 +vn -0.1147 0.9658 -0.2326 +vn 0.1147 0.9658 0.2326 +vn 0.3131 0.7063 0.6349 +vn 0.4273 0.2583 0.8664 +vn 0.4273 -0.2583 0.8664 +vn 0.3131 -0.7063 0.6349 +vn 0.1147 -0.9658 0.2326 +vn -0.1147 -0.9658 -0.2326 +vn -0.3131 -0.7063 -0.6349 +vn -0.4273 -0.2583 -0.8664 +vn -0.5367 0.2583 -0.8033 +vn -0.3933 0.7063 -0.5886 +vn -0.1441 0.9658 -0.2156 +vn 0.1441 0.9658 0.2156 +vn 0.3933 0.7063 0.5886 +vn 0.5367 0.2583 0.8033 +vn 0.5367 -0.2583 0.8033 +vn 0.3933 -0.7063 0.5886 +vn 0.1441 -0.9658 0.2156 +vn -0.1441 -0.9658 -0.2156 +vn -0.3933 -0.7063 -0.5886 +vn -0.5367 -0.2583 -0.8033 +vn -0.6370 0.2583 -0.7263 +vn -0.4667 0.7063 -0.5322 +vn -0.1710 0.9658 -0.1950 +vn 0.1710 0.9658 0.1950 +vn 0.4667 0.7063 0.5322 +vn 0.6370 0.2583 0.7263 +vn 0.6370 -0.2583 0.7263 +vn 0.4667 -0.7063 0.5322 +vn 0.1710 -0.9658 0.1950 +vn -0.1710 -0.9658 -0.1950 +vn -0.4667 -0.7063 -0.5322 +vn -0.6370 -0.2583 -0.7263 +vn -0.7263 0.2583 -0.6370 +vn -0.5322 0.7063 -0.4667 +vn -0.1950 0.9658 -0.1710 +vn 0.1950 0.9658 0.1710 +vn 0.5322 0.7063 0.4667 +vn 0.7263 0.2583 0.6370 +vn 0.7263 -0.2583 0.6370 +vn 0.5322 -0.7063 0.4667 +vn 0.1950 -0.9658 0.1710 +vn -0.1950 -0.9658 -0.1710 +vn -0.5322 -0.7063 -0.4667 +vn -0.7263 -0.2583 -0.6370 +vn -0.8033 0.2583 -0.5367 +vn -0.5886 0.7063 -0.3933 +vn -0.2156 0.9658 -0.1441 +vn 0.2156 0.9658 0.1441 +vn 0.5886 0.7063 0.3933 +vn 0.8033 0.2583 0.5367 +vn 0.8033 -0.2583 0.5367 +vn 0.5886 -0.7063 0.3933 +vn 0.2156 -0.9658 0.1441 +vn -0.2156 -0.9658 -0.1441 +vn -0.5886 -0.7063 -0.3933 +vn -0.8033 -0.2583 -0.5367 +vn -0.8664 0.2583 -0.4273 +vn -0.6349 0.7063 -0.3131 +vn -0.2326 0.9658 -0.1147 +vn 0.2326 0.9658 0.1147 +vn 0.6349 0.7063 0.3131 +vn 0.8664 0.2583 0.4273 +vn 0.8664 -0.2583 0.4273 +vn 0.6349 -0.7063 0.3131 +vn 0.2326 -0.9658 0.1147 +vn -0.2326 -0.9658 -0.1147 +vn -0.6349 -0.7063 -0.3131 +vn -0.8664 -0.2583 -0.4273 +vn -0.9148 0.2583 -0.3105 +vn -0.6703 0.7063 -0.2275 +vn -0.2456 0.9658 -0.0834 +vn 0.2456 0.9658 0.0834 +vn 0.6703 0.7063 0.2275 +vn 0.9148 0.2583 0.3105 +vn 0.9148 -0.2583 0.3105 +vn 0.6703 -0.7063 0.2275 +vn 0.2456 -0.9658 0.0834 +vn -0.2456 -0.9658 -0.0834 +vn -0.6703 -0.7063 -0.2275 +vn -0.9148 -0.2583 -0.3105 +vn -0.9475 0.2583 -0.1885 +vn -0.6943 0.7063 -0.1381 +vn -0.2544 0.9658 -0.0506 +vn 0.2544 0.9658 0.0506 +vn 0.6943 0.7063 0.1381 +vn 0.9475 0.2583 0.1885 +vn 0.9475 -0.2583 0.1885 +vn 0.6943 -0.7063 0.1381 +vn 0.2544 -0.9658 0.0506 +vn -0.2544 -0.9658 -0.0506 +vn -0.6943 -0.7063 -0.1381 +vn -0.9475 -0.2583 -0.1885 +vn -0.9640 0.2583 -0.0632 +vn -0.7063 0.7063 -0.0463 +vn -0.2588 0.9658 -0.0170 +vn 0.2588 0.9658 0.0170 +vn 0.7063 0.7063 0.0463 +vn 0.9640 0.2583 0.0632 +vn 0.9640 -0.2583 0.0632 +vn 0.7063 -0.7063 0.0463 +vn 0.2588 -0.9658 0.0170 +vn -0.2588 -0.9658 -0.0170 +vn -0.7063 -0.7063 -0.0463 +vn -0.9640 -0.2583 -0.0632 +usemtl None +s off +f 1//1 13//1 14//1 2//1 +f 2//2 14//2 15//2 3//2 +f 3//3 15//3 16//3 4//3 +f 4//4 16//4 17//4 5//4 +f 5//5 17//5 18//5 6//5 +f 6//6 18//6 19//6 7//6 +f 7//7 19//7 20//7 8//7 +f 8//8 20//8 21//8 9//8 +f 9//9 21//9 22//9 10//9 +f 10//10 22//10 23//10 11//10 +f 11//11 23//11 24//11 12//11 +f 1//12 12//12 24//12 13//12 +f 13//13 25//13 26//13 14//13 +f 14//14 26//14 27//14 15//14 +f 15//15 27//15 28//15 16//15 +f 16//16 28//16 29//16 17//16 +f 17//17 29//17 30//17 18//17 +f 18//18 30//18 31//18 19//18 +f 19//19 31//19 32//19 20//19 +f 20//20 32//20 33//20 21//20 +f 21//21 33//21 34//21 22//21 +f 22//22 34//22 35//22 23//22 +f 23//23 35//23 36//23 24//23 +f 24//24 36//24 25//24 13//24 +f 25//25 37//25 38//25 26//25 +f 26//26 38//26 39//26 27//26 +f 27//27 39//27 40//27 28//27 +f 28//28 40//28 41//28 29//28 +f 29//29 41//29 42//29 30//29 +f 30//30 42//30 43//30 31//30 +f 31//31 43//31 44//31 32//31 +f 32//32 44//32 45//32 33//32 +f 33//33 45//33 46//33 34//33 +f 34//34 46//34 47//34 35//34 +f 35//35 47//35 48//35 36//35 +f 36//36 48//36 37//36 25//36 +f 37//37 49//37 50//37 38//37 +f 38//38 50//38 51//38 39//38 +f 39//39 51//39 52//39 40//39 +f 40//40 52//40 53//40 41//40 +f 41//41 53//41 54//41 42//41 +f 42//42 54//42 55//42 43//42 +f 43//43 55//43 56//43 44//43 +f 44//44 56//44 57//44 45//44 +f 45//45 57//45 58//45 46//45 +f 46//46 58//46 59//46 47//46 +f 47//47 59//47 60//47 48//47 +f 48//48 60//48 49//48 37//48 +f 49//49 61//49 62//49 50//49 +f 50//50 62//50 63//50 51//50 +f 51//51 63//51 64//51 52//51 +f 52//52 64//52 65//52 53//52 +f 53//53 65//53 66//53 54//53 +f 54//54 66//54 67//54 55//54 +f 55//55 67//55 68//55 56//55 +f 56//56 68//56 69//56 57//56 +f 57//57 69//57 70//57 58//57 +f 58//58 70//58 71//58 59//58 +f 59//59 71//59 72//59 60//59 +f 60//60 72//60 61//60 49//60 +f 61//61 73//61 74//61 62//61 +f 62//62 74//62 75//62 63//62 +f 63//63 75//63 76//63 64//63 +f 64//64 76//64 77//64 65//64 +f 65//65 77//65 78//65 66//65 +f 66//66 78//66 79//66 67//66 +f 67//67 79//67 80//67 68//67 +f 68//68 80//68 81//68 69//68 +f 69//69 81//69 82//69 70//69 +f 70//70 82//70 83//70 71//70 +f 71//71 83//71 84//71 72//71 +f 72//72 84//72 73//72 61//72 +f 73//73 85//73 86//73 74//73 +f 74//74 86//74 87//74 75//74 +f 75//75 87//75 88//75 76//75 +f 76//76 88//76 89//76 77//76 +f 77//77 89//77 90//77 78//77 +f 78//78 90//78 91//78 79//78 +f 79//79 91//79 92//79 80//79 +f 80//80 92//80 93//80 81//80 +f 81//81 93//81 94//81 82//81 +f 82//82 94//82 95//82 83//82 +f 83//83 95//83 96//83 84//83 +f 84//84 96//84 85//84 73//84 +f 85//85 97//85 98//85 86//85 +f 86//86 98//86 99//86 87//86 +f 87//87 99//87 100//87 88//87 +f 88//88 100//88 101//88 89//88 +f 89//89 101//89 102//89 90//89 +f 90//90 102//90 103//90 91//90 +f 91//91 103//91 104//91 92//91 +f 92//92 104//92 105//92 93//92 +f 93//93 105//93 106//93 94//93 +f 94//94 106//94 107//94 95//94 +f 95//95 107//95 108//95 96//95 +f 96//96 108//96 97//96 85//96 +f 97//97 109//97 110//97 98//97 +f 98//98 110//98 111//98 99//98 +f 99//99 111//99 112//99 100//99 +f 100//100 112//100 113//100 101//100 +f 101//101 113//101 114//101 102//101 +f 102//102 114//102 115//102 103//102 +f 103//103 115//103 116//103 104//103 +f 104//104 116//104 117//104 105//104 +f 105//105 117//105 118//105 106//105 +f 106//106 118//106 119//106 107//106 +f 107//107 119//107 120//107 108//107 +f 108//108 120//108 109//108 97//108 +f 109//109 121//109 122//109 110//109 +f 110//110 122//110 123//110 111//110 +f 111//111 123//111 124//111 112//111 +f 112//112 124//112 125//112 113//112 +f 113//113 125//113 126//113 114//113 +f 114//114 126//114 127//114 115//114 +f 115//115 127//115 128//115 116//115 +f 116//116 128//116 129//116 117//116 +f 117//117 129//117 130//117 118//117 +f 118//118 130//118 131//118 119//118 +f 119//119 131//119 132//119 120//119 +f 120//120 132//120 121//120 109//120 +f 121//121 133//121 134//121 122//121 +f 122//122 134//122 135//122 123//122 +f 123//123 135//123 136//123 124//123 +f 124//124 136//124 137//124 125//124 +f 125//125 137//125 138//125 126//125 +f 126//126 138//126 139//126 127//126 +f 127//127 139//127 140//127 128//127 +f 128//128 140//128 141//128 129//128 +f 129//129 141//129 142//129 130//129 +f 130//130 142//130 143//130 131//130 +f 131//131 143//131 144//131 132//131 +f 132//132 144//132 133//132 121//132 +f 133//133 145//133 146//133 134//133 +f 134//134 146//134 147//134 135//134 +f 135//135 147//135 148//135 136//135 +f 136//136 148//136 149//136 137//136 +f 137//137 149//137 150//137 138//137 +f 138//138 150//138 151//138 139//138 +f 139//139 151//139 152//139 140//139 +f 140//140 152//140 153//140 141//140 +f 141//141 153//141 154//141 142//141 +f 142//142 154//142 155//142 143//142 +f 143//143 155//143 156//143 144//143 +f 144//144 156//144 145//144 133//144 +f 145//145 157//145 158//145 146//145 +f 146//146 158//146 159//146 147//146 +f 147//147 159//147 160//147 148//147 +f 148//148 160//148 161//148 149//148 +f 149//149 161//149 162//149 150//149 +f 150//150 162//150 163//150 151//150 +f 151//151 163//151 164//151 152//151 +f 152//152 164//152 165//152 153//152 +f 153//153 165//153 166//153 154//153 +f 154//154 166//154 167//154 155//154 +f 155//155 167//155 168//155 156//155 +f 156//156 168//156 157//156 145//156 +f 157//157 169//157 170//157 158//157 +f 158//158 170//158 171//158 159//158 +f 159//159 171//159 172//159 160//159 +f 160//160 172//160 173//160 161//160 +f 161//161 173//161 174//161 162//161 +f 162//162 174//162 175//162 163//162 +f 163//163 175//163 176//163 164//163 +f 164//164 176//164 177//164 165//164 +f 165//165 177//165 178//165 166//165 +f 166//166 178//166 179//166 167//166 +f 167//167 179//167 180//167 168//167 +f 168//168 180//168 169//168 157//168 +f 169//169 181//169 182//169 170//169 +f 170//170 182//170 183//170 171//170 +f 171//171 183//171 184//171 172//171 +f 172//172 184//172 185//172 173//172 +f 173//173 185//173 186//173 174//173 +f 174//174 186//174 187//174 175//174 +f 175//175 187//175 188//175 176//175 +f 176//176 188//176 189//176 177//176 +f 177//177 189//177 190//177 178//177 +f 178//178 190//178 191//178 179//178 +f 179//179 191//179 192//179 180//179 +f 180//180 192//180 181//180 169//180 +f 181//181 193//181 194//181 182//181 +f 182//182 194//182 195//182 183//182 +f 183//183 195//183 196//183 184//183 +f 184//184 196//184 197//184 185//184 +f 185//185 197//185 198//185 186//185 +f 186//186 198//186 199//186 187//186 +f 187//187 199//187 200//187 188//187 +f 188//188 200//188 201//188 189//188 +f 189//189 201//189 202//189 190//189 +f 190//190 202//190 203//190 191//190 +f 191//191 203//191 204//191 192//191 +f 192//192 204//192 193//192 181//192 +f 193//193 205//193 206//193 194//193 +f 194//194 206//194 207//194 195//194 +f 195//195 207//195 208//195 196//195 +f 196//196 208//196 209//196 197//196 +f 197//197 209//197 210//197 198//197 +f 198//198 210//198 211//198 199//198 +f 199//199 211//199 212//199 200//199 +f 200//200 212//200 213//200 201//200 +f 201//201 213//201 214//201 202//201 +f 202//202 214//202 215//202 203//202 +f 203//203 215//203 216//203 204//203 +f 204//204 216//204 205//204 193//204 +f 205//205 217//205 218//205 206//205 +f 206//206 218//206 219//206 207//206 +f 207//207 219//207 220//207 208//207 +f 208//208 220//208 221//208 209//208 +f 209//209 221//209 222//209 210//209 +f 210//210 222//210 223//210 211//210 +f 211//211 223//211 224//211 212//211 +f 212//212 224//212 225//212 213//212 +f 213//213 225//213 226//213 214//213 +f 214//214 226//214 227//214 215//214 +f 215//215 227//215 228//215 216//215 +f 216//216 228//216 217//216 205//216 +f 217//217 229//217 230//217 218//217 +f 218//218 230//218 231//218 219//218 +f 219//219 231//219 232//219 220//219 +f 220//220 232//220 233//220 221//220 +f 221//221 233//221 234//221 222//221 +f 222//222 234//222 235//222 223//222 +f 223//223 235//223 236//223 224//223 +f 224//224 236//224 237//224 225//224 +f 225//225 237//225 238//225 226//225 +f 226//226 238//226 239//226 227//226 +f 227//227 239//227 240//227 228//227 +f 228//228 240//228 229//228 217//228 +f 229//229 241//229 242//229 230//229 +f 230//230 242//230 243//230 231//230 +f 231//231 243//231 244//231 232//231 +f 232//232 244//232 245//232 233//232 +f 233//233 245//233 246//233 234//233 +f 234//234 246//234 247//234 235//234 +f 235//235 247//235 248//235 236//235 +f 236//236 248//236 249//236 237//236 +f 237//237 249//237 250//237 238//237 +f 238//238 250//238 251//238 239//238 +f 239//239 251//239 252//239 240//239 +f 240//240 252//240 241//240 229//240 +f 241//241 253//241 254//241 242//241 +f 242//242 254//242 255//242 243//242 +f 243//243 255//243 256//243 244//243 +f 244//244 256//244 257//244 245//244 +f 245//245 257//245 258//245 246//245 +f 246//246 258//246 259//246 247//246 +f 247//247 259//247 260//247 248//247 +f 248//248 260//248 261//248 249//248 +f 249//249 261//249 262//249 250//249 +f 250//250 262//250 263//250 251//250 +f 251//251 263//251 264//251 252//251 +f 252//252 264//252 253//252 241//252 +f 253//253 265//253 266//253 254//253 +f 254//254 266//254 267//254 255//254 +f 255//255 267//255 268//255 256//255 +f 256//256 268//256 269//256 257//256 +f 257//257 269//257 270//257 258//257 +f 258//258 270//258 271//258 259//258 +f 259//259 271//259 272//259 260//259 +f 260//260 272//260 273//260 261//260 +f 261//261 273//261 274//261 262//261 +f 262//262 274//262 275//262 263//262 +f 263//263 275//263 276//263 264//263 +f 264//264 276//264 265//264 253//264 +f 265//265 277//265 278//265 266//265 +f 266//266 278//266 279//266 267//266 +f 267//267 279//267 280//267 268//267 +f 268//268 280//268 281//268 269//268 +f 269//269 281//269 282//269 270//269 +f 270//270 282//270 283//270 271//270 +f 271//271 283//271 284//271 272//271 +f 272//272 284//272 285//272 273//272 +f 273//273 285//273 286//273 274//273 +f 274//274 286//274 287//274 275//274 +f 275//275 287//275 288//275 276//275 +f 276//276 288//276 277//276 265//276 +f 277//277 289//277 290//277 278//277 +f 278//278 290//278 291//278 279//278 +f 279//279 291//279 292//279 280//279 +f 280//280 292//280 293//280 281//280 +f 281//281 293//281 294//281 282//281 +f 282//282 294//282 295//282 283//282 +f 283//283 295//283 296//283 284//283 +f 284//284 296//284 297//284 285//284 +f 285//285 297//285 298//285 286//285 +f 286//286 298//286 299//286 287//286 +f 287//287 299//287 300//287 288//287 +f 288//288 300//288 289//288 277//288 +f 289//6 301//6 302//6 290//6 +f 290//5 302//5 303//5 291//5 +f 291//4 303//4 304//4 292//4 +f 292//3 304//3 305//3 293//3 +f 293//2 305//2 306//2 294//2 +f 294//1 306//1 307//1 295//1 +f 295//12 307//12 308//12 296//12 +f 296//11 308//11 309//11 297//11 +f 297//10 309//10 310//10 298//10 +f 298//9 310//9 311//9 299//9 +f 299//8 311//8 312//8 300//8 +f 300//7 312//7 301//7 289//7 +f 301//18 313//18 314//18 302//18 +f 302//17 314//17 315//17 303//17 +f 303//16 315//16 316//16 304//16 +f 304//15 316//15 317//15 305//15 +f 305//14 317//14 318//14 306//14 +f 306//13 318//13 319//13 307//13 +f 307//24 319//24 320//24 308//24 +f 308//23 320//23 321//23 309//23 +f 309//22 321//22 322//22 310//22 +f 310//21 322//21 323//21 311//21 +f 311//20 323//20 324//20 312//20 +f 312//19 324//19 313//19 301//19 +f 313//30 325//30 326//30 314//30 +f 314//29 326//29 327//29 315//29 +f 315//28 327//28 328//28 316//28 +f 316//27 328//27 329//27 317//27 +f 317//26 329//26 330//26 318//26 +f 318//25 330//25 331//25 319//25 +f 319//36 331//36 332//36 320//36 +f 320//35 332//35 333//35 321//35 +f 321//34 333//34 334//34 322//34 +f 322//33 334//33 335//33 323//33 +f 323//32 335//32 336//32 324//32 +f 324//31 336//31 325//31 313//31 +f 325//42 337//42 338//42 326//42 +f 326//41 338//41 339//41 327//41 +f 327//40 339//40 340//40 328//40 +f 328//39 340//39 341//39 329//39 +f 329//38 341//38 342//38 330//38 +f 330//37 342//37 343//37 331//37 +f 331//48 343//48 344//48 332//48 +f 332//47 344//47 345//47 333//47 +f 333//46 345//46 346//46 334//46 +f 334//45 346//45 347//45 335//45 +f 335//44 347//44 348//44 336//44 +f 336//43 348//43 337//43 325//43 +f 337//54 349//54 350//54 338//54 +f 338//53 350//53 351//53 339//53 +f 339//52 351//52 352//52 340//52 +f 340//51 352//51 353//51 341//51 +f 341//50 353//50 354//50 342//50 +f 342//49 354//49 355//49 343//49 +f 343//60 355//60 356//60 344//60 +f 344//59 356//59 357//59 345//59 +f 345//58 357//58 358//58 346//58 +f 346//57 358//57 359//57 347//57 +f 347//56 359//56 360//56 348//56 +f 348//55 360//55 349//55 337//55 +f 349//66 361//66 362//66 350//66 +f 350//65 362//65 363//65 351//65 +f 351//64 363//64 364//64 352//64 +f 352//63 364//63 365//63 353//63 +f 353//62 365//62 366//62 354//62 +f 354//61 366//61 367//61 355//61 +f 355//72 367//72 368//72 356//72 +f 356//71 368//71 369//71 357//71 +f 357//70 369//70 370//70 358//70 +f 358//69 370//69 371//69 359//69 +f 359//68 371//68 372//68 360//68 +f 360//67 372//67 361//67 349//67 +f 361//78 373//78 374//78 362//78 +f 362//77 374//77 375//77 363//77 +f 363//76 375//76 376//76 364//76 +f 364//75 376//75 377//75 365//75 +f 365//74 377//74 378//74 366//74 +f 366//73 378//73 379//73 367//73 +f 367//84 379//84 380//84 368//84 +f 368//83 380//83 381//83 369//83 +f 369//82 381//82 382//82 370//82 +f 370//81 382//81 383//81 371//81 +f 371//80 383//80 384//80 372//80 +f 372//79 384//79 373//79 361//79 +f 373//90 385//90 386//90 374//90 +f 374//89 386//89 387//89 375//89 +f 375//88 387//88 388//88 376//88 +f 376//87 388//87 389//87 377//87 +f 377//86 389//86 390//86 378//86 +f 378//85 390//85 391//85 379//85 +f 379//96 391//96 392//96 380//96 +f 380//95 392//95 393//95 381//95 +f 381//94 393//94 394//94 382//94 +f 382//93 394//93 395//93 383//93 +f 383//92 395//92 396//92 384//92 +f 384//91 396//91 385//91 373//91 +f 385//102 397//102 398//102 386//102 +f 386//101 398//101 399//101 387//101 +f 387//100 399//100 400//100 388//100 +f 388//99 400//99 401//99 389//99 +f 389//98 401//98 402//98 390//98 +f 390//97 402//97 403//97 391//97 +f 391//108 403//108 404//108 392//108 +f 392//107 404//107 405//107 393//107 +f 393//106 405//106 406//106 394//106 +f 394//105 406//105 407//105 395//105 +f 395//104 407//104 408//104 396//104 +f 396//103 408//103 397//103 385//103 +f 397//114 409//114 410//114 398//114 +f 398//113 410//113 411//113 399//113 +f 399//112 411//112 412//112 400//112 +f 400//111 412//111 413//111 401//111 +f 401//110 413//110 414//110 402//110 +f 402//109 414//109 415//109 403//109 +f 403//120 415//120 416//120 404//120 +f 404//119 416//119 417//119 405//119 +f 405//118 417//118 418//118 406//118 +f 406//117 418//117 419//117 407//117 +f 407//116 419//116 420//116 408//116 +f 408//115 420//115 409//115 397//115 +f 409//126 421//126 422//126 410//126 +f 410//125 422//125 423//125 411//125 +f 411//124 423//124 424//124 412//124 +f 412//123 424//123 425//123 413//123 +f 413//122 425//122 426//122 414//122 +f 414//121 426//121 427//121 415//121 +f 415//132 427//132 428//132 416//132 +f 416//131 428//131 429//131 417//131 +f 417//130 429//130 430//130 418//130 +f 418//129 430//129 431//129 419//129 +f 419//128 431//128 432//128 420//128 +f 420//127 432//127 421//127 409//127 +f 421//138 433//138 434//138 422//138 +f 422//137 434//137 435//137 423//137 +f 423//136 435//136 436//136 424//136 +f 424//135 436//135 437//135 425//135 +f 425//134 437//134 438//134 426//134 +f 426//133 438//133 439//133 427//133 +f 427//144 439//144 440//144 428//144 +f 428//143 440//143 441//143 429//143 +f 429//142 441//142 442//142 430//142 +f 430//141 442//141 443//141 431//141 +f 431//140 443//140 444//140 432//140 +f 432//139 444//139 433//139 421//139 +f 433//150 445//150 446//150 434//150 +f 434//149 446//149 447//149 435//149 +f 435//148 447//148 448//148 436//148 +f 436//147 448//147 449//147 437//147 +f 437//146 449//146 450//146 438//146 +f 438//145 450//145 451//145 439//145 +f 439//156 451//156 452//156 440//156 +f 440//155 452//155 453//155 441//155 +f 441//154 453//154 454//154 442//154 +f 442//153 454//153 455//153 443//153 +f 443//152 455//152 456//152 444//152 +f 444//151 456//151 445//151 433//151 +f 445//162 457//162 458//162 446//162 +f 446//161 458//161 459//161 447//161 +f 447//160 459//160 460//160 448//160 +f 448//159 460//159 461//159 449//159 +f 449//158 461//158 462//158 450//158 +f 450//157 462//157 463//157 451//157 +f 451//168 463//168 464//168 452//168 +f 452//167 464//167 465//167 453//167 +f 453//166 465//166 466//166 454//166 +f 454//165 466//165 467//165 455//165 +f 455//164 467//164 468//164 456//164 +f 456//163 468//163 457//163 445//163 +f 457//174 469//174 470//174 458//174 +f 458//173 470//173 471//173 459//173 +f 459//172 471//172 472//172 460//172 +f 460//171 472//171 473//171 461//171 +f 461//170 473//170 474//170 462//170 +f 462//169 474//169 475//169 463//169 +f 463//180 475//180 476//180 464//180 +f 464//179 476//179 477//179 465//179 +f 465//178 477//178 478//178 466//178 +f 466//177 478//177 479//177 467//177 +f 467//176 479//176 480//176 468//176 +f 468//175 480//175 469//175 457//175 +f 469//186 481//186 482//186 470//186 +f 470//185 482//185 483//185 471//185 +f 471//184 483//184 484//184 472//184 +f 472//183 484//183 485//183 473//183 +f 473//182 485//182 486//182 474//182 +f 474//181 486//181 487//181 475//181 +f 475//192 487//192 488//192 476//192 +f 476//191 488//191 489//191 477//191 +f 477//190 489//190 490//190 478//190 +f 478//189 490//189 491//189 479//189 +f 479//188 491//188 492//188 480//188 +f 480//187 492//187 481//187 469//187 +f 481//198 493//198 494//198 482//198 +f 482//197 494//197 495//197 483//197 +f 483//196 495//196 496//196 484//196 +f 484//195 496//195 497//195 485//195 +f 485//194 497//194 498//194 486//194 +f 486//193 498//193 499//193 487//193 +f 487//204 499//204 500//204 488//204 +f 488//203 500//203 501//203 489//203 +f 489//202 501//202 502//202 490//202 +f 490//201 502//201 503//201 491//201 +f 491//200 503//200 504//200 492//200 +f 492//199 504//199 493//199 481//199 +f 493//210 505//210 506//210 494//210 +f 494//209 506//209 507//209 495//209 +f 495//208 507//208 508//208 496//208 +f 496//207 508//207 509//207 497//207 +f 497//206 509//206 510//206 498//206 +f 498//205 510//205 511//205 499//205 +f 499//216 511//216 512//216 500//216 +f 500//215 512//215 513//215 501//215 +f 501//214 513//214 514//214 502//214 +f 502//213 514//213 515//213 503//213 +f 503//212 515//212 516//212 504//212 +f 504//211 516//211 505//211 493//211 +f 505//222 517//222 518//222 506//222 +f 506//221 518//221 519//221 507//221 +f 507//220 519//220 520//220 508//220 +f 508//219 520//219 521//219 509//219 +f 509//218 521//218 522//218 510//218 +f 510//217 522//217 523//217 511//217 +f 511//228 523//228 524//228 512//228 +f 512//227 524//227 525//227 513//227 +f 513//226 525//226 526//226 514//226 +f 514//225 526//225 527//225 515//225 +f 515//224 527//224 528//224 516//224 +f 516//223 528//223 517//223 505//223 +f 517//234 529//234 530//234 518//234 +f 518//233 530//233 531//233 519//233 +f 519//232 531//232 532//232 520//232 +f 520//231 532//231 533//231 521//231 +f 521//230 533//230 534//230 522//230 +f 522//229 534//229 535//229 523//229 +f 523//240 535//240 536//240 524//240 +f 524//239 536//239 537//239 525//239 +f 525//238 537//238 538//238 526//238 +f 526//237 538//237 539//237 527//237 +f 527//236 539//236 540//236 528//236 +f 528//235 540//235 529//235 517//235 +f 529//246 541//246 542//246 530//246 +f 530//245 542//245 543//245 531//245 +f 531//244 543//244 544//244 532//244 +f 532//243 544//243 545//243 533//243 +f 533//242 545//242 546//242 534//242 +f 534//241 546//241 547//241 535//241 +f 535//252 547//252 548//252 536//252 +f 536//251 548//251 549//251 537//251 +f 537//250 549//250 550//250 538//250 +f 538//249 550//249 551//249 539//249 +f 539//248 551//248 552//248 540//248 +f 540//247 552//247 541//247 529//247 +f 541//258 553//258 554//258 542//258 +f 542//257 554//257 555//257 543//257 +f 543//256 555//256 556//256 544//256 +f 544//255 556//255 557//255 545//255 +f 545//254 557//254 558//254 546//254 +f 546//253 558//253 559//253 547//253 +f 547//264 559//264 560//264 548//264 +f 548//263 560//263 561//263 549//263 +f 549//262 561//262 562//262 550//262 +f 550//261 562//261 563//261 551//261 +f 551//260 563//260 564//260 552//260 +f 552//259 564//259 553//259 541//259 +f 553//270 565//270 566//270 554//270 +f 554//269 566//269 567//269 555//269 +f 555//268 567//268 568//268 556//268 +f 556//267 568//267 569//267 557//267 +f 557//266 569//266 570//266 558//266 +f 558//265 570//265 571//265 559//265 +f 559//276 571//276 572//276 560//276 +f 560//275 572//275 573//275 561//275 +f 561//274 573//274 574//274 562//274 +f 562//273 574//273 575//273 563//273 +f 563//272 575//272 576//272 564//272 +f 564//271 576//271 565//271 553//271 +f 565//282 1//282 2//282 566//282 +f 566//281 2//281 3//281 567//281 +f 567//280 3//280 4//280 568//280 +f 568//279 4//279 5//279 569//279 +f 569//278 5//278 6//278 570//278 +f 570//277 6//277 7//277 571//277 +f 571//288 7//288 8//288 572//288 +f 572//287 8//287 9//287 573//287 +f 573//286 9//286 10//286 574//286 +f 574//285 10//285 11//285 575//285 +f 575//284 11//284 12//284 576//284 +f 576//283 12//283 1//283 565//283 diff --git a/data/torus/torus.urdf b/data/torus/torus.urdf new file mode 100644 index 000000000..57dc51c06 --- /dev/null +++ b/data/torus/torus.urdf @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/data/torus/torus_only.mtl b/data/torus/torus_only.mtl new file mode 100644 index 000000000..5361e19b8 --- /dev/null +++ b/data/torus/torus_only.mtl @@ -0,0 +1,12 @@ +# Blender MTL File: 'None' +# Material Count: 1 + +newmtl None +Ns 0.000000 +Ka 0.000000 0.000000 0.000000 +Kd 0.800000 0.800000 0.800000 +Ks 0.800000 0.800000 0.800000 +Ke 0.000000 0.000000 0.000000 +Ni 1.000000 +d 1.000000 +illum 2 diff --git a/data/torus/torus_only.obj b/data/torus/torus_only.obj new file mode 100644 index 000000000..a6776c93e --- /dev/null +++ b/data/torus/torus_only.obj @@ -0,0 +1,1474 @@ +# Blender v2.77 (sub 0) OBJ File: '' +# www.blender.org +mtllib torus_only.mtl +o Torus +v 1.269537 0.006289 1.359776 +v 1.258843 0.006289 1.196618 +v 1.225636 0.131289 1.200990 +v 1.236043 0.131289 1.359776 +v 1.134912 0.222796 1.212934 +v 1.144537 0.222796 1.359776 +v 1.010982 0.256289 1.229250 +v 1.019537 0.256289 1.359776 +v 0.887051 0.222796 1.245565 +v 0.894537 0.222796 1.359776 +v 0.796328 0.131289 1.257509 +v 0.803031 0.131289 1.359776 +v 0.763121 0.006289 1.261881 +v 0.769537 0.006289 1.359776 +v 0.796328 -0.118711 1.257509 +v 0.803031 -0.118711 1.359776 +v 0.887051 -0.210217 1.245565 +v 0.894537 -0.210217 1.359776 +v 1.010982 -0.243711 1.229250 +v 1.019537 -0.243711 1.359776 +v 1.134912 -0.210217 1.212934 +v 1.144537 -0.210217 1.359776 +v 1.225636 -0.118711 1.200990 +v 1.236043 -0.118711 1.359776 +v 1.226944 0.006289 1.036252 +v 1.194592 0.131289 1.044921 +v 1.106204 0.222796 1.068604 +v 0.985463 0.256289 1.100957 +v 0.864722 0.222796 1.133309 +v 0.776334 0.131289 1.156993 +v 0.743981 0.006289 1.165661 +v 0.776334 -0.118711 1.156993 +v 0.864722 -0.210217 1.133309 +v 0.985463 -0.243711 1.100957 +v 1.106204 -0.210217 1.068604 +v 1.194592 -0.118711 1.044921 +v 1.174387 0.006289 0.881421 +v 1.143442 0.131289 0.894239 +v 1.058902 0.222796 0.929257 +v 0.943417 0.256289 0.977092 +v 0.827932 0.222796 1.024928 +v 0.743391 0.131289 1.059946 +v 0.712447 0.006289 1.072763 +v 0.743391 -0.118711 1.059946 +v 0.827932 -0.210217 1.024928 +v 0.943417 -0.243711 0.977092 +v 1.058902 -0.210217 0.929257 +v 1.143442 -0.118711 0.894239 +v 1.102069 0.006289 0.734776 +v 1.073062 0.131289 0.751522 +v 0.993815 0.222796 0.797276 +v 0.885562 0.256289 0.859776 +v 0.777309 0.222796 0.922276 +v 0.698062 0.131289 0.968029 +v 0.669056 0.006289 0.984776 +v 0.698062 -0.118711 0.968029 +v 0.777309 -0.210217 0.922276 +v 0.885562 -0.243711 0.859776 +v 0.993815 -0.210217 0.797276 +v 1.073062 -0.118711 0.751522 +v 1.011229 0.006289 0.598824 +v 0.984656 0.131289 0.619214 +v 0.912059 0.222796 0.674919 +v 0.812890 0.256289 0.751014 +v 0.713721 0.222796 0.827109 +v 0.641124 0.131289 0.882815 +v 0.614552 0.006289 0.903205 +v 0.641124 -0.118711 0.882815 +v 0.713721 -0.210217 0.827109 +v 0.812890 -0.243711 0.751014 +v 0.912059 -0.210217 0.674919 +v 0.984656 -0.118711 0.619214 +v 0.903420 0.006289 0.475892 +v 0.879737 0.131289 0.499576 +v 0.815032 0.222796 0.564281 +v 0.726644 0.256289 0.652669 +v 0.638255 0.222796 0.741057 +v 0.573551 0.131289 0.805762 +v 0.549867 0.006289 0.829446 +v 0.573551 -0.118711 0.805762 +v 0.638255 -0.210217 0.741057 +v 0.726644 -0.243711 0.652669 +v 0.815032 -0.210217 0.564281 +v 0.879737 -0.118711 0.499576 +v 0.780489 0.006289 0.368084 +v 0.760099 0.131289 0.394656 +v 0.704394 0.222796 0.467253 +v 0.628298 0.256289 0.566423 +v 0.552203 0.222796 0.665592 +v 0.496498 0.131289 0.738188 +v 0.476108 0.006289 0.764761 +v 0.496498 -0.118711 0.738188 +v 0.552203 -0.210217 0.665592 +v 0.628298 -0.243711 0.566423 +v 0.704394 -0.210217 0.467253 +v 0.760099 -0.118711 0.394656 +v 0.644537 0.006289 0.277244 +v 0.627790 0.131289 0.306250 +v 0.582037 0.222796 0.385497 +v 0.519537 0.256289 0.493750 +v 0.457037 0.222796 0.602003 +v 0.411284 0.131289 0.681250 +v 0.394537 0.006289 0.710257 +v 0.411284 -0.118711 0.681250 +v 0.457037 -0.210217 0.602003 +v 0.519537 -0.243711 0.493750 +v 0.582037 -0.210217 0.385497 +v 0.627790 -0.118711 0.306250 +v 0.497891 0.006289 0.204926 +v 0.485074 0.131289 0.235871 +v 0.450056 0.222796 0.320411 +v 0.402221 0.256289 0.435896 +v 0.354385 0.222796 0.551381 +v 0.319367 0.131289 0.635922 +v 0.306550 0.006289 0.666866 +v 0.319367 -0.118711 0.635922 +v 0.354385 -0.210217 0.551381 +v 0.402221 -0.243711 0.435896 +v 0.450056 -0.210217 0.320411 +v 0.485074 -0.118711 0.235871 +v 0.343061 0.006289 0.152368 +v 0.334392 0.131289 0.184721 +v 0.310708 0.222796 0.273109 +v 0.278356 0.256289 0.393850 +v 0.246004 0.222796 0.514591 +v 0.222320 0.131289 0.602979 +v 0.213651 0.006289 0.635331 +v 0.222320 -0.118711 0.602979 +v 0.246004 -0.210217 0.514591 +v 0.278356 -0.243711 0.393850 +v 0.310708 -0.210217 0.273109 +v 0.334392 -0.118711 0.184721 +v 0.182694 0.006289 0.120470 +v 0.178323 0.131289 0.153677 +v 0.166379 0.222796 0.244400 +v 0.150063 0.256289 0.368331 +v 0.133747 0.222796 0.492261 +v 0.121803 0.131289 0.582985 +v 0.117431 0.006289 0.616192 +v 0.121803 -0.118711 0.582985 +v 0.133747 -0.210217 0.492261 +v 0.150063 -0.243711 0.368331 +v 0.166379 -0.210217 0.244400 +v 0.178323 -0.118711 0.153677 +v 0.019537 0.006289 0.109776 +v 0.019537 0.131289 0.143269 +v 0.019537 0.222796 0.234776 +v 0.019537 0.256289 0.359776 +v 0.019537 0.222796 0.484776 +v 0.019537 0.131289 0.576282 +v 0.019537 0.006289 0.609776 +v 0.019537 -0.118711 0.576282 +v 0.019537 -0.210217 0.484776 +v 0.019537 -0.243711 0.359776 +v 0.019537 -0.210217 0.234776 +v 0.019537 -0.118711 0.143269 +v -0.143621 0.006289 0.120470 +v -0.139249 0.131289 0.153677 +v -0.127305 0.222796 0.244400 +v -0.110989 0.256289 0.368331 +v -0.094674 0.222796 0.492261 +v -0.082730 0.131289 0.582985 +v -0.078358 0.006289 0.616192 +v -0.082730 -0.118711 0.582985 +v -0.094674 -0.210217 0.492261 +v -0.110989 -0.243711 0.368331 +v -0.127305 -0.210217 0.244400 +v -0.139249 -0.118711 0.153677 +v -0.303987 0.006289 0.152368 +v -0.295318 0.131289 0.184721 +v -0.271634 0.222796 0.273109 +v -0.239282 0.256289 0.393850 +v -0.206930 0.222796 0.514590 +v -0.183246 0.131289 0.602979 +v -0.174577 0.006289 0.635331 +v -0.183246 -0.118711 0.602979 +v -0.206930 -0.210217 0.514590 +v -0.239282 -0.243711 0.393850 +v -0.271634 -0.210217 0.273109 +v -0.295318 -0.118711 0.184721 +v -0.458818 0.006289 0.204926 +v -0.446000 0.131289 0.235870 +v -0.410982 0.222796 0.320411 +v -0.363147 0.256289 0.435896 +v -0.315311 0.222796 0.551381 +v -0.280293 0.131289 0.635922 +v -0.267476 0.006289 0.666866 +v -0.280293 -0.118711 0.635922 +v -0.315311 -0.210217 0.551381 +v -0.363147 -0.243711 0.435896 +v -0.410982 -0.210217 0.320411 +v -0.446000 -0.118711 0.235870 +v -0.605463 0.006289 0.277244 +v -0.588716 0.131289 0.306250 +v -0.542963 0.222796 0.385497 +v -0.480463 0.256289 0.493750 +v -0.417963 0.222796 0.602003 +v -0.372210 0.131289 0.681250 +v -0.355463 0.006289 0.710257 +v -0.372210 -0.118711 0.681250 +v -0.417963 -0.210217 0.602003 +v -0.480463 -0.243711 0.493750 +v -0.542963 -0.210217 0.385497 +v -0.588716 -0.118711 0.306250 +v -0.741415 0.006289 0.368084 +v -0.721025 0.131289 0.394656 +v -0.665320 0.222796 0.467253 +v -0.589225 0.256289 0.566422 +v -0.513129 0.222796 0.665592 +v -0.457424 0.131289 0.738188 +v -0.437034 0.006289 0.764761 +v -0.457424 -0.118711 0.738188 +v -0.513129 -0.210217 0.665592 +v -0.589225 -0.243711 0.566422 +v -0.665320 -0.210217 0.467253 +v -0.721025 -0.118711 0.394656 +v -0.864347 0.006289 0.475893 +v -0.840663 0.131289 0.499576 +v -0.775958 0.222796 0.564281 +v -0.687570 0.256289 0.652669 +v -0.599182 0.222796 0.741057 +v -0.534477 0.131289 0.805762 +v -0.510793 0.006289 0.829446 +v -0.534477 -0.118711 0.805762 +v -0.599182 -0.210217 0.741057 +v -0.687570 -0.243711 0.652669 +v -0.775958 -0.210217 0.564281 +v -0.840663 -0.118711 0.499576 +v -0.972155 0.006289 0.598824 +v -0.945583 0.131289 0.619214 +v -0.872986 0.222796 0.674919 +v -0.773816 0.256289 0.751014 +v -0.674647 0.222796 0.827109 +v -0.602050 0.131289 0.882815 +v -0.575478 0.006289 0.903205 +v -0.602050 -0.118711 0.882815 +v -0.674647 -0.210217 0.827109 +v -0.773816 -0.243711 0.751014 +v -0.872986 -0.210217 0.674919 +v -0.945583 -0.118711 0.619214 +v -1.062995 0.006289 0.734775 +v -1.033988 0.131289 0.751522 +v -0.954742 0.222796 0.797275 +v -0.846488 0.256289 0.859775 +v -0.738235 0.222796 0.922275 +v -0.658988 0.131289 0.968029 +v -0.629982 0.006289 0.984775 +v -0.658988 -0.118711 0.968029 +v -0.738235 -0.210217 0.922275 +v -0.846488 -0.243711 0.859775 +v -0.954742 -0.210217 0.797275 +v -1.033988 -0.118711 0.751522 +v -1.135312 0.006289 0.881421 +v -1.104368 0.131289 0.894239 +v -1.019827 0.222796 0.929257 +v -0.904343 0.256289 0.977092 +v -0.788858 0.222796 1.024928 +v -0.704317 0.131289 1.059946 +v -0.673373 0.006289 1.072763 +v -0.704317 -0.118711 1.059946 +v -0.788858 -0.210217 1.024928 +v -0.904343 -0.243711 0.977092 +v -1.019827 -0.210217 0.929257 +v -1.104368 -0.118711 0.894239 +v -1.187871 0.006289 1.036252 +v -1.155518 0.131289 1.044921 +v -1.067130 0.222796 1.068604 +v -0.946389 0.256289 1.100957 +v -0.825648 0.222796 1.133309 +v -0.737260 0.131289 1.156993 +v -0.704908 0.006289 1.165662 +v -0.737260 -0.118711 1.156993 +v -0.825648 -0.210217 1.133309 +v -0.946389 -0.243711 1.100957 +v -1.067130 -0.210217 1.068604 +v -1.155518 -0.118711 1.044921 +v -1.219769 0.006289 1.196618 +v -1.186562 0.131289 1.200990 +v -1.095839 0.222796 1.212934 +v -0.971908 0.256289 1.229249 +v -0.847977 0.222796 1.245565 +v -0.757254 0.131289 1.257509 +v -0.724047 0.006289 1.261881 +v -0.757254 -0.118711 1.257509 +v -0.847977 -0.210217 1.245565 +v -0.971908 -0.243711 1.229249 +v -1.095839 -0.210217 1.212934 +v -1.186562 -0.118711 1.200990 +v -1.230463 0.006289 1.359776 +v -1.196970 0.131289 1.359776 +v -1.105463 0.222796 1.359776 +v -0.980463 0.256289 1.359776 +v -0.855463 0.222796 1.359776 +v -0.763957 0.131289 1.359776 +v -0.730463 0.006289 1.359776 +v -0.763957 -0.118711 1.359776 +v -0.855463 -0.210217 1.359776 +v -0.980463 -0.243711 1.359776 +v -1.105463 -0.210217 1.359776 +v -1.196970 -0.118711 1.359776 +v -1.219769 0.006289 1.522934 +v -1.186562 0.131289 1.518562 +v -1.095839 0.222796 1.506618 +v -0.971908 0.256289 1.490302 +v -0.847977 0.222796 1.473986 +v -0.757254 0.131289 1.462042 +v -0.724047 0.006289 1.457670 +v -0.757254 -0.118711 1.462042 +v -0.847977 -0.210217 1.473986 +v -0.971908 -0.243711 1.490302 +v -1.095839 -0.210217 1.506618 +v -1.186562 -0.118711 1.518562 +v -1.187871 0.006289 1.683299 +v -1.155518 0.131289 1.674631 +v -1.067130 0.222796 1.650947 +v -0.946389 0.256289 1.618595 +v -0.825648 0.222796 1.586242 +v -0.737260 0.131289 1.562559 +v -0.704908 0.006289 1.553890 +v -0.737260 -0.118711 1.562559 +v -0.825648 -0.210217 1.586242 +v -0.946389 -0.243711 1.618595 +v -1.067130 -0.210217 1.650947 +v -1.155518 -0.118711 1.674631 +v -1.135313 0.006289 1.838130 +v -1.104369 0.131289 1.825312 +v -1.019828 0.222796 1.790294 +v -0.904343 0.256289 1.742459 +v -0.788858 0.222796 1.694623 +v -0.704317 0.131289 1.659605 +v -0.673373 0.006289 1.646788 +v -0.704317 -0.118711 1.659605 +v -0.788858 -0.210217 1.694623 +v -0.904343 -0.243711 1.742459 +v -1.019828 -0.210217 1.790294 +v -1.104369 -0.118711 1.825312 +v -1.062995 0.006289 1.984776 +v -1.033989 0.131289 1.968029 +v -0.954742 0.222796 1.922276 +v -0.846489 0.256289 1.859776 +v -0.738235 0.222796 1.797276 +v -0.658989 0.131289 1.751522 +v -0.629982 0.006289 1.734776 +v -0.658989 -0.118711 1.751522 +v -0.738235 -0.210217 1.797276 +v -0.846489 -0.243711 1.859776 +v -0.954742 -0.210217 1.922276 +v -1.033989 -0.118711 1.968029 +v -0.972155 0.006289 2.120728 +v -0.945583 0.131289 2.100338 +v -0.872986 0.222796 2.044632 +v -0.773816 0.256289 1.968537 +v -0.674647 0.222796 1.892442 +v -0.602050 0.131289 1.836736 +v -0.575478 0.006289 1.816347 +v -0.602050 -0.118711 1.836736 +v -0.674647 -0.210217 1.892442 +v -0.773816 -0.243711 1.968537 +v -0.872986 -0.210217 2.044632 +v -0.945583 -0.118711 2.100338 +v -0.864347 0.006289 2.243659 +v -0.840663 0.131289 2.219975 +v -0.775958 0.222796 2.155271 +v -0.687570 0.256289 2.066882 +v -0.599182 0.222796 1.978494 +v -0.534477 0.131289 1.913789 +v -0.510793 0.006289 1.890106 +v -0.534477 -0.118711 1.913789 +v -0.599182 -0.210217 1.978494 +v -0.687570 -0.243711 2.066882 +v -0.775958 -0.210217 2.155271 +v -0.840663 -0.118711 2.219975 +v -0.741416 0.006289 2.351467 +v -0.721026 0.131289 2.324895 +v -0.665320 0.222796 2.252298 +v -0.589225 0.256289 2.153129 +v -0.513130 0.222796 2.053960 +v -0.457424 0.131289 1.981363 +v -0.437034 0.006289 1.954791 +v -0.457424 -0.118711 1.981363 +v -0.513130 -0.210217 2.053960 +v -0.589225 -0.243711 2.153129 +v -0.665320 -0.210217 2.252298 +v -0.721026 -0.118711 2.324895 +v -0.605463 0.006289 2.442308 +v -0.588716 0.131289 2.413301 +v -0.542963 0.222796 2.334054 +v -0.480463 0.256289 2.225801 +v -0.417963 0.222796 2.117548 +v -0.372210 0.131289 2.038301 +v -0.355463 0.006289 2.009295 +v -0.372210 -0.118711 2.038301 +v -0.417963 -0.210217 2.117548 +v -0.480463 -0.243711 2.225801 +v -0.542963 -0.210217 2.334054 +v -0.588716 -0.118711 2.413301 +v -0.458818 0.006289 2.514625 +v -0.446000 0.131289 2.483681 +v -0.410982 0.222796 2.399140 +v -0.363147 0.256289 2.283655 +v -0.315311 0.222796 2.168170 +v -0.280293 0.131289 2.083629 +v -0.267476 0.006289 2.052685 +v -0.280293 -0.118711 2.083629 +v -0.315311 -0.210217 2.168170 +v -0.363147 -0.243711 2.283655 +v -0.410982 -0.210217 2.399140 +v -0.446000 -0.118711 2.483681 +v -0.303987 0.006289 2.567183 +v -0.295318 0.131289 2.534830 +v -0.271635 0.222796 2.446442 +v -0.239282 0.256289 2.325701 +v -0.206930 0.222796 2.204961 +v -0.183246 0.131289 2.116572 +v -0.174578 0.006289 2.084220 +v -0.183246 -0.118711 2.116572 +v -0.206930 -0.210217 2.204961 +v -0.239282 -0.243711 2.325701 +v -0.271635 -0.210217 2.446442 +v -0.295318 -0.118711 2.534830 +v -0.143622 0.006289 2.599082 +v -0.139250 0.131289 2.565874 +v -0.127306 0.222796 2.475151 +v -0.110990 0.256289 2.351220 +v -0.094674 0.222796 2.227290 +v -0.082730 0.131289 2.136566 +v -0.078358 0.006289 2.103359 +v -0.082730 -0.118711 2.136566 +v -0.094674 -0.210217 2.227290 +v -0.110990 -0.243711 2.351220 +v -0.127306 -0.210217 2.475151 +v -0.139250 -0.118711 2.565874 +v 0.019537 0.006289 2.609776 +v 0.019537 0.131289 2.576282 +v 0.019537 0.222796 2.484776 +v 0.019537 0.256289 2.359776 +v 0.019537 0.222796 2.234776 +v 0.019537 0.131289 2.143269 +v 0.019537 0.006289 2.109776 +v 0.019537 -0.118711 2.143269 +v 0.019537 -0.210217 2.234776 +v 0.019537 -0.243711 2.359776 +v 0.019537 -0.210217 2.484776 +v 0.019537 -0.118711 2.576282 +v 0.182694 0.006289 2.599082 +v 0.178323 0.131289 2.565875 +v 0.166379 0.222796 2.475151 +v 0.150063 0.256289 2.351221 +v 0.133747 0.222796 2.227290 +v 0.121803 0.131289 2.136566 +v 0.117431 0.006289 2.103359 +v 0.121803 -0.118711 2.136566 +v 0.133747 -0.210217 2.227290 +v 0.150063 -0.243711 2.351221 +v 0.166379 -0.210217 2.475151 +v 0.178323 -0.118711 2.565875 +v 0.343060 0.006289 2.567183 +v 0.334391 0.131289 2.534831 +v 0.310708 0.222796 2.446442 +v 0.278356 0.256289 2.325702 +v 0.246003 0.222796 2.204961 +v 0.222320 0.131289 2.116573 +v 0.213651 0.006289 2.084220 +v 0.222320 -0.118711 2.116573 +v 0.246003 -0.210217 2.204961 +v 0.278356 -0.243711 2.325702 +v 0.310708 -0.210217 2.446442 +v 0.334391 -0.118711 2.534831 +v 0.497891 0.006289 2.514625 +v 0.485074 0.131289 2.483681 +v 0.450056 0.222796 2.399140 +v 0.402221 0.256289 2.283655 +v 0.354385 0.222796 2.168170 +v 0.319367 0.131289 2.083629 +v 0.306550 0.006289 2.052685 +v 0.319367 -0.118711 2.083629 +v 0.354385 -0.210217 2.168170 +v 0.402221 -0.243711 2.283655 +v 0.450056 -0.210217 2.399140 +v 0.485074 -0.118711 2.483681 +v 0.644537 0.006289 2.442307 +v 0.627790 0.131289 2.413301 +v 0.582037 0.222796 2.334054 +v 0.519537 0.256289 2.225801 +v 0.457037 0.222796 2.117548 +v 0.411284 0.131289 2.038301 +v 0.394537 0.006289 2.009295 +v 0.411284 -0.118711 2.038301 +v 0.457037 -0.210217 2.117548 +v 0.519537 -0.243711 2.225801 +v 0.582037 -0.210217 2.334054 +v 0.627790 -0.118711 2.413301 +v 0.780488 0.006289 2.351468 +v 0.760099 0.131289 2.324895 +v 0.704393 0.222796 2.252298 +v 0.628298 0.256289 2.153129 +v 0.552203 0.222796 2.053960 +v 0.496497 0.131289 1.981363 +v 0.476108 0.006289 1.954791 +v 0.496497 -0.118711 1.981363 +v 0.552203 -0.210217 2.053960 +v 0.628298 -0.243711 2.153129 +v 0.704393 -0.210217 2.252298 +v 0.760099 -0.118711 2.324895 +v 0.903420 0.006289 2.243660 +v 0.879736 0.131289 2.219976 +v 0.815032 0.222796 2.155271 +v 0.726643 0.256289 2.066883 +v 0.638255 0.222796 1.978495 +v 0.573550 0.131289 1.913790 +v 0.549867 0.006289 1.890106 +v 0.573550 -0.118711 1.913790 +v 0.638255 -0.210217 1.978495 +v 0.726643 -0.243711 2.066883 +v 0.815032 -0.210217 2.155271 +v 0.879736 -0.118711 2.219976 +v 1.011229 0.006289 2.120727 +v 0.984656 0.131289 2.100338 +v 0.912059 0.222796 2.044632 +v 0.812890 0.256289 1.968537 +v 0.713721 0.222796 1.892442 +v 0.641124 0.131289 1.836736 +v 0.614552 0.006289 1.816347 +v 0.641124 -0.118711 1.836736 +v 0.713721 -0.210217 1.892442 +v 0.812890 -0.243711 1.968537 +v 0.912059 -0.210217 2.044632 +v 0.984656 -0.118711 2.100338 +v 1.102069 0.006289 1.984776 +v 1.073062 0.131289 1.968029 +v 0.993815 0.222796 1.922276 +v 0.885562 0.256289 1.859776 +v 0.777309 0.222796 1.797276 +v 0.698062 0.131289 1.751523 +v 0.669056 0.006289 1.734776 +v 0.698062 -0.118711 1.751523 +v 0.777309 -0.210217 1.797276 +v 0.885562 -0.243711 1.859776 +v 0.993815 -0.210217 1.922276 +v 1.073062 -0.118711 1.968029 +v 1.174386 0.006289 1.838130 +v 1.143442 0.131289 1.825313 +v 1.058901 0.222796 1.790295 +v 0.943416 0.256289 1.742460 +v 0.827931 0.222796 1.694624 +v 0.743391 0.131289 1.659606 +v 0.712446 0.006289 1.646789 +v 0.743391 -0.118711 1.659606 +v 0.827931 -0.210217 1.694624 +v 0.943416 -0.243711 1.742460 +v 1.058901 -0.210217 1.790295 +v 1.143442 -0.118711 1.825313 +v 1.226944 0.006289 1.683299 +v 1.194592 0.131289 1.674630 +v 1.106204 0.222796 1.650947 +v 0.985463 0.256289 1.618594 +v 0.864722 0.222796 1.586242 +v 0.776334 0.131289 1.562559 +v 0.743981 0.006289 1.553890 +v 0.776334 -0.118711 1.562559 +v 0.864722 -0.210217 1.586242 +v 0.985463 -0.243711 1.618594 +v 1.106204 -0.210217 1.650947 +v 1.194592 -0.118711 1.674630 +v 1.258843 0.006289 1.522933 +v 1.225636 0.131289 1.518562 +v 1.134912 0.222796 1.506618 +v 1.010982 0.256289 1.490302 +v 0.887051 0.222796 1.473986 +v 0.796328 0.131289 1.462042 +v 0.763121 0.006289 1.457670 +v 0.796328 -0.118711 1.462042 +v 0.887051 -0.210217 1.473986 +v 1.010982 -0.243711 1.490302 +v 1.134912 -0.210217 1.506618 +v 1.225636 -0.118711 1.518562 +vn 0.9640 0.2583 -0.0632 +vn 0.7064 0.7063 -0.0463 +vn 0.2588 0.9658 -0.0170 +vn -0.2588 0.9658 0.0170 +vn -0.7064 0.7063 0.0463 +vn -0.9640 0.2583 0.0632 +vn -0.9640 -0.2583 0.0632 +vn -0.7063 -0.7063 0.0463 +vn -0.2588 -0.9658 0.0170 +vn 0.2588 -0.9658 -0.0170 +vn 0.7063 -0.7064 -0.0463 +vn 0.9640 -0.2583 -0.0632 +vn 0.9475 0.2583 -0.1885 +vn 0.6943 0.7063 -0.1381 +vn 0.2543 0.9658 -0.0506 +vn -0.2543 0.9658 0.0506 +vn -0.6943 0.7063 0.1381 +vn -0.9475 0.2583 0.1885 +vn -0.9475 -0.2583 0.1885 +vn -0.6943 -0.7063 0.1381 +vn -0.2544 -0.9658 0.0506 +vn 0.2544 -0.9658 -0.0506 +vn 0.6943 -0.7063 -0.1381 +vn 0.9475 -0.2583 -0.1885 +vn 0.9148 0.2583 -0.3105 +vn 0.6703 0.7063 -0.2275 +vn 0.2456 0.9658 -0.0834 +vn -0.2456 0.9658 0.0834 +vn -0.6703 0.7063 0.2275 +vn -0.9148 0.2583 0.3105 +vn -0.9148 -0.2583 0.3105 +vn -0.6703 -0.7064 0.2275 +vn -0.2456 -0.9658 0.0834 +vn 0.2456 -0.9658 -0.0834 +vn 0.6703 -0.7063 -0.2275 +vn 0.9148 -0.2583 -0.3105 +vn 0.8664 0.2583 -0.4273 +vn 0.6349 0.7063 -0.3131 +vn 0.2326 0.9658 -0.1147 +vn -0.2326 0.9658 0.1147 +vn -0.6349 0.7063 0.3131 +vn -0.8664 0.2583 0.4273 +vn -0.8664 -0.2583 0.4273 +vn -0.6349 -0.7064 0.3131 +vn -0.2326 -0.9658 0.1147 +vn 0.2326 -0.9658 -0.1147 +vn 0.6349 -0.7064 -0.3131 +vn 0.8664 -0.2583 -0.4273 +vn 0.8033 0.2583 -0.5367 +vn 0.5886 0.7063 -0.3933 +vn 0.2156 0.9658 -0.1441 +vn -0.2156 0.9658 0.1441 +vn -0.5886 0.7063 0.3933 +vn -0.8033 0.2583 0.5367 +vn -0.8033 -0.2583 0.5367 +vn -0.5886 -0.7064 0.3933 +vn -0.2156 -0.9658 0.1441 +vn 0.2156 -0.9658 -0.1441 +vn 0.5886 -0.7063 -0.3933 +vn 0.8033 -0.2583 -0.5367 +vn 0.7263 0.2583 -0.6370 +vn 0.5322 0.7063 -0.4667 +vn 0.1950 0.9658 -0.1710 +vn -0.1950 0.9658 0.1710 +vn -0.5322 0.7063 0.4667 +vn -0.7263 0.2583 0.6370 +vn -0.7263 -0.2583 0.6370 +vn -0.5322 -0.7064 0.4667 +vn -0.1950 -0.9658 0.1710 +vn 0.1950 -0.9658 -0.1710 +vn 0.5322 -0.7063 -0.4667 +vn 0.7263 -0.2583 -0.6370 +vn 0.6370 0.2583 -0.7263 +vn 0.4667 0.7063 -0.5322 +vn 0.1710 0.9658 -0.1950 +vn -0.1710 0.9658 0.1950 +vn -0.4667 0.7063 0.5322 +vn -0.6370 0.2583 0.7263 +vn -0.6370 -0.2583 0.7263 +vn -0.4667 -0.7063 0.5322 +vn -0.1710 -0.9658 0.1950 +vn 0.1710 -0.9658 -0.1950 +vn 0.4667 -0.7064 -0.5322 +vn 0.6370 -0.2583 -0.7263 +vn 0.5367 0.2583 -0.8033 +vn 0.3933 0.7063 -0.5886 +vn 0.1441 0.9658 -0.2156 +vn -0.1441 0.9658 0.2156 +vn -0.3933 0.7063 0.5886 +vn -0.5367 0.2583 0.8033 +vn -0.5367 -0.2583 0.8033 +vn -0.3933 -0.7063 0.5886 +vn -0.1441 -0.9658 0.2156 +vn 0.1441 -0.9658 -0.2156 +vn 0.3933 -0.7063 -0.5886 +vn 0.5367 -0.2583 -0.8033 +vn 0.4273 0.2583 -0.8664 +vn 0.3131 0.7063 -0.6349 +vn 0.1147 0.9658 -0.2326 +vn -0.1147 0.9658 0.2326 +vn -0.3131 0.7063 0.6349 +vn -0.4273 0.2583 0.8664 +vn -0.4273 -0.2583 0.8664 +vn -0.3131 -0.7064 0.6349 +vn -0.1147 -0.9658 0.2326 +vn 0.1147 -0.9658 -0.2326 +vn 0.3131 -0.7063 -0.6349 +vn 0.4273 -0.2583 -0.8664 +vn 0.3105 0.2583 -0.9148 +vn 0.2275 0.7063 -0.6703 +vn 0.0834 0.9658 -0.2456 +vn -0.0834 0.9658 0.2456 +vn -0.2275 0.7063 0.6703 +vn -0.3105 0.2583 0.9148 +vn -0.3105 -0.2583 0.9148 +vn -0.2275 -0.7064 0.6703 +vn -0.0834 -0.9658 0.2456 +vn 0.0834 -0.9658 -0.2456 +vn 0.2275 -0.7063 -0.6703 +vn 0.3105 -0.2583 -0.9148 +vn 0.1885 0.2583 -0.9475 +vn 0.1381 0.7063 -0.6943 +vn 0.0506 0.9658 -0.2543 +vn -0.0506 0.9658 0.2543 +vn -0.1381 0.7063 0.6943 +vn -0.1885 0.2583 0.9475 +vn -0.1885 -0.2583 0.9475 +vn -0.1381 -0.7064 0.6943 +vn -0.0506 -0.9658 0.2544 +vn 0.0506 -0.9658 -0.2544 +vn 0.1381 -0.7063 -0.6943 +vn 0.1885 -0.2583 -0.9475 +vn 0.0632 0.2583 -0.9640 +vn 0.0463 0.7063 -0.7064 +vn 0.0170 0.9658 -0.2588 +vn -0.0170 0.9658 0.2588 +vn -0.0463 0.7063 0.7064 +vn -0.0632 0.2583 0.9640 +vn -0.0632 -0.2583 0.9640 +vn -0.0463 -0.7064 0.7063 +vn -0.0170 -0.9658 0.2588 +vn 0.0170 -0.9658 -0.2588 +vn 0.0463 -0.7064 -0.7063 +vn 0.0632 -0.2583 -0.9640 +vn -0.0632 0.2583 -0.9640 +vn -0.0463 0.7063 -0.7064 +vn -0.0170 0.9658 -0.2588 +vn 0.0170 0.9658 0.2588 +vn 0.0463 0.7063 0.7064 +vn 0.0632 0.2583 0.9640 +vn 0.0632 -0.2583 0.9640 +vn 0.0463 -0.7064 0.7063 +vn 0.0170 -0.9658 0.2588 +vn -0.0170 -0.9658 -0.2588 +vn -0.0463 -0.7064 -0.7063 +vn -0.0632 -0.2583 -0.9640 +vn -0.1885 0.2583 -0.9475 +vn -0.1381 0.7063 -0.6943 +vn -0.0506 0.9658 -0.2543 +vn 0.0506 0.9658 0.2544 +vn 0.1381 0.7063 0.6943 +vn 0.1885 0.2583 0.9475 +vn 0.1885 -0.2583 0.9475 +vn 0.1381 -0.7064 0.6943 +vn 0.0506 -0.9658 0.2544 +vn -0.0506 -0.9658 -0.2544 +vn -0.1381 -0.7063 -0.6943 +vn -0.1885 -0.2583 -0.9475 +vn -0.3105 0.2583 -0.9148 +vn -0.2275 0.7063 -0.6703 +vn -0.0834 0.9658 -0.2456 +vn 0.0834 0.9658 0.2456 +vn 0.2275 0.7063 0.6703 +vn 0.3105 0.2583 0.9148 +vn 0.3105 -0.2583 0.9148 +vn 0.2275 -0.7064 0.6703 +vn 0.0834 -0.9658 0.2456 +vn -0.0834 -0.9658 -0.2456 +vn -0.2275 -0.7063 -0.6703 +vn -0.3105 -0.2583 -0.9148 +vn -0.4273 0.2583 -0.8664 +vn -0.3131 0.7063 -0.6349 +vn -0.1147 0.9658 -0.2326 +vn 0.1147 0.9658 0.2326 +vn 0.3131 0.7063 0.6349 +vn 0.4273 0.2583 0.8664 +vn 0.4273 -0.2583 0.8664 +vn 0.3131 -0.7064 0.6349 +vn 0.1147 -0.9658 0.2326 +vn -0.1147 -0.9658 -0.2326 +vn -0.3131 -0.7064 -0.6349 +vn -0.4273 -0.2583 -0.8664 +vn -0.5367 0.2583 -0.8033 +vn -0.3933 0.7063 -0.5886 +vn -0.1441 0.9658 -0.2156 +vn 0.1441 0.9658 0.2156 +vn 0.3933 0.7063 0.5886 +vn 0.5367 0.2583 0.8033 +vn 0.5367 -0.2583 0.8033 +vn 0.3933 -0.7063 0.5886 +vn 0.1441 -0.9658 0.2156 +vn -0.1441 -0.9658 -0.2156 +vn -0.3933 -0.7063 -0.5886 +vn -0.5367 -0.2583 -0.8033 +vn -0.6370 0.2583 -0.7263 +vn -0.4667 0.7063 -0.5322 +vn -0.1710 0.9658 -0.1950 +vn 0.1710 0.9658 0.1950 +vn 0.4667 0.7063 0.5322 +vn 0.6370 0.2583 0.7263 +vn 0.6370 -0.2583 0.7263 +vn 0.4667 -0.7063 0.5322 +vn 0.1710 -0.9658 0.1950 +vn -0.1710 -0.9658 -0.1950 +vn -0.4667 -0.7063 -0.5322 +vn -0.6370 -0.2583 -0.7263 +vn -0.7263 0.2583 -0.6370 +vn -0.5322 0.7063 -0.4667 +vn -0.1950 0.9658 -0.1710 +vn 0.1950 0.9658 0.1710 +vn 0.5322 0.7063 0.4667 +vn 0.7263 0.2583 0.6370 +vn 0.7263 -0.2583 0.6370 +vn 0.5322 -0.7064 0.4667 +vn 0.1950 -0.9658 0.1710 +vn -0.1950 -0.9658 -0.1710 +vn -0.5322 -0.7063 -0.4667 +vn -0.7263 -0.2583 -0.6370 +vn -0.8033 0.2583 -0.5367 +vn -0.5886 0.7063 -0.3933 +vn -0.2156 0.9658 -0.1441 +vn 0.2156 0.9658 0.1441 +vn 0.5886 0.7063 0.3933 +vn 0.8033 0.2583 0.5367 +vn 0.8033 -0.2583 0.5367 +vn 0.5886 -0.7064 0.3933 +vn 0.2156 -0.9658 0.1441 +vn -0.2156 -0.9658 -0.1441 +vn -0.5886 -0.7063 -0.3933 +vn -0.8033 -0.2583 -0.5367 +vn -0.8664 0.2583 -0.4273 +vn -0.6349 0.7063 -0.3131 +vn -0.2326 0.9658 -0.1147 +vn 0.2326 0.9658 0.1147 +vn 0.6349 0.7063 0.3131 +vn 0.8664 0.2583 0.4273 +vn 0.8664 -0.2583 0.4273 +vn 0.6349 -0.7064 0.3131 +vn 0.2326 -0.9658 0.1147 +vn -0.2326 -0.9658 -0.1147 +vn -0.6349 -0.7063 -0.3131 +vn -0.8664 -0.2583 -0.4273 +vn -0.9148 0.2583 -0.3105 +vn -0.6703 0.7063 -0.2275 +vn -0.2456 0.9658 -0.0834 +vn 0.2456 0.9658 0.0834 +vn 0.6703 0.7063 0.2275 +vn 0.9148 0.2583 0.3105 +vn 0.9148 -0.2583 0.3105 +vn 0.6703 -0.7064 0.2275 +vn 0.2456 -0.9658 0.0834 +vn -0.2456 -0.9658 -0.0834 +vn -0.6703 -0.7063 -0.2275 +vn -0.9148 -0.2583 -0.3105 +vn -0.9475 0.2583 -0.1885 +vn -0.6943 0.7063 -0.1381 +vn -0.2543 0.9658 -0.0506 +vn 0.2543 0.9658 0.0506 +vn 0.6943 0.7063 0.1381 +vn 0.9475 0.2583 0.1885 +vn 0.9475 -0.2583 0.1885 +vn 0.6943 -0.7063 0.1381 +vn 0.2544 -0.9658 0.0506 +vn -0.2544 -0.9658 -0.0506 +vn -0.6943 -0.7063 -0.1381 +vn -0.9475 -0.2583 -0.1885 +vn -0.9640 0.2583 -0.0632 +vn -0.7064 0.7063 -0.0463 +vn -0.2588 0.9658 -0.0170 +vn 0.2588 0.9658 0.0170 +vn 0.7064 0.7063 0.0463 +vn 0.9640 0.2583 0.0632 +vn 0.9640 -0.2583 0.0632 +vn 0.7063 -0.7063 0.0463 +vn 0.2588 -0.9658 0.0170 +vn -0.2588 -0.9658 -0.0170 +vn -0.7063 -0.7064 -0.0463 +vn -0.9640 -0.2583 -0.0632 +vn 0.7063 -0.7063 -0.0463 +vn -0.7063 -0.7064 0.0463 +vn 0.6349 -0.7063 -0.3131 +vn 0.5886 -0.7064 -0.3933 +vn 0.5322 -0.7064 -0.4667 +vn -0.4667 -0.7064 0.5322 +vn 0.3933 -0.7064 -0.5886 +vn -0.3933 -0.7064 0.5886 +vn 0.3131 -0.7064 -0.6349 +vn 0.2275 -0.7064 -0.6703 +vn -0.2275 -0.7063 0.6703 +vn 0.0506 0.9658 -0.2544 +vn 0.1381 -0.7064 -0.6943 +vn -0.1381 -0.7063 0.6943 +vn 0.0463 0.7063 -0.7063 +vn -0.0463 -0.7063 0.7063 +vn -0.0463 0.7063 -0.7063 +vn -0.3933 -0.7064 -0.5886 +vn 0.3933 -0.7064 0.5886 +vn -0.4667 -0.7064 -0.5322 +vn 0.4667 -0.7064 0.5322 +vn -0.5322 -0.7064 -0.4667 +vn -0.5886 -0.7064 -0.3933 +vn 0.6703 -0.7063 0.2275 +vn 0.2544 0.9658 0.0506 +vn 0.6943 -0.7064 0.1381 +vn -0.7063 -0.7063 -0.0463 +vn 0.7063 -0.7064 0.0463 +usemtl None +s 1 +f 1//1 2//1 3//1 4//1 +f 4//2 3//2 5//2 6//2 +f 6//3 5//3 7//3 8//3 +f 8//4 7//4 9//4 10//4 +f 10//5 9//5 11//5 12//5 +f 12//6 11//6 13//6 14//6 +f 14//7 13//7 15//7 16//7 +f 16//8 15//8 17//8 18//8 +f 18//9 17//9 19//9 20//9 +f 20//10 19//10 21//10 22//10 +f 22//11 21//11 23//11 24//11 +f 1//12 24//12 23//12 2//12 +f 2//13 25//13 26//13 3//13 +f 3//14 26//14 27//14 5//14 +f 5//15 27//15 28//15 7//15 +f 7//16 28//16 29//16 9//16 +f 9//17 29//17 30//17 11//17 +f 11//18 30//18 31//18 13//18 +f 13//19 31//19 32//19 15//19 +f 15//20 32//20 33//20 17//20 +f 17//21 33//21 34//21 19//21 +f 19//22 34//22 35//22 21//22 +f 21//23 35//23 36//23 23//23 +f 23//24 36//24 25//24 2//24 +f 25//25 37//25 38//25 26//25 +f 26//26 38//26 39//26 27//26 +f 27//27 39//27 40//27 28//27 +f 28//28 40//28 41//28 29//28 +f 29//29 41//29 42//29 30//29 +f 30//30 42//30 43//30 31//30 +f 31//31 43//31 44//31 32//31 +f 32//32 44//32 45//32 33//32 +f 33//33 45//33 46//33 34//33 +f 34//34 46//34 47//34 35//34 +f 35//35 47//35 48//35 36//35 +f 36//36 48//36 37//36 25//36 +f 37//37 49//37 50//37 38//37 +f 38//38 50//38 51//38 39//38 +f 39//39 51//39 52//39 40//39 +f 40//40 52//40 53//40 41//40 +f 41//41 53//41 54//41 42//41 +f 42//42 54//42 55//42 43//42 +f 43//43 55//43 56//43 44//43 +f 44//44 56//44 57//44 45//44 +f 45//45 57//45 58//45 46//45 +f 46//46 58//46 59//46 47//46 +f 47//47 59//47 60//47 48//47 +f 48//48 60//48 49//48 37//48 +f 49//49 61//49 62//49 50//49 +f 50//50 62//50 63//50 51//50 +f 51//51 63//51 64//51 52//51 +f 52//52 64//52 65//52 53//52 +f 53//53 65//53 66//53 54//53 +f 54//54 66//54 67//54 55//54 +f 55//55 67//55 68//55 56//55 +f 56//56 68//56 69//56 57//56 +f 57//57 69//57 70//57 58//57 +f 58//58 70//58 71//58 59//58 +f 59//59 71//59 72//59 60//59 +f 60//60 72//60 61//60 49//60 +f 61//61 73//61 74//61 62//61 +f 62//62 74//62 75//62 63//62 +f 63//63 75//63 76//63 64//63 +f 64//64 76//64 77//64 65//64 +f 65//65 77//65 78//65 66//65 +f 66//66 78//66 79//66 67//66 +f 67//67 79//67 80//67 68//67 +f 68//68 80//68 81//68 69//68 +f 69//69 81//69 82//69 70//69 +f 70//70 82//70 83//70 71//70 +f 71//71 83//71 84//71 72//71 +f 72//72 84//72 73//72 61//72 +f 73//73 85//73 86//73 74//73 +f 74//74 86//74 87//74 75//74 +f 75//75 87//75 88//75 76//75 +f 76//76 88//76 89//76 77//76 +f 77//77 89//77 90//77 78//77 +f 78//78 90//78 91//78 79//78 +f 79//79 91//79 92//79 80//79 +f 80//80 92//80 93//80 81//80 +f 81//81 93//81 94//81 82//81 +f 82//82 94//82 95//82 83//82 +f 83//83 95//83 96//83 84//83 +f 84//84 96//84 85//84 73//84 +f 85//85 97//85 98//85 86//85 +f 86//86 98//86 99//86 87//86 +f 87//87 99//87 100//87 88//87 +f 88//88 100//88 101//88 89//88 +f 89//89 101//89 102//89 90//89 +f 90//90 102//90 103//90 91//90 +f 91//91 103//91 104//91 92//91 +f 92//92 104//92 105//92 93//92 +f 93//93 105//93 106//93 94//93 +f 94//94 106//94 107//94 95//94 +f 95//95 107//95 108//95 96//95 +f 96//96 108//96 97//96 85//96 +f 97//97 109//97 110//97 98//97 +f 98//98 110//98 111//98 99//98 +f 99//99 111//99 112//99 100//99 +f 100//100 112//100 113//100 101//100 +f 101//101 113//101 114//101 102//101 +f 102//102 114//102 115//102 103//102 +f 103//103 115//103 116//103 104//103 +f 104//104 116//104 117//104 105//104 +f 105//105 117//105 118//105 106//105 +f 106//106 118//106 119//106 107//106 +f 107//107 119//107 120//107 108//107 +f 108//108 120//108 109//108 97//108 +f 109//109 121//109 122//109 110//109 +f 110//110 122//110 123//110 111//110 +f 111//111 123//111 124//111 112//111 +f 112//112 124//112 125//112 113//112 +f 113//113 125//113 126//113 114//113 +f 114//114 126//114 127//114 115//114 +f 115//115 127//115 128//115 116//115 +f 116//116 128//116 129//116 117//116 +f 117//117 129//117 130//117 118//117 +f 118//118 130//118 131//118 119//118 +f 119//119 131//119 132//119 120//119 +f 120//120 132//120 121//120 109//120 +f 121//121 133//121 134//121 122//121 +f 122//122 134//122 135//122 123//122 +f 123//123 135//123 136//123 124//123 +f 124//124 136//124 137//124 125//124 +f 125//125 137//125 138//125 126//125 +f 126//126 138//126 139//126 127//126 +f 127//127 139//127 140//127 128//127 +f 128//128 140//128 141//128 129//128 +f 129//129 141//129 142//129 130//129 +f 130//130 142//130 143//130 131//130 +f 131//131 143//131 144//131 132//131 +f 132//132 144//132 133//132 121//132 +f 133//133 145//133 146//133 134//133 +f 134//134 146//134 147//134 135//134 +f 135//135 147//135 148//135 136//135 +f 136//136 148//136 149//136 137//136 +f 137//137 149//137 150//137 138//137 +f 138//138 150//138 151//138 139//138 +f 139//139 151//139 152//139 140//139 +f 140//140 152//140 153//140 141//140 +f 141//141 153//141 154//141 142//141 +f 142//142 154//142 155//142 143//142 +f 143//143 155//143 156//143 144//143 +f 144//144 156//144 145//144 133//144 +f 145//145 157//145 158//145 146//145 +f 146//146 158//146 159//146 147//146 +f 147//147 159//147 160//147 148//147 +f 148//148 160//148 161//148 149//148 +f 149//149 161//149 162//149 150//149 +f 150//150 162//150 163//150 151//150 +f 151//151 163//151 164//151 152//151 +f 152//152 164//152 165//152 153//152 +f 153//153 165//153 166//153 154//153 +f 154//154 166//154 167//154 155//154 +f 155//155 167//155 168//155 156//155 +f 156//156 168//156 157//156 145//156 +f 157//157 169//157 170//157 158//157 +f 158//158 170//158 171//158 159//158 +f 159//159 171//159 172//159 160//159 +f 160//160 172//160 173//160 161//160 +f 161//161 173//161 174//161 162//161 +f 162//162 174//162 175//162 163//162 +f 163//163 175//163 176//163 164//163 +f 164//164 176//164 177//164 165//164 +f 165//165 177//165 178//165 166//165 +f 166//166 178//166 179//166 167//166 +f 167//167 179//167 180//167 168//167 +f 168//168 180//168 169//168 157//168 +f 169//169 181//169 182//169 170//169 +f 170//170 182//170 183//170 171//170 +f 171//171 183//171 184//171 172//171 +f 172//172 184//172 185//172 173//172 +f 173//173 185//173 186//173 174//173 +f 174//174 186//174 187//174 175//174 +f 175//175 187//175 188//175 176//175 +f 176//176 188//176 189//176 177//176 +f 177//177 189//177 190//177 178//177 +f 178//178 190//178 191//178 179//178 +f 179//179 191//179 192//179 180//179 +f 180//180 192//180 181//180 169//180 +f 181//181 193//181 194//181 182//181 +f 182//182 194//182 195//182 183//182 +f 183//183 195//183 196//183 184//183 +f 184//184 196//184 197//184 185//184 +f 185//185 197//185 198//185 186//185 +f 186//186 198//186 199//186 187//186 +f 187//187 199//187 200//187 188//187 +f 188//188 200//188 201//188 189//188 +f 189//189 201//189 202//189 190//189 +f 190//190 202//190 203//190 191//190 +f 191//191 203//191 204//191 192//191 +f 192//192 204//192 193//192 181//192 +f 193//193 205//193 206//193 194//193 +f 194//194 206//194 207//194 195//194 +f 195//195 207//195 208//195 196//195 +f 196//196 208//196 209//196 197//196 +f 197//197 209//197 210//197 198//197 +f 198//198 210//198 211//198 199//198 +f 199//199 211//199 212//199 200//199 +f 200//200 212//200 213//200 201//200 +f 201//201 213//201 214//201 202//201 +f 202//202 214//202 215//202 203//202 +f 203//203 215//203 216//203 204//203 +f 204//204 216//204 205//204 193//204 +f 205//205 217//205 218//205 206//205 +f 206//206 218//206 219//206 207//206 +f 207//207 219//207 220//207 208//207 +f 208//208 220//208 221//208 209//208 +f 209//209 221//209 222//209 210//209 +f 210//210 222//210 223//210 211//210 +f 211//211 223//211 224//211 212//211 +f 212//212 224//212 225//212 213//212 +f 213//213 225//213 226//213 214//213 +f 214//214 226//214 227//214 215//214 +f 215//215 227//215 228//215 216//215 +f 216//216 228//216 217//216 205//216 +f 217//217 229//217 230//217 218//217 +f 218//218 230//218 231//218 219//218 +f 219//219 231//219 232//219 220//219 +f 220//220 232//220 233//220 221//220 +f 221//221 233//221 234//221 222//221 +f 222//222 234//222 235//222 223//222 +f 223//223 235//223 236//223 224//223 +f 224//224 236//224 237//224 225//224 +f 225//225 237//225 238//225 226//225 +f 226//226 238//226 239//226 227//226 +f 227//227 239//227 240//227 228//227 +f 228//228 240//228 229//228 217//228 +f 229//229 241//229 242//229 230//229 +f 230//230 242//230 243//230 231//230 +f 231//231 243//231 244//231 232//231 +f 232//232 244//232 245//232 233//232 +f 233//233 245//233 246//233 234//233 +f 234//234 246//234 247//234 235//234 +f 235//235 247//235 248//235 236//235 +f 236//236 248//236 249//236 237//236 +f 237//237 249//237 250//237 238//237 +f 238//238 250//238 251//238 239//238 +f 239//239 251//239 252//239 240//239 +f 240//240 252//240 241//240 229//240 +f 241//241 253//241 254//241 242//241 +f 242//242 254//242 255//242 243//242 +f 243//243 255//243 256//243 244//243 +f 244//244 256//244 257//244 245//244 +f 245//245 257//245 258//245 246//245 +f 246//246 258//246 259//246 247//246 +f 247//247 259//247 260//247 248//247 +f 248//248 260//248 261//248 249//248 +f 249//249 261//249 262//249 250//249 +f 250//250 262//250 263//250 251//250 +f 251//251 263//251 264//251 252//251 +f 252//252 264//252 253//252 241//252 +f 253//253 265//253 266//253 254//253 +f 254//254 266//254 267//254 255//254 +f 255//255 267//255 268//255 256//255 +f 256//256 268//256 269//256 257//256 +f 257//257 269//257 270//257 258//257 +f 258//258 270//258 271//258 259//258 +f 259//259 271//259 272//259 260//259 +f 260//260 272//260 273//260 261//260 +f 261//261 273//261 274//261 262//261 +f 262//262 274//262 275//262 263//262 +f 263//263 275//263 276//263 264//263 +f 264//264 276//264 265//264 253//264 +f 265//265 277//265 278//265 266//265 +f 266//266 278//266 279//266 267//266 +f 267//267 279//267 280//267 268//267 +f 268//268 280//268 281//268 269//268 +f 269//269 281//269 282//269 270//269 +f 270//270 282//270 283//270 271//270 +f 271//271 283//271 284//271 272//271 +f 272//272 284//272 285//272 273//272 +f 273//273 285//273 286//273 274//273 +f 274//274 286//274 287//274 275//274 +f 275//275 287//275 288//275 276//275 +f 276//276 288//276 277//276 265//276 +f 277//277 289//277 290//277 278//277 +f 278//278 290//278 291//278 279//278 +f 279//279 291//279 292//279 280//279 +f 280//280 292//280 293//280 281//280 +f 281//281 293//281 294//281 282//281 +f 282//282 294//282 295//282 283//282 +f 283//283 295//283 296//283 284//283 +f 284//284 296//284 297//284 285//284 +f 285//285 297//285 298//285 286//285 +f 286//286 298//286 299//286 287//286 +f 287//287 299//287 300//287 288//287 +f 288//288 300//288 289//288 277//288 +f 289//6 301//6 302//6 290//6 +f 290//5 302//5 303//5 291//5 +f 291//4 303//4 304//4 292//4 +f 292//3 304//3 305//3 293//3 +f 293//2 305//2 306//2 294//2 +f 294//1 306//1 307//1 295//1 +f 295//12 307//12 308//12 296//12 +f 296//289 308//289 309//289 297//289 +f 297//10 309//10 310//10 298//10 +f 298//9 310//9 311//9 299//9 +f 299//290 311//290 312//290 300//290 +f 300//7 312//7 301//7 289//7 +f 301//18 313//18 314//18 302//18 +f 302//17 314//17 315//17 303//17 +f 303//16 315//16 316//16 304//16 +f 304//15 316//15 317//15 305//15 +f 305//14 317//14 318//14 306//14 +f 306//13 318//13 319//13 307//13 +f 307//24 319//24 320//24 308//24 +f 308//23 320//23 321//23 309//23 +f 309//22 321//22 322//22 310//22 +f 310//21 322//21 323//21 311//21 +f 311//20 323//20 324//20 312//20 +f 312//19 324//19 313//19 301//19 +f 313//30 325//30 326//30 314//30 +f 314//29 326//29 327//29 315//29 +f 315//28 327//28 328//28 316//28 +f 316//27 328//27 329//27 317//27 +f 317//26 329//26 330//26 318//26 +f 318//25 330//25 331//25 319//25 +f 319//36 331//36 332//36 320//36 +f 320//35 332//35 333//35 321//35 +f 321//34 333//34 334//34 322//34 +f 322//33 334//33 335//33 323//33 +f 323//32 335//32 336//32 324//32 +f 324//31 336//31 325//31 313//31 +f 325//42 337//42 338//42 326//42 +f 326//41 338//41 339//41 327//41 +f 327//40 339//40 340//40 328//40 +f 328//39 340//39 341//39 329//39 +f 329//38 341//38 342//38 330//38 +f 330//37 342//37 343//37 331//37 +f 331//48 343//48 344//48 332//48 +f 332//291 344//291 345//291 333//291 +f 333//46 345//46 346//46 334//46 +f 334//45 346//45 347//45 335//45 +f 335//44 347//44 348//44 336//44 +f 336//43 348//43 337//43 325//43 +f 337//54 349//54 350//54 338//54 +f 338//53 350//53 351//53 339//53 +f 339//52 351//52 352//52 340//52 +f 340//51 352//51 353//51 341//51 +f 341//50 353//50 354//50 342//50 +f 342//49 354//49 355//49 343//49 +f 343//60 355//60 356//60 344//60 +f 344//292 356//292 357//292 345//292 +f 345//58 357//58 358//58 346//58 +f 346//57 358//57 359//57 347//57 +f 347//56 359//56 360//56 348//56 +f 348//55 360//55 349//55 337//55 +f 349//66 361//66 362//66 350//66 +f 350//65 362//65 363//65 351//65 +f 351//64 363//64 364//64 352//64 +f 352//63 364//63 365//63 353//63 +f 353//62 365//62 366//62 354//62 +f 354//61 366//61 367//61 355//61 +f 355//72 367//72 368//72 356//72 +f 356//293 368//293 369//293 357//293 +f 357//70 369//70 370//70 358//70 +f 358//69 370//69 371//69 359//69 +f 359//68 371//68 372//68 360//68 +f 360//67 372//67 361//67 349//67 +f 361//78 373//78 374//78 362//78 +f 362//77 374//77 375//77 363//77 +f 363//76 375//76 376//76 364//76 +f 364//75 376//75 377//75 365//75 +f 365//74 377//74 378//74 366//74 +f 366//73 378//73 379//73 367//73 +f 367//84 379//84 380//84 368//84 +f 368//83 380//83 381//83 369//83 +f 369//82 381//82 382//82 370//82 +f 370//81 382//81 383//81 371//81 +f 371//294 383//294 384//294 372//294 +f 372//79 384//79 373//79 361//79 +f 373//90 385//90 386//90 374//90 +f 374//89 386//89 387//89 375//89 +f 375//88 387//88 388//88 376//88 +f 376//87 388//87 389//87 377//87 +f 377//86 389//86 390//86 378//86 +f 378//85 390//85 391//85 379//85 +f 379//96 391//96 392//96 380//96 +f 380//295 392//295 393//295 381//295 +f 381//94 393//94 394//94 382//94 +f 382//93 394//93 395//93 383//93 +f 383//296 395//296 396//296 384//296 +f 384//91 396//91 385//91 373//91 +f 385//102 397//102 398//102 386//102 +f 386//101 398//101 399//101 387//101 +f 387//100 399//100 400//100 388//100 +f 388//99 400//99 401//99 389//99 +f 389//98 401//98 402//98 390//98 +f 390//97 402//97 403//97 391//97 +f 391//108 403//108 404//108 392//108 +f 392//297 404//297 405//297 393//297 +f 393//106 405//106 406//106 394//106 +f 394//105 406//105 407//105 395//105 +f 395//104 407//104 408//104 396//104 +f 396//103 408//103 397//103 385//103 +f 397//114 409//114 410//114 398//114 +f 398//113 410//113 411//113 399//113 +f 399//112 411//112 412//112 400//112 +f 400//111 412//111 413//111 401//111 +f 401//110 413//110 414//110 402//110 +f 402//109 414//109 415//109 403//109 +f 403//120 415//120 416//120 404//120 +f 404//298 416//298 417//298 405//298 +f 405//118 417//118 418//118 406//118 +f 406//117 418//117 419//117 407//117 +f 407//299 419//299 420//299 408//299 +f 408//115 420//115 409//115 397//115 +f 409//126 421//126 422//126 410//126 +f 410//125 422//125 423//125 411//125 +f 411//124 423//124 424//124 412//124 +f 412//300 424//300 425//300 413//300 +f 413//122 425//122 426//122 414//122 +f 414//121 426//121 427//121 415//121 +f 415//132 427//132 428//132 416//132 +f 416//301 428//301 429//301 417//301 +f 417//130 429//130 430//130 418//130 +f 418//129 430//129 431//129 419//129 +f 419//302 431//302 432//302 420//302 +f 420//127 432//127 421//127 409//127 +f 421//138 433//138 434//138 422//138 +f 422//137 434//137 435//137 423//137 +f 423//136 435//136 436//136 424//136 +f 424//135 436//135 437//135 425//135 +f 425//303 437//303 438//303 426//303 +f 426//133 438//133 439//133 427//133 +f 427//144 439//144 440//144 428//144 +f 428//143 440//143 441//143 429//143 +f 429//142 441//142 442//142 430//142 +f 430//141 442//141 443//141 431//141 +f 431//304 443//304 444//304 432//304 +f 432//139 444//139 433//139 421//139 +f 433//150 445//150 446//150 434//150 +f 434//149 446//149 447//149 435//149 +f 435//148 447//148 448//148 436//148 +f 436//147 448//147 449//147 437//147 +f 437//305 449//305 450//305 438//305 +f 438//145 450//145 451//145 439//145 +f 439//156 451//156 452//156 440//156 +f 440//155 452//155 453//155 441//155 +f 441//154 453//154 454//154 442//154 +f 442//153 454//153 455//153 443//153 +f 443//152 455//152 456//152 444//152 +f 444//151 456//151 445//151 433//151 +f 445//162 457//162 458//162 446//162 +f 446//161 458//161 459//161 447//161 +f 447//160 459//160 460//160 448//160 +f 448//159 460//159 461//159 449//159 +f 449//158 461//158 462//158 450//158 +f 450//157 462//157 463//157 451//157 +f 451//168 463//168 464//168 452//168 +f 452//167 464//167 465//167 453//167 +f 453//166 465//166 466//166 454//166 +f 454//165 466//165 467//165 455//165 +f 455//164 467//164 468//164 456//164 +f 456//163 468//163 457//163 445//163 +f 457//174 469//174 470//174 458//174 +f 458//173 470//173 471//173 459//173 +f 459//172 471//172 472//172 460//172 +f 460//171 472//171 473//171 461//171 +f 461//170 473//170 474//170 462//170 +f 462//169 474//169 475//169 463//169 +f 463//180 475//180 476//180 464//180 +f 464//179 476//179 477//179 465//179 +f 465//178 477//178 478//178 466//178 +f 466//177 478//177 479//177 467//177 +f 467//176 479//176 480//176 468//176 +f 468//175 480//175 469//175 457//175 +f 469//186 481//186 482//186 470//186 +f 470//185 482//185 483//185 471//185 +f 471//184 483//184 484//184 472//184 +f 472//183 484//183 485//183 473//183 +f 473//182 485//182 486//182 474//182 +f 474//181 486//181 487//181 475//181 +f 475//192 487//192 488//192 476//192 +f 476//191 488//191 489//191 477//191 +f 477//190 489//190 490//190 478//190 +f 478//189 490//189 491//189 479//189 +f 479//188 491//188 492//188 480//188 +f 480//187 492//187 481//187 469//187 +f 481//198 493//198 494//198 482//198 +f 482//197 494//197 495//197 483//197 +f 483//196 495//196 496//196 484//196 +f 484//195 496//195 497//195 485//195 +f 485//194 497//194 498//194 486//194 +f 486//193 498//193 499//193 487//193 +f 487//204 499//204 500//204 488//204 +f 488//306 500//306 501//306 489//306 +f 489//202 501//202 502//202 490//202 +f 490//201 502//201 503//201 491//201 +f 491//307 503//307 504//307 492//307 +f 492//199 504//199 493//199 481//199 +f 493//210 505//210 506//210 494//210 +f 494//209 506//209 507//209 495//209 +f 495//208 507//208 508//208 496//208 +f 496//207 508//207 509//207 497//207 +f 497//206 509//206 510//206 498//206 +f 498//205 510//205 511//205 499//205 +f 499//216 511//216 512//216 500//216 +f 500//308 512//308 513//308 501//308 +f 501//214 513//214 514//214 502//214 +f 502//213 514//213 515//213 503//213 +f 503//309 515//309 516//309 504//309 +f 504//211 516//211 505//211 493//211 +f 505//222 517//222 518//222 506//222 +f 506//221 518//221 519//221 507//221 +f 507//220 519//220 520//220 508//220 +f 508//219 520//219 521//219 509//219 +f 509//218 521//218 522//218 510//218 +f 510//217 522//217 523//217 511//217 +f 511//228 523//228 524//228 512//228 +f 512//310 524//310 525//310 513//310 +f 513//226 525//226 526//226 514//226 +f 514//225 526//225 527//225 515//225 +f 515//224 527//224 528//224 516//224 +f 516//223 528//223 517//223 505//223 +f 517//234 529//234 530//234 518//234 +f 518//233 530//233 531//233 519//233 +f 519//232 531//232 532//232 520//232 +f 520//231 532//231 533//231 521//231 +f 521//230 533//230 534//230 522//230 +f 522//229 534//229 535//229 523//229 +f 523//240 535//240 536//240 524//240 +f 524//311 536//311 537//311 525//311 +f 525//238 537//238 538//238 526//238 +f 526//237 538//237 539//237 527//237 +f 527//236 539//236 540//236 528//236 +f 528//235 540//235 529//235 517//235 +f 529//246 541//246 542//246 530//246 +f 530//245 542//245 543//245 531//245 +f 531//244 543//244 544//244 532//244 +f 532//243 544//243 545//243 533//243 +f 533//242 545//242 546//242 534//242 +f 534//241 546//241 547//241 535//241 +f 535//252 547//252 548//252 536//252 +f 536//251 548//251 549//251 537//251 +f 537//250 549//250 550//250 538//250 +f 538//249 550//249 551//249 539//249 +f 539//248 551//248 552//248 540//248 +f 540//247 552//247 541//247 529//247 +f 541//258 553//258 554//258 542//258 +f 542//257 554//257 555//257 543//257 +f 543//256 555//256 556//256 544//256 +f 544//255 556//255 557//255 545//255 +f 545//254 557//254 558//254 546//254 +f 546//253 558//253 559//253 547//253 +f 547//264 559//264 560//264 548//264 +f 548//263 560//263 561//263 549//263 +f 549//262 561//262 562//262 550//262 +f 550//261 562//261 563//261 551//261 +f 551//312 563//312 564//312 552//312 +f 552//259 564//259 553//259 541//259 +f 553//270 565//270 566//270 554//270 +f 554//269 566//269 567//269 555//269 +f 555//313 567//313 568//313 556//313 +f 556//267 568//267 569//267 557//267 +f 557//266 569//266 570//266 558//266 +f 558//265 570//265 571//265 559//265 +f 559//276 571//276 572//276 560//276 +f 560//275 572//275 573//275 561//275 +f 561//274 573//274 574//274 562//274 +f 562//273 574//273 575//273 563//273 +f 563//314 575//314 576//314 564//314 +f 564//271 576//271 565//271 553//271 +f 565//282 1//282 4//282 566//282 +f 566//281 4//281 6//281 567//281 +f 567//280 6//280 8//280 568//280 +f 568//279 8//279 10//279 569//279 +f 569//278 10//278 12//278 570//278 +f 570//277 12//277 14//277 571//277 +f 571//288 14//288 16//288 572//288 +f 572//315 16//315 18//315 573//315 +f 573//286 18//286 20//286 574//286 +f 574//285 20//285 22//285 575//285 +f 575//316 22//316 24//316 576//316 +f 576//283 24//283 1//283 565//283 diff --git a/data/torus/torus_with_plane.mtl b/data/torus/torus_with_plane.mtl new file mode 100644 index 000000000..70d3ba1da --- /dev/null +++ b/data/torus/torus_with_plane.mtl @@ -0,0 +1,10 @@ +# Blender MTL File: 'None' +# Material Count: 1 + +newmtl None +Ns 0 +Ka 0.000000 0.000000 0.000000 +Kd 0.8 0.8 0.8 +Ks 0.8 0.8 0.8 +d 1 +illum 2 diff --git a/data/torus/torus_with_plane.obj b/data/torus/torus_with_plane.obj new file mode 100644 index 000000000..b036d9fdd --- /dev/null +++ b/data/torus/torus_with_plane.obj @@ -0,0 +1,9384 @@ +# Blender v2.77 (sub 0) OBJ File: '' +# www.blender.org +mtllib torus_with_plane.mtl +o Plane +v -2.312398 -6.126618 0.566384 +v 6.032325 -2.575601 0.280679 +v -5.874205 2.203907 0.074895 +v 2.470518 5.754926 -0.210810 +v -5.804365 2.040563 0.084532 +v -5.734526 1.877220 0.094169 +v -5.664686 1.713876 0.103806 +v -5.594847 1.550532 0.113443 +v -5.525007 1.387189 0.123080 +v -5.455168 1.223845 0.132717 +v -5.385328 1.060502 0.142354 +v -5.315490 0.897157 0.151991 +v -5.245650 0.733814 0.161628 +v -5.175811 0.570470 0.171265 +v -5.105971 0.407127 0.180902 +v -5.036132 0.243783 0.190539 +v -4.966292 0.080439 0.200176 +v -4.896453 -0.082904 0.209813 +v -4.826613 -0.246248 0.219450 +v -4.756775 -0.409592 0.229087 +v -4.686935 -0.572935 0.238724 +v -4.617096 -0.736279 0.248362 +v -4.547256 -0.899623 0.257998 +v -4.477417 -1.062966 0.267636 +v -4.407578 -1.226310 0.277273 +v -4.337738 -1.389654 0.286910 +v -4.267900 -1.552997 0.296547 +v -4.198060 -1.716341 0.306184 +v -4.128221 -1.879685 0.315821 +v -4.058381 -2.043028 0.325458 +v -3.988542 -2.206372 0.335095 +v -3.918703 -2.369716 0.344732 +v -3.848863 -2.533059 0.354369 +v -3.779024 -2.696403 0.364006 +v -3.709185 -2.859747 0.373643 +v -3.639345 -3.023091 0.383280 +v -3.569506 -3.186434 0.392917 +v -3.499667 -3.349777 0.402554 +v -3.429827 -3.513121 0.412191 +v -3.359988 -3.676465 0.421829 +v -3.290149 -3.839808 0.431465 +v -3.220309 -4.003152 0.441103 +v -3.150470 -4.166496 0.450740 +v -3.080631 -4.329839 0.460377 +v -3.010791 -4.493183 0.470014 +v -2.940952 -4.656527 0.479651 +v -2.871112 -4.819870 0.489288 +v -2.801273 -4.983214 0.498925 +v -2.731434 -5.146557 0.508562 +v -2.661594 -5.309901 0.518199 +v -2.591755 -5.473244 0.527836 +v -2.521916 -5.636589 0.537473 +v -2.452076 -5.799932 0.547110 +v -2.382237 -5.963276 0.556747 +v -2.148776 -6.056991 0.560782 +v -1.985154 -5.987363 0.555180 +v -1.821532 -5.917735 0.549578 +v -1.657910 -5.848107 0.543976 +v -1.494288 -5.778480 0.538374 +v -1.330665 -5.708852 0.532772 +v -1.167043 -5.639224 0.527170 +v -1.003422 -5.569596 0.521568 +v -0.839799 -5.499969 0.515965 +v -0.676177 -5.430341 0.510363 +v -0.512555 -5.360713 0.504761 +v -0.348933 -5.291085 0.499159 +v -0.185311 -5.221457 0.493557 +v -0.021689 -5.151829 0.487955 +v 0.141933 -5.082201 0.482353 +v 0.305555 -5.012573 0.476751 +v 0.469177 -4.942945 0.471149 +v 0.632799 -4.873318 0.465547 +v 0.796421 -4.803690 0.459945 +v 0.960043 -4.734062 0.454343 +v 1.123665 -4.664434 0.448741 +v 1.287287 -4.594807 0.443139 +v 1.450909 -4.525179 0.437537 +v 1.614531 -4.455551 0.431935 +v 1.778153 -4.385922 0.426333 +v 1.941775 -4.316295 0.420731 +v 2.105397 -4.246667 0.415129 +v 2.269019 -4.177039 0.409527 +v 2.432641 -4.107412 0.403924 +v 2.596263 -4.037785 0.398322 +v 2.759885 -3.968157 0.392720 +v 2.923507 -3.898529 0.387118 +v 3.087129 -3.828902 0.381516 +v 3.250751 -3.759273 0.375914 +v 3.414372 -3.689645 0.370312 +v 3.577994 -3.620018 0.364710 +v 3.741616 -3.550390 0.359108 +v 3.905239 -3.480762 0.353506 +v 4.068861 -3.411134 0.347904 +v 4.232483 -3.341506 0.342302 +v 4.396105 -3.271878 0.336700 +v 4.559727 -3.202251 0.331098 +v 4.723349 -3.132623 0.325496 +v 4.886971 -3.062995 0.319894 +v 5.050592 -2.993367 0.314292 +v 5.214214 -2.923740 0.308690 +v 5.377837 -2.854112 0.303087 +v 5.541458 -2.784484 0.297485 +v 5.705081 -2.714856 0.291883 +v 5.868702 -2.645229 0.286281 +v 5.962485 -2.412257 0.271042 +v 5.892646 -2.248913 0.261405 +v 5.822806 -2.085569 0.251768 +v 5.752967 -1.922226 0.242131 +v 5.683127 -1.758882 0.232494 +v 5.613288 -1.595538 0.222857 +v 5.543449 -1.432195 0.213220 +v 5.473610 -1.268851 0.203583 +v 5.403770 -1.105507 0.193946 +v 5.333931 -0.942164 0.184309 +v 5.264091 -0.778820 0.174672 +v 5.194252 -0.615476 0.165035 +v 5.124413 -0.452132 0.155398 +v 5.054573 -0.288789 0.145761 +v 4.984735 -0.125445 0.136124 +v 4.914895 0.037898 0.126487 +v 4.845056 0.201242 0.116849 +v 4.775216 0.364586 0.107213 +v 4.705377 0.527929 0.097575 +v 4.635537 0.691273 0.087938 +v 4.565698 0.854617 0.078301 +v 4.495859 1.017960 0.068664 +v 4.426020 1.181304 0.059027 +v 4.356180 1.344648 0.049390 +v 4.286341 1.507991 0.039753 +v 4.216501 1.671335 0.030116 +v 4.146662 1.834678 0.020479 +v 4.076822 1.998022 0.010842 +v 4.006983 2.161365 0.001205 +v 3.937144 2.324709 -0.008432 +v 3.867305 2.488053 -0.018069 +v 3.797465 2.651397 -0.027706 +v 3.727626 2.814740 -0.037343 +v 3.657787 2.978083 -0.046980 +v 3.587947 3.141428 -0.056617 +v 3.518108 3.304771 -0.066254 +v 3.448268 3.468114 -0.075891 +v 3.378429 3.631458 -0.085528 +v 3.308590 3.794802 -0.095165 +v 3.238750 3.958145 -0.104803 +v 3.168911 4.121490 -0.114440 +v 3.099072 4.284833 -0.124077 +v 3.029233 4.448177 -0.133714 +v 2.959393 4.611520 -0.143351 +v 2.889554 4.774864 -0.152988 +v 2.819715 4.938208 -0.162625 +v 2.749875 5.101552 -0.172262 +v 2.680036 5.264896 -0.181899 +v 2.610196 5.428238 -0.191536 +v 2.540357 5.591582 -0.201173 +v 2.306895 5.685298 -0.205208 +v 2.143273 5.615670 -0.199606 +v 1.979651 5.546042 -0.194004 +v 1.816030 5.476415 -0.188402 +v 1.652407 5.406787 -0.182800 +v 1.488786 5.337159 -0.177198 +v 1.325163 5.267531 -0.171596 +v 1.161541 5.197904 -0.165994 +v 0.997919 5.128276 -0.160392 +v 0.834297 5.058648 -0.154789 +v 0.670675 4.989020 -0.149187 +v 0.507053 4.919393 -0.143585 +v 0.343431 4.849765 -0.137983 +v 0.179809 4.780137 -0.132381 +v 0.016187 4.710509 -0.126779 +v -0.147435 4.640882 -0.121177 +v -0.311057 4.571253 -0.115575 +v -0.474679 4.501625 -0.109973 +v -0.638301 4.431997 -0.104371 +v -0.801923 4.362370 -0.098769 +v -0.965545 4.292742 -0.093167 +v -1.129167 4.223114 -0.087565 +v -1.292789 4.153486 -0.081963 +v -1.456411 4.083858 -0.076361 +v -1.620033 4.014231 -0.070759 +v -1.783655 3.944603 -0.065157 +v -1.947277 3.874975 -0.059554 +v -2.110899 3.805346 -0.053952 +v -2.274521 3.735718 -0.048350 +v -2.438143 3.666091 -0.042748 +v -2.601765 3.596463 -0.037146 +v -2.765387 3.526835 -0.031544 +v -2.929009 3.457207 -0.025942 +v -3.092631 3.387580 -0.020340 +v -3.256253 3.317952 -0.014738 +v -3.419875 3.248324 -0.009136 +v -3.583497 3.178696 -0.003534 +v -3.747118 3.109069 0.002068 +v -3.910740 3.039441 0.007670 +v -4.074363 2.969813 0.013272 +v -4.237985 2.900185 0.018874 +v -4.401607 2.830558 0.024476 +v -4.565228 2.760930 0.030078 +v -4.728850 2.691302 0.035680 +v -4.892472 2.621674 0.041282 +v -5.056094 2.552047 0.046885 +v -5.219716 2.482419 0.052487 +v -5.383339 2.412791 0.058089 +v -5.546961 2.343162 0.063691 +v -5.710583 2.273535 0.069293 +v -5.640743 2.110191 0.078930 +v -5.407282 2.016475 0.082965 +v -5.173820 1.922760 0.087000 +v -4.940358 1.829044 0.091035 +v -4.706897 1.735328 0.095070 +v -4.473435 1.641612 0.099105 +v -4.239974 1.547897 0.103140 +v -4.006513 1.454180 0.107175 +v -3.773051 1.360465 0.111210 +v -3.539590 1.266749 0.115245 +v -3.306129 1.173033 0.119280 +v -3.072667 1.079317 0.123315 +v -2.839206 0.985601 0.127350 +v -2.605745 0.891885 0.131385 +v -2.372283 0.798169 0.135420 +v -2.138822 0.704454 0.139455 +v -1.905361 0.610738 0.143490 +v -1.671899 0.517022 0.147525 +v -1.438438 0.423306 0.151560 +v -1.204977 0.329590 0.155595 +v -0.971515 0.235874 0.159630 +v -0.738054 0.142159 0.163665 +v -0.504593 0.048443 0.167700 +v -0.271131 -0.045273 0.171735 +v -0.037670 -0.138989 0.175770 +v 0.195791 -0.232705 0.179805 +v 0.429253 -0.326421 0.183840 +v 0.662714 -0.420136 0.187875 +v 0.896175 -0.513852 0.191910 +v 1.129637 -0.607568 0.195945 +v 1.363098 -0.701284 0.199980 +v 1.596559 -0.795000 0.204015 +v 1.830021 -0.888716 0.208049 +v 2.063482 -0.982431 0.212084 +v 2.296943 -1.076147 0.216119 +v 2.530405 -1.169863 0.220154 +v 2.763866 -1.263579 0.224189 +v 2.997327 -1.357295 0.228224 +v 3.230788 -1.451011 0.232259 +v 3.464250 -1.544726 0.236294 +v 3.697711 -1.638442 0.240329 +v 3.931173 -1.732158 0.244364 +v 4.164635 -1.825874 0.248399 +v 4.398096 -1.919590 0.252434 +v 4.631557 -2.013306 0.256469 +v 4.865018 -2.107021 0.260504 +v 5.098479 -2.200737 0.264539 +v 5.331941 -2.294453 0.268574 +v 5.565402 -2.388169 0.272609 +v 5.798862 -2.481885 0.276644 +v -5.477121 2.179819 0.073328 +v -5.243659 2.086103 0.077363 +v -5.313498 2.249447 0.067726 +v -5.010198 1.992388 0.081398 +v -5.080037 2.155731 0.071761 +v -5.149877 2.319074 0.062124 +v -4.776736 1.898672 0.085433 +v -4.846576 2.062015 0.075796 +v -4.916415 2.225359 0.066159 +v -4.986255 2.388702 0.056522 +v -4.543275 1.804956 0.089468 +v -4.613114 1.968299 0.079831 +v -4.682954 2.131643 0.070194 +v -4.752793 2.294986 0.060557 +v -4.822633 2.458330 0.050920 +v -4.309813 1.711240 0.093503 +v -4.379653 1.874583 0.083866 +v -4.449492 2.037927 0.074229 +v -4.519332 2.201271 0.064592 +v -4.589171 2.364614 0.054955 +v -4.659011 2.527958 0.045318 +v -4.076352 1.617524 0.097538 +v -4.146192 1.780868 0.087901 +v -4.216031 1.944211 0.078264 +v -4.285871 2.107555 0.068627 +v -4.355710 2.270899 0.058990 +v -4.425550 2.434242 0.049352 +v -4.495389 2.597585 0.039715 +v -3.842891 1.523808 0.101573 +v -3.912730 1.687152 0.091936 +v -3.982570 1.850495 0.082299 +v -4.052409 2.013839 0.072662 +v -4.122249 2.177183 0.063025 +v -4.192088 2.340526 0.053387 +v -4.261928 2.503870 0.043751 +v -4.331767 2.667213 0.034113 +v -3.609429 1.430092 0.105608 +v -3.679269 1.593436 0.095971 +v -3.749108 1.756780 0.086334 +v -3.818948 1.920124 0.076697 +v -3.888787 2.083467 0.067060 +v -3.958627 2.246810 0.057422 +v -4.028465 2.410154 0.047786 +v -4.098306 2.573498 0.038148 +v -4.168145 2.736841 0.028511 +v -3.375968 1.336377 0.109643 +v -3.445807 1.499720 0.100006 +v -3.515647 1.663064 0.090369 +v -3.585486 1.826408 0.080732 +v -3.655326 1.989751 0.071095 +v -3.725165 2.153095 0.061457 +v -3.795005 2.316438 0.051821 +v -3.864844 2.479782 0.042183 +v -3.934684 2.643125 0.032546 +v -4.004523 2.806469 0.022909 +v -3.142507 1.242661 0.113678 +v -3.212346 1.406005 0.104041 +v -3.282185 1.569348 0.094404 +v -3.352025 1.732692 0.084767 +v -3.421864 1.896036 0.075130 +v -3.491704 2.059379 0.065492 +v -3.561543 2.222723 0.055856 +v -3.631382 2.386066 0.046218 +v -3.701222 2.549410 0.036581 +v -3.771061 2.712753 0.026944 +v -3.840901 2.876097 0.017307 +v -2.909045 1.148945 0.117713 +v -2.978885 1.312288 0.108076 +v -3.048724 1.475632 0.098439 +v -3.118563 1.638976 0.088801 +v -3.188403 1.802320 0.079165 +v -3.258242 1.965663 0.069527 +v -3.328082 2.129007 0.059891 +v -3.397921 2.292350 0.050253 +v -3.467761 2.455694 0.040616 +v -3.537600 2.619037 0.030979 +v -3.607439 2.782381 0.021342 +v -3.677279 2.945725 0.011705 +v -2.675584 1.055229 0.121748 +v -2.745423 1.218573 0.112111 +v -2.815263 1.381916 0.102473 +v -2.885102 1.545260 0.092836 +v -2.954941 1.708604 0.083200 +v -3.024781 1.871947 0.073562 +v -3.094620 2.035291 0.063925 +v -3.164460 2.198635 0.054288 +v -3.234299 2.361978 0.044651 +v -3.304139 2.525321 0.035014 +v -3.373978 2.688665 0.025377 +v -3.443818 2.852009 0.015740 +v -3.513657 3.015353 0.006103 +v -2.442123 0.961513 0.125782 +v -2.511962 1.124857 0.116146 +v -2.581802 1.288201 0.106508 +v -2.651641 1.451544 0.096871 +v -2.721480 1.614888 0.087234 +v -2.791320 1.778232 0.077597 +v -2.861159 1.941575 0.067960 +v -2.930999 2.104919 0.058323 +v -3.000838 2.268262 0.048686 +v -3.070677 2.431606 0.039049 +v -3.140517 2.594950 0.029412 +v -3.210356 2.758293 0.019775 +v -3.280196 2.921637 0.010138 +v -3.350035 3.084981 0.000501 +v -2.208661 0.867797 0.129817 +v -2.278501 1.031141 0.120181 +v -2.348340 1.194485 0.110543 +v -2.418180 1.357828 0.100906 +v -2.488019 1.521172 0.091269 +v -2.557858 1.684516 0.081632 +v -2.627698 1.847859 0.071995 +v -2.697537 2.011203 0.062358 +v -2.767377 2.174546 0.052721 +v -2.837216 2.337890 0.043084 +v -2.907056 2.501234 0.033447 +v -2.976895 2.664578 0.023810 +v -3.046734 2.827921 0.014173 +v -3.116574 2.991265 0.004536 +v -3.186413 3.154608 -0.005101 +v -1.975200 0.774081 0.133852 +v -2.045039 0.937425 0.124216 +v -2.114879 1.100769 0.114578 +v -2.184718 1.264112 0.104941 +v -2.254558 1.427456 0.095304 +v -2.324397 1.590800 0.085667 +v -2.394237 1.754144 0.076030 +v -2.464076 1.917487 0.066393 +v -2.533916 2.080831 0.056756 +v -2.603755 2.244174 0.047119 +v -2.673594 2.407518 0.037482 +v -2.743433 2.570862 0.027845 +v -2.813273 2.734205 0.018208 +v -2.883112 2.897548 0.008571 +v -2.952952 3.060892 -0.001066 +v -3.022791 3.224236 -0.010703 +v -1.741739 0.680366 0.137887 +v -1.811578 0.843709 0.128251 +v -1.881418 1.007053 0.118613 +v -1.951257 1.170397 0.108976 +v -2.021096 1.333740 0.099339 +v -2.090936 1.497084 0.089702 +v -2.160775 1.660428 0.080065 +v -2.230615 1.823772 0.070428 +v -2.300454 1.987115 0.060791 +v -2.370294 2.150458 0.051154 +v -2.440133 2.313802 0.041517 +v -2.509972 2.477146 0.031880 +v -2.579812 2.640490 0.022243 +v -2.649651 2.803833 0.012606 +v -2.719491 2.967177 0.002969 +v -2.789330 3.130521 -0.006668 +v -2.859169 3.293864 -0.016305 +v -1.508277 0.586650 0.141922 +v -1.578117 0.749993 0.132286 +v -1.647956 0.913337 0.122648 +v -1.717796 1.076681 0.113011 +v -1.787635 1.240025 0.103374 +v -1.857474 1.403368 0.093737 +v -1.927314 1.566712 0.084100 +v -1.997153 1.730055 0.074463 +v -2.066993 1.893399 0.064826 +v -2.136832 2.056743 0.055189 +v -2.206672 2.220086 0.045552 +v -2.276511 2.383430 0.035915 +v -2.346350 2.546774 0.026278 +v -2.416190 2.710117 0.016641 +v -2.486029 2.873461 0.007004 +v -2.555869 3.036804 -0.002633 +v -2.625708 3.200148 -0.012270 +v -2.695547 3.363492 -0.021907 +v -1.274816 0.492934 0.145957 +v -1.344656 0.656278 0.136321 +v -1.414495 0.819621 0.126683 +v -1.484334 0.982965 0.117046 +v -1.554174 1.146308 0.107409 +v -1.624013 1.309652 0.097772 +v -1.693853 1.472996 0.088135 +v -1.763692 1.636340 0.078498 +v -1.833531 1.799683 0.068861 +v -1.903371 1.963027 0.059224 +v -1.973210 2.126370 0.049587 +v -2.043050 2.289714 0.039950 +v -2.112889 2.453058 0.030313 +v -2.182729 2.616402 0.020676 +v -2.252568 2.779745 0.011039 +v -2.322407 2.943089 0.001402 +v -2.392247 3.106432 -0.008235 +v -2.462086 3.269776 -0.017872 +v -2.531925 3.433120 -0.027509 +v -1.041355 0.399218 0.149992 +v -1.111194 0.562562 0.140356 +v -1.181034 0.725905 0.130718 +v -1.250873 0.889249 0.121081 +v -1.320712 1.052593 0.111444 +v -1.390552 1.215936 0.101807 +v -1.460391 1.379280 0.092170 +v -1.530231 1.542624 0.082533 +v -1.600070 1.705968 0.072896 +v -1.669910 1.869311 0.063259 +v -1.739749 2.032655 0.053622 +v -1.809589 2.195998 0.043985 +v -1.879428 2.359342 0.034348 +v -1.949267 2.522686 0.024711 +v -2.019107 2.686029 0.015074 +v -2.088946 2.849373 0.005437 +v -2.158785 3.012717 -0.004200 +v -2.228625 3.176060 -0.013837 +v -2.298464 3.339404 -0.023474 +v -2.368304 3.502747 -0.033111 +v -0.807893 0.305502 0.154027 +v -0.877733 0.468846 0.144391 +v -0.947572 0.632190 0.134753 +v -1.017412 0.795533 0.125116 +v -1.087251 0.958877 0.115479 +v -1.157091 1.122221 0.105842 +v -1.226930 1.285564 0.096205 +v -1.296769 1.448908 0.086568 +v -1.366609 1.612251 0.076931 +v -1.436448 1.775595 0.067294 +v -1.506288 1.938939 0.057657 +v -1.576127 2.102283 0.048020 +v -1.645967 2.265626 0.038383 +v -1.715806 2.428969 0.028746 +v -1.785645 2.592313 0.019109 +v -1.855485 2.755657 0.009472 +v -1.925324 2.919001 -0.000165 +v -1.995163 3.082345 -0.009802 +v -2.065003 3.245688 -0.019439 +v -2.134842 3.409032 -0.029076 +v -2.204681 3.572375 -0.038713 +v -0.574432 0.211786 0.158062 +v -0.644271 0.375130 0.148426 +v -0.714111 0.538474 0.138788 +v -0.783950 0.701817 0.129151 +v -0.853790 0.865161 0.119514 +v -0.923629 1.028505 0.109877 +v -0.993469 1.191848 0.100240 +v -1.063308 1.355192 0.090603 +v -1.133147 1.518536 0.080966 +v -1.202987 1.681879 0.071329 +v -1.272826 1.845223 0.061692 +v -1.342666 2.008567 0.052055 +v -1.412505 2.171911 0.042418 +v -1.482344 2.335254 0.032781 +v -1.552184 2.498598 0.023144 +v -1.622023 2.661941 0.013507 +v -1.691863 2.825285 0.003870 +v -1.761702 2.988628 -0.005767 +v -1.831541 3.151972 -0.015404 +v -1.901381 3.315316 -0.025041 +v -1.971220 3.478660 -0.034678 +v -2.041059 3.642003 -0.044315 +v -0.340971 0.118071 0.162097 +v -0.410810 0.281414 0.152461 +v -0.480650 0.444758 0.142823 +v -0.550489 0.608102 0.133186 +v -0.620328 0.771445 0.123549 +v -0.690168 0.934789 0.113912 +v -0.760007 1.098133 0.104275 +v -0.829847 1.261476 0.094638 +v -0.899686 1.424820 0.085001 +v -0.969525 1.588164 0.075364 +v -1.039365 1.751507 0.065727 +v -1.109204 1.914851 0.056090 +v -1.179044 2.078194 0.046453 +v -1.248883 2.241538 0.036816 +v -1.318722 2.404882 0.027179 +v -1.388562 2.568226 0.017542 +v -1.458401 2.731569 0.007905 +v -1.528241 2.894913 -0.001732 +v -1.598080 3.058257 -0.011369 +v -1.667919 3.221600 -0.021006 +v -1.737759 3.384944 -0.030643 +v -1.807598 3.548288 -0.040280 +v -1.877437 3.711631 -0.049917 +v -0.107509 0.024355 0.166132 +v -0.177349 0.187698 0.156495 +v -0.247188 0.351042 0.146858 +v -0.317028 0.514386 0.137221 +v -0.386867 0.677729 0.127584 +v -0.456706 0.841073 0.117947 +v -0.526546 1.004417 0.108310 +v -0.596385 1.167760 0.098673 +v -0.666225 1.331104 0.089036 +v -0.736064 1.494448 0.079399 +v -0.805903 1.657791 0.069762 +v -0.875743 1.821135 0.060125 +v -0.945582 1.984479 0.050488 +v -1.015422 2.147822 0.040851 +v -1.085261 2.311166 0.031214 +v -1.155100 2.474510 0.021577 +v -1.224940 2.637853 0.011940 +v -1.294779 2.801197 0.002303 +v -1.364619 2.964541 -0.007334 +v -1.434458 3.127884 -0.016971 +v -1.504297 3.291228 -0.026608 +v -1.574137 3.454572 -0.036245 +v -1.643976 3.617915 -0.045882 +v -1.713815 3.781258 -0.055519 +v 0.125952 -0.069361 0.170167 +v 0.056113 0.093983 0.160530 +v -0.013727 0.257326 0.150893 +v -0.083566 0.420670 0.141256 +v -0.153406 0.584014 0.131619 +v -0.223245 0.747357 0.121982 +v -0.293084 0.910701 0.112345 +v -0.362924 1.074044 0.102708 +v -0.432763 1.237388 0.093071 +v -0.502603 1.400732 0.083434 +v -0.572442 1.564076 0.073797 +v -0.642281 1.727419 0.064160 +v -0.712121 1.890763 0.054523 +v -0.781960 2.054106 0.044886 +v -0.851800 2.217450 0.035249 +v -0.921639 2.380794 0.025612 +v -0.991478 2.544138 0.015975 +v -1.061318 2.707481 0.006338 +v -1.131157 2.870825 -0.003299 +v -1.200997 3.034168 -0.012936 +v -1.270836 3.197512 -0.022573 +v -1.340675 3.360856 -0.032210 +v -1.410515 3.524200 -0.041847 +v -1.480354 3.687543 -0.051485 +v -1.550194 3.850887 -0.061122 +v 0.359413 -0.163077 0.174202 +v 0.289574 0.000267 0.164565 +v 0.219735 0.163610 0.154928 +v 0.149895 0.326954 0.145291 +v 0.080056 0.490298 0.135654 +v 0.010216 0.653641 0.126017 +v -0.059623 0.816985 0.116380 +v -0.129462 0.980329 0.106743 +v -0.199302 1.143672 0.097106 +v -0.269141 1.307016 0.087469 +v -0.338981 1.470360 0.077832 +v -0.408820 1.633703 0.068195 +v -0.478659 1.797047 0.058558 +v -0.548499 1.960391 0.048921 +v -0.618338 2.123734 0.039284 +v -0.688178 2.287078 0.029647 +v -0.758017 2.450422 0.020010 +v -0.827856 2.613765 0.010373 +v -0.897696 2.777109 0.000736 +v -0.967535 2.940452 -0.008901 +v -1.037375 3.103796 -0.018538 +v -1.107214 3.267140 -0.028175 +v -1.177053 3.430484 -0.037812 +v -1.246893 3.593827 -0.047450 +v -1.316732 3.757171 -0.057087 +v -1.386572 3.920515 -0.066724 +v 0.592875 -0.256793 0.178237 +v 0.523035 -0.093449 0.168600 +v 0.453196 0.069894 0.158963 +v 0.383356 0.233238 0.149326 +v 0.313517 0.396582 0.139689 +v 0.243678 0.559926 0.130052 +v 0.173838 0.723269 0.120415 +v 0.103999 0.886613 0.110778 +v 0.034160 1.049956 0.101141 +v -0.035680 1.213300 0.091504 +v -0.105519 1.376644 0.081867 +v -0.175359 1.539987 0.072230 +v -0.245198 1.703331 0.062593 +v -0.315037 1.866675 0.052956 +v -0.384877 2.030019 0.043319 +v -0.454716 2.193362 0.033682 +v -0.524556 2.356706 0.024045 +v -0.594395 2.520050 0.014408 +v -0.664234 2.683393 0.004771 +v -0.734074 2.846737 -0.004866 +v -0.803913 3.010080 -0.014503 +v -0.873753 3.173424 -0.024140 +v -0.943592 3.336768 -0.033778 +v -1.013431 3.500112 -0.043415 +v -1.083271 3.663455 -0.053052 +v -1.153110 3.826799 -0.062689 +v -1.222950 3.990143 -0.072326 +v 0.826336 -0.350509 0.182272 +v 0.756497 -0.187165 0.172635 +v 0.686657 -0.023821 0.162998 +v 0.616818 0.139522 0.153361 +v 0.546978 0.302866 0.143724 +v 0.477139 0.466210 0.134087 +v 0.407299 0.629553 0.124450 +v 0.337460 0.792897 0.114813 +v 0.267621 0.956241 0.105176 +v 0.197781 1.119584 0.095539 +v 0.127942 1.282928 0.085902 +v 0.058103 1.446272 0.076265 +v -0.011737 1.609615 0.066628 +v -0.081576 1.772959 0.056991 +v -0.151416 1.936302 0.047354 +v -0.221255 2.099646 0.037717 +v -0.291094 2.262990 0.028080 +v -0.360934 2.426333 0.018443 +v -0.430773 2.589677 0.008806 +v -0.500613 2.753021 -0.000831 +v -0.570452 2.916364 -0.010468 +v -0.640291 3.079708 -0.020105 +v -0.710131 3.243052 -0.029743 +v -0.779970 3.406395 -0.039380 +v -0.849809 3.569739 -0.049017 +v -0.919649 3.733083 -0.058654 +v -0.989488 3.896427 -0.068291 +v -1.059328 4.059771 -0.077928 +v 1.059797 -0.444224 0.186307 +v 0.989958 -0.280881 0.176670 +v 0.920118 -0.117537 0.167033 +v 0.850279 0.045806 0.157396 +v 0.780440 0.209150 0.147759 +v 0.710600 0.372494 0.138122 +v 0.640761 0.535838 0.128485 +v 0.570921 0.699181 0.118848 +v 0.501082 0.862525 0.109211 +v 0.431243 1.025868 0.099574 +v 0.361403 1.189212 0.089937 +v 0.291564 1.352556 0.080300 +v 0.221724 1.515899 0.070663 +v 0.151885 1.679243 0.061026 +v 0.082046 1.842587 0.051389 +v 0.012206 2.005930 0.041752 +v -0.057633 2.169274 0.032115 +v -0.127473 2.332618 0.022478 +v -0.197312 2.495961 0.012841 +v -0.267151 2.659305 0.003203 +v -0.336991 2.822649 -0.006433 +v -0.406830 2.985992 -0.016070 +v -0.476670 3.149336 -0.025708 +v -0.546509 3.312680 -0.035345 +v -0.616348 3.476023 -0.044982 +v -0.686188 3.639367 -0.054619 +v -0.756027 3.802711 -0.064256 +v -0.825866 3.966055 -0.073893 +v -0.895706 4.129398 -0.083530 +v 1.293259 -0.537940 0.190342 +v 1.223419 -0.374597 0.180705 +v 1.153580 -0.211253 0.171068 +v 1.083740 -0.047909 0.161431 +v 1.013901 0.115434 0.151794 +v 0.944062 0.278778 0.142157 +v 0.874222 0.442122 0.132520 +v 0.804383 0.605465 0.122883 +v 0.734543 0.768809 0.113246 +v 0.664704 0.932153 0.103609 +v 0.594865 1.095496 0.093972 +v 0.525025 1.258840 0.084335 +v 0.455186 1.422184 0.074698 +v 0.385347 1.585527 0.065061 +v 0.315507 1.748871 0.055424 +v 0.245668 1.912214 0.045787 +v 0.175828 2.075558 0.036150 +v 0.105989 2.238902 0.026513 +v 0.036150 2.402245 0.016876 +v -0.033690 2.565589 0.007238 +v -0.103529 2.728933 -0.002398 +v -0.173369 2.892277 -0.012035 +v -0.243208 3.055620 -0.021673 +v -0.313048 3.218964 -0.031310 +v -0.382887 3.382308 -0.040947 +v -0.452726 3.545651 -0.050584 +v -0.522565 3.708995 -0.060221 +v -0.592405 3.872339 -0.069858 +v -0.662244 4.035683 -0.079495 +v -0.732084 4.199026 -0.089132 +v 1.526720 -0.631656 0.194377 +v 1.456881 -0.468312 0.184740 +v 1.387041 -0.304969 0.175103 +v 1.317202 -0.141625 0.165466 +v 1.247363 0.021719 0.155829 +v 1.177523 0.185062 0.146192 +v 1.107684 0.348406 0.136555 +v 1.037845 0.511750 0.126918 +v 0.968005 0.675093 0.117281 +v 0.898166 0.838437 0.107644 +v 0.828327 1.001781 0.098007 +v 0.758487 1.165124 0.088370 +v 0.688648 1.328468 0.078733 +v 0.618808 1.491812 0.069096 +v 0.548969 1.655155 0.059459 +v 0.479130 1.818499 0.049822 +v 0.409290 1.981842 0.040185 +v 0.339451 2.145186 0.030548 +v 0.269611 2.308530 0.020911 +v 0.199772 2.471873 0.011274 +v 0.129933 2.635217 0.001636 +v 0.060093 2.798561 -0.008000 +v -0.009746 2.961904 -0.017638 +v -0.079586 3.125248 -0.027275 +v -0.149425 3.288592 -0.036912 +v -0.219265 3.451936 -0.046549 +v -0.289104 3.615279 -0.056186 +v -0.358943 3.778623 -0.065823 +v -0.428783 3.941966 -0.075460 +v -0.498622 4.105311 -0.085097 +v -0.568462 4.268654 -0.094734 +v 1.760181 -0.725372 0.198412 +v 1.690342 -0.562028 0.188775 +v 1.620502 -0.398685 0.179138 +v 1.550663 -0.235341 0.169501 +v 1.480824 -0.071997 0.159864 +v 1.410985 0.091346 0.150227 +v 1.341145 0.254690 0.140590 +v 1.271306 0.418034 0.130953 +v 1.201466 0.581377 0.121316 +v 1.131627 0.744721 0.111679 +v 1.061788 0.908065 0.102042 +v 0.991948 1.071408 0.092405 +v 0.922109 1.234752 0.082768 +v 0.852270 1.398096 0.073131 +v 0.782430 1.561439 0.063494 +v 0.712591 1.724783 0.053857 +v 0.642752 1.888126 0.044220 +v 0.572912 2.051470 0.034583 +v 0.503073 2.214814 0.024946 +v 0.433233 2.378157 0.015309 +v 0.363394 2.541501 0.005672 +v 0.293555 2.704845 -0.003965 +v 0.223715 2.868189 -0.013603 +v 0.153876 3.031532 -0.023240 +v 0.084036 3.194876 -0.032877 +v 0.014197 3.358220 -0.042514 +v -0.055643 3.521563 -0.052151 +v -0.125482 3.684907 -0.061788 +v -0.195321 3.848251 -0.071425 +v -0.265161 4.011594 -0.081062 +v -0.335000 4.174939 -0.090699 +v -0.404840 4.338282 -0.100336 +v 1.993642 -0.819088 0.202447 +v 1.923803 -0.655744 0.192810 +v 1.853964 -0.492400 0.183173 +v 1.784124 -0.329057 0.173536 +v 1.714285 -0.165713 0.163899 +v 1.644446 -0.002369 0.154262 +v 1.574606 0.160974 0.144625 +v 1.504767 0.324318 0.134988 +v 1.434928 0.487662 0.125351 +v 1.365088 0.651005 0.115714 +v 1.295249 0.814349 0.106077 +v 1.225410 0.977692 0.096440 +v 1.155570 1.141036 0.086803 +v 1.085731 1.304380 0.077166 +v 1.015892 1.467724 0.067529 +v 0.946052 1.631067 0.057892 +v 0.876213 1.794411 0.048255 +v 0.806373 1.957754 0.038618 +v 0.736534 2.121098 0.028981 +v 0.666695 2.284442 0.019344 +v 0.596855 2.447785 0.009706 +v 0.527016 2.611129 0.000069 +v 0.457176 2.774473 -0.009568 +v 0.387337 2.937817 -0.019205 +v 0.317498 3.101161 -0.028842 +v 0.247658 3.264504 -0.038479 +v 0.177819 3.427847 -0.048116 +v 0.107979 3.591191 -0.057753 +v 0.038140 3.754535 -0.067390 +v -0.031699 3.917878 -0.077027 +v -0.101539 4.081222 -0.086664 +v -0.171378 4.244566 -0.096301 +v -0.241217 4.407909 -0.105938 +v 2.227104 -0.912804 0.206482 +v 2.157264 -0.749460 0.196845 +v 2.087425 -0.586116 0.187208 +v 2.017586 -0.422773 0.177571 +v 1.947746 -0.259429 0.167934 +v 1.877907 -0.096085 0.158297 +v 1.808068 0.067258 0.148660 +v 1.738228 0.230602 0.139023 +v 1.668389 0.393946 0.129386 +v 1.598550 0.557289 0.119749 +v 1.528710 0.720633 0.110112 +v 1.458871 0.883977 0.100475 +v 1.389032 1.047320 0.090838 +v 1.319192 1.210664 0.081201 +v 1.249353 1.374008 0.071564 +v 1.179514 1.537351 0.061927 +v 1.109674 1.700695 0.052290 +v 1.039835 1.864038 0.042653 +v 0.969995 2.027382 0.033016 +v 0.900156 2.190726 0.023379 +v 0.830317 2.354070 0.013741 +v 0.760477 2.517413 0.004105 +v 0.690638 2.680757 -0.005533 +v 0.620798 2.844100 -0.015170 +v 0.550959 3.007444 -0.024807 +v 0.481119 3.170788 -0.034444 +v 0.411280 3.334132 -0.044081 +v 0.341441 3.497475 -0.053718 +v 0.271601 3.660819 -0.063355 +v 0.201762 3.824162 -0.072992 +v 0.131922 3.987506 -0.082629 +v 0.062083 4.150850 -0.092266 +v -0.007756 4.314194 -0.101903 +v -0.077596 4.477537 -0.111540 +v 2.460565 -1.006519 0.210517 +v 2.390726 -0.843176 0.200880 +v 2.320886 -0.679832 0.191243 +v 2.251047 -0.516488 0.181606 +v 2.181208 -0.353145 0.171969 +v 2.111368 -0.189801 0.162332 +v 2.041529 -0.026457 0.152695 +v 1.971690 0.136886 0.143058 +v 1.901850 0.300230 0.133421 +v 1.832011 0.463574 0.123784 +v 1.762172 0.626917 0.114147 +v 1.692332 0.790261 0.104510 +v 1.622493 0.953604 0.094873 +v 1.552653 1.116948 0.085236 +v 1.482814 1.280292 0.075599 +v 1.412975 1.443635 0.065962 +v 1.343135 1.606979 0.056325 +v 1.273296 1.770323 0.046688 +v 1.203457 1.933666 0.037051 +v 1.133617 2.097010 0.027414 +v 1.063778 2.260354 0.017776 +v 0.993939 2.423697 0.008140 +v 0.924099 2.587041 -0.001498 +v 0.854260 2.750385 -0.011135 +v 0.784420 2.913728 -0.020772 +v 0.714581 3.077072 -0.030409 +v 0.644741 3.240416 -0.040046 +v 0.574902 3.403759 -0.049683 +v 0.505063 3.567103 -0.059320 +v 0.435223 3.730447 -0.068957 +v 0.365384 3.893790 -0.078594 +v 0.295545 4.057134 -0.088231 +v 0.225705 4.220478 -0.097868 +v 0.155866 4.383822 -0.107505 +v 0.086026 4.547165 -0.117142 +v 2.694026 -1.100235 0.214552 +v 2.624187 -0.936891 0.204915 +v 2.554348 -0.773548 0.195278 +v 2.484508 -0.610204 0.185641 +v 2.414669 -0.446860 0.176004 +v 2.344830 -0.283517 0.166367 +v 2.274990 -0.120173 0.156730 +v 2.205151 0.043171 0.147093 +v 2.135312 0.206514 0.137456 +v 2.065472 0.369858 0.127819 +v 1.995633 0.533202 0.118182 +v 1.925793 0.696545 0.108545 +v 1.855954 0.859889 0.098908 +v 1.786115 1.023233 0.089271 +v 1.716275 1.186576 0.079634 +v 1.646436 1.349920 0.069997 +v 1.576597 1.513264 0.060360 +v 1.506757 1.676607 0.050723 +v 1.436918 1.839951 0.041086 +v 1.367079 2.003294 0.031449 +v 1.297239 2.166638 0.021811 +v 1.227400 2.329982 0.012175 +v 1.157561 2.493325 0.002537 +v 1.087721 2.656669 -0.007100 +v 1.017882 2.820013 -0.016737 +v 0.948043 2.983356 -0.026374 +v 0.878203 3.146700 -0.036011 +v 0.808364 3.310044 -0.045648 +v 0.738524 3.473387 -0.055285 +v 0.668685 3.636731 -0.064922 +v 0.598846 3.800074 -0.074559 +v 0.529006 3.963418 -0.084196 +v 0.459167 4.126763 -0.093833 +v 0.389327 4.290105 -0.103470 +v 0.319488 4.453450 -0.113107 +v 0.249648 4.616793 -0.122744 +v 2.927488 -1.193951 0.218587 +v 2.857649 -1.030607 0.208950 +v 2.787809 -0.867264 0.199313 +v 2.717970 -0.703920 0.189676 +v 2.648130 -0.540576 0.180039 +v 2.578291 -0.377233 0.170402 +v 2.508452 -0.213889 0.160765 +v 2.438612 -0.050545 0.151128 +v 2.368773 0.112799 0.141491 +v 2.298934 0.276142 0.131854 +v 2.229095 0.439486 0.122217 +v 2.159255 0.602829 0.112580 +v 2.089416 0.766173 0.102943 +v 2.019576 0.929517 0.093306 +v 1.949737 1.092860 0.083669 +v 1.879898 1.256204 0.074032 +v 1.810058 1.419548 0.064395 +v 1.740219 1.582891 0.054758 +v 1.670380 1.746235 0.045121 +v 1.600540 1.909578 0.035484 +v 1.530701 2.072922 0.025846 +v 1.460862 2.236266 0.016210 +v 1.391022 2.399609 0.006572 +v 1.321183 2.562953 -0.003065 +v 1.251343 2.726297 -0.012702 +v 1.181504 2.889640 -0.022339 +v 1.111665 3.052984 -0.031976 +v 1.041825 3.216328 -0.041613 +v 0.971986 3.379672 -0.051250 +v 0.902147 3.543015 -0.060887 +v 0.832307 3.706359 -0.070524 +v 0.762468 3.869703 -0.080161 +v 0.692628 4.033046 -0.089798 +v 0.622789 4.196391 -0.099435 +v 0.552949 4.359733 -0.109072 +v 0.483110 4.523077 -0.118709 +v 0.413270 4.686420 -0.128346 +v 3.160949 -1.287667 0.222622 +v 3.091110 -1.124323 0.212985 +v 3.021271 -0.960980 0.203348 +v 2.951431 -0.797636 0.193711 +v 2.881592 -0.634292 0.184074 +v 2.811752 -0.470948 0.174437 +v 2.741913 -0.307605 0.164800 +v 2.672074 -0.144261 0.155163 +v 2.602234 0.019083 0.145526 +v 2.532395 0.182426 0.135889 +v 2.462556 0.345770 0.126252 +v 2.392716 0.509114 0.116615 +v 2.322877 0.672457 0.106978 +v 2.253038 0.835801 0.097341 +v 2.183198 0.999145 0.087704 +v 2.113359 1.162488 0.078067 +v 2.043519 1.325832 0.068430 +v 1.973680 1.489176 0.058793 +v 1.903841 1.652519 0.049156 +v 1.834001 1.815863 0.039519 +v 1.764162 1.979206 0.029881 +v 1.694323 2.142550 0.020245 +v 1.624483 2.305894 0.010607 +v 1.554644 2.469237 0.000970 +v 1.484805 2.632581 -0.008667 +v 1.414965 2.795925 -0.018304 +v 1.345126 2.959268 -0.027941 +v 1.275287 3.122612 -0.037578 +v 1.205447 3.285956 -0.047215 +v 1.135608 3.449299 -0.056852 +v 1.065768 3.612643 -0.066489 +v 0.995929 3.775987 -0.076126 +v 0.926090 3.939330 -0.085763 +v 0.856250 4.102675 -0.095400 +v 0.786411 4.266018 -0.105037 +v 0.716572 4.429361 -0.114674 +v 0.646732 4.592705 -0.124311 +v 0.576893 4.756048 -0.133948 +v 3.394411 -1.381383 0.226657 +v 3.324571 -1.218039 0.217020 +v 3.254732 -1.054695 0.207383 +v 3.184893 -0.891352 0.197746 +v 3.115053 -0.728008 0.188109 +v 3.045214 -0.564664 0.178472 +v 2.975374 -0.401321 0.168835 +v 2.905535 -0.237977 0.159198 +v 2.835696 -0.074633 0.149561 +v 2.765857 0.088711 0.139924 +v 2.696017 0.252054 0.130287 +v 2.626178 0.415398 0.120650 +v 2.556339 0.578741 0.111013 +v 2.486499 0.742085 0.101376 +v 2.416660 0.905429 0.091739 +v 2.346820 1.068772 0.082102 +v 2.276981 1.232116 0.072465 +v 2.207142 1.395460 0.062828 +v 2.137302 1.558803 0.053190 +v 2.067463 1.722147 0.043554 +v 1.997624 1.885490 0.033916 +v 1.927784 2.048834 0.024279 +v 1.857945 2.212178 0.014642 +v 1.788106 2.375521 0.005005 +v 1.718266 2.538865 -0.004632 +v 1.648427 2.702209 -0.014269 +v 1.578587 2.865552 -0.023906 +v 1.508748 3.028896 -0.033543 +v 1.438909 3.192240 -0.043180 +v 1.369069 3.355584 -0.052817 +v 1.299230 3.518927 -0.062454 +v 1.229391 3.682271 -0.072091 +v 1.159551 3.845615 -0.081728 +v 1.089712 4.008958 -0.091365 +v 1.019872 4.172303 -0.101002 +v 0.950033 4.335646 -0.110639 +v 0.880193 4.498990 -0.120276 +v 0.810354 4.662333 -0.129913 +v 0.740515 4.825676 -0.139550 +v 3.627872 -1.475098 0.230692 +v 3.558033 -1.311755 0.221055 +v 3.488194 -1.148411 0.211418 +v 3.418354 -0.985067 0.201781 +v 3.348515 -0.821724 0.192144 +v 3.278676 -0.658380 0.182507 +v 3.208836 -0.495036 0.172870 +v 3.138997 -0.331693 0.163233 +v 3.069157 -0.168349 0.153596 +v 2.999318 -0.005005 0.143959 +v 2.929479 0.158338 0.134322 +v 2.859639 0.321682 0.124685 +v 2.789800 0.485026 0.115048 +v 2.719961 0.648369 0.105411 +v 2.650121 0.811713 0.095774 +v 2.580282 0.975057 0.086137 +v 2.510442 1.138400 0.076500 +v 2.440603 1.301744 0.066863 +v 2.370764 1.465088 0.057225 +v 2.300925 1.628431 0.047589 +v 2.231085 1.791775 0.037951 +v 2.161246 1.955118 0.028314 +v 2.091406 2.118462 0.018677 +v 2.021567 2.281806 0.009040 +v 1.951728 2.445150 -0.000597 +v 1.881888 2.608493 -0.010234 +v 1.812049 2.771837 -0.019871 +v 1.742210 2.935180 -0.029508 +v 1.672370 3.098524 -0.039145 +v 1.602531 3.261868 -0.048782 +v 1.532691 3.425211 -0.058419 +v 1.462852 3.588555 -0.068056 +v 1.393013 3.751899 -0.077693 +v 1.323173 3.915242 -0.087330 +v 1.253334 4.078587 -0.096967 +v 1.183494 4.241930 -0.106604 +v 1.113655 4.405274 -0.116241 +v 1.043816 4.568617 -0.125878 +v 0.973976 4.731961 -0.135515 +v 0.904137 4.895304 -0.145152 +v 3.861333 -1.568815 0.234727 +v 3.791494 -1.405471 0.225090 +v 3.721655 -1.242127 0.215453 +v 3.651815 -1.078783 0.205816 +v 3.581976 -0.915440 0.196179 +v 3.512137 -0.752096 0.186542 +v 3.442297 -0.588752 0.176905 +v 3.372458 -0.425409 0.167268 +v 3.302619 -0.262065 0.157631 +v 3.232779 -0.098721 0.147994 +v 3.162940 0.064623 0.138357 +v 3.093101 0.227966 0.128720 +v 3.023261 0.391310 0.119083 +v 2.953422 0.554654 0.109446 +v 2.883583 0.717997 0.099809 +v 2.813743 0.881341 0.090172 +v 2.743904 1.044684 0.080535 +v 2.674064 1.208028 0.070898 +v 2.604225 1.371372 0.061260 +v 2.534386 1.534715 0.051624 +v 2.464546 1.698059 0.041986 +v 2.394707 1.861402 0.032349 +v 2.324868 2.024746 0.022712 +v 2.255028 2.188090 0.013075 +v 2.185189 2.351433 0.003438 +v 2.115350 2.514777 -0.006199 +v 2.045510 2.678120 -0.015836 +v 1.975671 2.841465 -0.025473 +v 1.905831 3.004808 -0.035110 +v 1.835992 3.168152 -0.044747 +v 1.766153 3.331496 -0.054384 +v 1.696313 3.494839 -0.064021 +v 1.626474 3.658183 -0.073658 +v 1.556635 3.821527 -0.083295 +v 1.486795 3.984870 -0.092932 +v 1.416956 4.148214 -0.102569 +v 1.347116 4.311558 -0.112206 +v 1.277277 4.474902 -0.121843 +v 1.207438 4.638245 -0.131480 +v 1.137598 4.801589 -0.141117 +v 1.067759 4.964931 -0.150754 +v 4.094795 -1.662530 0.238762 +v 4.024956 -1.499186 0.229125 +v 3.955116 -1.335843 0.219488 +v 3.885277 -1.172499 0.209851 +v 3.815438 -1.009155 0.200214 +v 3.745598 -0.845812 0.190577 +v 3.675759 -0.682468 0.180940 +v 3.605919 -0.519124 0.171303 +v 3.536080 -0.355781 0.161666 +v 3.466241 -0.192437 0.152029 +v 3.396401 -0.029093 0.142392 +v 3.326562 0.134250 0.132755 +v 3.256723 0.297594 0.123118 +v 3.186883 0.460938 0.113481 +v 3.117044 0.624281 0.103844 +v 3.047205 0.787625 0.094207 +v 2.977365 0.950969 0.084570 +v 2.907526 1.114312 0.074933 +v 2.837687 1.277656 0.065295 +v 2.767847 1.440999 0.055659 +v 2.698008 1.604343 0.046021 +v 2.628169 1.767687 0.036384 +v 2.558329 1.931030 0.026747 +v 2.488490 2.094374 0.017110 +v 2.418651 2.257718 0.007473 +v 2.348811 2.421061 -0.002164 +v 2.278972 2.584405 -0.011801 +v 2.209132 2.747748 -0.021438 +v 2.139293 2.911092 -0.031075 +v 2.069454 3.074436 -0.040712 +v 1.999614 3.237780 -0.050349 +v 1.929775 3.401124 -0.059986 +v 1.859936 3.564467 -0.069623 +v 1.790096 3.727811 -0.079260 +v 1.720257 3.891155 -0.088897 +v 1.650417 4.054498 -0.098534 +v 1.580578 4.217842 -0.108171 +v 1.510738 4.381186 -0.117808 +v 1.440899 4.544529 -0.127445 +v 1.371060 4.707873 -0.137082 +v 1.301220 4.871216 -0.146720 +v 1.231381 5.034559 -0.156357 +v 4.328257 -1.756246 0.242797 +v 4.258417 -1.592903 0.233160 +v 4.188578 -1.429559 0.223523 +v 4.118738 -1.266215 0.213886 +v 4.048899 -1.102871 0.204249 +v 3.979060 -0.939528 0.194612 +v 3.909220 -0.776184 0.184975 +v 3.839381 -0.612840 0.175338 +v 3.769542 -0.449497 0.165701 +v 3.699702 -0.286153 0.156064 +v 3.629863 -0.122809 0.146427 +v 3.560024 0.040535 0.136790 +v 3.490184 0.203878 0.127153 +v 3.420345 0.367222 0.117516 +v 3.350505 0.530566 0.107879 +v 3.280666 0.693909 0.098242 +v 3.210827 0.857253 0.088605 +v 3.140987 1.020596 0.078968 +v 3.071148 1.183940 0.069330 +v 3.001309 1.347284 0.059694 +v 2.931469 1.510627 0.050056 +v 2.861630 1.673971 0.040419 +v 2.791791 1.837314 0.030782 +v 2.721951 2.000658 0.021145 +v 2.652112 2.164002 0.011508 +v 2.582273 2.327345 0.001871 +v 2.512433 2.490689 -0.007766 +v 2.442594 2.654033 -0.017403 +v 2.372755 2.817376 -0.027040 +v 2.302915 2.980720 -0.036677 +v 2.233076 3.144064 -0.046314 +v 2.163237 3.307407 -0.055951 +v 2.093397 3.470751 -0.065588 +v 2.023558 3.634095 -0.075225 +v 1.953718 3.797439 -0.084862 +v 1.883879 3.960782 -0.094499 +v 1.814040 4.124126 -0.104136 +v 1.744200 4.287470 -0.113773 +v 1.674361 4.450814 -0.123410 +v 1.604521 4.614157 -0.133048 +v 1.534682 4.777501 -0.142685 +v 1.464842 4.940844 -0.152322 +v 1.395003 5.104187 -0.161959 +v 4.561718 -1.849962 0.246832 +v 4.491879 -1.686618 0.237195 +v 4.422039 -1.523275 0.227558 +v 4.352200 -1.359931 0.217921 +v 4.282360 -1.196587 0.208284 +v 4.212521 -1.033243 0.198647 +v 4.142681 -0.869900 0.189010 +v 4.072842 -0.706556 0.179373 +v 4.003003 -0.543212 0.169736 +v 3.933163 -0.379869 0.160099 +v 3.863324 -0.216525 0.150462 +v 3.793484 -0.053181 0.140825 +v 3.723645 0.110162 0.131188 +v 3.653806 0.273506 0.121551 +v 3.583966 0.436850 0.111914 +v 3.514127 0.600194 0.102277 +v 3.444288 0.763537 0.092639 +v 3.374448 0.926881 0.083003 +v 3.304609 1.090224 0.073365 +v 3.234770 1.253568 0.063729 +v 3.164930 1.416912 0.054091 +v 3.095091 1.580255 0.044454 +v 3.025252 1.743599 0.034817 +v 2.955412 1.906943 0.025180 +v 2.885573 2.070286 0.015543 +v 2.815734 2.233629 0.005906 +v 2.745894 2.396973 -0.003731 +v 2.676055 2.560317 -0.013368 +v 2.606216 2.723661 -0.023005 +v 2.536376 2.887004 -0.032642 +v 2.466537 3.050348 -0.042279 +v 2.396698 3.213691 -0.051916 +v 2.326858 3.377035 -0.061553 +v 2.257019 3.540379 -0.071190 +v 2.187180 3.703722 -0.080827 +v 2.117340 3.867067 -0.090464 +v 2.047501 4.030410 -0.100101 +v 1.977661 4.193754 -0.109738 +v 1.907822 4.357098 -0.119375 +v 1.837982 4.520442 -0.129013 +v 1.768143 4.683785 -0.138650 +v 1.698304 4.847129 -0.148287 +v 1.628464 5.010472 -0.157924 +v 1.558625 5.173815 -0.167561 +v 4.795178 -1.943678 0.250867 +v 4.725339 -1.780334 0.241230 +v 4.655500 -1.616990 0.231593 +v 4.585661 -1.453647 0.221956 +v 4.515821 -1.290303 0.212319 +v 4.445982 -1.126959 0.202682 +v 4.376143 -0.963615 0.193045 +v 4.306303 -0.800272 0.183408 +v 4.236464 -0.636928 0.173771 +v 4.166625 -0.473584 0.164134 +v 4.096786 -0.310241 0.154497 +v 4.026946 -0.146897 0.144860 +v 3.957106 0.016446 0.135223 +v 3.887267 0.179790 0.125586 +v 3.817428 0.343134 0.115949 +v 3.747588 0.506478 0.106312 +v 3.677749 0.669821 0.096674 +v 3.607910 0.833165 0.087038 +v 3.538070 0.996508 0.077400 +v 3.468231 1.159852 0.067763 +v 3.398391 1.323196 0.058126 +v 3.328552 1.486539 0.048489 +v 3.258713 1.649883 0.038852 +v 3.188874 1.813227 0.029215 +v 3.119034 1.976570 0.019578 +v 3.049195 2.139914 0.009941 +v 2.979356 2.303257 0.000304 +v 2.909516 2.466601 -0.009333 +v 2.839677 2.629944 -0.018970 +v 2.769838 2.793288 -0.028607 +v 2.699998 2.956631 -0.038244 +v 2.630159 3.119976 -0.047881 +v 2.560319 3.283319 -0.057518 +v 2.490480 3.446663 -0.067155 +v 2.420641 3.610007 -0.076792 +v 2.350801 3.773350 -0.086429 +v 2.280962 3.936694 -0.096066 +v 2.211123 4.100038 -0.105703 +v 2.141283 4.263381 -0.115340 +v 2.071444 4.426725 -0.124978 +v 2.001605 4.590069 -0.134615 +v 1.931765 4.753413 -0.144252 +v 1.861926 4.916757 -0.153889 +v 1.792086 5.080100 -0.163526 +v 1.722247 5.243443 -0.173163 +v 5.028641 -2.037393 0.254902 +v 4.958801 -1.874050 0.245265 +v 4.888962 -1.710706 0.235628 +v 4.819122 -1.547362 0.225991 +v 4.749283 -1.384019 0.216354 +v 4.679443 -1.220675 0.206717 +v 4.609604 -1.057331 0.197080 +v 4.539764 -0.893988 0.187443 +v 4.469925 -0.730644 0.177806 +v 4.400086 -0.567300 0.168169 +v 4.330247 -0.403957 0.158532 +v 4.260407 -0.240613 0.148895 +v 4.190568 -0.077269 0.139258 +v 4.120728 0.086074 0.129621 +v 4.050889 0.249418 0.119984 +v 3.981050 0.412762 0.110347 +v 3.911211 0.576105 0.100709 +v 3.841371 0.739449 0.091073 +v 3.771532 0.902793 0.081435 +v 3.701692 1.066136 0.071798 +v 3.631853 1.229480 0.062161 +v 3.562014 1.392824 0.052524 +v 3.492174 1.556167 0.042887 +v 3.422335 1.719511 0.033250 +v 3.352496 1.882854 0.023613 +v 3.282656 2.046198 0.013976 +v 3.212817 2.209542 0.004339 +v 3.142978 2.372885 -0.005298 +v 3.073138 2.536229 -0.014935 +v 3.003299 2.699573 -0.024572 +v 2.933460 2.862916 -0.034209 +v 2.863620 3.026260 -0.043846 +v 2.793781 3.189603 -0.053483 +v 2.723942 3.352947 -0.063120 +v 2.654102 3.516291 -0.072757 +v 2.584263 3.679635 -0.082394 +v 2.514423 3.842979 -0.092031 +v 2.444584 4.006322 -0.101668 +v 2.374745 4.169666 -0.111305 +v 2.304905 4.333009 -0.120943 +v 2.235066 4.496353 -0.130580 +v 2.165227 4.659697 -0.140217 +v 2.095387 4.823040 -0.149854 +v 2.025548 4.986385 -0.159491 +v 1.955708 5.149727 -0.169128 +v 1.885869 5.313070 -0.178765 +v 5.262101 -2.131109 0.258937 +v 5.192262 -1.967766 0.249300 +v 5.122422 -1.804422 0.239663 +v 5.052583 -1.641078 0.230026 +v 4.982744 -1.477734 0.220389 +v 4.912905 -1.314391 0.210752 +v 4.843065 -1.151047 0.201115 +v 4.773226 -0.987703 0.191478 +v 4.703386 -0.824360 0.181841 +v 4.633547 -0.661016 0.172204 +v 4.563707 -0.497672 0.162567 +v 4.493869 -0.334329 0.152930 +v 4.424029 -0.170985 0.143293 +v 4.354190 -0.007642 0.133656 +v 4.284350 0.155702 0.124019 +v 4.214511 0.319046 0.114382 +v 4.144671 0.482390 0.104744 +v 4.074832 0.645733 0.095108 +v 4.004992 0.809077 0.085470 +v 3.935153 0.972420 0.075833 +v 3.865314 1.135764 0.066196 +v 3.795475 1.299108 0.056559 +v 3.725635 1.462451 0.046922 +v 3.655796 1.625795 0.037285 +v 3.585957 1.789138 0.027648 +v 3.516117 1.952482 0.018011 +v 3.446278 2.115826 0.008374 +v 3.376439 2.279169 -0.001263 +v 3.306599 2.442513 -0.010900 +v 3.236760 2.605856 -0.020537 +v 3.166921 2.769200 -0.030174 +v 3.097081 2.932544 -0.039811 +v 3.027242 3.095887 -0.049448 +v 2.957403 3.259231 -0.059085 +v 2.887563 3.422575 -0.068722 +v 2.817724 3.585918 -0.078359 +v 2.747885 3.749262 -0.087996 +v 2.678045 3.912606 -0.097633 +v 2.608206 4.075950 -0.107270 +v 2.538366 4.239294 -0.116908 +v 2.468527 4.402637 -0.126545 +v 2.398688 4.565981 -0.136182 +v 2.328848 4.729325 -0.145819 +v 2.259009 4.892668 -0.155456 +v 2.189170 5.056013 -0.165093 +v 2.119330 5.219355 -0.174730 +v 2.049491 5.382698 -0.184367 +v 5.495563 -2.224826 0.262972 +v 5.425723 -2.061481 0.253335 +v 5.355885 -1.898138 0.243698 +v 5.286045 -1.734794 0.234061 +v 5.216206 -1.571451 0.224424 +v 5.146366 -1.408107 0.214787 +v 5.076527 -1.244763 0.205150 +v 5.006687 -1.081420 0.195513 +v 4.936848 -0.918076 0.185876 +v 4.867008 -0.754732 0.176239 +v 4.797169 -0.591388 0.166602 +v 4.727330 -0.428045 0.156965 +v 4.657491 -0.264701 0.147328 +v 4.587651 -0.101357 0.137691 +v 4.517812 0.061986 0.128054 +v 4.447972 0.225330 0.118417 +v 4.378133 0.388674 0.108779 +v 4.308293 0.552017 0.099143 +v 4.238455 0.715361 0.089505 +v 4.168615 0.878705 0.079868 +v 4.098776 1.042048 0.070231 +v 4.028936 1.205392 0.060594 +v 3.959097 1.368735 0.050957 +v 3.889257 1.532079 0.041320 +v 3.819418 1.695423 0.031683 +v 3.749579 1.858766 0.022046 +v 3.679739 2.022110 0.012409 +v 3.609900 2.185454 0.002772 +v 3.540061 2.348797 -0.006865 +v 3.470222 2.512141 -0.016502 +v 3.400382 2.675484 -0.026139 +v 3.330543 2.838828 -0.035776 +v 3.260704 3.002172 -0.045413 +v 3.190864 3.165515 -0.055050 +v 3.121025 3.328859 -0.064687 +v 3.051185 3.492203 -0.074324 +v 2.981346 3.655546 -0.083961 +v 2.911507 3.818890 -0.093598 +v 2.841667 3.982234 -0.103236 +v 2.771828 4.145578 -0.112873 +v 2.701989 4.308921 -0.122510 +v 2.632149 4.472265 -0.132147 +v 2.562310 4.635609 -0.141784 +v 2.492471 4.798953 -0.151421 +v 2.422631 4.962296 -0.161058 +v 2.352792 5.125640 -0.170695 +v 2.282953 5.288983 -0.180332 +v 2.213113 5.452327 -0.189969 +v 5.729023 -2.318541 0.267007 +v 5.659184 -2.155197 0.257370 +v 5.589345 -1.991854 0.247733 +v 5.519506 -1.828510 0.238096 +v 5.449666 -1.665166 0.228459 +v 5.379827 -1.501822 0.218822 +v 5.309987 -1.338479 0.209185 +v 5.240148 -1.175135 0.199548 +v 5.170308 -1.011791 0.189911 +v 5.100470 -0.848448 0.180274 +v 5.030630 -0.685104 0.170637 +v 4.960791 -0.521760 0.161000 +v 4.890951 -0.358416 0.151363 +v 4.821112 -0.195073 0.141726 +v 4.751272 -0.031729 0.132089 +v 4.681433 0.131614 0.122452 +v 4.611594 0.294958 0.112814 +v 4.541755 0.458302 0.103178 +v 4.471915 0.621645 0.093540 +v 4.402076 0.784989 0.083903 +v 4.332236 0.948332 0.074266 +v 4.262397 1.111676 0.064629 +v 4.192557 1.275020 0.054992 +v 4.122719 1.438363 0.045355 +v 4.052879 1.601707 0.035718 +v 3.983040 1.765051 0.026081 +v 3.913200 1.928394 0.016444 +v 3.843361 2.091738 0.006807 +v 3.773521 2.255081 -0.002830 +v 3.703682 2.418425 -0.012467 +v 3.633843 2.581769 -0.022104 +v 3.564003 2.745112 -0.031741 +v 3.494164 2.908456 -0.041378 +v 3.424325 3.071799 -0.051015 +v 3.354486 3.235143 -0.060652 +v 3.284646 3.398487 -0.070289 +v 3.214807 3.561830 -0.079926 +v 3.144968 3.725174 -0.089563 +v 3.075128 3.888518 -0.099200 +v 3.005289 4.051861 -0.108838 +v 2.935449 4.215206 -0.118475 +v 2.865610 4.378549 -0.128112 +v 2.795771 4.541893 -0.137749 +v 2.725931 4.705236 -0.147386 +v 2.656092 4.868580 -0.157023 +v 2.586253 5.031924 -0.166660 +v 2.516413 5.195268 -0.176297 +v 2.446574 5.358611 -0.185934 +v 2.376735 5.521955 -0.195571 +v -2.218616 -5.893647 0.551145 +v -2.054993 -5.824019 0.545543 +v -2.288455 -5.730304 0.541508 +v -1.891371 -5.754392 0.539941 +v -2.124833 -5.660676 0.535906 +v -2.358294 -5.566959 0.531871 +v -1.727749 -5.684764 0.534339 +v -1.961210 -5.591048 0.530304 +v -2.194672 -5.497332 0.526269 +v -2.428133 -5.403617 0.522234 +v -1.564127 -5.615136 0.528737 +v -1.797588 -5.521420 0.524702 +v -2.031050 -5.427704 0.520667 +v -2.264511 -5.333989 0.516632 +v -2.497972 -5.240272 0.512597 +v -1.400505 -5.545508 0.523135 +v -1.633966 -5.451793 0.519100 +v -1.867428 -5.358076 0.515065 +v -2.100889 -5.264361 0.511030 +v -2.334351 -5.170644 0.506995 +v -2.567812 -5.076930 0.502960 +v -1.236883 -5.475881 0.517533 +v -1.470344 -5.382164 0.513498 +v -1.703806 -5.288448 0.509463 +v -1.937267 -5.194733 0.505428 +v -2.170728 -5.101017 0.501393 +v -2.404190 -5.007302 0.497358 +v -2.637651 -4.913586 0.493323 +v -1.073261 -5.406252 0.511930 +v -1.306722 -5.312536 0.507895 +v -1.540184 -5.218821 0.503860 +v -1.773645 -5.125105 0.499825 +v -2.007106 -5.031389 0.495791 +v -2.240568 -4.937673 0.491756 +v -2.474029 -4.843958 0.487721 +v -2.707490 -4.750243 0.483686 +v -0.909639 -5.336624 0.506329 +v -1.143100 -5.242908 0.502294 +v -1.376562 -5.149193 0.498259 +v -1.610023 -5.055477 0.494224 +v -1.843484 -4.961761 0.490189 +v -2.076945 -4.868045 0.486154 +v -2.310407 -4.774330 0.482119 +v -2.543869 -4.680614 0.478084 +v -2.777330 -4.586899 0.474049 +v -0.746017 -5.266996 0.500726 +v -0.979478 -5.173281 0.496691 +v -1.212940 -5.079565 0.492656 +v -1.446401 -4.985850 0.488621 +v -1.679862 -4.892134 0.484586 +v -1.913324 -4.798418 0.480551 +v -2.146785 -4.704702 0.476516 +v -2.380247 -4.610986 0.472481 +v -2.613708 -4.517271 0.468446 +v -2.847169 -4.423555 0.464411 +v -0.582395 -5.197369 0.495124 +v -0.815856 -5.103653 0.491089 +v -1.049317 -5.009937 0.487054 +v -1.282779 -4.916221 0.483019 +v -1.516240 -4.822505 0.478984 +v -1.749701 -4.728789 0.474949 +v -1.983163 -4.635074 0.470914 +v -2.216624 -4.541358 0.466880 +v -2.450086 -4.447642 0.462845 +v -2.683547 -4.353927 0.458810 +v -2.917009 -4.260211 0.454775 +v -0.418772 -5.127741 0.489522 +v -0.652234 -5.034025 0.485487 +v -0.885695 -4.940310 0.481452 +v -1.119157 -4.846593 0.477417 +v -1.352618 -4.752878 0.473382 +v -1.586080 -4.659162 0.469347 +v -1.819541 -4.565446 0.465312 +v -2.053002 -4.471730 0.461277 +v -2.286463 -4.378014 0.457242 +v -2.519925 -4.284298 0.453207 +v -2.753386 -4.190583 0.449172 +v -2.986848 -4.096868 0.445138 +v -0.255151 -5.058113 0.483920 +v -0.488612 -4.964397 0.479885 +v -0.722073 -4.870682 0.475850 +v -0.955535 -4.776966 0.471815 +v -1.188996 -4.683250 0.467780 +v -1.422458 -4.589534 0.463745 +v -1.655919 -4.495819 0.459710 +v -1.889380 -4.402102 0.455675 +v -2.122842 -4.308386 0.451640 +v -2.356303 -4.214671 0.447605 +v -2.589765 -4.120955 0.443570 +v -2.823226 -4.027239 0.439535 +v -3.056687 -3.933524 0.435500 +v -0.091529 -4.988485 0.478318 +v -0.324990 -4.894770 0.474283 +v -0.558451 -4.801054 0.470248 +v -0.791913 -4.707338 0.466213 +v -1.025374 -4.613622 0.462178 +v -1.258836 -4.519907 0.458143 +v -1.492297 -4.426191 0.454108 +v -1.725758 -4.332475 0.450073 +v -1.959220 -4.238759 0.446038 +v -2.192681 -4.145043 0.442003 +v -2.426142 -4.051328 0.437968 +v -2.659604 -3.957612 0.433933 +v -2.893065 -3.863896 0.429899 +v -3.126527 -3.770180 0.425864 +v 0.072093 -4.918858 0.472716 +v -0.161368 -4.825142 0.468681 +v -0.394830 -4.731426 0.464646 +v -0.628291 -4.637710 0.460611 +v -0.861752 -4.543994 0.456576 +v -1.095214 -4.450279 0.452541 +v -1.328675 -4.356562 0.448506 +v -1.562136 -4.262847 0.444471 +v -1.795598 -4.169131 0.440436 +v -2.029059 -4.075416 0.436401 +v -2.262521 -3.981699 0.432366 +v -2.495982 -3.887984 0.428331 +v -2.729443 -3.794269 0.424296 +v -2.962905 -3.700552 0.420261 +v -3.196366 -3.606837 0.416226 +v 0.235715 -4.849230 0.467114 +v 0.002254 -4.755514 0.463079 +v -0.231208 -4.661798 0.459044 +v -0.464669 -4.568082 0.455009 +v -0.698130 -4.474367 0.450974 +v -0.931592 -4.380651 0.446939 +v -1.165053 -4.286934 0.442904 +v -1.398514 -4.193219 0.438869 +v -1.631976 -4.099504 0.434834 +v -1.865437 -4.005788 0.430799 +v -2.098898 -3.912072 0.426764 +v -2.332360 -3.818356 0.422729 +v -2.565821 -3.724640 0.418694 +v -2.799283 -3.630925 0.414659 +v -3.032744 -3.537209 0.410624 +v -3.266205 -3.443493 0.406589 +v 0.399337 -4.779602 0.461512 +v 0.165876 -4.685886 0.457477 +v -0.067586 -4.592171 0.453442 +v -0.301047 -4.498455 0.449407 +v -0.534508 -4.404739 0.445372 +v -0.767970 -4.311023 0.441337 +v -1.001431 -4.217307 0.437302 +v -1.234892 -4.123591 0.433267 +v -1.468354 -4.029876 0.429232 +v -1.701815 -3.936160 0.425197 +v -1.935277 -3.842444 0.421162 +v -2.168738 -3.748729 0.417127 +v -2.402199 -3.655013 0.413092 +v -2.635661 -3.561297 0.409057 +v -2.869122 -3.467582 0.405022 +v -3.102583 -3.373866 0.400987 +v -3.336045 -3.280150 0.396952 +v 0.562959 -4.709974 0.455910 +v 0.329498 -4.616258 0.451875 +v 0.096036 -4.522543 0.447840 +v -0.137425 -4.428827 0.443805 +v -0.370887 -4.335111 0.439770 +v -0.604348 -4.241395 0.435735 +v -0.837809 -4.147679 0.431700 +v -1.071271 -4.053964 0.427665 +v -1.304732 -3.960248 0.423630 +v -1.538193 -3.866532 0.419595 +v -1.771655 -3.772816 0.415560 +v -2.005116 -3.679101 0.411525 +v -2.238577 -3.585385 0.407490 +v -2.472039 -3.491669 0.403455 +v -2.705500 -3.397954 0.399420 +v -2.938962 -3.304238 0.395385 +v -3.172423 -3.210522 0.391350 +v -3.405884 -3.116806 0.387315 +v 0.726581 -4.640347 0.450308 +v 0.493120 -4.546630 0.446273 +v 0.259658 -4.452915 0.442238 +v 0.026197 -4.359199 0.438203 +v -0.207264 -4.265483 0.434168 +v -0.440726 -4.171768 0.430133 +v -0.674187 -4.078052 0.426098 +v -0.907648 -3.984335 0.422063 +v -1.141110 -3.890620 0.418028 +v -1.374571 -3.796905 0.413993 +v -1.608033 -3.703188 0.409958 +v -1.841494 -3.609473 0.405923 +v -2.074955 -3.515757 0.401888 +v -2.308417 -3.422041 0.397853 +v -2.541878 -3.328326 0.393818 +v -2.775339 -3.234610 0.389783 +v -3.008801 -3.140894 0.385748 +v -3.242262 -3.047179 0.381713 +v -3.475723 -2.953463 0.377678 +v 0.890203 -4.570719 0.444706 +v 0.656742 -4.477002 0.440671 +v 0.423280 -4.383287 0.436636 +v 0.189819 -4.289571 0.432601 +v -0.043642 -4.195856 0.428566 +v -0.277104 -4.102139 0.424531 +v -0.510565 -4.008424 0.420496 +v -0.744026 -3.914708 0.416461 +v -0.977488 -3.820992 0.412426 +v -1.210949 -3.727276 0.408391 +v -1.444410 -3.633561 0.404356 +v -1.677872 -3.539845 0.400321 +v -1.911333 -3.446129 0.396286 +v -2.144794 -3.352414 0.392251 +v -2.378256 -3.258698 0.388216 +v -2.611717 -3.164982 0.384181 +v -2.845179 -3.071266 0.380146 +v -3.078640 -2.977550 0.376111 +v -3.312101 -2.883835 0.372076 +v -3.545563 -2.790119 0.368041 +v 1.053825 -4.501091 0.439104 +v 0.820364 -4.407374 0.435069 +v 0.586903 -4.313660 0.431034 +v 0.353441 -4.219944 0.426999 +v 0.119980 -4.126228 0.422964 +v -0.113482 -4.032512 0.418929 +v -0.346943 -3.938796 0.414894 +v -0.580405 -3.845080 0.410859 +v -0.813866 -3.751364 0.406824 +v -1.047327 -3.657649 0.402789 +v -1.280789 -3.563933 0.398754 +v -1.514250 -3.470217 0.394719 +v -1.747711 -3.376501 0.390684 +v -1.981173 -3.282785 0.386649 +v -2.214634 -3.189070 0.382614 +v -2.448095 -3.095354 0.378579 +v -2.681557 -3.001638 0.374544 +v -2.915018 -2.907923 0.370509 +v -3.148480 -2.814207 0.366474 +v -3.381941 -2.720491 0.362439 +v -3.615402 -2.626775 0.358404 +v 1.217447 -4.431463 0.433502 +v 0.983986 -4.337747 0.429467 +v 0.750524 -4.244032 0.425432 +v 0.517063 -4.150316 0.421397 +v 0.283602 -4.056600 0.417362 +v 0.050140 -3.962884 0.413327 +v -0.183321 -3.869168 0.409292 +v -0.416783 -3.775452 0.405257 +v -0.650244 -3.681736 0.401222 +v -0.883705 -3.588021 0.397187 +v -1.117167 -3.494305 0.393152 +v -1.350628 -3.400589 0.389117 +v -1.584089 -3.306873 0.385082 +v -1.817551 -3.213157 0.381047 +v -2.051012 -3.119442 0.377012 +v -2.284473 -3.025727 0.372977 +v -2.517935 -2.932010 0.368942 +v -2.751396 -2.838295 0.364907 +v -2.984857 -2.744579 0.360872 +v -3.218319 -2.650863 0.356837 +v -3.451780 -2.557148 0.352802 +v -3.685241 -2.463431 0.348767 +v 1.381069 -4.361835 0.427900 +v 1.147608 -4.268119 0.423865 +v 0.914147 -4.174404 0.419830 +v 0.680685 -4.080688 0.415795 +v 0.447224 -3.986972 0.411760 +v 0.213762 -3.893256 0.407725 +v -0.019699 -3.799540 0.403690 +v -0.253161 -3.705824 0.399655 +v -0.486622 -3.612109 0.395620 +v -0.720084 -3.518393 0.391585 +v -0.953545 -3.424677 0.387550 +v -1.187006 -3.330961 0.383515 +v -1.420467 -3.237246 0.379480 +v -1.653929 -3.143530 0.375445 +v -1.887390 -3.049814 0.371410 +v -2.120852 -2.956098 0.367375 +v -2.354313 -2.862382 0.363340 +v -2.587774 -2.768667 0.359305 +v -2.821235 -2.674951 0.355270 +v -3.054697 -2.581235 0.351235 +v -3.288158 -2.487519 0.347200 +v -3.521620 -2.393804 0.343165 +v -3.755081 -2.300088 0.339130 +v 1.544691 -4.292208 0.422298 +v 1.311230 -4.198491 0.418263 +v 1.077768 -4.104776 0.414228 +v 0.844307 -4.011060 0.410193 +v 0.610846 -3.917344 0.406158 +v 0.377384 -3.823628 0.402123 +v 0.143923 -3.729912 0.398088 +v -0.089539 -3.636197 0.394053 +v -0.323000 -3.542481 0.390018 +v -0.556461 -3.448765 0.385983 +v -0.789923 -3.355049 0.381948 +v -1.023384 -3.261333 0.377913 +v -1.256845 -3.167618 0.373878 +v -1.490307 -3.073902 0.369843 +v -1.723768 -2.980186 0.365808 +v -1.957229 -2.886470 0.361773 +v -2.190691 -2.792754 0.357738 +v -2.424152 -2.699039 0.353703 +v -2.657614 -2.605323 0.349668 +v -2.891075 -2.511607 0.345633 +v -3.124536 -2.417892 0.341598 +v -3.357998 -2.324176 0.337563 +v -3.591459 -2.230460 0.333528 +v -3.824920 -2.136744 0.329493 +v 1.708313 -4.222580 0.416696 +v 1.474852 -4.128863 0.412661 +v 1.241390 -4.035148 0.408626 +v 1.007929 -3.941432 0.404591 +v 0.774468 -3.847716 0.400556 +v 0.541006 -3.754000 0.396521 +v 0.307545 -3.660285 0.392486 +v 0.074084 -3.566569 0.388451 +v -0.159378 -3.472853 0.384416 +v -0.392839 -3.379137 0.380381 +v -0.626301 -3.285421 0.376346 +v -0.859762 -3.191705 0.372311 +v -1.093223 -3.097989 0.368276 +v -1.326685 -3.004274 0.364241 +v -1.560146 -2.910558 0.360206 +v -1.793607 -2.816843 0.356171 +v -2.027069 -2.723127 0.352136 +v -2.260530 -2.629411 0.348101 +v -2.493991 -2.535695 0.344066 +v -2.727453 -2.441979 0.340031 +v -2.960914 -2.348264 0.335996 +v -3.194375 -2.254548 0.331961 +v -3.427837 -2.160832 0.327926 +v -3.661298 -2.067116 0.323891 +v -3.894759 -1.973400 0.319856 +v 1.871935 -4.152952 0.411094 +v 1.638474 -4.059236 0.407059 +v 1.405012 -3.965520 0.403024 +v 1.171551 -3.871805 0.398989 +v 0.938090 -3.778089 0.394954 +v 0.704628 -3.684372 0.390919 +v 0.471167 -3.590657 0.386884 +v 0.237706 -3.496941 0.382849 +v 0.004244 -3.403225 0.378814 +v -0.229217 -3.309509 0.374779 +v -0.462679 -3.215794 0.370744 +v -0.696140 -3.122078 0.366709 +v -0.929602 -3.028362 0.362674 +v -1.163063 -2.934646 0.358639 +v -1.396524 -2.840931 0.354604 +v -1.629985 -2.747215 0.350569 +v -1.863447 -2.653499 0.346534 +v -2.096908 -2.559783 0.342499 +v -2.330369 -2.466068 0.338464 +v -2.563831 -2.372352 0.334429 +v -2.797292 -2.278636 0.330394 +v -3.030753 -2.184920 0.326359 +v -3.264215 -2.091204 0.322324 +v -3.497676 -1.997488 0.318289 +v -3.731138 -1.903773 0.314254 +v -3.964599 -1.810057 0.310219 +v 2.035557 -4.083324 0.405492 +v 1.802096 -3.989609 0.401457 +v 1.568634 -3.895892 0.397422 +v 1.335173 -3.802177 0.393387 +v 1.101712 -3.708461 0.389352 +v 0.868250 -3.614745 0.385317 +v 0.634789 -3.521029 0.381282 +v 0.401328 -3.427313 0.377247 +v 0.167866 -3.333597 0.373212 +v -0.065595 -3.239882 0.369177 +v -0.299057 -3.146165 0.365142 +v -0.532518 -3.052450 0.361107 +v -0.765979 -2.958734 0.357072 +v -0.999441 -2.865018 0.353036 +v -1.232902 -2.771303 0.349001 +v -1.466363 -2.677587 0.344966 +v -1.699825 -2.583871 0.340932 +v -1.933286 -2.490155 0.336897 +v -2.166747 -2.396440 0.332862 +v -2.400209 -2.302724 0.328827 +v -2.633670 -2.209008 0.324792 +v -2.867131 -2.115292 0.320757 +v -3.100593 -2.021576 0.316722 +v -3.334054 -1.927860 0.312687 +v -3.567516 -1.834145 0.308652 +v -3.800977 -1.740429 0.304617 +v -4.034438 -1.646713 0.300582 +v 2.199179 -4.013697 0.399889 +v 1.965718 -3.919981 0.395854 +v 1.732256 -3.826265 0.391819 +v 1.498795 -3.732549 0.387784 +v 1.265334 -3.638833 0.383749 +v 1.031872 -3.545117 0.379714 +v 0.798411 -3.451401 0.375679 +v 0.564950 -3.357686 0.371644 +v 0.331488 -3.263969 0.367610 +v 0.098027 -3.170254 0.363575 +v -0.135435 -3.076538 0.359540 +v -0.368896 -2.982822 0.355505 +v -0.602357 -2.889106 0.351470 +v -0.835819 -2.795390 0.347435 +v -1.069280 -2.701675 0.343400 +v -1.302741 -2.607959 0.339365 +v -1.536203 -2.514243 0.335330 +v -1.769664 -2.420527 0.331295 +v -2.003125 -2.326812 0.327260 +v -2.236587 -2.233096 0.323225 +v -2.470048 -2.139380 0.319190 +v -2.703509 -2.045664 0.315155 +v -2.936971 -1.951948 0.311120 +v -3.170432 -1.858232 0.307085 +v -3.403893 -1.764517 0.303050 +v -3.637355 -1.670801 0.299015 +v -3.870816 -1.577085 0.294980 +v -4.104278 -1.483369 0.290945 +v 2.362801 -3.944069 0.394287 +v 2.129340 -3.850353 0.390253 +v 1.895878 -3.756637 0.386218 +v 1.662417 -3.662921 0.382183 +v 1.428956 -3.569205 0.378148 +v 1.195494 -3.475489 0.374113 +v 0.962033 -3.381773 0.370078 +v 0.728572 -3.288058 0.366043 +v 0.495110 -3.194342 0.362008 +v 0.261649 -3.100626 0.357973 +v 0.028187 -3.006910 0.353938 +v -0.205274 -2.913194 0.349903 +v -0.438735 -2.819478 0.345867 +v -0.672197 -2.725763 0.341832 +v -0.905658 -2.632047 0.337797 +v -1.139120 -2.538331 0.333762 +v -1.372581 -2.444616 0.329727 +v -1.606042 -2.350899 0.325692 +v -1.839504 -2.257183 0.321657 +v -2.072965 -2.163467 0.317622 +v -2.306426 -2.069752 0.313587 +v -2.539887 -1.976036 0.309552 +v -2.773349 -1.882320 0.305517 +v -3.006810 -1.788605 0.301483 +v -3.240271 -1.694889 0.297448 +v -3.473733 -1.601173 0.293413 +v -3.707194 -1.507457 0.289378 +v -3.940656 -1.413742 0.285343 +v -4.174116 -1.320026 0.281308 +v 2.526423 -3.874441 0.388685 +v 2.292962 -3.780725 0.384650 +v 2.059500 -3.687009 0.380615 +v 1.826039 -3.593294 0.376580 +v 1.592578 -3.499577 0.372545 +v 1.359116 -3.405861 0.368510 +v 1.125655 -3.312146 0.364475 +v 0.892194 -3.218430 0.360440 +v 0.658732 -3.124714 0.356405 +v 0.425271 -3.030998 0.352371 +v 0.191809 -2.937282 0.348336 +v -0.041652 -2.843566 0.344300 +v -0.275113 -2.749850 0.340265 +v -0.508575 -2.656135 0.336230 +v -0.742036 -2.562419 0.332195 +v -0.975497 -2.468703 0.328160 +v -1.208959 -2.374988 0.324125 +v -1.442420 -2.281271 0.320090 +v -1.675881 -2.187556 0.316055 +v -1.909343 -2.093840 0.312021 +v -2.142804 -2.000124 0.307986 +v -2.376266 -1.906408 0.303951 +v -2.609727 -1.812692 0.299916 +v -2.843188 -1.718977 0.295881 +v -3.076649 -1.625261 0.291846 +v -3.310111 -1.531545 0.287811 +v -3.543572 -1.437829 0.283776 +v -3.777034 -1.344114 0.279741 +v -4.010494 -1.250398 0.275706 +v -4.243956 -1.156682 0.271671 +v 2.690045 -3.804814 0.383083 +v 2.456584 -3.711097 0.379048 +v 2.223123 -3.617381 0.375013 +v 1.989661 -3.523665 0.370978 +v 1.756200 -3.429949 0.366943 +v 1.522738 -3.336234 0.362908 +v 1.289277 -3.242518 0.358873 +v 1.055816 -3.148802 0.354838 +v 0.822354 -3.055086 0.350803 +v 0.588893 -2.961370 0.346768 +v 0.355431 -2.867654 0.342733 +v 0.121970 -2.773938 0.338698 +v -0.111491 -2.680223 0.334663 +v -0.344953 -2.586506 0.330628 +v -0.578414 -2.492791 0.326593 +v -0.811875 -2.399075 0.322558 +v -1.045337 -2.305359 0.318523 +v -1.278798 -2.211644 0.314488 +v -1.512259 -2.117928 0.310453 +v -1.745721 -2.024212 0.306418 +v -1.979182 -1.930496 0.302383 +v -2.212643 -1.836780 0.298348 +v -2.446105 -1.743064 0.294313 +v -2.679566 -1.649349 0.290278 +v -2.913028 -1.555633 0.286243 +v -3.146489 -1.461917 0.282208 +v -3.379950 -1.368201 0.278173 +v -3.613411 -1.274486 0.274138 +v -3.846873 -1.180770 0.270103 +v -4.080334 -1.087054 0.266068 +v -4.313795 -0.993338 0.262033 +v 2.853667 -3.735186 0.377481 +v 2.620206 -3.641469 0.373446 +v 2.386744 -3.547754 0.369411 +v 2.153283 -3.454038 0.365376 +v 1.919822 -3.360322 0.361341 +v 1.686360 -3.266606 0.357306 +v 1.452899 -3.172890 0.353271 +v 1.219437 -3.079174 0.349236 +v 0.985976 -2.985458 0.345201 +v 0.752515 -2.891742 0.341166 +v 0.519053 -2.798027 0.337131 +v 0.285592 -2.704310 0.333096 +v 0.052131 -2.610595 0.329061 +v -0.181331 -2.516879 0.325026 +v -0.414792 -2.423163 0.320991 +v -0.648253 -2.329447 0.316956 +v -0.881715 -2.235731 0.312921 +v -1.115176 -2.142015 0.308886 +v -1.348638 -2.048300 0.304851 +v -1.582099 -1.954584 0.300816 +v -1.815560 -1.860868 0.296781 +v -2.049021 -1.767152 0.292746 +v -2.282483 -1.673437 0.288711 +v -2.515944 -1.579721 0.284676 +v -2.749406 -1.486005 0.280641 +v -2.982867 -1.392290 0.276606 +v -3.216328 -1.298574 0.272572 +v -3.449790 -1.204858 0.268537 +v -3.683251 -1.111142 0.264502 +v -3.916712 -1.017426 0.260467 +v -4.150173 -0.923711 0.256432 +v -4.383635 -0.829995 0.252397 +v 3.017289 -3.665558 0.371879 +v 2.783828 -3.571841 0.367844 +v 2.550366 -3.478126 0.363809 +v 2.316905 -3.384410 0.359774 +v 2.083444 -3.290694 0.355739 +v 1.849982 -3.196978 0.351704 +v 1.616521 -3.103262 0.347669 +v 1.383060 -3.009546 0.343634 +v 1.149598 -2.915830 0.339599 +v 0.916137 -2.822114 0.335564 +v 0.682675 -2.728399 0.331529 +v 0.449214 -2.634683 0.327494 +v 0.215753 -2.540967 0.323459 +v -0.017709 -2.447251 0.319424 +v -0.251170 -2.353535 0.315389 +v -0.484631 -2.259820 0.311354 +v -0.718093 -2.166104 0.307319 +v -0.951554 -2.072388 0.303284 +v -1.185016 -1.978672 0.299249 +v -1.418477 -1.884956 0.295214 +v -1.651938 -1.791241 0.291179 +v -1.885400 -1.697525 0.287144 +v -2.118861 -1.603809 0.283109 +v -2.352322 -1.510093 0.279074 +v -2.585784 -1.416377 0.275039 +v -2.819245 -1.322662 0.271004 +v -3.052706 -1.228946 0.266969 +v -3.286168 -1.135230 0.262934 +v -3.519629 -1.041514 0.258899 +v -3.753090 -0.947798 0.254864 +v -3.986552 -0.854083 0.250829 +v -4.220013 -0.760367 0.246794 +v -4.453474 -0.666651 0.242759 +v 3.180911 -3.595930 0.366277 +v 2.947450 -3.502214 0.362242 +v 2.713988 -3.408498 0.358207 +v 2.480527 -3.314782 0.354172 +v 2.247066 -3.221066 0.350137 +v 2.013604 -3.127350 0.346102 +v 1.780143 -3.033635 0.342067 +v 1.546681 -2.939919 0.338032 +v 1.313220 -2.846202 0.333997 +v 1.079759 -2.752487 0.329962 +v 0.846297 -2.658771 0.325927 +v 0.612836 -2.565055 0.321892 +v 0.379375 -2.471339 0.317857 +v 0.145913 -2.377623 0.313822 +v -0.087548 -2.283908 0.309787 +v -0.321009 -2.190192 0.305752 +v -0.554471 -2.096476 0.301717 +v -0.787932 -2.002760 0.297682 +v -1.021394 -1.909044 0.293647 +v -1.254855 -1.815328 0.289612 +v -1.488316 -1.721613 0.285577 +v -1.721778 -1.627897 0.281542 +v -1.955239 -1.534181 0.277507 +v -2.188700 -1.440465 0.273472 +v -2.422162 -1.346750 0.269437 +v -2.655623 -1.253034 0.265402 +v -2.889084 -1.159318 0.261367 +v -3.122546 -1.065602 0.257332 +v -3.356007 -0.971886 0.253297 +v -3.589468 -0.878170 0.249262 +v -3.822929 -0.784455 0.245227 +v -4.056391 -0.690739 0.241192 +v -4.289852 -0.597024 0.237157 +v -4.523314 -0.503308 0.233122 +v 3.344533 -3.526303 0.360675 +v 3.111072 -3.432586 0.356640 +v 2.877610 -3.338870 0.352605 +v 2.644149 -3.245154 0.348570 +v 2.410687 -3.151438 0.344535 +v 2.177226 -3.057723 0.340500 +v 1.943765 -2.964007 0.336465 +v 1.710303 -2.870291 0.332430 +v 1.476842 -2.776575 0.328395 +v 1.243381 -2.682859 0.324360 +v 1.009919 -2.589143 0.320325 +v 0.776458 -2.495427 0.316290 +v 0.542997 -2.401711 0.312255 +v 0.309535 -2.307995 0.308220 +v 0.076074 -2.214280 0.304185 +v -0.157387 -2.120564 0.300150 +v -0.390849 -2.026848 0.296115 +v -0.624310 -1.933132 0.292080 +v -0.857772 -1.839417 0.288045 +v -1.091233 -1.745700 0.284010 +v -1.324694 -1.651985 0.279975 +v -1.558156 -1.558269 0.275940 +v -1.791617 -1.464553 0.271905 +v -2.025078 -1.370837 0.267870 +v -2.258540 -1.277122 0.263835 +v -2.492001 -1.183406 0.259800 +v -2.725462 -1.089690 0.255765 +v -2.958924 -0.995974 0.251730 +v -3.192385 -0.902259 0.247695 +v -3.425846 -0.808543 0.243660 +v -3.659307 -0.714827 0.239625 +v -3.892769 -0.621111 0.235590 +v -4.126230 -0.527396 0.231555 +v -4.359692 -0.433680 0.227520 +v -4.593153 -0.339964 0.223485 +v 3.508155 -3.456674 0.355073 +v 3.274693 -3.362958 0.351038 +v 3.041232 -3.269243 0.347003 +v 2.807771 -3.175527 0.342968 +v 2.574309 -3.081810 0.338933 +v 2.340848 -2.988095 0.334898 +v 2.107387 -2.894379 0.330863 +v 1.873925 -2.800663 0.326828 +v 1.640464 -2.706947 0.322793 +v 1.407002 -2.613231 0.318758 +v 1.173541 -2.519516 0.314723 +v 0.940080 -2.425799 0.310688 +v 0.706618 -2.332083 0.306653 +v 0.473157 -2.238368 0.302618 +v 0.239696 -2.144652 0.298583 +v 0.006234 -2.050936 0.294548 +v -0.227227 -1.957220 0.290513 +v -0.460688 -1.863505 0.286478 +v -0.694150 -1.769789 0.282443 +v -0.927611 -1.676073 0.278408 +v -1.161072 -1.582357 0.274373 +v -1.394534 -1.488641 0.270338 +v -1.627995 -1.394925 0.266303 +v -1.861456 -1.301210 0.262268 +v -2.094918 -1.207494 0.258233 +v -2.328379 -1.113778 0.254198 +v -2.561840 -1.020062 0.250163 +v -2.795302 -0.926347 0.246128 +v -3.028763 -0.832631 0.242093 +v -3.262224 -0.738915 0.238058 +v -3.495686 -0.645199 0.234023 +v -3.729147 -0.551483 0.229988 +v -3.962608 -0.457768 0.225953 +v -4.196070 -0.364052 0.221918 +v -4.429531 -0.270336 0.217883 +v -4.662992 -0.176620 0.213848 +v 3.671777 -3.387047 0.349471 +v 3.438316 -3.293330 0.345436 +v 3.204854 -3.199615 0.341401 +v 2.971393 -3.105899 0.337366 +v 2.737931 -3.012183 0.333331 +v 2.504470 -2.918467 0.329296 +v 2.271009 -2.824751 0.325261 +v 2.037547 -2.731035 0.321226 +v 1.804086 -2.637319 0.317191 +v 1.570624 -2.543603 0.313156 +v 1.337163 -2.449888 0.309121 +v 1.103702 -2.356172 0.305086 +v 0.870240 -2.262455 0.301051 +v 0.636779 -2.168740 0.297016 +v 0.403318 -2.075024 0.292981 +v 0.169856 -1.981308 0.288946 +v -0.063605 -1.887592 0.284911 +v -0.297066 -1.793877 0.280876 +v -0.530528 -1.700161 0.276841 +v -0.763989 -1.606445 0.272806 +v -0.997450 -1.512729 0.268771 +v -1.230912 -1.419013 0.264736 +v -1.464373 -1.325298 0.260701 +v -1.697834 -1.231582 0.256666 +v -1.931295 -1.137866 0.252631 +v -2.164757 -1.044150 0.248596 +v -2.398218 -0.950434 0.244561 +v -2.631680 -0.856719 0.240526 +v -2.865141 -0.763003 0.236491 +v -3.098603 -0.669287 0.232456 +v -3.332064 -0.575571 0.228421 +v -3.565525 -0.481856 0.224386 +v -3.798986 -0.388140 0.220351 +v -4.032447 -0.294424 0.216316 +v -4.265909 -0.200708 0.212281 +v -4.499370 -0.106993 0.208246 +v -4.732831 -0.013277 0.204211 +v 3.835399 -3.317418 0.343869 +v 3.601938 -3.223703 0.339834 +v 3.368476 -3.129987 0.335799 +v 3.135015 -3.036271 0.331764 +v 2.901554 -2.942555 0.327729 +v 2.668092 -2.848839 0.323694 +v 2.434631 -2.755123 0.319659 +v 2.201169 -2.661407 0.315624 +v 1.967708 -2.567691 0.311589 +v 1.734246 -2.473976 0.307554 +v 1.500785 -2.380260 0.303519 +v 1.267324 -2.286544 0.299484 +v 1.033862 -2.192828 0.295449 +v 0.800401 -2.099112 0.291414 +v 0.566940 -2.005396 0.287379 +v 0.333478 -1.911680 0.283344 +v 0.100017 -1.817965 0.279309 +v -0.133444 -1.724249 0.275274 +v -0.366906 -1.630533 0.271239 +v -0.600367 -1.536817 0.267204 +v -0.833828 -1.443102 0.263169 +v -1.067290 -1.349386 0.259134 +v -1.300751 -1.255670 0.255099 +v -1.534212 -1.161954 0.251064 +v -1.767674 -1.068238 0.247029 +v -2.001135 -0.974522 0.242994 +v -2.234596 -0.880807 0.238959 +v -2.468058 -0.787091 0.234924 +v -2.701519 -0.693375 0.230889 +v -2.934980 -0.599659 0.226854 +v -3.168442 -0.505944 0.222819 +v -3.401903 -0.412228 0.218784 +v -3.635364 -0.318512 0.214749 +v -3.868825 -0.224796 0.210714 +v -4.102286 -0.131081 0.206679 +v -4.335748 -0.037365 0.202644 +v -4.569209 0.056351 0.198609 +v -4.802670 0.150067 0.194574 +v 3.999021 -3.247791 0.338267 +v 3.765560 -3.154075 0.334232 +v 3.532098 -3.060359 0.330197 +v 3.298637 -2.966643 0.326162 +v 3.065176 -2.872927 0.322127 +v 2.831714 -2.779212 0.318092 +v 2.598253 -2.685495 0.314057 +v 2.364791 -2.591780 0.310022 +v 2.131330 -2.498064 0.305987 +v 1.897868 -2.404348 0.301952 +v 1.664407 -2.310632 0.297917 +v 1.430946 -2.216916 0.293882 +v 1.197484 -2.123200 0.289847 +v 0.964023 -2.029484 0.285812 +v 0.730562 -1.935768 0.281777 +v 0.497100 -1.842052 0.277742 +v 0.263639 -1.748337 0.273707 +v 0.030178 -1.654621 0.269672 +v -0.203284 -1.560905 0.265637 +v -0.436745 -1.467189 0.261602 +v -0.670206 -1.373474 0.257567 +v -0.903668 -1.279758 0.253532 +v -1.137129 -1.186042 0.249497 +v -1.370590 -1.092326 0.245462 +v -1.604052 -0.998610 0.241427 +v -1.837513 -0.904895 0.237392 +v -2.070974 -0.811179 0.233357 +v -2.304435 -0.717463 0.229322 +v -2.537897 -0.623747 0.225287 +v -2.771358 -0.530031 0.221252 +v -3.004820 -0.436316 0.217217 +v -3.238281 -0.342600 0.213182 +v -3.471742 -0.248884 0.209147 +v -3.705204 -0.155168 0.205112 +v -3.938665 -0.061453 0.201077 +v -4.172126 0.032263 0.197042 +v -4.405587 0.125979 0.193007 +v -4.639049 0.219695 0.188972 +v -4.872510 0.313411 0.184937 +v 4.162643 -3.178163 0.332665 +v 3.929182 -3.084447 0.328630 +v 3.695721 -2.990731 0.324595 +v 3.462259 -2.897015 0.320560 +v 3.228797 -2.803299 0.316525 +v 2.995336 -2.709584 0.312490 +v 2.761875 -2.615868 0.308455 +v 2.528413 -2.522151 0.304420 +v 2.294952 -2.428436 0.300385 +v 2.061491 -2.334720 0.296350 +v 1.828029 -2.241004 0.292315 +v 1.594568 -2.147288 0.288280 +v 1.361106 -2.053572 0.284245 +v 1.127645 -1.959856 0.280210 +v 0.894184 -1.866141 0.276175 +v 0.660722 -1.772425 0.272140 +v 0.427261 -1.678709 0.268105 +v 0.193800 -1.584993 0.264070 +v -0.039662 -1.491277 0.260035 +v -0.273123 -1.397561 0.256000 +v -0.506584 -1.303846 0.251965 +v -0.740046 -1.210130 0.247930 +v -0.973507 -1.116414 0.243895 +v -1.206968 -1.022698 0.239860 +v -1.440430 -0.928983 0.235825 +v -1.673891 -0.835267 0.231790 +v -1.907352 -0.741551 0.227755 +v -2.140813 -0.647835 0.223720 +v -2.374275 -0.554119 0.219685 +v -2.607736 -0.460404 0.215650 +v -2.841197 -0.366688 0.211615 +v -3.074659 -0.272972 0.207580 +v -3.308120 -0.179256 0.203545 +v -3.541582 -0.085541 0.199510 +v -3.775043 0.008175 0.195475 +v -4.008504 0.101891 0.191440 +v -4.241965 0.195607 0.187405 +v -4.475427 0.289323 0.183370 +v -4.708888 0.383039 0.179335 +v -4.942349 0.476755 0.175300 +v 4.326265 -3.108535 0.327063 +v 4.092804 -3.014819 0.323028 +v 3.859343 -2.921103 0.318993 +v 3.625881 -2.827387 0.314958 +v 3.392420 -2.733672 0.310923 +v 3.158958 -2.639956 0.306888 +v 2.925497 -2.546240 0.302853 +v 2.692035 -2.452524 0.298818 +v 2.458574 -2.358808 0.294783 +v 2.225112 -2.265092 0.290748 +v 1.991651 -2.171377 0.286713 +v 1.758190 -2.077660 0.282678 +v 1.524728 -1.983944 0.278643 +v 1.291267 -1.890228 0.274608 +v 1.057806 -1.796513 0.270573 +v 0.824344 -1.702797 0.266538 +v 0.590883 -1.609081 0.262503 +v 0.357422 -1.515365 0.258468 +v 0.123960 -1.421649 0.254433 +v -0.109501 -1.327934 0.250398 +v -0.342962 -1.234218 0.246363 +v -0.576424 -1.140502 0.242328 +v -0.809885 -1.046786 0.238293 +v -1.043346 -0.953071 0.234258 +v -1.276808 -0.859355 0.230223 +v -1.510269 -0.765639 0.226188 +v -1.743730 -0.671923 0.222153 +v -1.977192 -0.578207 0.218118 +v -2.210653 -0.484491 0.214083 +v -2.444114 -0.390776 0.210048 +v -2.677576 -0.297060 0.206013 +v -2.911037 -0.203344 0.201978 +v -3.144498 -0.109628 0.197943 +v -3.377960 -0.015913 0.193908 +v -3.611421 0.077803 0.189873 +v -3.844882 0.171519 0.185838 +v -4.078343 0.265235 0.181803 +v -4.311805 0.358951 0.177768 +v -4.545266 0.452667 0.173733 +v -4.778728 0.546382 0.169698 +v -5.012189 0.640098 0.165663 +v 4.489887 -3.038907 0.321461 +v 4.256426 -2.945192 0.317426 +v 4.022964 -2.851475 0.313390 +v 3.789503 -2.757760 0.309355 +v 3.556042 -2.664043 0.305321 +v 3.322580 -2.570328 0.301286 +v 3.089119 -2.476612 0.297251 +v 2.855658 -2.382896 0.293216 +v 2.622196 -2.289180 0.289181 +v 2.388735 -2.195465 0.285146 +v 2.155273 -2.101748 0.281111 +v 1.921812 -2.008032 0.277076 +v 1.688350 -1.914317 0.273041 +v 1.454889 -1.820600 0.269006 +v 1.221428 -1.726885 0.264971 +v 0.987966 -1.633169 0.260936 +v 0.754505 -1.539453 0.256901 +v 0.521044 -1.445737 0.252866 +v 0.287582 -1.352022 0.248831 +v 0.054121 -1.258306 0.244796 +v -0.179340 -1.164590 0.240761 +v -0.412802 -1.070874 0.236726 +v -0.646263 -0.977158 0.232691 +v -0.879724 -0.883443 0.228656 +v -1.113186 -0.789727 0.224621 +v -1.346647 -0.696011 0.220586 +v -1.580108 -0.602295 0.216551 +v -1.813570 -0.508579 0.212516 +v -2.047031 -0.414864 0.208481 +v -2.280492 -0.321148 0.204446 +v -2.513954 -0.227432 0.200411 +v -2.747415 -0.133716 0.196376 +v -2.980876 -0.040001 0.192341 +v -3.214338 0.053715 0.188306 +v -3.447799 0.147431 0.184271 +v -3.681260 0.241147 0.180236 +v -3.914722 0.334863 0.176201 +v -4.148183 0.428579 0.172166 +v -4.381644 0.522295 0.168131 +v -4.615106 0.616011 0.164096 +v -4.848567 0.709726 0.160061 +v -5.082028 0.803442 0.156026 +v 4.653510 -2.969280 0.315859 +v 4.420048 -2.875564 0.311824 +v 4.186587 -2.781847 0.307789 +v 3.953125 -2.688132 0.303754 +v 3.719664 -2.594416 0.299719 +v 3.486202 -2.500700 0.295684 +v 3.252741 -2.406984 0.291649 +v 3.019279 -2.313268 0.287614 +v 2.785818 -2.219553 0.283579 +v 2.552357 -2.125836 0.279544 +v 2.318895 -2.032120 0.275509 +v 2.085434 -1.938404 0.271474 +v 1.851972 -1.844689 0.267439 +v 1.618511 -1.750973 0.263404 +v 1.385050 -1.657257 0.259369 +v 1.151588 -1.563541 0.255334 +v 0.918127 -1.469826 0.251299 +v 0.684666 -1.376110 0.247264 +v 0.451204 -1.282394 0.243229 +v 0.217743 -1.188678 0.239194 +v -0.015718 -1.094962 0.235159 +v -0.249180 -1.001246 0.231124 +v -0.482641 -0.907531 0.227089 +v -0.716102 -0.813815 0.223054 +v -0.949564 -0.720099 0.219019 +v -1.183025 -0.626383 0.214984 +v -1.416486 -0.532667 0.210949 +v -1.649948 -0.438952 0.206914 +v -1.883409 -0.345236 0.202879 +v -2.116870 -0.251520 0.198844 +v -2.350331 -0.157804 0.194809 +v -2.583793 -0.064088 0.190774 +v -2.817254 0.029627 0.186739 +v -3.050715 0.123343 0.182704 +v -3.284177 0.217059 0.178669 +v -3.517638 0.310775 0.174634 +v -3.751100 0.404491 0.170599 +v -3.984561 0.498207 0.166564 +v -4.218022 0.591923 0.162529 +v -4.451484 0.685638 0.158494 +v -4.684945 0.779354 0.154459 +v -4.918406 0.873070 0.150424 +v -5.151868 0.966786 0.146389 +v 4.817132 -2.899652 0.310257 +v 4.583670 -2.805936 0.306221 +v 4.350208 -2.712219 0.302186 +v 4.116747 -2.618504 0.298151 +v 3.883286 -2.524788 0.294116 +v 3.649824 -2.431072 0.290082 +v 3.416363 -2.337356 0.286047 +v 3.182901 -2.243640 0.282012 +v 2.949440 -2.149925 0.277977 +v 2.715979 -2.056208 0.273942 +v 2.482517 -1.962493 0.269907 +v 2.249056 -1.868777 0.265872 +v 2.015594 -1.775061 0.261837 +v 1.782133 -1.681345 0.257802 +v 1.548671 -1.587629 0.253767 +v 1.315210 -1.493914 0.249732 +v 1.081749 -1.400198 0.245697 +v 0.848288 -1.306482 0.241662 +v 0.614826 -1.212766 0.237627 +v 0.381365 -1.119050 0.233592 +v 0.147904 -1.025334 0.229557 +v -0.085558 -0.931619 0.225522 +v -0.319019 -0.837903 0.221487 +v -0.552480 -0.744187 0.217452 +v -0.785942 -0.650471 0.213417 +v -1.019403 -0.556755 0.209382 +v -1.252864 -0.463039 0.205347 +v -1.486326 -0.369324 0.201312 +v -1.719787 -0.275608 0.197277 +v -1.953248 -0.181892 0.193242 +v -2.186710 -0.088176 0.189207 +v -2.420171 0.005539 0.185172 +v -2.653632 0.099255 0.181137 +v -2.887094 0.192971 0.177102 +v -3.120555 0.286687 0.173067 +v -3.354016 0.380403 0.169032 +v -3.587478 0.474118 0.164997 +v -3.820939 0.567834 0.160962 +v -4.054400 0.661550 0.156927 +v -4.287862 0.755266 0.152892 +v -4.521323 0.848982 0.148857 +v -4.754785 0.942698 0.144822 +v -4.988246 1.036414 0.140787 +v -5.221706 1.130129 0.136752 +v 4.980753 -2.830024 0.304654 +v 4.747292 -2.736308 0.300619 +v 4.513830 -2.642592 0.296584 +v 4.280369 -2.548876 0.292549 +v 4.046907 -2.455160 0.288514 +v 3.813446 -2.361444 0.284479 +v 3.579985 -2.267728 0.280444 +v 3.346523 -2.174013 0.276409 +v 3.113062 -2.080297 0.272375 +v 2.879601 -1.986581 0.268340 +v 2.646139 -1.892865 0.264305 +v 2.412678 -1.799149 0.260270 +v 2.179216 -1.705433 0.256235 +v 1.945755 -1.611717 0.252200 +v 1.712294 -1.518002 0.248165 +v 1.478832 -1.424286 0.244130 +v 1.245371 -1.330570 0.240095 +v 1.011909 -1.236854 0.236060 +v 0.778448 -1.143138 0.232025 +v 0.544987 -1.049423 0.227990 +v 0.311526 -0.955707 0.223955 +v 0.078064 -0.861991 0.219920 +v -0.155397 -0.768275 0.215885 +v -0.388859 -0.674559 0.211850 +v -0.622320 -0.580843 0.207815 +v -0.855781 -0.487128 0.203780 +v -1.089242 -0.393412 0.199745 +v -1.322704 -0.299696 0.195710 +v -1.556165 -0.205980 0.191675 +v -1.789626 -0.112264 0.187640 +v -2.023088 -0.018548 0.183605 +v -2.256549 0.075167 0.179570 +v -2.490010 0.168883 0.175535 +v -2.723472 0.262599 0.171500 +v -2.956933 0.356315 0.167465 +v -3.190394 0.450030 0.163430 +v -3.423856 0.543746 0.159395 +v -3.657317 0.637462 0.155360 +v -3.890779 0.731178 0.151325 +v -4.124240 0.824894 0.147290 +v -4.357701 0.918610 0.143255 +v -4.591162 1.012325 0.139220 +v -4.824624 1.106042 0.135185 +v -5.058085 1.199757 0.131150 +v -5.291546 1.293473 0.127115 +v 5.144376 -2.760396 0.299052 +v 4.910913 -2.666680 0.295017 +v 4.677453 -2.572964 0.290982 +v 4.443991 -2.479249 0.286947 +v 4.210530 -2.385532 0.282912 +v 3.977068 -2.291817 0.278877 +v 3.743607 -2.198101 0.274843 +v 3.510145 -2.104385 0.270808 +v 3.276684 -2.010669 0.266773 +v 3.043222 -1.916953 0.262738 +v 2.809761 -1.823237 0.258703 +v 2.576299 -1.729521 0.254668 +v 2.342838 -1.635805 0.250633 +v 2.109377 -1.542089 0.246598 +v 1.875915 -1.448374 0.242563 +v 1.642454 -1.354658 0.238528 +v 1.408993 -1.260942 0.234493 +v 1.175532 -1.167226 0.230458 +v 0.942070 -1.073511 0.226423 +v 0.708609 -0.979795 0.222388 +v 0.475148 -0.886079 0.218353 +v 0.241686 -0.792363 0.214318 +v 0.008225 -0.698647 0.210283 +v -0.225236 -0.604931 0.206248 +v -0.458698 -0.511216 0.202213 +v -0.692159 -0.417500 0.198178 +v -0.925620 -0.323784 0.194143 +v -1.159082 -0.230068 0.190108 +v -1.392543 -0.136352 0.186073 +v -1.626004 -0.042636 0.182038 +v -1.859466 0.051079 0.178003 +v -2.092927 0.144795 0.173968 +v -2.326388 0.238511 0.169933 +v -2.559850 0.332227 0.165898 +v -2.793311 0.425943 0.161863 +v -3.026772 0.519658 0.157828 +v -3.260234 0.613374 0.153793 +v -3.493695 0.707090 0.149758 +v -3.727157 0.800806 0.145723 +v -3.960618 0.894522 0.141688 +v -4.194079 0.988238 0.137653 +v -4.427540 1.081954 0.133618 +v -4.661001 1.175669 0.129583 +v -4.894464 1.269385 0.125548 +v -5.127924 1.363101 0.121513 +v -5.361385 1.456817 0.117478 +v 5.307998 -2.690768 0.293450 +v 5.074536 -2.597052 0.289415 +v 4.841075 -2.503336 0.285380 +v 4.607614 -2.409621 0.281345 +v 4.374152 -2.315905 0.277310 +v 4.140691 -2.222188 0.273275 +v 3.907229 -2.128473 0.269240 +v 3.673767 -2.034757 0.265205 +v 3.440306 -1.941041 0.261170 +v 3.206845 -1.847325 0.257135 +v 2.973383 -1.753609 0.253100 +v 2.739922 -1.659893 0.249065 +v 2.506460 -1.566177 0.245030 +v 2.272999 -1.472462 0.240995 +v 2.039538 -1.378746 0.236960 +v 1.806076 -1.285030 0.232925 +v 1.572615 -1.191314 0.228890 +v 1.339153 -1.097599 0.224855 +v 1.105692 -1.003883 0.220821 +v 0.872231 -0.910167 0.216786 +v 0.638770 -0.816451 0.212751 +v 0.405308 -0.722735 0.208716 +v 0.171847 -0.629019 0.204681 +v -0.061614 -0.535303 0.200646 +v -0.295076 -0.441588 0.196611 +v -0.528537 -0.347872 0.192576 +v -0.761998 -0.254156 0.188541 +v -0.995460 -0.160440 0.184506 +v -1.228921 -0.066724 0.180471 +v -1.462382 0.026991 0.176436 +v -1.695844 0.120707 0.172401 +v -1.929305 0.214423 0.168366 +v -2.162766 0.308139 0.164331 +v -2.396228 0.401855 0.160296 +v -2.629689 0.495571 0.156261 +v -2.863150 0.589286 0.152226 +v -3.096612 0.683002 0.148191 +v -3.330073 0.776718 0.144156 +v -3.563535 0.870434 0.140121 +v -3.796996 0.964150 0.136086 +v -4.030457 1.057866 0.132051 +v -4.263918 1.151582 0.128016 +v -4.497379 1.245297 0.123981 +v -4.730841 1.339013 0.119946 +v -4.964303 1.432729 0.115911 +v -5.197763 1.526445 0.111876 +v -5.431225 1.620160 0.107841 +v 5.471620 -2.621141 0.287848 +v 5.238158 -2.527424 0.283813 +v 5.004697 -2.433708 0.279778 +v 4.771235 -2.339993 0.275743 +v 4.537774 -2.246277 0.271708 +v 4.304313 -2.152560 0.267673 +v 4.070851 -2.058845 0.263638 +v 3.837389 -1.965129 0.259603 +v 3.603928 -1.871413 0.255568 +v 3.370467 -1.777697 0.251533 +v 3.137005 -1.683981 0.247498 +v 2.903544 -1.590265 0.243463 +v 2.670082 -1.496549 0.239429 +v 2.436621 -1.402834 0.235394 +v 2.203160 -1.309118 0.231359 +v 1.969698 -1.215402 0.227324 +v 1.736237 -1.121686 0.223289 +v 1.502776 -1.027971 0.219254 +v 1.269314 -0.934255 0.215219 +v 1.035853 -0.840539 0.211184 +v 0.802391 -0.746823 0.207149 +v 0.568930 -0.653107 0.203114 +v 0.335469 -0.559391 0.199079 +v 0.102008 -0.465676 0.195044 +v -0.131454 -0.371960 0.191009 +v -0.364915 -0.278244 0.186974 +v -0.598377 -0.184528 0.182939 +v -0.831838 -0.090812 0.178904 +v -1.065299 0.002903 0.174869 +v -1.298761 0.096619 0.170834 +v -1.532222 0.190335 0.166799 +v -1.765683 0.284051 0.162764 +v -1.999144 0.377767 0.158729 +v -2.232605 0.471483 0.154694 +v -2.466067 0.565198 0.150659 +v -2.699528 0.658914 0.146624 +v -2.932990 0.752630 0.142589 +v -3.166451 0.846346 0.138554 +v -3.399912 0.940062 0.134519 +v -3.633374 1.033778 0.130484 +v -3.866836 1.127494 0.126449 +v -4.100297 1.221209 0.122414 +v -4.333757 1.314925 0.118379 +v -4.567219 1.408641 0.114344 +v -4.800680 1.502357 0.110309 +v -5.034142 1.596073 0.106274 +v -5.267603 1.689788 0.102239 +v -5.501064 1.783504 0.098204 +v 5.635241 -2.551513 0.282246 +v 5.401779 -2.457797 0.278211 +v 5.168319 -2.364081 0.274176 +v 4.934856 -2.270365 0.270141 +v 4.701396 -2.176649 0.266106 +v 4.467934 -2.082933 0.262071 +v 4.234472 -1.989217 0.258036 +v 4.001011 -1.895501 0.254001 +v 3.767550 -1.801785 0.249966 +v 3.534088 -1.708070 0.245931 +v 3.300627 -1.614354 0.241896 +v 3.067165 -1.520638 0.237861 +v 2.833704 -1.426922 0.233826 +v 2.600243 -1.333206 0.229791 +v 2.366781 -1.239491 0.225756 +v 2.133320 -1.145774 0.221721 +v 1.899859 -1.052059 0.217686 +v 1.666397 -0.958343 0.213651 +v 1.432936 -0.864627 0.209616 +v 1.199475 -0.770911 0.205581 +v 0.966013 -0.677196 0.201546 +v 0.732552 -0.583480 0.197511 +v 0.499091 -0.489764 0.193476 +v 0.265629 -0.396048 0.189441 +v 0.032168 -0.302332 0.185406 +v -0.201293 -0.208616 0.181371 +v -0.434755 -0.114901 0.177336 +v -0.668216 -0.021185 0.173302 +v -0.901677 0.072531 0.169267 +v -1.135139 0.166247 0.165232 +v -1.368600 0.259963 0.161197 +v -1.602061 0.353679 0.157162 +v -1.835523 0.447395 0.153127 +v -2.068984 0.541110 0.149092 +v -2.302445 0.634826 0.145057 +v -2.535906 0.728542 0.141022 +v -2.769368 0.822258 0.136987 +v -3.002829 0.915974 0.132952 +v -3.236290 1.009689 0.128917 +v -3.469752 1.103406 0.124882 +v -3.703213 1.197121 0.120847 +v -3.936675 1.290837 0.116812 +v -4.170135 1.384553 0.112777 +v -4.403597 1.478269 0.108742 +v -4.637058 1.571984 0.104707 +v -4.870520 1.665701 0.100672 +v -5.103981 1.759416 0.096637 +v -5.337442 1.853132 0.092602 +v -5.570904 1.946848 0.088567 +vn 0.0077 0.0622 0.9980 +usemtl None +s off +f 2//1 254//1 104//1 +f 2//1 105//1 254//1 +f 205//1 204//1 3//1 +f 206//1 255//1 205//1 +f 207//1 256//1 206//1 +f 208//1 258//1 207//1 +f 209//1 261//1 208//1 +f 210//1 265//1 209//1 +f 211//1 270//1 210//1 +f 212//1 276//1 211//1 +f 213//1 283//1 212//1 +f 214//1 291//1 213//1 +f 215//1 300//1 214//1 +f 216//1 310//1 215//1 +f 217//1 321//1 216//1 +f 218//1 333//1 217//1 +f 219//1 346//1 218//1 +f 220//1 360//1 219//1 +f 221//1 375//1 220//1 +f 222//1 391//1 221//1 +f 223//1 408//1 222//1 +f 224//1 426//1 223//1 +f 225//1 445//1 224//1 +f 226//1 465//1 225//1 +f 227//1 486//1 226//1 +f 228//1 508//1 227//1 +f 229//1 531//1 228//1 +f 230//1 555//1 229//1 +f 231//1 580//1 230//1 +f 232//1 606//1 231//1 +f 233//1 633//1 232//1 +f 234//1 661//1 233//1 +f 235//1 690//1 234//1 +f 236//1 720//1 235//1 +f 237//1 751//1 236//1 +f 238//1 783//1 237//1 +f 239//1 816//1 238//1 +f 240//1 850//1 239//1 +f 241//1 885//1 240//1 +f 242//1 921//1 241//1 +f 243//1 958//1 242//1 +f 244//1 996//1 243//1 +f 245//1 1035//1 244//1 +f 246//1 1075//1 245//1 +f 247//1 1116//1 246//1 +f 248//1 1158//1 247//1 +f 249//1 1201//1 248//1 +f 250//1 1245//1 249//1 +f 251//1 1290//1 250//1 +f 252//1 1336//1 251//1 +f 253//1 1383//1 252//1 +f 254//1 1431//1 253//1 +f 205//1 255//1 204//1 +f 255//1 203//1 204//1 +f 206//1 256//1 255//1 +f 256//1 257//1 255//1 +f 255//1 257//1 203//1 +f 257//1 202//1 203//1 +f 207//1 258//1 256//1 +f 258//1 259//1 256//1 +f 256//1 259//1 257//1 +f 259//1 260//1 257//1 +f 257//1 260//1 202//1 +f 260//1 201//1 202//1 +f 208//1 261//1 258//1 +f 261//1 262//1 258//1 +f 258//1 262//1 259//1 +f 262//1 263//1 259//1 +f 259//1 263//1 260//1 +f 263//1 264//1 260//1 +f 260//1 264//1 201//1 +f 264//1 200//1 201//1 +f 209//1 265//1 261//1 +f 265//1 266//1 261//1 +f 261//1 266//1 262//1 +f 266//1 267//1 262//1 +f 262//1 267//1 263//1 +f 267//1 268//1 263//1 +f 263//1 268//1 264//1 +f 268//1 269//1 264//1 +f 264//1 269//1 200//1 +f 269//1 199//1 200//1 +f 210//1 270//1 265//1 +f 270//1 271//1 265//1 +f 265//1 271//1 266//1 +f 271//1 272//1 266//1 +f 266//1 272//1 267//1 +f 272//1 273//1 267//1 +f 267//1 273//1 268//1 +f 273//1 274//1 268//1 +f 268//1 274//1 269//1 +f 274//1 275//1 269//1 +f 269//1 275//1 199//1 +f 275//1 198//1 199//1 +f 211//1 276//1 270//1 +f 276//1 277//1 270//1 +f 270//1 277//1 271//1 +f 277//1 278//1 271//1 +f 271//1 278//1 272//1 +f 278//1 279//1 272//1 +f 272//1 279//1 273//1 +f 279//1 280//1 273//1 +f 273//1 280//1 274//1 +f 280//1 281//1 274//1 +f 274//1 281//1 275//1 +f 281//1 282//1 275//1 +f 275//1 282//1 198//1 +f 282//1 197//1 198//1 +f 212//1 283//1 276//1 +f 283//1 284//1 276//1 +f 276//1 284//1 277//1 +f 284//1 285//1 277//1 +f 277//1 285//1 278//1 +f 285//1 286//1 278//1 +f 278//1 286//1 279//1 +f 286//1 287//1 279//1 +f 279//1 287//1 280//1 +f 287//1 288//1 280//1 +f 280//1 288//1 281//1 +f 288//1 289//1 281//1 +f 281//1 289//1 282//1 +f 289//1 290//1 282//1 +f 282//1 290//1 197//1 +f 290//1 196//1 197//1 +f 213//1 291//1 283//1 +f 291//1 292//1 283//1 +f 283//1 292//1 284//1 +f 292//1 293//1 284//1 +f 284//1 293//1 285//1 +f 293//1 294//1 285//1 +f 285//1 294//1 286//1 +f 294//1 295//1 286//1 +f 286//1 295//1 287//1 +f 295//1 296//1 287//1 +f 287//1 296//1 288//1 +f 296//1 297//1 288//1 +f 288//1 297//1 289//1 +f 297//1 298//1 289//1 +f 289//1 298//1 290//1 +f 298//1 299//1 290//1 +f 290//1 299//1 196//1 +f 299//1 195//1 196//1 +f 214//1 300//1 291//1 +f 300//1 301//1 291//1 +f 291//1 301//1 292//1 +f 301//1 302//1 292//1 +f 292//1 302//1 293//1 +f 302//1 303//1 293//1 +f 293//1 303//1 294//1 +f 303//1 304//1 294//1 +f 294//1 304//1 295//1 +f 304//1 305//1 295//1 +f 295//1 305//1 296//1 +f 305//1 306//1 296//1 +f 296//1 306//1 297//1 +f 306//1 307//1 297//1 +f 297//1 307//1 298//1 +f 307//1 308//1 298//1 +f 298//1 308//1 299//1 +f 308//1 309//1 299//1 +f 299//1 309//1 195//1 +f 309//1 194//1 195//1 +f 215//1 310//1 300//1 +f 310//1 311//1 300//1 +f 300//1 311//1 301//1 +f 311//1 312//1 301//1 +f 301//1 312//1 302//1 +f 312//1 313//1 302//1 +f 302//1 313//1 303//1 +f 313//1 314//1 303//1 +f 303//1 314//1 304//1 +f 314//1 315//1 304//1 +f 304//1 315//1 305//1 +f 315//1 316//1 305//1 +f 305//1 316//1 306//1 +f 316//1 317//1 306//1 +f 306//1 317//1 307//1 +f 317//1 318//1 307//1 +f 307//1 318//1 308//1 +f 318//1 319//1 308//1 +f 308//1 319//1 309//1 +f 319//1 320//1 309//1 +f 309//1 320//1 194//1 +f 320//1 193//1 194//1 +f 216//1 321//1 310//1 +f 321//1 322//1 310//1 +f 310//1 322//1 311//1 +f 322//1 323//1 311//1 +f 311//1 323//1 312//1 +f 323//1 324//1 312//1 +f 312//1 324//1 313//1 +f 324//1 325//1 313//1 +f 313//1 325//1 314//1 +f 325//1 326//1 314//1 +f 314//1 326//1 315//1 +f 326//1 327//1 315//1 +f 315//1 327//1 316//1 +f 327//1 328//1 316//1 +f 316//1 328//1 317//1 +f 328//1 329//1 317//1 +f 317//1 329//1 318//1 +f 329//1 330//1 318//1 +f 318//1 330//1 319//1 +f 330//1 331//1 319//1 +f 319//1 331//1 320//1 +f 331//1 332//1 320//1 +f 320//1 332//1 193//1 +f 332//1 192//1 193//1 +f 217//1 333//1 321//1 +f 333//1 334//1 321//1 +f 321//1 334//1 322//1 +f 334//1 335//1 322//1 +f 322//1 335//1 323//1 +f 335//1 336//1 323//1 +f 323//1 336//1 324//1 +f 336//1 337//1 324//1 +f 324//1 337//1 325//1 +f 337//1 338//1 325//1 +f 325//1 338//1 326//1 +f 338//1 339//1 326//1 +f 326//1 339//1 327//1 +f 339//1 340//1 327//1 +f 327//1 340//1 328//1 +f 340//1 341//1 328//1 +f 328//1 341//1 329//1 +f 341//1 342//1 329//1 +f 329//1 342//1 330//1 +f 342//1 343//1 330//1 +f 330//1 343//1 331//1 +f 343//1 344//1 331//1 +f 331//1 344//1 332//1 +f 344//1 345//1 332//1 +f 332//1 345//1 192//1 +f 345//1 191//1 192//1 +f 218//1 346//1 333//1 +f 346//1 347//1 333//1 +f 333//1 347//1 334//1 +f 347//1 348//1 334//1 +f 334//1 348//1 335//1 +f 348//1 349//1 335//1 +f 335//1 349//1 336//1 +f 349//1 350//1 336//1 +f 336//1 350//1 337//1 +f 350//1 351//1 337//1 +f 337//1 351//1 338//1 +f 351//1 352//1 338//1 +f 338//1 352//1 339//1 +f 352//1 353//1 339//1 +f 339//1 353//1 340//1 +f 353//1 354//1 340//1 +f 340//1 354//1 341//1 +f 354//1 355//1 341//1 +f 341//1 355//1 342//1 +f 355//1 356//1 342//1 +f 342//1 356//1 343//1 +f 356//1 357//1 343//1 +f 343//1 357//1 344//1 +f 357//1 358//1 344//1 +f 344//1 358//1 345//1 +f 358//1 359//1 345//1 +f 345//1 359//1 191//1 +f 359//1 190//1 191//1 +f 219//1 360//1 346//1 +f 360//1 361//1 346//1 +f 346//1 361//1 347//1 +f 361//1 362//1 347//1 +f 347//1 362//1 348//1 +f 362//1 363//1 348//1 +f 348//1 363//1 349//1 +f 363//1 364//1 349//1 +f 349//1 364//1 350//1 +f 364//1 365//1 350//1 +f 350//1 365//1 351//1 +f 365//1 366//1 351//1 +f 351//1 366//1 352//1 +f 366//1 367//1 352//1 +f 352//1 367//1 353//1 +f 367//1 368//1 353//1 +f 353//1 368//1 354//1 +f 368//1 369//1 354//1 +f 354//1 369//1 355//1 +f 369//1 370//1 355//1 +f 355//1 370//1 356//1 +f 370//1 371//1 356//1 +f 356//1 371//1 357//1 +f 371//1 372//1 357//1 +f 357//1 372//1 358//1 +f 372//1 373//1 358//1 +f 358//1 373//1 359//1 +f 373//1 374//1 359//1 +f 359//1 374//1 190//1 +f 374//1 189//1 190//1 +f 220//1 375//1 360//1 +f 375//1 376//1 360//1 +f 360//1 376//1 361//1 +f 376//1 377//1 361//1 +f 361//1 377//1 362//1 +f 377//1 378//1 362//1 +f 362//1 378//1 363//1 +f 378//1 379//1 363//1 +f 363//1 379//1 364//1 +f 379//1 380//1 364//1 +f 364//1 380//1 365//1 +f 380//1 381//1 365//1 +f 365//1 381//1 366//1 +f 381//1 382//1 366//1 +f 366//1 382//1 367//1 +f 382//1 383//1 367//1 +f 367//1 383//1 368//1 +f 383//1 384//1 368//1 +f 368//1 384//1 369//1 +f 384//1 385//1 369//1 +f 369//1 385//1 370//1 +f 385//1 386//1 370//1 +f 370//1 386//1 371//1 +f 386//1 387//1 371//1 +f 371//1 387//1 372//1 +f 387//1 388//1 372//1 +f 372//1 388//1 373//1 +f 388//1 389//1 373//1 +f 373//1 389//1 374//1 +f 389//1 390//1 374//1 +f 374//1 390//1 189//1 +f 390//1 188//1 189//1 +f 221//1 391//1 375//1 +f 391//1 392//1 375//1 +f 375//1 392//1 376//1 +f 392//1 393//1 376//1 +f 376//1 393//1 377//1 +f 393//1 394//1 377//1 +f 377//1 394//1 378//1 +f 394//1 395//1 378//1 +f 378//1 395//1 379//1 +f 395//1 396//1 379//1 +f 379//1 396//1 380//1 +f 396//1 397//1 380//1 +f 380//1 397//1 381//1 +f 397//1 398//1 381//1 +f 381//1 398//1 382//1 +f 398//1 399//1 382//1 +f 382//1 399//1 383//1 +f 399//1 400//1 383//1 +f 383//1 400//1 384//1 +f 400//1 401//1 384//1 +f 384//1 401//1 385//1 +f 401//1 402//1 385//1 +f 385//1 402//1 386//1 +f 402//1 403//1 386//1 +f 386//1 403//1 387//1 +f 403//1 404//1 387//1 +f 387//1 404//1 388//1 +f 404//1 405//1 388//1 +f 388//1 405//1 389//1 +f 405//1 406//1 389//1 +f 389//1 406//1 390//1 +f 406//1 407//1 390//1 +f 390//1 407//1 188//1 +f 407//1 187//1 188//1 +f 222//1 408//1 391//1 +f 408//1 409//1 391//1 +f 391//1 409//1 392//1 +f 409//1 410//1 392//1 +f 392//1 410//1 393//1 +f 410//1 411//1 393//1 +f 393//1 411//1 394//1 +f 411//1 412//1 394//1 +f 394//1 412//1 395//1 +f 412//1 413//1 395//1 +f 395//1 413//1 396//1 +f 413//1 414//1 396//1 +f 396//1 414//1 397//1 +f 414//1 415//1 397//1 +f 397//1 415//1 398//1 +f 415//1 416//1 398//1 +f 398//1 416//1 399//1 +f 416//1 417//1 399//1 +f 399//1 417//1 400//1 +f 417//1 418//1 400//1 +f 400//1 418//1 401//1 +f 418//1 419//1 401//1 +f 401//1 419//1 402//1 +f 419//1 420//1 402//1 +f 402//1 420//1 403//1 +f 420//1 421//1 403//1 +f 403//1 421//1 404//1 +f 421//1 422//1 404//1 +f 404//1 422//1 405//1 +f 422//1 423//1 405//1 +f 405//1 423//1 406//1 +f 423//1 424//1 406//1 +f 406//1 424//1 407//1 +f 424//1 425//1 407//1 +f 407//1 425//1 187//1 +f 425//1 186//1 187//1 +f 223//1 426//1 408//1 +f 426//1 427//1 408//1 +f 408//1 427//1 409//1 +f 427//1 428//1 409//1 +f 409//1 428//1 410//1 +f 428//1 429//1 410//1 +f 410//1 429//1 411//1 +f 429//1 430//1 411//1 +f 411//1 430//1 412//1 +f 430//1 431//1 412//1 +f 412//1 431//1 413//1 +f 431//1 432//1 413//1 +f 413//1 432//1 414//1 +f 432//1 433//1 414//1 +f 414//1 433//1 415//1 +f 433//1 434//1 415//1 +f 415//1 434//1 416//1 +f 434//1 435//1 416//1 +f 416//1 435//1 417//1 +f 435//1 436//1 417//1 +f 417//1 436//1 418//1 +f 436//1 437//1 418//1 +f 418//1 437//1 419//1 +f 437//1 438//1 419//1 +f 419//1 438//1 420//1 +f 438//1 439//1 420//1 +f 420//1 439//1 421//1 +f 439//1 440//1 421//1 +f 421//1 440//1 422//1 +f 440//1 441//1 422//1 +f 422//1 441//1 423//1 +f 441//1 442//1 423//1 +f 423//1 442//1 424//1 +f 442//1 443//1 424//1 +f 424//1 443//1 425//1 +f 443//1 444//1 425//1 +f 425//1 444//1 186//1 +f 444//1 185//1 186//1 +f 224//1 445//1 426//1 +f 445//1 446//1 426//1 +f 426//1 446//1 427//1 +f 446//1 447//1 427//1 +f 427//1 447//1 428//1 +f 447//1 448//1 428//1 +f 428//1 448//1 429//1 +f 448//1 449//1 429//1 +f 429//1 449//1 430//1 +f 449//1 450//1 430//1 +f 430//1 450//1 431//1 +f 450//1 451//1 431//1 +f 431//1 451//1 432//1 +f 451//1 452//1 432//1 +f 432//1 452//1 433//1 +f 452//1 453//1 433//1 +f 433//1 453//1 434//1 +f 453//1 454//1 434//1 +f 434//1 454//1 435//1 +f 454//1 455//1 435//1 +f 435//1 455//1 436//1 +f 455//1 456//1 436//1 +f 436//1 456//1 437//1 +f 456//1 457//1 437//1 +f 437//1 457//1 438//1 +f 457//1 458//1 438//1 +f 438//1 458//1 439//1 +f 458//1 459//1 439//1 +f 439//1 459//1 440//1 +f 459//1 460//1 440//1 +f 440//1 460//1 441//1 +f 460//1 461//1 441//1 +f 441//1 461//1 442//1 +f 461//1 462//1 442//1 +f 442//1 462//1 443//1 +f 462//1 463//1 443//1 +f 443//1 463//1 444//1 +f 463//1 464//1 444//1 +f 444//1 464//1 185//1 +f 464//1 184//1 185//1 +f 225//1 465//1 445//1 +f 465//1 466//1 445//1 +f 445//1 466//1 446//1 +f 466//1 467//1 446//1 +f 446//1 467//1 447//1 +f 467//1 468//1 447//1 +f 447//1 468//1 448//1 +f 468//1 469//1 448//1 +f 448//1 469//1 449//1 +f 469//1 470//1 449//1 +f 449//1 470//1 450//1 +f 470//1 471//1 450//1 +f 450//1 471//1 451//1 +f 471//1 472//1 451//1 +f 451//1 472//1 452//1 +f 472//1 473//1 452//1 +f 452//1 473//1 453//1 +f 473//1 474//1 453//1 +f 453//1 474//1 454//1 +f 474//1 475//1 454//1 +f 454//1 475//1 455//1 +f 475//1 476//1 455//1 +f 455//1 476//1 456//1 +f 476//1 477//1 456//1 +f 456//1 477//1 457//1 +f 477//1 478//1 457//1 +f 457//1 478//1 458//1 +f 478//1 479//1 458//1 +f 458//1 479//1 459//1 +f 479//1 480//1 459//1 +f 459//1 480//1 460//1 +f 480//1 481//1 460//1 +f 460//1 481//1 461//1 +f 481//1 482//1 461//1 +f 461//1 482//1 462//1 +f 482//1 483//1 462//1 +f 462//1 483//1 463//1 +f 483//1 484//1 463//1 +f 463//1 484//1 464//1 +f 484//1 485//1 464//1 +f 464//1 485//1 184//1 +f 485//1 183//1 184//1 +f 226//1 486//1 465//1 +f 486//1 487//1 465//1 +f 465//1 487//1 466//1 +f 487//1 488//1 466//1 +f 466//1 488//1 467//1 +f 488//1 489//1 467//1 +f 467//1 489//1 468//1 +f 489//1 490//1 468//1 +f 468//1 490//1 469//1 +f 490//1 491//1 469//1 +f 469//1 491//1 470//1 +f 491//1 492//1 470//1 +f 470//1 492//1 471//1 +f 492//1 493//1 471//1 +f 471//1 493//1 472//1 +f 493//1 494//1 472//1 +f 472//1 494//1 473//1 +f 494//1 495//1 473//1 +f 473//1 495//1 474//1 +f 495//1 496//1 474//1 +f 474//1 496//1 475//1 +f 496//1 497//1 475//1 +f 475//1 497//1 476//1 +f 497//1 498//1 476//1 +f 476//1 498//1 477//1 +f 498//1 499//1 477//1 +f 477//1 499//1 478//1 +f 499//1 500//1 478//1 +f 478//1 500//1 479//1 +f 500//1 501//1 479//1 +f 479//1 501//1 480//1 +f 501//1 502//1 480//1 +f 480//1 502//1 481//1 +f 502//1 503//1 481//1 +f 481//1 503//1 482//1 +f 503//1 504//1 482//1 +f 482//1 504//1 483//1 +f 504//1 505//1 483//1 +f 483//1 505//1 484//1 +f 505//1 506//1 484//1 +f 484//1 506//1 485//1 +f 506//1 507//1 485//1 +f 485//1 507//1 183//1 +f 507//1 182//1 183//1 +f 227//1 508//1 486//1 +f 508//1 509//1 486//1 +f 486//1 509//1 487//1 +f 509//1 510//1 487//1 +f 487//1 510//1 488//1 +f 510//1 511//1 488//1 +f 488//1 511//1 489//1 +f 511//1 512//1 489//1 +f 489//1 512//1 490//1 +f 512//1 513//1 490//1 +f 490//1 513//1 491//1 +f 513//1 514//1 491//1 +f 491//1 514//1 492//1 +f 514//1 515//1 492//1 +f 492//1 515//1 493//1 +f 515//1 516//1 493//1 +f 493//1 516//1 494//1 +f 516//1 517//1 494//1 +f 494//1 517//1 495//1 +f 517//1 518//1 495//1 +f 495//1 518//1 496//1 +f 518//1 519//1 496//1 +f 496//1 519//1 497//1 +f 519//1 520//1 497//1 +f 497//1 520//1 498//1 +f 520//1 521//1 498//1 +f 498//1 521//1 499//1 +f 521//1 522//1 499//1 +f 499//1 522//1 500//1 +f 522//1 523//1 500//1 +f 500//1 523//1 501//1 +f 523//1 524//1 501//1 +f 501//1 524//1 502//1 +f 524//1 525//1 502//1 +f 502//1 525//1 503//1 +f 525//1 526//1 503//1 +f 503//1 526//1 504//1 +f 526//1 527//1 504//1 +f 504//1 527//1 505//1 +f 527//1 528//1 505//1 +f 505//1 528//1 506//1 +f 528//1 529//1 506//1 +f 506//1 529//1 507//1 +f 529//1 530//1 507//1 +f 507//1 530//1 182//1 +f 530//1 181//1 182//1 +f 228//1 531//1 508//1 +f 531//1 532//1 508//1 +f 508//1 532//1 509//1 +f 532//1 533//1 509//1 +f 509//1 533//1 510//1 +f 533//1 534//1 510//1 +f 510//1 534//1 511//1 +f 534//1 535//1 511//1 +f 511//1 535//1 512//1 +f 535//1 536//1 512//1 +f 512//1 536//1 513//1 +f 536//1 537//1 513//1 +f 513//1 537//1 514//1 +f 537//1 538//1 514//1 +f 514//1 538//1 515//1 +f 538//1 539//1 515//1 +f 515//1 539//1 516//1 +f 539//1 540//1 516//1 +f 516//1 540//1 517//1 +f 540//1 541//1 517//1 +f 517//1 541//1 518//1 +f 541//1 542//1 518//1 +f 518//1 542//1 519//1 +f 542//1 543//1 519//1 +f 519//1 543//1 520//1 +f 543//1 544//1 520//1 +f 520//1 544//1 521//1 +f 544//1 545//1 521//1 +f 521//1 545//1 522//1 +f 545//1 546//1 522//1 +f 522//1 546//1 523//1 +f 546//1 547//1 523//1 +f 523//1 547//1 524//1 +f 547//1 548//1 524//1 +f 524//1 548//1 525//1 +f 548//1 549//1 525//1 +f 525//1 549//1 526//1 +f 549//1 550//1 526//1 +f 526//1 550//1 527//1 +f 550//1 551//1 527//1 +f 527//1 551//1 528//1 +f 551//1 552//1 528//1 +f 528//1 552//1 529//1 +f 552//1 553//1 529//1 +f 529//1 553//1 530//1 +f 553//1 554//1 530//1 +f 530//1 554//1 181//1 +f 554//1 180//1 181//1 +f 229//1 555//1 531//1 +f 555//1 556//1 531//1 +f 531//1 556//1 532//1 +f 556//1 557//1 532//1 +f 532//1 557//1 533//1 +f 557//1 558//1 533//1 +f 533//1 558//1 534//1 +f 558//1 559//1 534//1 +f 534//1 559//1 535//1 +f 559//1 560//1 535//1 +f 535//1 560//1 536//1 +f 560//1 561//1 536//1 +f 536//1 561//1 537//1 +f 561//1 562//1 537//1 +f 537//1 562//1 538//1 +f 562//1 563//1 538//1 +f 538//1 563//1 539//1 +f 563//1 564//1 539//1 +f 539//1 564//1 540//1 +f 564//1 565//1 540//1 +f 540//1 565//1 541//1 +f 565//1 566//1 541//1 +f 541//1 566//1 542//1 +f 566//1 567//1 542//1 +f 542//1 567//1 543//1 +f 567//1 568//1 543//1 +f 543//1 568//1 544//1 +f 568//1 569//1 544//1 +f 544//1 569//1 545//1 +f 569//1 570//1 545//1 +f 545//1 570//1 546//1 +f 570//1 571//1 546//1 +f 546//1 571//1 547//1 +f 571//1 572//1 547//1 +f 547//1 572//1 548//1 +f 572//1 573//1 548//1 +f 548//1 573//1 549//1 +f 573//1 574//1 549//1 +f 549//1 574//1 550//1 +f 574//1 575//1 550//1 +f 550//1 575//1 551//1 +f 575//1 576//1 551//1 +f 551//1 576//1 552//1 +f 576//1 577//1 552//1 +f 552//1 577//1 553//1 +f 577//1 578//1 553//1 +f 553//1 578//1 554//1 +f 578//1 579//1 554//1 +f 554//1 579//1 180//1 +f 579//1 179//1 180//1 +f 230//1 580//1 555//1 +f 580//1 581//1 555//1 +f 555//1 581//1 556//1 +f 581//1 582//1 556//1 +f 556//1 582//1 557//1 +f 582//1 583//1 557//1 +f 557//1 583//1 558//1 +f 583//1 584//1 558//1 +f 558//1 584//1 559//1 +f 584//1 585//1 559//1 +f 559//1 585//1 560//1 +f 585//1 586//1 560//1 +f 560//1 586//1 561//1 +f 586//1 587//1 561//1 +f 561//1 587//1 562//1 +f 587//1 588//1 562//1 +f 562//1 588//1 563//1 +f 588//1 589//1 563//1 +f 563//1 589//1 564//1 +f 589//1 590//1 564//1 +f 564//1 590//1 565//1 +f 590//1 591//1 565//1 +f 565//1 591//1 566//1 +f 591//1 592//1 566//1 +f 566//1 592//1 567//1 +f 592//1 593//1 567//1 +f 567//1 593//1 568//1 +f 593//1 594//1 568//1 +f 568//1 594//1 569//1 +f 594//1 595//1 569//1 +f 569//1 595//1 570//1 +f 595//1 596//1 570//1 +f 570//1 596//1 571//1 +f 596//1 597//1 571//1 +f 571//1 597//1 572//1 +f 597//1 598//1 572//1 +f 572//1 598//1 573//1 +f 598//1 599//1 573//1 +f 573//1 599//1 574//1 +f 599//1 600//1 574//1 +f 574//1 600//1 575//1 +f 600//1 601//1 575//1 +f 575//1 601//1 576//1 +f 601//1 602//1 576//1 +f 576//1 602//1 577//1 +f 602//1 603//1 577//1 +f 577//1 603//1 578//1 +f 603//1 604//1 578//1 +f 578//1 604//1 579//1 +f 604//1 605//1 579//1 +f 579//1 605//1 179//1 +f 605//1 178//1 179//1 +f 231//1 606//1 580//1 +f 606//1 607//1 580//1 +f 580//1 607//1 581//1 +f 607//1 608//1 581//1 +f 581//1 608//1 582//1 +f 608//1 609//1 582//1 +f 582//1 609//1 583//1 +f 609//1 610//1 583//1 +f 583//1 610//1 584//1 +f 610//1 611//1 584//1 +f 584//1 611//1 585//1 +f 611//1 612//1 585//1 +f 585//1 612//1 586//1 +f 612//1 613//1 586//1 +f 586//1 613//1 587//1 +f 613//1 614//1 587//1 +f 587//1 614//1 588//1 +f 614//1 615//1 588//1 +f 588//1 615//1 589//1 +f 615//1 616//1 589//1 +f 589//1 616//1 590//1 +f 616//1 617//1 590//1 +f 590//1 617//1 591//1 +f 617//1 618//1 591//1 +f 591//1 618//1 592//1 +f 618//1 619//1 592//1 +f 592//1 619//1 593//1 +f 619//1 620//1 593//1 +f 593//1 620//1 594//1 +f 620//1 621//1 594//1 +f 594//1 621//1 595//1 +f 621//1 622//1 595//1 +f 595//1 622//1 596//1 +f 622//1 623//1 596//1 +f 596//1 623//1 597//1 +f 623//1 624//1 597//1 +f 597//1 624//1 598//1 +f 624//1 625//1 598//1 +f 598//1 625//1 599//1 +f 625//1 626//1 599//1 +f 599//1 626//1 600//1 +f 626//1 627//1 600//1 +f 600//1 627//1 601//1 +f 627//1 628//1 601//1 +f 601//1 628//1 602//1 +f 628//1 629//1 602//1 +f 602//1 629//1 603//1 +f 629//1 630//1 603//1 +f 603//1 630//1 604//1 +f 630//1 631//1 604//1 +f 604//1 631//1 605//1 +f 631//1 632//1 605//1 +f 605//1 632//1 178//1 +f 632//1 177//1 178//1 +f 232//1 633//1 606//1 +f 633//1 634//1 606//1 +f 606//1 634//1 607//1 +f 634//1 635//1 607//1 +f 607//1 635//1 608//1 +f 635//1 636//1 608//1 +f 608//1 636//1 609//1 +f 636//1 637//1 609//1 +f 609//1 637//1 610//1 +f 637//1 638//1 610//1 +f 610//1 638//1 611//1 +f 638//1 639//1 611//1 +f 611//1 639//1 612//1 +f 639//1 640//1 612//1 +f 612//1 640//1 613//1 +f 640//1 641//1 613//1 +f 613//1 641//1 614//1 +f 641//1 642//1 614//1 +f 614//1 642//1 615//1 +f 642//1 643//1 615//1 +f 615//1 643//1 616//1 +f 643//1 644//1 616//1 +f 616//1 644//1 617//1 +f 644//1 645//1 617//1 +f 617//1 645//1 618//1 +f 645//1 646//1 618//1 +f 618//1 646//1 619//1 +f 646//1 647//1 619//1 +f 619//1 647//1 620//1 +f 647//1 648//1 620//1 +f 620//1 648//1 621//1 +f 648//1 649//1 621//1 +f 621//1 649//1 622//1 +f 649//1 650//1 622//1 +f 622//1 650//1 623//1 +f 650//1 651//1 623//1 +f 623//1 651//1 624//1 +f 651//1 652//1 624//1 +f 624//1 652//1 625//1 +f 652//1 653//1 625//1 +f 625//1 653//1 626//1 +f 653//1 654//1 626//1 +f 626//1 654//1 627//1 +f 654//1 655//1 627//1 +f 627//1 655//1 628//1 +f 655//1 656//1 628//1 +f 628//1 656//1 629//1 +f 656//1 657//1 629//1 +f 629//1 657//1 630//1 +f 657//1 658//1 630//1 +f 630//1 658//1 631//1 +f 658//1 659//1 631//1 +f 631//1 659//1 632//1 +f 659//1 660//1 632//1 +f 632//1 660//1 177//1 +f 660//1 176//1 177//1 +f 233//1 661//1 633//1 +f 661//1 662//1 633//1 +f 633//1 662//1 634//1 +f 662//1 663//1 634//1 +f 634//1 663//1 635//1 +f 663//1 664//1 635//1 +f 635//1 664//1 636//1 +f 664//1 665//1 636//1 +f 636//1 665//1 637//1 +f 665//1 666//1 637//1 +f 637//1 666//1 638//1 +f 666//1 667//1 638//1 +f 638//1 667//1 639//1 +f 667//1 668//1 639//1 +f 639//1 668//1 640//1 +f 668//1 669//1 640//1 +f 640//1 669//1 641//1 +f 669//1 670//1 641//1 +f 641//1 670//1 642//1 +f 670//1 671//1 642//1 +f 642//1 671//1 643//1 +f 671//1 672//1 643//1 +f 643//1 672//1 644//1 +f 672//1 673//1 644//1 +f 644//1 673//1 645//1 +f 673//1 674//1 645//1 +f 645//1 674//1 646//1 +f 674//1 675//1 646//1 +f 646//1 675//1 647//1 +f 675//1 676//1 647//1 +f 647//1 676//1 648//1 +f 676//1 677//1 648//1 +f 648//1 677//1 649//1 +f 677//1 678//1 649//1 +f 649//1 678//1 650//1 +f 678//1 679//1 650//1 +f 650//1 679//1 651//1 +f 679//1 680//1 651//1 +f 651//1 680//1 652//1 +f 680//1 681//1 652//1 +f 652//1 681//1 653//1 +f 681//1 682//1 653//1 +f 653//1 682//1 654//1 +f 682//1 683//1 654//1 +f 654//1 683//1 655//1 +f 683//1 684//1 655//1 +f 655//1 684//1 656//1 +f 684//1 685//1 656//1 +f 656//1 685//1 657//1 +f 685//1 686//1 657//1 +f 657//1 686//1 658//1 +f 686//1 687//1 658//1 +f 658//1 687//1 659//1 +f 687//1 688//1 659//1 +f 659//1 688//1 660//1 +f 688//1 689//1 660//1 +f 660//1 689//1 176//1 +f 689//1 175//1 176//1 +f 234//1 690//1 661//1 +f 690//1 691//1 661//1 +f 661//1 691//1 662//1 +f 691//1 692//1 662//1 +f 662//1 692//1 663//1 +f 692//1 693//1 663//1 +f 663//1 693//1 664//1 +f 693//1 694//1 664//1 +f 664//1 694//1 665//1 +f 694//1 695//1 665//1 +f 665//1 695//1 666//1 +f 695//1 696//1 666//1 +f 666//1 696//1 667//1 +f 696//1 697//1 667//1 +f 667//1 697//1 668//1 +f 697//1 698//1 668//1 +f 668//1 698//1 669//1 +f 698//1 699//1 669//1 +f 669//1 699//1 670//1 +f 699//1 700//1 670//1 +f 670//1 700//1 671//1 +f 700//1 701//1 671//1 +f 671//1 701//1 672//1 +f 701//1 702//1 672//1 +f 672//1 702//1 673//1 +f 702//1 703//1 673//1 +f 673//1 703//1 674//1 +f 703//1 704//1 674//1 +f 674//1 704//1 675//1 +f 704//1 705//1 675//1 +f 675//1 705//1 676//1 +f 705//1 706//1 676//1 +f 676//1 706//1 677//1 +f 706//1 707//1 677//1 +f 677//1 707//1 678//1 +f 707//1 708//1 678//1 +f 678//1 708//1 679//1 +f 708//1 709//1 679//1 +f 679//1 709//1 680//1 +f 709//1 710//1 680//1 +f 680//1 710//1 681//1 +f 710//1 711//1 681//1 +f 681//1 711//1 682//1 +f 711//1 712//1 682//1 +f 682//1 712//1 683//1 +f 712//1 713//1 683//1 +f 683//1 713//1 684//1 +f 713//1 714//1 684//1 +f 684//1 714//1 685//1 +f 714//1 715//1 685//1 +f 685//1 715//1 686//1 +f 715//1 716//1 686//1 +f 686//1 716//1 687//1 +f 716//1 717//1 687//1 +f 687//1 717//1 688//1 +f 717//1 718//1 688//1 +f 688//1 718//1 689//1 +f 718//1 719//1 689//1 +f 689//1 719//1 175//1 +f 719//1 174//1 175//1 +f 235//1 720//1 690//1 +f 720//1 721//1 690//1 +f 690//1 721//1 691//1 +f 721//1 722//1 691//1 +f 691//1 722//1 692//1 +f 722//1 723//1 692//1 +f 692//1 723//1 693//1 +f 723//1 724//1 693//1 +f 693//1 724//1 694//1 +f 724//1 725//1 694//1 +f 694//1 725//1 695//1 +f 725//1 726//1 695//1 +f 695//1 726//1 696//1 +f 726//1 727//1 696//1 +f 696//1 727//1 697//1 +f 727//1 728//1 697//1 +f 697//1 728//1 698//1 +f 728//1 729//1 698//1 +f 698//1 729//1 699//1 +f 729//1 730//1 699//1 +f 699//1 730//1 700//1 +f 730//1 731//1 700//1 +f 700//1 731//1 701//1 +f 731//1 732//1 701//1 +f 701//1 732//1 702//1 +f 732//1 733//1 702//1 +f 702//1 733//1 703//1 +f 733//1 734//1 703//1 +f 703//1 734//1 704//1 +f 734//1 735//1 704//1 +f 704//1 735//1 705//1 +f 735//1 736//1 705//1 +f 705//1 736//1 706//1 +f 736//1 737//1 706//1 +f 706//1 737//1 707//1 +f 737//1 738//1 707//1 +f 707//1 738//1 708//1 +f 738//1 739//1 708//1 +f 708//1 739//1 709//1 +f 739//1 740//1 709//1 +f 709//1 740//1 710//1 +f 740//1 741//1 710//1 +f 710//1 741//1 711//1 +f 741//1 742//1 711//1 +f 711//1 742//1 712//1 +f 742//1 743//1 712//1 +f 712//1 743//1 713//1 +f 743//1 744//1 713//1 +f 713//1 744//1 714//1 +f 744//1 745//1 714//1 +f 714//1 745//1 715//1 +f 745//1 746//1 715//1 +f 715//1 746//1 716//1 +f 746//1 747//1 716//1 +f 716//1 747//1 717//1 +f 747//1 748//1 717//1 +f 717//1 748//1 718//1 +f 748//1 749//1 718//1 +f 718//1 749//1 719//1 +f 749//1 750//1 719//1 +f 719//1 750//1 174//1 +f 750//1 173//1 174//1 +f 236//1 751//1 720//1 +f 751//1 752//1 720//1 +f 720//1 752//1 721//1 +f 752//1 753//1 721//1 +f 721//1 753//1 722//1 +f 753//1 754//1 722//1 +f 722//1 754//1 723//1 +f 754//1 755//1 723//1 +f 723//1 755//1 724//1 +f 755//1 756//1 724//1 +f 724//1 756//1 725//1 +f 756//1 757//1 725//1 +f 725//1 757//1 726//1 +f 757//1 758//1 726//1 +f 726//1 758//1 727//1 +f 758//1 759//1 727//1 +f 727//1 759//1 728//1 +f 759//1 760//1 728//1 +f 728//1 760//1 729//1 +f 760//1 761//1 729//1 +f 729//1 761//1 730//1 +f 761//1 762//1 730//1 +f 730//1 762//1 731//1 +f 762//1 763//1 731//1 +f 731//1 763//1 732//1 +f 763//1 764//1 732//1 +f 732//1 764//1 733//1 +f 764//1 765//1 733//1 +f 733//1 765//1 734//1 +f 765//1 766//1 734//1 +f 734//1 766//1 735//1 +f 766//1 767//1 735//1 +f 735//1 767//1 736//1 +f 767//1 768//1 736//1 +f 736//1 768//1 737//1 +f 768//1 769//1 737//1 +f 737//1 769//1 738//1 +f 769//1 770//1 738//1 +f 738//1 770//1 739//1 +f 770//1 771//1 739//1 +f 739//1 771//1 740//1 +f 771//1 772//1 740//1 +f 740//1 772//1 741//1 +f 772//1 773//1 741//1 +f 741//1 773//1 742//1 +f 773//1 774//1 742//1 +f 742//1 774//1 743//1 +f 774//1 775//1 743//1 +f 743//1 775//1 744//1 +f 775//1 776//1 744//1 +f 744//1 776//1 745//1 +f 776//1 777//1 745//1 +f 745//1 777//1 746//1 +f 777//1 778//1 746//1 +f 746//1 778//1 747//1 +f 778//1 779//1 747//1 +f 747//1 779//1 748//1 +f 779//1 780//1 748//1 +f 748//1 780//1 749//1 +f 780//1 781//1 749//1 +f 749//1 781//1 750//1 +f 781//1 782//1 750//1 +f 750//1 782//1 173//1 +f 782//1 172//1 173//1 +f 237//1 783//1 751//1 +f 783//1 784//1 751//1 +f 751//1 784//1 752//1 +f 784//1 785//1 752//1 +f 752//1 785//1 753//1 +f 785//1 786//1 753//1 +f 753//1 786//1 754//1 +f 786//1 787//1 754//1 +f 754//1 787//1 755//1 +f 787//1 788//1 755//1 +f 755//1 788//1 756//1 +f 788//1 789//1 756//1 +f 756//1 789//1 757//1 +f 789//1 790//1 757//1 +f 757//1 790//1 758//1 +f 790//1 791//1 758//1 +f 758//1 791//1 759//1 +f 791//1 792//1 759//1 +f 759//1 792//1 760//1 +f 792//1 793//1 760//1 +f 760//1 793//1 761//1 +f 793//1 794//1 761//1 +f 761//1 794//1 762//1 +f 794//1 795//1 762//1 +f 762//1 795//1 763//1 +f 795//1 796//1 763//1 +f 763//1 796//1 764//1 +f 796//1 797//1 764//1 +f 764//1 797//1 765//1 +f 797//1 798//1 765//1 +f 765//1 798//1 766//1 +f 798//1 799//1 766//1 +f 766//1 799//1 767//1 +f 799//1 800//1 767//1 +f 767//1 800//1 768//1 +f 800//1 801//1 768//1 +f 768//1 801//1 769//1 +f 801//1 802//1 769//1 +f 769//1 802//1 770//1 +f 802//1 803//1 770//1 +f 770//1 803//1 771//1 +f 803//1 804//1 771//1 +f 771//1 804//1 772//1 +f 804//1 805//1 772//1 +f 772//1 805//1 773//1 +f 805//1 806//1 773//1 +f 773//1 806//1 774//1 +f 806//1 807//1 774//1 +f 774//1 807//1 775//1 +f 807//1 808//1 775//1 +f 775//1 808//1 776//1 +f 808//1 809//1 776//1 +f 776//1 809//1 777//1 +f 809//1 810//1 777//1 +f 777//1 810//1 778//1 +f 810//1 811//1 778//1 +f 778//1 811//1 779//1 +f 811//1 812//1 779//1 +f 779//1 812//1 780//1 +f 812//1 813//1 780//1 +f 780//1 813//1 781//1 +f 813//1 814//1 781//1 +f 781//1 814//1 782//1 +f 814//1 815//1 782//1 +f 782//1 815//1 172//1 +f 815//1 171//1 172//1 +f 238//1 816//1 783//1 +f 816//1 817//1 783//1 +f 783//1 817//1 784//1 +f 817//1 818//1 784//1 +f 784//1 818//1 785//1 +f 818//1 819//1 785//1 +f 785//1 819//1 786//1 +f 819//1 820//1 786//1 +f 786//1 820//1 787//1 +f 820//1 821//1 787//1 +f 787//1 821//1 788//1 +f 821//1 822//1 788//1 +f 788//1 822//1 789//1 +f 822//1 823//1 789//1 +f 789//1 823//1 790//1 +f 823//1 824//1 790//1 +f 790//1 824//1 791//1 +f 824//1 825//1 791//1 +f 791//1 825//1 792//1 +f 825//1 826//1 792//1 +f 792//1 826//1 793//1 +f 826//1 827//1 793//1 +f 793//1 827//1 794//1 +f 827//1 828//1 794//1 +f 794//1 828//1 795//1 +f 828//1 829//1 795//1 +f 795//1 829//1 796//1 +f 829//1 830//1 796//1 +f 796//1 830//1 797//1 +f 830//1 831//1 797//1 +f 797//1 831//1 798//1 +f 831//1 832//1 798//1 +f 798//1 832//1 799//1 +f 832//1 833//1 799//1 +f 799//1 833//1 800//1 +f 833//1 834//1 800//1 +f 800//1 834//1 801//1 +f 834//1 835//1 801//1 +f 801//1 835//1 802//1 +f 835//1 836//1 802//1 +f 802//1 836//1 803//1 +f 836//1 837//1 803//1 +f 803//1 837//1 804//1 +f 837//1 838//1 804//1 +f 804//1 838//1 805//1 +f 838//1 839//1 805//1 +f 805//1 839//1 806//1 +f 839//1 840//1 806//1 +f 806//1 840//1 807//1 +f 840//1 841//1 807//1 +f 807//1 841//1 808//1 +f 841//1 842//1 808//1 +f 808//1 842//1 809//1 +f 842//1 843//1 809//1 +f 809//1 843//1 810//1 +f 843//1 844//1 810//1 +f 810//1 844//1 811//1 +f 844//1 845//1 811//1 +f 811//1 845//1 812//1 +f 845//1 846//1 812//1 +f 812//1 846//1 813//1 +f 846//1 847//1 813//1 +f 813//1 847//1 814//1 +f 847//1 848//1 814//1 +f 814//1 848//1 815//1 +f 848//1 849//1 815//1 +f 815//1 849//1 171//1 +f 849//1 170//1 171//1 +f 239//1 850//1 816//1 +f 850//1 851//1 816//1 +f 816//1 851//1 817//1 +f 851//1 852//1 817//1 +f 817//1 852//1 818//1 +f 852//1 853//1 818//1 +f 818//1 853//1 819//1 +f 853//1 854//1 819//1 +f 819//1 854//1 820//1 +f 854//1 855//1 820//1 +f 820//1 855//1 821//1 +f 855//1 856//1 821//1 +f 821//1 856//1 822//1 +f 856//1 857//1 822//1 +f 822//1 857//1 823//1 +f 857//1 858//1 823//1 +f 823//1 858//1 824//1 +f 858//1 859//1 824//1 +f 824//1 859//1 825//1 +f 859//1 860//1 825//1 +f 825//1 860//1 826//1 +f 860//1 861//1 826//1 +f 826//1 861//1 827//1 +f 861//1 862//1 827//1 +f 827//1 862//1 828//1 +f 862//1 863//1 828//1 +f 828//1 863//1 829//1 +f 863//1 864//1 829//1 +f 829//1 864//1 830//1 +f 864//1 865//1 830//1 +f 830//1 865//1 831//1 +f 865//1 866//1 831//1 +f 831//1 866//1 832//1 +f 866//1 867//1 832//1 +f 832//1 867//1 833//1 +f 867//1 868//1 833//1 +f 833//1 868//1 834//1 +f 868//1 869//1 834//1 +f 834//1 869//1 835//1 +f 869//1 870//1 835//1 +f 835//1 870//1 836//1 +f 870//1 871//1 836//1 +f 836//1 871//1 837//1 +f 871//1 872//1 837//1 +f 837//1 872//1 838//1 +f 872//1 873//1 838//1 +f 838//1 873//1 839//1 +f 873//1 874//1 839//1 +f 839//1 874//1 840//1 +f 874//1 875//1 840//1 +f 840//1 875//1 841//1 +f 875//1 876//1 841//1 +f 841//1 876//1 842//1 +f 876//1 877//1 842//1 +f 842//1 877//1 843//1 +f 877//1 878//1 843//1 +f 843//1 878//1 844//1 +f 878//1 879//1 844//1 +f 844//1 879//1 845//1 +f 879//1 880//1 845//1 +f 845//1 880//1 846//1 +f 880//1 881//1 846//1 +f 846//1 881//1 847//1 +f 881//1 882//1 847//1 +f 847//1 882//1 848//1 +f 882//1 883//1 848//1 +f 848//1 883//1 849//1 +f 883//1 884//1 849//1 +f 849//1 884//1 170//1 +f 884//1 169//1 170//1 +f 240//1 885//1 850//1 +f 885//1 886//1 850//1 +f 850//1 886//1 851//1 +f 886//1 887//1 851//1 +f 851//1 887//1 852//1 +f 887//1 888//1 852//1 +f 852//1 888//1 853//1 +f 888//1 889//1 853//1 +f 853//1 889//1 854//1 +f 889//1 890//1 854//1 +f 854//1 890//1 855//1 +f 890//1 891//1 855//1 +f 855//1 891//1 856//1 +f 891//1 892//1 856//1 +f 856//1 892//1 857//1 +f 892//1 893//1 857//1 +f 857//1 893//1 858//1 +f 893//1 894//1 858//1 +f 858//1 894//1 859//1 +f 894//1 895//1 859//1 +f 859//1 895//1 860//1 +f 895//1 896//1 860//1 +f 860//1 896//1 861//1 +f 896//1 897//1 861//1 +f 861//1 897//1 862//1 +f 897//1 898//1 862//1 +f 862//1 898//1 863//1 +f 898//1 899//1 863//1 +f 863//1 899//1 864//1 +f 899//1 900//1 864//1 +f 864//1 900//1 865//1 +f 900//1 901//1 865//1 +f 865//1 901//1 866//1 +f 901//1 902//1 866//1 +f 866//1 902//1 867//1 +f 902//1 903//1 867//1 +f 867//1 903//1 868//1 +f 903//1 904//1 868//1 +f 868//1 904//1 869//1 +f 904//1 905//1 869//1 +f 869//1 905//1 870//1 +f 905//1 906//1 870//1 +f 870//1 906//1 871//1 +f 906//1 907//1 871//1 +f 871//1 907//1 872//1 +f 907//1 908//1 872//1 +f 872//1 908//1 873//1 +f 908//1 909//1 873//1 +f 873//1 909//1 874//1 +f 909//1 910//1 874//1 +f 874//1 910//1 875//1 +f 910//1 911//1 875//1 +f 875//1 911//1 876//1 +f 911//1 912//1 876//1 +f 876//1 912//1 877//1 +f 912//1 913//1 877//1 +f 877//1 913//1 878//1 +f 913//1 914//1 878//1 +f 878//1 914//1 879//1 +f 914//1 915//1 879//1 +f 879//1 915//1 880//1 +f 915//1 916//1 880//1 +f 880//1 916//1 881//1 +f 916//1 917//1 881//1 +f 881//1 917//1 882//1 +f 917//1 918//1 882//1 +f 882//1 918//1 883//1 +f 918//1 919//1 883//1 +f 883//1 919//1 884//1 +f 919//1 920//1 884//1 +f 884//1 920//1 169//1 +f 920//1 168//1 169//1 +f 241//1 921//1 885//1 +f 921//1 922//1 885//1 +f 885//1 922//1 886//1 +f 922//1 923//1 886//1 +f 886//1 923//1 887//1 +f 923//1 924//1 887//1 +f 887//1 924//1 888//1 +f 924//1 925//1 888//1 +f 888//1 925//1 889//1 +f 925//1 926//1 889//1 +f 889//1 926//1 890//1 +f 926//1 927//1 890//1 +f 890//1 927//1 891//1 +f 927//1 928//1 891//1 +f 891//1 928//1 892//1 +f 928//1 929//1 892//1 +f 892//1 929//1 893//1 +f 929//1 930//1 893//1 +f 893//1 930//1 894//1 +f 930//1 931//1 894//1 +f 894//1 931//1 895//1 +f 931//1 932//1 895//1 +f 895//1 932//1 896//1 +f 932//1 933//1 896//1 +f 896//1 933//1 897//1 +f 933//1 934//1 897//1 +f 897//1 934//1 898//1 +f 934//1 935//1 898//1 +f 898//1 935//1 899//1 +f 935//1 936//1 899//1 +f 899//1 936//1 900//1 +f 936//1 937//1 900//1 +f 900//1 937//1 901//1 +f 937//1 938//1 901//1 +f 901//1 938//1 902//1 +f 938//1 939//1 902//1 +f 902//1 939//1 903//1 +f 939//1 940//1 903//1 +f 903//1 940//1 904//1 +f 940//1 941//1 904//1 +f 904//1 941//1 905//1 +f 941//1 942//1 905//1 +f 905//1 942//1 906//1 +f 942//1 943//1 906//1 +f 906//1 943//1 907//1 +f 943//1 944//1 907//1 +f 907//1 944//1 908//1 +f 944//1 945//1 908//1 +f 908//1 945//1 909//1 +f 945//1 946//1 909//1 +f 909//1 946//1 910//1 +f 946//1 947//1 910//1 +f 910//1 947//1 911//1 +f 947//1 948//1 911//1 +f 911//1 948//1 912//1 +f 948//1 949//1 912//1 +f 912//1 949//1 913//1 +f 949//1 950//1 913//1 +f 913//1 950//1 914//1 +f 950//1 951//1 914//1 +f 914//1 951//1 915//1 +f 951//1 952//1 915//1 +f 915//1 952//1 916//1 +f 952//1 953//1 916//1 +f 916//1 953//1 917//1 +f 953//1 954//1 917//1 +f 917//1 954//1 918//1 +f 954//1 955//1 918//1 +f 918//1 955//1 919//1 +f 955//1 956//1 919//1 +f 919//1 956//1 920//1 +f 956//1 957//1 920//1 +f 920//1 957//1 168//1 +f 957//1 167//1 168//1 +f 242//1 958//1 921//1 +f 958//1 959//1 921//1 +f 921//1 959//1 922//1 +f 959//1 960//1 922//1 +f 922//1 960//1 923//1 +f 960//1 961//1 923//1 +f 923//1 961//1 924//1 +f 961//1 962//1 924//1 +f 924//1 962//1 925//1 +f 962//1 963//1 925//1 +f 925//1 963//1 926//1 +f 963//1 964//1 926//1 +f 926//1 964//1 927//1 +f 964//1 965//1 927//1 +f 927//1 965//1 928//1 +f 965//1 966//1 928//1 +f 928//1 966//1 929//1 +f 966//1 967//1 929//1 +f 929//1 967//1 930//1 +f 967//1 968//1 930//1 +f 930//1 968//1 931//1 +f 968//1 969//1 931//1 +f 931//1 969//1 932//1 +f 969//1 970//1 932//1 +f 932//1 970//1 933//1 +f 970//1 971//1 933//1 +f 933//1 971//1 934//1 +f 971//1 972//1 934//1 +f 934//1 972//1 935//1 +f 972//1 973//1 935//1 +f 935//1 973//1 936//1 +f 973//1 974//1 936//1 +f 936//1 974//1 937//1 +f 974//1 975//1 937//1 +f 937//1 975//1 938//1 +f 975//1 976//1 938//1 +f 938//1 976//1 939//1 +f 976//1 977//1 939//1 +f 939//1 977//1 940//1 +f 977//1 978//1 940//1 +f 940//1 978//1 941//1 +f 978//1 979//1 941//1 +f 941//1 979//1 942//1 +f 979//1 980//1 942//1 +f 942//1 980//1 943//1 +f 980//1 981//1 943//1 +f 943//1 981//1 944//1 +f 981//1 982//1 944//1 +f 944//1 982//1 945//1 +f 982//1 983//1 945//1 +f 945//1 983//1 946//1 +f 983//1 984//1 946//1 +f 946//1 984//1 947//1 +f 984//1 985//1 947//1 +f 947//1 985//1 948//1 +f 985//1 986//1 948//1 +f 948//1 986//1 949//1 +f 986//1 987//1 949//1 +f 949//1 987//1 950//1 +f 987//1 988//1 950//1 +f 950//1 988//1 951//1 +f 988//1 989//1 951//1 +f 951//1 989//1 952//1 +f 989//1 990//1 952//1 +f 952//1 990//1 953//1 +f 990//1 991//1 953//1 +f 953//1 991//1 954//1 +f 991//1 992//1 954//1 +f 954//1 992//1 955//1 +f 992//1 993//1 955//1 +f 955//1 993//1 956//1 +f 993//1 994//1 956//1 +f 956//1 994//1 957//1 +f 994//1 995//1 957//1 +f 957//1 995//1 167//1 +f 995//1 166//1 167//1 +f 243//1 996//1 958//1 +f 996//1 997//1 958//1 +f 958//1 997//1 959//1 +f 997//1 998//1 959//1 +f 959//1 998//1 960//1 +f 998//1 999//1 960//1 +f 960//1 999//1 961//1 +f 999//1 1000//1 961//1 +f 961//1 1000//1 962//1 +f 1000//1 1001//1 962//1 +f 962//1 1001//1 963//1 +f 1001//1 1002//1 963//1 +f 963//1 1002//1 964//1 +f 1002//1 1003//1 964//1 +f 964//1 1003//1 965//1 +f 1003//1 1004//1 965//1 +f 965//1 1004//1 966//1 +f 1004//1 1005//1 966//1 +f 966//1 1005//1 967//1 +f 1005//1 1006//1 967//1 +f 967//1 1006//1 968//1 +f 1006//1 1007//1 968//1 +f 968//1 1007//1 969//1 +f 1007//1 1008//1 969//1 +f 969//1 1008//1 970//1 +f 1008//1 1009//1 970//1 +f 970//1 1009//1 971//1 +f 1009//1 1010//1 971//1 +f 971//1 1010//1 972//1 +f 1010//1 1011//1 972//1 +f 972//1 1011//1 973//1 +f 1011//1 1012//1 973//1 +f 973//1 1012//1 974//1 +f 1012//1 1013//1 974//1 +f 974//1 1013//1 975//1 +f 1013//1 1014//1 975//1 +f 975//1 1014//1 976//1 +f 1014//1 1015//1 976//1 +f 976//1 1015//1 977//1 +f 1015//1 1016//1 977//1 +f 977//1 1016//1 978//1 +f 1016//1 1017//1 978//1 +f 978//1 1017//1 979//1 +f 1017//1 1018//1 979//1 +f 979//1 1018//1 980//1 +f 1018//1 1019//1 980//1 +f 980//1 1019//1 981//1 +f 1019//1 1020//1 981//1 +f 981//1 1020//1 982//1 +f 1020//1 1021//1 982//1 +f 982//1 1021//1 983//1 +f 1021//1 1022//1 983//1 +f 983//1 1022//1 984//1 +f 1022//1 1023//1 984//1 +f 984//1 1023//1 985//1 +f 1023//1 1024//1 985//1 +f 985//1 1024//1 986//1 +f 1024//1 1025//1 986//1 +f 986//1 1025//1 987//1 +f 1025//1 1026//1 987//1 +f 987//1 1026//1 988//1 +f 1026//1 1027//1 988//1 +f 988//1 1027//1 989//1 +f 1027//1 1028//1 989//1 +f 989//1 1028//1 990//1 +f 1028//1 1029//1 990//1 +f 990//1 1029//1 991//1 +f 1029//1 1030//1 991//1 +f 991//1 1030//1 992//1 +f 1030//1 1031//1 992//1 +f 992//1 1031//1 993//1 +f 1031//1 1032//1 993//1 +f 993//1 1032//1 994//1 +f 1032//1 1033//1 994//1 +f 994//1 1033//1 995//1 +f 1033//1 1034//1 995//1 +f 995//1 1034//1 166//1 +f 1034//1 165//1 166//1 +f 244//1 1035//1 996//1 +f 1035//1 1036//1 996//1 +f 996//1 1036//1 997//1 +f 1036//1 1037//1 997//1 +f 997//1 1037//1 998//1 +f 1037//1 1038//1 998//1 +f 998//1 1038//1 999//1 +f 1038//1 1039//1 999//1 +f 999//1 1039//1 1000//1 +f 1039//1 1040//1 1000//1 +f 1000//1 1040//1 1001//1 +f 1040//1 1041//1 1001//1 +f 1001//1 1041//1 1002//1 +f 1041//1 1042//1 1002//1 +f 1002//1 1042//1 1003//1 +f 1042//1 1043//1 1003//1 +f 1003//1 1043//1 1004//1 +f 1043//1 1044//1 1004//1 +f 1004//1 1044//1 1005//1 +f 1044//1 1045//1 1005//1 +f 1005//1 1045//1 1006//1 +f 1045//1 1046//1 1006//1 +f 1006//1 1046//1 1007//1 +f 1046//1 1047//1 1007//1 +f 1007//1 1047//1 1008//1 +f 1047//1 1048//1 1008//1 +f 1008//1 1048//1 1009//1 +f 1048//1 1049//1 1009//1 +f 1009//1 1049//1 1010//1 +f 1049//1 1050//1 1010//1 +f 1010//1 1050//1 1011//1 +f 1050//1 1051//1 1011//1 +f 1011//1 1051//1 1012//1 +f 1051//1 1052//1 1012//1 +f 1012//1 1052//1 1013//1 +f 1052//1 1053//1 1013//1 +f 1013//1 1053//1 1014//1 +f 1053//1 1054//1 1014//1 +f 1014//1 1054//1 1015//1 +f 1054//1 1055//1 1015//1 +f 1015//1 1055//1 1016//1 +f 1055//1 1056//1 1016//1 +f 1016//1 1056//1 1017//1 +f 1056//1 1057//1 1017//1 +f 1017//1 1057//1 1018//1 +f 1057//1 1058//1 1018//1 +f 1018//1 1058//1 1019//1 +f 1058//1 1059//1 1019//1 +f 1019//1 1059//1 1020//1 +f 1059//1 1060//1 1020//1 +f 1020//1 1060//1 1021//1 +f 1060//1 1061//1 1021//1 +f 1021//1 1061//1 1022//1 +f 1061//1 1062//1 1022//1 +f 1022//1 1062//1 1023//1 +f 1062//1 1063//1 1023//1 +f 1023//1 1063//1 1024//1 +f 1063//1 1064//1 1024//1 +f 1024//1 1064//1 1025//1 +f 1064//1 1065//1 1025//1 +f 1025//1 1065//1 1026//1 +f 1065//1 1066//1 1026//1 +f 1026//1 1066//1 1027//1 +f 1066//1 1067//1 1027//1 +f 1027//1 1067//1 1028//1 +f 1067//1 1068//1 1028//1 +f 1028//1 1068//1 1029//1 +f 1068//1 1069//1 1029//1 +f 1029//1 1069//1 1030//1 +f 1069//1 1070//1 1030//1 +f 1030//1 1070//1 1031//1 +f 1070//1 1071//1 1031//1 +f 1031//1 1071//1 1032//1 +f 1071//1 1072//1 1032//1 +f 1032//1 1072//1 1033//1 +f 1072//1 1073//1 1033//1 +f 1033//1 1073//1 1034//1 +f 1073//1 1074//1 1034//1 +f 1034//1 1074//1 165//1 +f 1074//1 164//1 165//1 +f 245//1 1075//1 1035//1 +f 1075//1 1076//1 1035//1 +f 1035//1 1076//1 1036//1 +f 1076//1 1077//1 1036//1 +f 1036//1 1077//1 1037//1 +f 1077//1 1078//1 1037//1 +f 1037//1 1078//1 1038//1 +f 1078//1 1079//1 1038//1 +f 1038//1 1079//1 1039//1 +f 1079//1 1080//1 1039//1 +f 1039//1 1080//1 1040//1 +f 1080//1 1081//1 1040//1 +f 1040//1 1081//1 1041//1 +f 1081//1 1082//1 1041//1 +f 1041//1 1082//1 1042//1 +f 1082//1 1083//1 1042//1 +f 1042//1 1083//1 1043//1 +f 1083//1 1084//1 1043//1 +f 1043//1 1084//1 1044//1 +f 1084//1 1085//1 1044//1 +f 1044//1 1085//1 1045//1 +f 1085//1 1086//1 1045//1 +f 1045//1 1086//1 1046//1 +f 1086//1 1087//1 1046//1 +f 1046//1 1087//1 1047//1 +f 1087//1 1088//1 1047//1 +f 1047//1 1088//1 1048//1 +f 1088//1 1089//1 1048//1 +f 1048//1 1089//1 1049//1 +f 1089//1 1090//1 1049//1 +f 1049//1 1090//1 1050//1 +f 1090//1 1091//1 1050//1 +f 1050//1 1091//1 1051//1 +f 1091//1 1092//1 1051//1 +f 1051//1 1092//1 1052//1 +f 1092//1 1093//1 1052//1 +f 1052//1 1093//1 1053//1 +f 1093//1 1094//1 1053//1 +f 1053//1 1094//1 1054//1 +f 1094//1 1095//1 1054//1 +f 1054//1 1095//1 1055//1 +f 1095//1 1096//1 1055//1 +f 1055//1 1096//1 1056//1 +f 1096//1 1097//1 1056//1 +f 1056//1 1097//1 1057//1 +f 1097//1 1098//1 1057//1 +f 1057//1 1098//1 1058//1 +f 1098//1 1099//1 1058//1 +f 1058//1 1099//1 1059//1 +f 1099//1 1100//1 1059//1 +f 1059//1 1100//1 1060//1 +f 1100//1 1101//1 1060//1 +f 1060//1 1101//1 1061//1 +f 1101//1 1102//1 1061//1 +f 1061//1 1102//1 1062//1 +f 1102//1 1103//1 1062//1 +f 1062//1 1103//1 1063//1 +f 1103//1 1104//1 1063//1 +f 1063//1 1104//1 1064//1 +f 1104//1 1105//1 1064//1 +f 1064//1 1105//1 1065//1 +f 1105//1 1106//1 1065//1 +f 1065//1 1106//1 1066//1 +f 1106//1 1107//1 1066//1 +f 1066//1 1107//1 1067//1 +f 1107//1 1108//1 1067//1 +f 1067//1 1108//1 1068//1 +f 1108//1 1109//1 1068//1 +f 1068//1 1109//1 1069//1 +f 1109//1 1110//1 1069//1 +f 1069//1 1110//1 1070//1 +f 1110//1 1111//1 1070//1 +f 1070//1 1111//1 1071//1 +f 1111//1 1112//1 1071//1 +f 1071//1 1112//1 1072//1 +f 1112//1 1113//1 1072//1 +f 1072//1 1113//1 1073//1 +f 1113//1 1114//1 1073//1 +f 1073//1 1114//1 1074//1 +f 1114//1 1115//1 1074//1 +f 1074//1 1115//1 164//1 +f 1115//1 163//1 164//1 +f 246//1 1116//1 1075//1 +f 1116//1 1117//1 1075//1 +f 1075//1 1117//1 1076//1 +f 1117//1 1118//1 1076//1 +f 1076//1 1118//1 1077//1 +f 1118//1 1119//1 1077//1 +f 1077//1 1119//1 1078//1 +f 1119//1 1120//1 1078//1 +f 1078//1 1120//1 1079//1 +f 1120//1 1121//1 1079//1 +f 1079//1 1121//1 1080//1 +f 1121//1 1122//1 1080//1 +f 1080//1 1122//1 1081//1 +f 1122//1 1123//1 1081//1 +f 1081//1 1123//1 1082//1 +f 1123//1 1124//1 1082//1 +f 1082//1 1124//1 1083//1 +f 1124//1 1125//1 1083//1 +f 1083//1 1125//1 1084//1 +f 1125//1 1126//1 1084//1 +f 1084//1 1126//1 1085//1 +f 1126//1 1127//1 1085//1 +f 1085//1 1127//1 1086//1 +f 1127//1 1128//1 1086//1 +f 1086//1 1128//1 1087//1 +f 1128//1 1129//1 1087//1 +f 1087//1 1129//1 1088//1 +f 1129//1 1130//1 1088//1 +f 1088//1 1130//1 1089//1 +f 1130//1 1131//1 1089//1 +f 1089//1 1131//1 1090//1 +f 1131//1 1132//1 1090//1 +f 1090//1 1132//1 1091//1 +f 1132//1 1133//1 1091//1 +f 1091//1 1133//1 1092//1 +f 1133//1 1134//1 1092//1 +f 1092//1 1134//1 1093//1 +f 1134//1 1135//1 1093//1 +f 1093//1 1135//1 1094//1 +f 1135//1 1136//1 1094//1 +f 1094//1 1136//1 1095//1 +f 1136//1 1137//1 1095//1 +f 1095//1 1137//1 1096//1 +f 1137//1 1138//1 1096//1 +f 1096//1 1138//1 1097//1 +f 1138//1 1139//1 1097//1 +f 1097//1 1139//1 1098//1 +f 1139//1 1140//1 1098//1 +f 1098//1 1140//1 1099//1 +f 1140//1 1141//1 1099//1 +f 1099//1 1141//1 1100//1 +f 1141//1 1142//1 1100//1 +f 1100//1 1142//1 1101//1 +f 1142//1 1143//1 1101//1 +f 1101//1 1143//1 1102//1 +f 1143//1 1144//1 1102//1 +f 1102//1 1144//1 1103//1 +f 1144//1 1145//1 1103//1 +f 1103//1 1145//1 1104//1 +f 1145//1 1146//1 1104//1 +f 1104//1 1146//1 1105//1 +f 1146//1 1147//1 1105//1 +f 1105//1 1147//1 1106//1 +f 1147//1 1148//1 1106//1 +f 1106//1 1148//1 1107//1 +f 1148//1 1149//1 1107//1 +f 1107//1 1149//1 1108//1 +f 1149//1 1150//1 1108//1 +f 1108//1 1150//1 1109//1 +f 1150//1 1151//1 1109//1 +f 1109//1 1151//1 1110//1 +f 1151//1 1152//1 1110//1 +f 1110//1 1152//1 1111//1 +f 1152//1 1153//1 1111//1 +f 1111//1 1153//1 1112//1 +f 1153//1 1154//1 1112//1 +f 1112//1 1154//1 1113//1 +f 1154//1 1155//1 1113//1 +f 1113//1 1155//1 1114//1 +f 1155//1 1156//1 1114//1 +f 1114//1 1156//1 1115//1 +f 1156//1 1157//1 1115//1 +f 1115//1 1157//1 163//1 +f 1157//1 162//1 163//1 +f 247//1 1158//1 1116//1 +f 1158//1 1159//1 1116//1 +f 1116//1 1159//1 1117//1 +f 1159//1 1160//1 1117//1 +f 1117//1 1160//1 1118//1 +f 1160//1 1161//1 1118//1 +f 1118//1 1161//1 1119//1 +f 1161//1 1162//1 1119//1 +f 1119//1 1162//1 1120//1 +f 1162//1 1163//1 1120//1 +f 1120//1 1163//1 1121//1 +f 1163//1 1164//1 1121//1 +f 1121//1 1164//1 1122//1 +f 1164//1 1165//1 1122//1 +f 1122//1 1165//1 1123//1 +f 1165//1 1166//1 1123//1 +f 1123//1 1166//1 1124//1 +f 1166//1 1167//1 1124//1 +f 1124//1 1167//1 1125//1 +f 1167//1 1168//1 1125//1 +f 1125//1 1168//1 1126//1 +f 1168//1 1169//1 1126//1 +f 1126//1 1169//1 1127//1 +f 1169//1 1170//1 1127//1 +f 1127//1 1170//1 1128//1 +f 1170//1 1171//1 1128//1 +f 1128//1 1171//1 1129//1 +f 1171//1 1172//1 1129//1 +f 1129//1 1172//1 1130//1 +f 1172//1 1173//1 1130//1 +f 1130//1 1173//1 1131//1 +f 1173//1 1174//1 1131//1 +f 1131//1 1174//1 1132//1 +f 1174//1 1175//1 1132//1 +f 1132//1 1175//1 1133//1 +f 1175//1 1176//1 1133//1 +f 1133//1 1176//1 1134//1 +f 1176//1 1177//1 1134//1 +f 1134//1 1177//1 1135//1 +f 1177//1 1178//1 1135//1 +f 1135//1 1178//1 1136//1 +f 1178//1 1179//1 1136//1 +f 1136//1 1179//1 1137//1 +f 1179//1 1180//1 1137//1 +f 1137//1 1180//1 1138//1 +f 1180//1 1181//1 1138//1 +f 1138//1 1181//1 1139//1 +f 1181//1 1182//1 1139//1 +f 1139//1 1182//1 1140//1 +f 1182//1 1183//1 1140//1 +f 1140//1 1183//1 1141//1 +f 1183//1 1184//1 1141//1 +f 1141//1 1184//1 1142//1 +f 1184//1 1185//1 1142//1 +f 1142//1 1185//1 1143//1 +f 1185//1 1186//1 1143//1 +f 1143//1 1186//1 1144//1 +f 1186//1 1187//1 1144//1 +f 1144//1 1187//1 1145//1 +f 1187//1 1188//1 1145//1 +f 1145//1 1188//1 1146//1 +f 1188//1 1189//1 1146//1 +f 1146//1 1189//1 1147//1 +f 1189//1 1190//1 1147//1 +f 1147//1 1190//1 1148//1 +f 1190//1 1191//1 1148//1 +f 1148//1 1191//1 1149//1 +f 1191//1 1192//1 1149//1 +f 1149//1 1192//1 1150//1 +f 1192//1 1193//1 1150//1 +f 1150//1 1193//1 1151//1 +f 1193//1 1194//1 1151//1 +f 1151//1 1194//1 1152//1 +f 1194//1 1195//1 1152//1 +f 1152//1 1195//1 1153//1 +f 1195//1 1196//1 1153//1 +f 1153//1 1196//1 1154//1 +f 1196//1 1197//1 1154//1 +f 1154//1 1197//1 1155//1 +f 1197//1 1198//1 1155//1 +f 1155//1 1198//1 1156//1 +f 1198//1 1199//1 1156//1 +f 1156//1 1199//1 1157//1 +f 1199//1 1200//1 1157//1 +f 1157//1 1200//1 162//1 +f 1200//1 161//1 162//1 +f 248//1 1201//1 1158//1 +f 1201//1 1202//1 1158//1 +f 1158//1 1202//1 1159//1 +f 1202//1 1203//1 1159//1 +f 1159//1 1203//1 1160//1 +f 1203//1 1204//1 1160//1 +f 1160//1 1204//1 1161//1 +f 1204//1 1205//1 1161//1 +f 1161//1 1205//1 1162//1 +f 1205//1 1206//1 1162//1 +f 1162//1 1206//1 1163//1 +f 1206//1 1207//1 1163//1 +f 1163//1 1207//1 1164//1 +f 1207//1 1208//1 1164//1 +f 1164//1 1208//1 1165//1 +f 1208//1 1209//1 1165//1 +f 1165//1 1209//1 1166//1 +f 1209//1 1210//1 1166//1 +f 1166//1 1210//1 1167//1 +f 1210//1 1211//1 1167//1 +f 1167//1 1211//1 1168//1 +f 1211//1 1212//1 1168//1 +f 1168//1 1212//1 1169//1 +f 1212//1 1213//1 1169//1 +f 1169//1 1213//1 1170//1 +f 1213//1 1214//1 1170//1 +f 1170//1 1214//1 1171//1 +f 1214//1 1215//1 1171//1 +f 1171//1 1215//1 1172//1 +f 1215//1 1216//1 1172//1 +f 1172//1 1216//1 1173//1 +f 1216//1 1217//1 1173//1 +f 1173//1 1217//1 1174//1 +f 1217//1 1218//1 1174//1 +f 1174//1 1218//1 1175//1 +f 1218//1 1219//1 1175//1 +f 1175//1 1219//1 1176//1 +f 1219//1 1220//1 1176//1 +f 1176//1 1220//1 1177//1 +f 1220//1 1221//1 1177//1 +f 1177//1 1221//1 1178//1 +f 1221//1 1222//1 1178//1 +f 1178//1 1222//1 1179//1 +f 1222//1 1223//1 1179//1 +f 1179//1 1223//1 1180//1 +f 1223//1 1224//1 1180//1 +f 1180//1 1224//1 1181//1 +f 1224//1 1225//1 1181//1 +f 1181//1 1225//1 1182//1 +f 1225//1 1226//1 1182//1 +f 1182//1 1226//1 1183//1 +f 1226//1 1227//1 1183//1 +f 1183//1 1227//1 1184//1 +f 1227//1 1228//1 1184//1 +f 1184//1 1228//1 1185//1 +f 1228//1 1229//1 1185//1 +f 1185//1 1229//1 1186//1 +f 1229//1 1230//1 1186//1 +f 1186//1 1230//1 1187//1 +f 1230//1 1231//1 1187//1 +f 1187//1 1231//1 1188//1 +f 1231//1 1232//1 1188//1 +f 1188//1 1232//1 1189//1 +f 1232//1 1233//1 1189//1 +f 1189//1 1233//1 1190//1 +f 1233//1 1234//1 1190//1 +f 1190//1 1234//1 1191//1 +f 1234//1 1235//1 1191//1 +f 1191//1 1235//1 1192//1 +f 1235//1 1236//1 1192//1 +f 1192//1 1236//1 1193//1 +f 1236//1 1237//1 1193//1 +f 1193//1 1237//1 1194//1 +f 1237//1 1238//1 1194//1 +f 1194//1 1238//1 1195//1 +f 1238//1 1239//1 1195//1 +f 1195//1 1239//1 1196//1 +f 1239//1 1240//1 1196//1 +f 1196//1 1240//1 1197//1 +f 1240//1 1241//1 1197//1 +f 1197//1 1241//1 1198//1 +f 1241//1 1242//1 1198//1 +f 1198//1 1242//1 1199//1 +f 1242//1 1243//1 1199//1 +f 1199//1 1243//1 1200//1 +f 1243//1 1244//1 1200//1 +f 1200//1 1244//1 161//1 +f 1244//1 160//1 161//1 +f 249//1 1245//1 1201//1 +f 1245//1 1246//1 1201//1 +f 1201//1 1246//1 1202//1 +f 1246//1 1247//1 1202//1 +f 1202//1 1247//1 1203//1 +f 1247//1 1248//1 1203//1 +f 1203//1 1248//1 1204//1 +f 1248//1 1249//1 1204//1 +f 1204//1 1249//1 1205//1 +f 1249//1 1250//1 1205//1 +f 1205//1 1250//1 1206//1 +f 1250//1 1251//1 1206//1 +f 1206//1 1251//1 1207//1 +f 1251//1 1252//1 1207//1 +f 1207//1 1252//1 1208//1 +f 1252//1 1253//1 1208//1 +f 1208//1 1253//1 1209//1 +f 1253//1 1254//1 1209//1 +f 1209//1 1254//1 1210//1 +f 1254//1 1255//1 1210//1 +f 1210//1 1255//1 1211//1 +f 1255//1 1256//1 1211//1 +f 1211//1 1256//1 1212//1 +f 1256//1 1257//1 1212//1 +f 1212//1 1257//1 1213//1 +f 1257//1 1258//1 1213//1 +f 1213//1 1258//1 1214//1 +f 1258//1 1259//1 1214//1 +f 1214//1 1259//1 1215//1 +f 1259//1 1260//1 1215//1 +f 1215//1 1260//1 1216//1 +f 1260//1 1261//1 1216//1 +f 1216//1 1261//1 1217//1 +f 1261//1 1262//1 1217//1 +f 1217//1 1262//1 1218//1 +f 1262//1 1263//1 1218//1 +f 1218//1 1263//1 1219//1 +f 1263//1 1264//1 1219//1 +f 1219//1 1264//1 1220//1 +f 1264//1 1265//1 1220//1 +f 1220//1 1265//1 1221//1 +f 1265//1 1266//1 1221//1 +f 1221//1 1266//1 1222//1 +f 1266//1 1267//1 1222//1 +f 1222//1 1267//1 1223//1 +f 1267//1 1268//1 1223//1 +f 1223//1 1268//1 1224//1 +f 1268//1 1269//1 1224//1 +f 1224//1 1269//1 1225//1 +f 1269//1 1270//1 1225//1 +f 1225//1 1270//1 1226//1 +f 1270//1 1271//1 1226//1 +f 1226//1 1271//1 1227//1 +f 1271//1 1272//1 1227//1 +f 1227//1 1272//1 1228//1 +f 1272//1 1273//1 1228//1 +f 1228//1 1273//1 1229//1 +f 1273//1 1274//1 1229//1 +f 1229//1 1274//1 1230//1 +f 1274//1 1275//1 1230//1 +f 1230//1 1275//1 1231//1 +f 1275//1 1276//1 1231//1 +f 1231//1 1276//1 1232//1 +f 1276//1 1277//1 1232//1 +f 1232//1 1277//1 1233//1 +f 1277//1 1278//1 1233//1 +f 1233//1 1278//1 1234//1 +f 1278//1 1279//1 1234//1 +f 1234//1 1279//1 1235//1 +f 1279//1 1280//1 1235//1 +f 1235//1 1280//1 1236//1 +f 1280//1 1281//1 1236//1 +f 1236//1 1281//1 1237//1 +f 1281//1 1282//1 1237//1 +f 1237//1 1282//1 1238//1 +f 1282//1 1283//1 1238//1 +f 1238//1 1283//1 1239//1 +f 1283//1 1284//1 1239//1 +f 1239//1 1284//1 1240//1 +f 1284//1 1285//1 1240//1 +f 1240//1 1285//1 1241//1 +f 1285//1 1286//1 1241//1 +f 1241//1 1286//1 1242//1 +f 1286//1 1287//1 1242//1 +f 1242//1 1287//1 1243//1 +f 1287//1 1288//1 1243//1 +f 1243//1 1288//1 1244//1 +f 1288//1 1289//1 1244//1 +f 1244//1 1289//1 160//1 +f 1289//1 159//1 160//1 +f 250//1 1290//1 1245//1 +f 1290//1 1291//1 1245//1 +f 1245//1 1291//1 1246//1 +f 1291//1 1292//1 1246//1 +f 1246//1 1292//1 1247//1 +f 1292//1 1293//1 1247//1 +f 1247//1 1293//1 1248//1 +f 1293//1 1294//1 1248//1 +f 1248//1 1294//1 1249//1 +f 1294//1 1295//1 1249//1 +f 1249//1 1295//1 1250//1 +f 1295//1 1296//1 1250//1 +f 1250//1 1296//1 1251//1 +f 1296//1 1297//1 1251//1 +f 1251//1 1297//1 1252//1 +f 1297//1 1298//1 1252//1 +f 1252//1 1298//1 1253//1 +f 1298//1 1299//1 1253//1 +f 1253//1 1299//1 1254//1 +f 1299//1 1300//1 1254//1 +f 1254//1 1300//1 1255//1 +f 1300//1 1301//1 1255//1 +f 1255//1 1301//1 1256//1 +f 1301//1 1302//1 1256//1 +f 1256//1 1302//1 1257//1 +f 1302//1 1303//1 1257//1 +f 1257//1 1303//1 1258//1 +f 1303//1 1304//1 1258//1 +f 1258//1 1304//1 1259//1 +f 1304//1 1305//1 1259//1 +f 1259//1 1305//1 1260//1 +f 1305//1 1306//1 1260//1 +f 1260//1 1306//1 1261//1 +f 1306//1 1307//1 1261//1 +f 1261//1 1307//1 1262//1 +f 1307//1 1308//1 1262//1 +f 1262//1 1308//1 1263//1 +f 1308//1 1309//1 1263//1 +f 1263//1 1309//1 1264//1 +f 1309//1 1310//1 1264//1 +f 1264//1 1310//1 1265//1 +f 1310//1 1311//1 1265//1 +f 1265//1 1311//1 1266//1 +f 1311//1 1312//1 1266//1 +f 1266//1 1312//1 1267//1 +f 1312//1 1313//1 1267//1 +f 1267//1 1313//1 1268//1 +f 1313//1 1314//1 1268//1 +f 1268//1 1314//1 1269//1 +f 1314//1 1315//1 1269//1 +f 1269//1 1315//1 1270//1 +f 1315//1 1316//1 1270//1 +f 1270//1 1316//1 1271//1 +f 1316//1 1317//1 1271//1 +f 1271//1 1317//1 1272//1 +f 1317//1 1318//1 1272//1 +f 1272//1 1318//1 1273//1 +f 1318//1 1319//1 1273//1 +f 1273//1 1319//1 1274//1 +f 1319//1 1320//1 1274//1 +f 1274//1 1320//1 1275//1 +f 1320//1 1321//1 1275//1 +f 1275//1 1321//1 1276//1 +f 1321//1 1322//1 1276//1 +f 1276//1 1322//1 1277//1 +f 1322//1 1323//1 1277//1 +f 1277//1 1323//1 1278//1 +f 1323//1 1324//1 1278//1 +f 1278//1 1324//1 1279//1 +f 1324//1 1325//1 1279//1 +f 1279//1 1325//1 1280//1 +f 1325//1 1326//1 1280//1 +f 1280//1 1326//1 1281//1 +f 1326//1 1327//1 1281//1 +f 1281//1 1327//1 1282//1 +f 1327//1 1328//1 1282//1 +f 1282//1 1328//1 1283//1 +f 1328//1 1329//1 1283//1 +f 1283//1 1329//1 1284//1 +f 1329//1 1330//1 1284//1 +f 1284//1 1330//1 1285//1 +f 1330//1 1331//1 1285//1 +f 1285//1 1331//1 1286//1 +f 1331//1 1332//1 1286//1 +f 1286//1 1332//1 1287//1 +f 1332//1 1333//1 1287//1 +f 1287//1 1333//1 1288//1 +f 1333//1 1334//1 1288//1 +f 1288//1 1334//1 1289//1 +f 1334//1 1335//1 1289//1 +f 1289//1 1335//1 159//1 +f 1335//1 158//1 159//1 +f 251//1 1336//1 1290//1 +f 1336//1 1337//1 1290//1 +f 1290//1 1337//1 1291//1 +f 1337//1 1338//1 1291//1 +f 1291//1 1338//1 1292//1 +f 1338//1 1339//1 1292//1 +f 1292//1 1339//1 1293//1 +f 1339//1 1340//1 1293//1 +f 1293//1 1340//1 1294//1 +f 1340//1 1341//1 1294//1 +f 1294//1 1341//1 1295//1 +f 1341//1 1342//1 1295//1 +f 1295//1 1342//1 1296//1 +f 1342//1 1343//1 1296//1 +f 1296//1 1343//1 1297//1 +f 1343//1 1344//1 1297//1 +f 1297//1 1344//1 1298//1 +f 1344//1 1345//1 1298//1 +f 1298//1 1345//1 1299//1 +f 1345//1 1346//1 1299//1 +f 1299//1 1346//1 1300//1 +f 1346//1 1347//1 1300//1 +f 1300//1 1347//1 1301//1 +f 1347//1 1348//1 1301//1 +f 1301//1 1348//1 1302//1 +f 1348//1 1349//1 1302//1 +f 1302//1 1349//1 1303//1 +f 1349//1 1350//1 1303//1 +f 1303//1 1350//1 1304//1 +f 1350//1 1351//1 1304//1 +f 1304//1 1351//1 1305//1 +f 1351//1 1352//1 1305//1 +f 1305//1 1352//1 1306//1 +f 1352//1 1353//1 1306//1 +f 1306//1 1353//1 1307//1 +f 1353//1 1354//1 1307//1 +f 1307//1 1354//1 1308//1 +f 1354//1 1355//1 1308//1 +f 1308//1 1355//1 1309//1 +f 1355//1 1356//1 1309//1 +f 1309//1 1356//1 1310//1 +f 1356//1 1357//1 1310//1 +f 1310//1 1357//1 1311//1 +f 1357//1 1358//1 1311//1 +f 1311//1 1358//1 1312//1 +f 1358//1 1359//1 1312//1 +f 1312//1 1359//1 1313//1 +f 1359//1 1360//1 1313//1 +f 1313//1 1360//1 1314//1 +f 1360//1 1361//1 1314//1 +f 1314//1 1361//1 1315//1 +f 1361//1 1362//1 1315//1 +f 1315//1 1362//1 1316//1 +f 1362//1 1363//1 1316//1 +f 1316//1 1363//1 1317//1 +f 1363//1 1364//1 1317//1 +f 1317//1 1364//1 1318//1 +f 1364//1 1365//1 1318//1 +f 1318//1 1365//1 1319//1 +f 1365//1 1366//1 1319//1 +f 1319//1 1366//1 1320//1 +f 1366//1 1367//1 1320//1 +f 1320//1 1367//1 1321//1 +f 1367//1 1368//1 1321//1 +f 1321//1 1368//1 1322//1 +f 1368//1 1369//1 1322//1 +f 1322//1 1369//1 1323//1 +f 1369//1 1370//1 1323//1 +f 1323//1 1370//1 1324//1 +f 1370//1 1371//1 1324//1 +f 1324//1 1371//1 1325//1 +f 1371//1 1372//1 1325//1 +f 1325//1 1372//1 1326//1 +f 1372//1 1373//1 1326//1 +f 1326//1 1373//1 1327//1 +f 1373//1 1374//1 1327//1 +f 1327//1 1374//1 1328//1 +f 1374//1 1375//1 1328//1 +f 1328//1 1375//1 1329//1 +f 1375//1 1376//1 1329//1 +f 1329//1 1376//1 1330//1 +f 1376//1 1377//1 1330//1 +f 1330//1 1377//1 1331//1 +f 1377//1 1378//1 1331//1 +f 1331//1 1378//1 1332//1 +f 1378//1 1379//1 1332//1 +f 1332//1 1379//1 1333//1 +f 1379//1 1380//1 1333//1 +f 1333//1 1380//1 1334//1 +f 1380//1 1381//1 1334//1 +f 1334//1 1381//1 1335//1 +f 1381//1 1382//1 1335//1 +f 1335//1 1382//1 158//1 +f 1382//1 157//1 158//1 +f 252//1 1383//1 1336//1 +f 1383//1 1384//1 1336//1 +f 1336//1 1384//1 1337//1 +f 1384//1 1385//1 1337//1 +f 1337//1 1385//1 1338//1 +f 1385//1 1386//1 1338//1 +f 1338//1 1386//1 1339//1 +f 1386//1 1387//1 1339//1 +f 1339//1 1387//1 1340//1 +f 1387//1 1388//1 1340//1 +f 1340//1 1388//1 1341//1 +f 1388//1 1389//1 1341//1 +f 1341//1 1389//1 1342//1 +f 1389//1 1390//1 1342//1 +f 1342//1 1390//1 1343//1 +f 1390//1 1391//1 1343//1 +f 1343//1 1391//1 1344//1 +f 1391//1 1392//1 1344//1 +f 1344//1 1392//1 1345//1 +f 1392//1 1393//1 1345//1 +f 1345//1 1393//1 1346//1 +f 1393//1 1394//1 1346//1 +f 1346//1 1394//1 1347//1 +f 1394//1 1395//1 1347//1 +f 1347//1 1395//1 1348//1 +f 1395//1 1396//1 1348//1 +f 1348//1 1396//1 1349//1 +f 1396//1 1397//1 1349//1 +f 1349//1 1397//1 1350//1 +f 1397//1 1398//1 1350//1 +f 1350//1 1398//1 1351//1 +f 1398//1 1399//1 1351//1 +f 1351//1 1399//1 1352//1 +f 1399//1 1400//1 1352//1 +f 1352//1 1400//1 1353//1 +f 1400//1 1401//1 1353//1 +f 1353//1 1401//1 1354//1 +f 1401//1 1402//1 1354//1 +f 1354//1 1402//1 1355//1 +f 1402//1 1403//1 1355//1 +f 1355//1 1403//1 1356//1 +f 1403//1 1404//1 1356//1 +f 1356//1 1404//1 1357//1 +f 1404//1 1405//1 1357//1 +f 1357//1 1405//1 1358//1 +f 1405//1 1406//1 1358//1 +f 1358//1 1406//1 1359//1 +f 1406//1 1407//1 1359//1 +f 1359//1 1407//1 1360//1 +f 1407//1 1408//1 1360//1 +f 1360//1 1408//1 1361//1 +f 1408//1 1409//1 1361//1 +f 1361//1 1409//1 1362//1 +f 1409//1 1410//1 1362//1 +f 1362//1 1410//1 1363//1 +f 1410//1 1411//1 1363//1 +f 1363//1 1411//1 1364//1 +f 1411//1 1412//1 1364//1 +f 1364//1 1412//1 1365//1 +f 1412//1 1413//1 1365//1 +f 1365//1 1413//1 1366//1 +f 1413//1 1414//1 1366//1 +f 1366//1 1414//1 1367//1 +f 1414//1 1415//1 1367//1 +f 1367//1 1415//1 1368//1 +f 1415//1 1416//1 1368//1 +f 1368//1 1416//1 1369//1 +f 1416//1 1417//1 1369//1 +f 1369//1 1417//1 1370//1 +f 1417//1 1418//1 1370//1 +f 1370//1 1418//1 1371//1 +f 1418//1 1419//1 1371//1 +f 1371//1 1419//1 1372//1 +f 1419//1 1420//1 1372//1 +f 1372//1 1420//1 1373//1 +f 1420//1 1421//1 1373//1 +f 1373//1 1421//1 1374//1 +f 1421//1 1422//1 1374//1 +f 1374//1 1422//1 1375//1 +f 1422//1 1423//1 1375//1 +f 1375//1 1423//1 1376//1 +f 1423//1 1424//1 1376//1 +f 1376//1 1424//1 1377//1 +f 1424//1 1425//1 1377//1 +f 1377//1 1425//1 1378//1 +f 1425//1 1426//1 1378//1 +f 1378//1 1426//1 1379//1 +f 1426//1 1427//1 1379//1 +f 1379//1 1427//1 1380//1 +f 1427//1 1428//1 1380//1 +f 1380//1 1428//1 1381//1 +f 1428//1 1429//1 1381//1 +f 1381//1 1429//1 1382//1 +f 1429//1 1430//1 1382//1 +f 1382//1 1430//1 157//1 +f 1430//1 156//1 157//1 +f 253//1 1431//1 1383//1 +f 1431//1 1432//1 1383//1 +f 1383//1 1432//1 1384//1 +f 1432//1 1433//1 1384//1 +f 1384//1 1433//1 1385//1 +f 1433//1 1434//1 1385//1 +f 1385//1 1434//1 1386//1 +f 1434//1 1435//1 1386//1 +f 1386//1 1435//1 1387//1 +f 1435//1 1436//1 1387//1 +f 1387//1 1436//1 1388//1 +f 1436//1 1437//1 1388//1 +f 1388//1 1437//1 1389//1 +f 1437//1 1438//1 1389//1 +f 1389//1 1438//1 1390//1 +f 1438//1 1439//1 1390//1 +f 1390//1 1439//1 1391//1 +f 1439//1 1440//1 1391//1 +f 1391//1 1440//1 1392//1 +f 1440//1 1441//1 1392//1 +f 1392//1 1441//1 1393//1 +f 1441//1 1442//1 1393//1 +f 1393//1 1442//1 1394//1 +f 1442//1 1443//1 1394//1 +f 1394//1 1443//1 1395//1 +f 1443//1 1444//1 1395//1 +f 1395//1 1444//1 1396//1 +f 1444//1 1445//1 1396//1 +f 1396//1 1445//1 1397//1 +f 1445//1 1446//1 1397//1 +f 1397//1 1446//1 1398//1 +f 1446//1 1447//1 1398//1 +f 1398//1 1447//1 1399//1 +f 1447//1 1448//1 1399//1 +f 1399//1 1448//1 1400//1 +f 1448//1 1449//1 1400//1 +f 1400//1 1449//1 1401//1 +f 1449//1 1450//1 1401//1 +f 1401//1 1450//1 1402//1 +f 1450//1 1451//1 1402//1 +f 1402//1 1451//1 1403//1 +f 1451//1 1452//1 1403//1 +f 1403//1 1452//1 1404//1 +f 1452//1 1453//1 1404//1 +f 1404//1 1453//1 1405//1 +f 1453//1 1454//1 1405//1 +f 1405//1 1454//1 1406//1 +f 1454//1 1455//1 1406//1 +f 1406//1 1455//1 1407//1 +f 1455//1 1456//1 1407//1 +f 1407//1 1456//1 1408//1 +f 1456//1 1457//1 1408//1 +f 1408//1 1457//1 1409//1 +f 1457//1 1458//1 1409//1 +f 1409//1 1458//1 1410//1 +f 1458//1 1459//1 1410//1 +f 1410//1 1459//1 1411//1 +f 1459//1 1460//1 1411//1 +f 1411//1 1460//1 1412//1 +f 1460//1 1461//1 1412//1 +f 1412//1 1461//1 1413//1 +f 1461//1 1462//1 1413//1 +f 1413//1 1462//1 1414//1 +f 1462//1 1463//1 1414//1 +f 1414//1 1463//1 1415//1 +f 1463//1 1464//1 1415//1 +f 1415//1 1464//1 1416//1 +f 1464//1 1465//1 1416//1 +f 1416//1 1465//1 1417//1 +f 1465//1 1466//1 1417//1 +f 1417//1 1466//1 1418//1 +f 1466//1 1467//1 1418//1 +f 1418//1 1467//1 1419//1 +f 1467//1 1468//1 1419//1 +f 1419//1 1468//1 1420//1 +f 1468//1 1469//1 1420//1 +f 1420//1 1469//1 1421//1 +f 1469//1 1470//1 1421//1 +f 1421//1 1470//1 1422//1 +f 1470//1 1471//1 1422//1 +f 1422//1 1471//1 1423//1 +f 1471//1 1472//1 1423//1 +f 1423//1 1472//1 1424//1 +f 1472//1 1473//1 1424//1 +f 1424//1 1473//1 1425//1 +f 1473//1 1474//1 1425//1 +f 1425//1 1474//1 1426//1 +f 1474//1 1475//1 1426//1 +f 1426//1 1475//1 1427//1 +f 1475//1 1476//1 1427//1 +f 1427//1 1476//1 1428//1 +f 1476//1 1477//1 1428//1 +f 1428//1 1477//1 1429//1 +f 1477//1 1478//1 1429//1 +f 1429//1 1478//1 1430//1 +f 1478//1 1479//1 1430//1 +f 1430//1 1479//1 156//1 +f 1479//1 155//1 156//1 +f 254//1 105//1 1431//1 +f 105//1 106//1 1431//1 +f 1431//1 106//1 1432//1 +f 106//1 107//1 1432//1 +f 1432//1 107//1 1433//1 +f 107//1 108//1 1433//1 +f 1433//1 108//1 1434//1 +f 108//1 109//1 1434//1 +f 1434//1 109//1 1435//1 +f 109//1 110//1 1435//1 +f 1435//1 110//1 1436//1 +f 110//1 111//1 1436//1 +f 1436//1 111//1 1437//1 +f 111//1 112//1 1437//1 +f 1437//1 112//1 1438//1 +f 112//1 113//1 1438//1 +f 1438//1 113//1 1439//1 +f 113//1 114//1 1439//1 +f 1439//1 114//1 1440//1 +f 114//1 115//1 1440//1 +f 1440//1 115//1 1441//1 +f 115//1 116//1 1441//1 +f 1441//1 116//1 1442//1 +f 116//1 117//1 1442//1 +f 1442//1 117//1 1443//1 +f 117//1 118//1 1443//1 +f 1443//1 118//1 1444//1 +f 118//1 119//1 1444//1 +f 1444//1 119//1 1445//1 +f 119//1 120//1 1445//1 +f 1445//1 120//1 1446//1 +f 120//1 121//1 1446//1 +f 1446//1 121//1 1447//1 +f 121//1 122//1 1447//1 +f 1447//1 122//1 1448//1 +f 122//1 123//1 1448//1 +f 1448//1 123//1 1449//1 +f 123//1 124//1 1449//1 +f 1449//1 124//1 1450//1 +f 124//1 125//1 1450//1 +f 1450//1 125//1 1451//1 +f 125//1 126//1 1451//1 +f 1451//1 126//1 1452//1 +f 126//1 127//1 1452//1 +f 1452//1 127//1 1453//1 +f 127//1 128//1 1453//1 +f 1453//1 128//1 1454//1 +f 128//1 129//1 1454//1 +f 1454//1 129//1 1455//1 +f 129//1 130//1 1455//1 +f 1455//1 130//1 1456//1 +f 130//1 131//1 1456//1 +f 1456//1 131//1 1457//1 +f 131//1 132//1 1457//1 +f 1457//1 132//1 1458//1 +f 132//1 133//1 1458//1 +f 1458//1 133//1 1459//1 +f 133//1 134//1 1459//1 +f 1459//1 134//1 1460//1 +f 134//1 135//1 1460//1 +f 1460//1 135//1 1461//1 +f 135//1 136//1 1461//1 +f 1461//1 136//1 1462//1 +f 136//1 137//1 1462//1 +f 1462//1 137//1 1463//1 +f 137//1 138//1 1463//1 +f 1463//1 138//1 1464//1 +f 138//1 139//1 1464//1 +f 1464//1 139//1 1465//1 +f 139//1 140//1 1465//1 +f 1465//1 140//1 1466//1 +f 140//1 141//1 1466//1 +f 1466//1 141//1 1467//1 +f 141//1 142//1 1467//1 +f 1467//1 142//1 1468//1 +f 142//1 143//1 1468//1 +f 1468//1 143//1 1469//1 +f 143//1 144//1 1469//1 +f 1469//1 144//1 1470//1 +f 144//1 145//1 1470//1 +f 1470//1 145//1 1471//1 +f 145//1 146//1 1471//1 +f 1471//1 146//1 1472//1 +f 146//1 147//1 1472//1 +f 1472//1 147//1 1473//1 +f 147//1 148//1 1473//1 +f 1473//1 148//1 1474//1 +f 148//1 149//1 1474//1 +f 1474//1 149//1 1475//1 +f 149//1 150//1 1475//1 +f 1475//1 150//1 1476//1 +f 150//1 151//1 1476//1 +f 1476//1 151//1 1477//1 +f 151//1 152//1 1477//1 +f 1477//1 152//1 1478//1 +f 152//1 153//1 1478//1 +f 1478//1 153//1 1479//1 +f 153//1 154//1 1479//1 +f 1479//1 154//1 155//1 +f 154//1 4//1 155//1 +f 55//1 54//1 1//1 +f 56//1 1480//1 55//1 +f 57//1 1481//1 56//1 +f 58//1 1483//1 57//1 +f 59//1 1486//1 58//1 +f 60//1 1490//1 59//1 +f 61//1 1495//1 60//1 +f 62//1 1501//1 61//1 +f 63//1 1508//1 62//1 +f 64//1 1516//1 63//1 +f 65//1 1525//1 64//1 +f 66//1 1535//1 65//1 +f 67//1 1546//1 66//1 +f 68//1 1558//1 67//1 +f 69//1 1571//1 68//1 +f 70//1 1585//1 69//1 +f 71//1 1600//1 70//1 +f 72//1 1616//1 71//1 +f 73//1 1633//1 72//1 +f 74//1 1651//1 73//1 +f 75//1 1670//1 74//1 +f 76//1 1690//1 75//1 +f 77//1 1711//1 76//1 +f 78//1 1733//1 77//1 +f 79//1 1756//1 78//1 +f 80//1 1780//1 79//1 +f 81//1 1805//1 80//1 +f 82//1 1831//1 81//1 +f 83//1 1858//1 82//1 +f 84//1 1886//1 83//1 +f 85//1 1915//1 84//1 +f 86//1 1945//1 85//1 +f 87//1 1976//1 86//1 +f 88//1 2008//1 87//1 +f 89//1 2041//1 88//1 +f 90//1 2075//1 89//1 +f 91//1 2110//1 90//1 +f 92//1 2146//1 91//1 +f 93//1 2183//1 92//1 +f 94//1 2221//1 93//1 +f 95//1 2260//1 94//1 +f 96//1 2300//1 95//1 +f 97//1 2341//1 96//1 +f 98//1 2383//1 97//1 +f 99//1 2426//1 98//1 +f 100//1 2470//1 99//1 +f 101//1 2515//1 100//1 +f 102//1 2561//1 101//1 +f 103//1 2608//1 102//1 +f 104//1 2656//1 103//1 +f 55//1 1480//1 54//1 +f 1480//1 53//1 54//1 +f 56//1 1481//1 1480//1 +f 1481//1 1482//1 1480//1 +f 1480//1 1482//1 53//1 +f 1482//1 52//1 53//1 +f 57//1 1483//1 1481//1 +f 1483//1 1484//1 1481//1 +f 1481//1 1484//1 1482//1 +f 1484//1 1485//1 1482//1 +f 1482//1 1485//1 52//1 +f 1485//1 51//1 52//1 +f 58//1 1486//1 1483//1 +f 1486//1 1487//1 1483//1 +f 1483//1 1487//1 1484//1 +f 1487//1 1488//1 1484//1 +f 1484//1 1488//1 1485//1 +f 1488//1 1489//1 1485//1 +f 1485//1 1489//1 51//1 +f 1489//1 50//1 51//1 +f 59//1 1490//1 1486//1 +f 1490//1 1491//1 1486//1 +f 1486//1 1491//1 1487//1 +f 1491//1 1492//1 1487//1 +f 1487//1 1492//1 1488//1 +f 1492//1 1493//1 1488//1 +f 1488//1 1493//1 1489//1 +f 1493//1 1494//1 1489//1 +f 1489//1 1494//1 50//1 +f 1494//1 49//1 50//1 +f 60//1 1495//1 1490//1 +f 1495//1 1496//1 1490//1 +f 1490//1 1496//1 1491//1 +f 1496//1 1497//1 1491//1 +f 1491//1 1497//1 1492//1 +f 1497//1 1498//1 1492//1 +f 1492//1 1498//1 1493//1 +f 1498//1 1499//1 1493//1 +f 1493//1 1499//1 1494//1 +f 1499//1 1500//1 1494//1 +f 1494//1 1500//1 49//1 +f 1500//1 48//1 49//1 +f 61//1 1501//1 1495//1 +f 1501//1 1502//1 1495//1 +f 1495//1 1502//1 1496//1 +f 1502//1 1503//1 1496//1 +f 1496//1 1503//1 1497//1 +f 1503//1 1504//1 1497//1 +f 1497//1 1504//1 1498//1 +f 1504//1 1505//1 1498//1 +f 1498//1 1505//1 1499//1 +f 1505//1 1506//1 1499//1 +f 1499//1 1506//1 1500//1 +f 1506//1 1507//1 1500//1 +f 1500//1 1507//1 48//1 +f 1507//1 47//1 48//1 +f 62//1 1508//1 1501//1 +f 1508//1 1509//1 1501//1 +f 1501//1 1509//1 1502//1 +f 1509//1 1510//1 1502//1 +f 1502//1 1510//1 1503//1 +f 1510//1 1511//1 1503//1 +f 1503//1 1511//1 1504//1 +f 1511//1 1512//1 1504//1 +f 1504//1 1512//1 1505//1 +f 1512//1 1513//1 1505//1 +f 1505//1 1513//1 1506//1 +f 1513//1 1514//1 1506//1 +f 1506//1 1514//1 1507//1 +f 1514//1 1515//1 1507//1 +f 1507//1 1515//1 47//1 +f 1515//1 46//1 47//1 +f 63//1 1516//1 1508//1 +f 1516//1 1517//1 1508//1 +f 1508//1 1517//1 1509//1 +f 1517//1 1518//1 1509//1 +f 1509//1 1518//1 1510//1 +f 1518//1 1519//1 1510//1 +f 1510//1 1519//1 1511//1 +f 1519//1 1520//1 1511//1 +f 1511//1 1520//1 1512//1 +f 1520//1 1521//1 1512//1 +f 1512//1 1521//1 1513//1 +f 1521//1 1522//1 1513//1 +f 1513//1 1522//1 1514//1 +f 1522//1 1523//1 1514//1 +f 1514//1 1523//1 1515//1 +f 1523//1 1524//1 1515//1 +f 1515//1 1524//1 46//1 +f 1524//1 45//1 46//1 +f 64//1 1525//1 1516//1 +f 1525//1 1526//1 1516//1 +f 1516//1 1526//1 1517//1 +f 1526//1 1527//1 1517//1 +f 1517//1 1527//1 1518//1 +f 1527//1 1528//1 1518//1 +f 1518//1 1528//1 1519//1 +f 1528//1 1529//1 1519//1 +f 1519//1 1529//1 1520//1 +f 1529//1 1530//1 1520//1 +f 1520//1 1530//1 1521//1 +f 1530//1 1531//1 1521//1 +f 1521//1 1531//1 1522//1 +f 1531//1 1532//1 1522//1 +f 1522//1 1532//1 1523//1 +f 1532//1 1533//1 1523//1 +f 1523//1 1533//1 1524//1 +f 1533//1 1534//1 1524//1 +f 1524//1 1534//1 45//1 +f 1534//1 44//1 45//1 +f 65//1 1535//1 1525//1 +f 1535//1 1536//1 1525//1 +f 1525//1 1536//1 1526//1 +f 1536//1 1537//1 1526//1 +f 1526//1 1537//1 1527//1 +f 1537//1 1538//1 1527//1 +f 1527//1 1538//1 1528//1 +f 1538//1 1539//1 1528//1 +f 1528//1 1539//1 1529//1 +f 1539//1 1540//1 1529//1 +f 1529//1 1540//1 1530//1 +f 1540//1 1541//1 1530//1 +f 1530//1 1541//1 1531//1 +f 1541//1 1542//1 1531//1 +f 1531//1 1542//1 1532//1 +f 1542//1 1543//1 1532//1 +f 1532//1 1543//1 1533//1 +f 1543//1 1544//1 1533//1 +f 1533//1 1544//1 1534//1 +f 1544//1 1545//1 1534//1 +f 1534//1 1545//1 44//1 +f 1545//1 43//1 44//1 +f 66//1 1546//1 1535//1 +f 1546//1 1547//1 1535//1 +f 1535//1 1547//1 1536//1 +f 1547//1 1548//1 1536//1 +f 1536//1 1548//1 1537//1 +f 1548//1 1549//1 1537//1 +f 1537//1 1549//1 1538//1 +f 1549//1 1550//1 1538//1 +f 1538//1 1550//1 1539//1 +f 1550//1 1551//1 1539//1 +f 1539//1 1551//1 1540//1 +f 1551//1 1552//1 1540//1 +f 1540//1 1552//1 1541//1 +f 1552//1 1553//1 1541//1 +f 1541//1 1553//1 1542//1 +f 1553//1 1554//1 1542//1 +f 1542//1 1554//1 1543//1 +f 1554//1 1555//1 1543//1 +f 1543//1 1555//1 1544//1 +f 1555//1 1556//1 1544//1 +f 1544//1 1556//1 1545//1 +f 1556//1 1557//1 1545//1 +f 1545//1 1557//1 43//1 +f 1557//1 42//1 43//1 +f 67//1 1558//1 1546//1 +f 1558//1 1559//1 1546//1 +f 1546//1 1559//1 1547//1 +f 1559//1 1560//1 1547//1 +f 1547//1 1560//1 1548//1 +f 1560//1 1561//1 1548//1 +f 1548//1 1561//1 1549//1 +f 1561//1 1562//1 1549//1 +f 1549//1 1562//1 1550//1 +f 1562//1 1563//1 1550//1 +f 1550//1 1563//1 1551//1 +f 1563//1 1564//1 1551//1 +f 1551//1 1564//1 1552//1 +f 1564//1 1565//1 1552//1 +f 1552//1 1565//1 1553//1 +f 1565//1 1566//1 1553//1 +f 1553//1 1566//1 1554//1 +f 1566//1 1567//1 1554//1 +f 1554//1 1567//1 1555//1 +f 1567//1 1568//1 1555//1 +f 1555//1 1568//1 1556//1 +f 1568//1 1569//1 1556//1 +f 1556//1 1569//1 1557//1 +f 1569//1 1570//1 1557//1 +f 1557//1 1570//1 42//1 +f 1570//1 41//1 42//1 +f 68//1 1571//1 1558//1 +f 1571//1 1572//1 1558//1 +f 1558//1 1572//1 1559//1 +f 1572//1 1573//1 1559//1 +f 1559//1 1573//1 1560//1 +f 1573//1 1574//1 1560//1 +f 1560//1 1574//1 1561//1 +f 1574//1 1575//1 1561//1 +f 1561//1 1575//1 1562//1 +f 1575//1 1576//1 1562//1 +f 1562//1 1576//1 1563//1 +f 1576//1 1577//1 1563//1 +f 1563//1 1577//1 1564//1 +f 1577//1 1578//1 1564//1 +f 1564//1 1578//1 1565//1 +f 1578//1 1579//1 1565//1 +f 1565//1 1579//1 1566//1 +f 1579//1 1580//1 1566//1 +f 1566//1 1580//1 1567//1 +f 1580//1 1581//1 1567//1 +f 1567//1 1581//1 1568//1 +f 1581//1 1582//1 1568//1 +f 1568//1 1582//1 1569//1 +f 1582//1 1583//1 1569//1 +f 1569//1 1583//1 1570//1 +f 1583//1 1584//1 1570//1 +f 1570//1 1584//1 41//1 +f 1584//1 40//1 41//1 +f 69//1 1585//1 1571//1 +f 1585//1 1586//1 1571//1 +f 1571//1 1586//1 1572//1 +f 1586//1 1587//1 1572//1 +f 1572//1 1587//1 1573//1 +f 1587//1 1588//1 1573//1 +f 1573//1 1588//1 1574//1 +f 1588//1 1589//1 1574//1 +f 1574//1 1589//1 1575//1 +f 1589//1 1590//1 1575//1 +f 1575//1 1590//1 1576//1 +f 1590//1 1591//1 1576//1 +f 1576//1 1591//1 1577//1 +f 1591//1 1592//1 1577//1 +f 1577//1 1592//1 1578//1 +f 1592//1 1593//1 1578//1 +f 1578//1 1593//1 1579//1 +f 1593//1 1594//1 1579//1 +f 1579//1 1594//1 1580//1 +f 1594//1 1595//1 1580//1 +f 1580//1 1595//1 1581//1 +f 1595//1 1596//1 1581//1 +f 1581//1 1596//1 1582//1 +f 1596//1 1597//1 1582//1 +f 1582//1 1597//1 1583//1 +f 1597//1 1598//1 1583//1 +f 1583//1 1598//1 1584//1 +f 1598//1 1599//1 1584//1 +f 1584//1 1599//1 40//1 +f 1599//1 39//1 40//1 +f 70//1 1600//1 1585//1 +f 1600//1 1601//1 1585//1 +f 1585//1 1601//1 1586//1 +f 1601//1 1602//1 1586//1 +f 1586//1 1602//1 1587//1 +f 1602//1 1603//1 1587//1 +f 1587//1 1603//1 1588//1 +f 1603//1 1604//1 1588//1 +f 1588//1 1604//1 1589//1 +f 1604//1 1605//1 1589//1 +f 1589//1 1605//1 1590//1 +f 1605//1 1606//1 1590//1 +f 1590//1 1606//1 1591//1 +f 1606//1 1607//1 1591//1 +f 1591//1 1607//1 1592//1 +f 1607//1 1608//1 1592//1 +f 1592//1 1608//1 1593//1 +f 1608//1 1609//1 1593//1 +f 1593//1 1609//1 1594//1 +f 1609//1 1610//1 1594//1 +f 1594//1 1610//1 1595//1 +f 1610//1 1611//1 1595//1 +f 1595//1 1611//1 1596//1 +f 1611//1 1612//1 1596//1 +f 1596//1 1612//1 1597//1 +f 1612//1 1613//1 1597//1 +f 1597//1 1613//1 1598//1 +f 1613//1 1614//1 1598//1 +f 1598//1 1614//1 1599//1 +f 1614//1 1615//1 1599//1 +f 1599//1 1615//1 39//1 +f 1615//1 38//1 39//1 +f 71//1 1616//1 1600//1 +f 1616//1 1617//1 1600//1 +f 1600//1 1617//1 1601//1 +f 1617//1 1618//1 1601//1 +f 1601//1 1618//1 1602//1 +f 1618//1 1619//1 1602//1 +f 1602//1 1619//1 1603//1 +f 1619//1 1620//1 1603//1 +f 1603//1 1620//1 1604//1 +f 1620//1 1621//1 1604//1 +f 1604//1 1621//1 1605//1 +f 1621//1 1622//1 1605//1 +f 1605//1 1622//1 1606//1 +f 1622//1 1623//1 1606//1 +f 1606//1 1623//1 1607//1 +f 1623//1 1624//1 1607//1 +f 1607//1 1624//1 1608//1 +f 1624//1 1625//1 1608//1 +f 1608//1 1625//1 1609//1 +f 1625//1 1626//1 1609//1 +f 1609//1 1626//1 1610//1 +f 1626//1 1627//1 1610//1 +f 1610//1 1627//1 1611//1 +f 1627//1 1628//1 1611//1 +f 1611//1 1628//1 1612//1 +f 1628//1 1629//1 1612//1 +f 1612//1 1629//1 1613//1 +f 1629//1 1630//1 1613//1 +f 1613//1 1630//1 1614//1 +f 1630//1 1631//1 1614//1 +f 1614//1 1631//1 1615//1 +f 1631//1 1632//1 1615//1 +f 1615//1 1632//1 38//1 +f 1632//1 37//1 38//1 +f 72//1 1633//1 1616//1 +f 1633//1 1634//1 1616//1 +f 1616//1 1634//1 1617//1 +f 1634//1 1635//1 1617//1 +f 1617//1 1635//1 1618//1 +f 1635//1 1636//1 1618//1 +f 1618//1 1636//1 1619//1 +f 1636//1 1637//1 1619//1 +f 1619//1 1637//1 1620//1 +f 1637//1 1638//1 1620//1 +f 1620//1 1638//1 1621//1 +f 1638//1 1639//1 1621//1 +f 1621//1 1639//1 1622//1 +f 1639//1 1640//1 1622//1 +f 1622//1 1640//1 1623//1 +f 1640//1 1641//1 1623//1 +f 1623//1 1641//1 1624//1 +f 1641//1 1642//1 1624//1 +f 1624//1 1642//1 1625//1 +f 1642//1 1643//1 1625//1 +f 1625//1 1643//1 1626//1 +f 1643//1 1644//1 1626//1 +f 1626//1 1644//1 1627//1 +f 1644//1 1645//1 1627//1 +f 1627//1 1645//1 1628//1 +f 1645//1 1646//1 1628//1 +f 1628//1 1646//1 1629//1 +f 1646//1 1647//1 1629//1 +f 1629//1 1647//1 1630//1 +f 1647//1 1648//1 1630//1 +f 1630//1 1648//1 1631//1 +f 1648//1 1649//1 1631//1 +f 1631//1 1649//1 1632//1 +f 1649//1 1650//1 1632//1 +f 1632//1 1650//1 37//1 +f 1650//1 36//1 37//1 +f 73//1 1651//1 1633//1 +f 1651//1 1652//1 1633//1 +f 1633//1 1652//1 1634//1 +f 1652//1 1653//1 1634//1 +f 1634//1 1653//1 1635//1 +f 1653//1 1654//1 1635//1 +f 1635//1 1654//1 1636//1 +f 1654//1 1655//1 1636//1 +f 1636//1 1655//1 1637//1 +f 1655//1 1656//1 1637//1 +f 1637//1 1656//1 1638//1 +f 1656//1 1657//1 1638//1 +f 1638//1 1657//1 1639//1 +f 1657//1 1658//1 1639//1 +f 1639//1 1658//1 1640//1 +f 1658//1 1659//1 1640//1 +f 1640//1 1659//1 1641//1 +f 1659//1 1660//1 1641//1 +f 1641//1 1660//1 1642//1 +f 1660//1 1661//1 1642//1 +f 1642//1 1661//1 1643//1 +f 1661//1 1662//1 1643//1 +f 1643//1 1662//1 1644//1 +f 1662//1 1663//1 1644//1 +f 1644//1 1663//1 1645//1 +f 1663//1 1664//1 1645//1 +f 1645//1 1664//1 1646//1 +f 1664//1 1665//1 1646//1 +f 1646//1 1665//1 1647//1 +f 1665//1 1666//1 1647//1 +f 1647//1 1666//1 1648//1 +f 1666//1 1667//1 1648//1 +f 1648//1 1667//1 1649//1 +f 1667//1 1668//1 1649//1 +f 1649//1 1668//1 1650//1 +f 1668//1 1669//1 1650//1 +f 1650//1 1669//1 36//1 +f 1669//1 35//1 36//1 +f 74//1 1670//1 1651//1 +f 1670//1 1671//1 1651//1 +f 1651//1 1671//1 1652//1 +f 1671//1 1672//1 1652//1 +f 1652//1 1672//1 1653//1 +f 1672//1 1673//1 1653//1 +f 1653//1 1673//1 1654//1 +f 1673//1 1674//1 1654//1 +f 1654//1 1674//1 1655//1 +f 1674//1 1675//1 1655//1 +f 1655//1 1675//1 1656//1 +f 1675//1 1676//1 1656//1 +f 1656//1 1676//1 1657//1 +f 1676//1 1677//1 1657//1 +f 1657//1 1677//1 1658//1 +f 1677//1 1678//1 1658//1 +f 1658//1 1678//1 1659//1 +f 1678//1 1679//1 1659//1 +f 1659//1 1679//1 1660//1 +f 1679//1 1680//1 1660//1 +f 1660//1 1680//1 1661//1 +f 1680//1 1681//1 1661//1 +f 1661//1 1681//1 1662//1 +f 1681//1 1682//1 1662//1 +f 1662//1 1682//1 1663//1 +f 1682//1 1683//1 1663//1 +f 1663//1 1683//1 1664//1 +f 1683//1 1684//1 1664//1 +f 1664//1 1684//1 1665//1 +f 1684//1 1685//1 1665//1 +f 1665//1 1685//1 1666//1 +f 1685//1 1686//1 1666//1 +f 1666//1 1686//1 1667//1 +f 1686//1 1687//1 1667//1 +f 1667//1 1687//1 1668//1 +f 1687//1 1688//1 1668//1 +f 1668//1 1688//1 1669//1 +f 1688//1 1689//1 1669//1 +f 1669//1 1689//1 35//1 +f 1689//1 34//1 35//1 +f 75//1 1690//1 1670//1 +f 1690//1 1691//1 1670//1 +f 1670//1 1691//1 1671//1 +f 1691//1 1692//1 1671//1 +f 1671//1 1692//1 1672//1 +f 1692//1 1693//1 1672//1 +f 1672//1 1693//1 1673//1 +f 1693//1 1694//1 1673//1 +f 1673//1 1694//1 1674//1 +f 1694//1 1695//1 1674//1 +f 1674//1 1695//1 1675//1 +f 1695//1 1696//1 1675//1 +f 1675//1 1696//1 1676//1 +f 1696//1 1697//1 1676//1 +f 1676//1 1697//1 1677//1 +f 1697//1 1698//1 1677//1 +f 1677//1 1698//1 1678//1 +f 1698//1 1699//1 1678//1 +f 1678//1 1699//1 1679//1 +f 1699//1 1700//1 1679//1 +f 1679//1 1700//1 1680//1 +f 1700//1 1701//1 1680//1 +f 1680//1 1701//1 1681//1 +f 1701//1 1702//1 1681//1 +f 1681//1 1702//1 1682//1 +f 1702//1 1703//1 1682//1 +f 1682//1 1703//1 1683//1 +f 1703//1 1704//1 1683//1 +f 1683//1 1704//1 1684//1 +f 1704//1 1705//1 1684//1 +f 1684//1 1705//1 1685//1 +f 1705//1 1706//1 1685//1 +f 1685//1 1706//1 1686//1 +f 1706//1 1707//1 1686//1 +f 1686//1 1707//1 1687//1 +f 1707//1 1708//1 1687//1 +f 1687//1 1708//1 1688//1 +f 1708//1 1709//1 1688//1 +f 1688//1 1709//1 1689//1 +f 1709//1 1710//1 1689//1 +f 1689//1 1710//1 34//1 +f 1710//1 33//1 34//1 +f 76//1 1711//1 1690//1 +f 1711//1 1712//1 1690//1 +f 1690//1 1712//1 1691//1 +f 1712//1 1713//1 1691//1 +f 1691//1 1713//1 1692//1 +f 1713//1 1714//1 1692//1 +f 1692//1 1714//1 1693//1 +f 1714//1 1715//1 1693//1 +f 1693//1 1715//1 1694//1 +f 1715//1 1716//1 1694//1 +f 1694//1 1716//1 1695//1 +f 1716//1 1717//1 1695//1 +f 1695//1 1717//1 1696//1 +f 1717//1 1718//1 1696//1 +f 1696//1 1718//1 1697//1 +f 1718//1 1719//1 1697//1 +f 1697//1 1719//1 1698//1 +f 1719//1 1720//1 1698//1 +f 1698//1 1720//1 1699//1 +f 1720//1 1721//1 1699//1 +f 1699//1 1721//1 1700//1 +f 1721//1 1722//1 1700//1 +f 1700//1 1722//1 1701//1 +f 1722//1 1723//1 1701//1 +f 1701//1 1723//1 1702//1 +f 1723//1 1724//1 1702//1 +f 1702//1 1724//1 1703//1 +f 1724//1 1725//1 1703//1 +f 1703//1 1725//1 1704//1 +f 1725//1 1726//1 1704//1 +f 1704//1 1726//1 1705//1 +f 1726//1 1727//1 1705//1 +f 1705//1 1727//1 1706//1 +f 1727//1 1728//1 1706//1 +f 1706//1 1728//1 1707//1 +f 1728//1 1729//1 1707//1 +f 1707//1 1729//1 1708//1 +f 1729//1 1730//1 1708//1 +f 1708//1 1730//1 1709//1 +f 1730//1 1731//1 1709//1 +f 1709//1 1731//1 1710//1 +f 1731//1 1732//1 1710//1 +f 1710//1 1732//1 33//1 +f 1732//1 32//1 33//1 +f 77//1 1733//1 1711//1 +f 1733//1 1734//1 1711//1 +f 1711//1 1734//1 1712//1 +f 1734//1 1735//1 1712//1 +f 1712//1 1735//1 1713//1 +f 1735//1 1736//1 1713//1 +f 1713//1 1736//1 1714//1 +f 1736//1 1737//1 1714//1 +f 1714//1 1737//1 1715//1 +f 1737//1 1738//1 1715//1 +f 1715//1 1738//1 1716//1 +f 1738//1 1739//1 1716//1 +f 1716//1 1739//1 1717//1 +f 1739//1 1740//1 1717//1 +f 1717//1 1740//1 1718//1 +f 1740//1 1741//1 1718//1 +f 1718//1 1741//1 1719//1 +f 1741//1 1742//1 1719//1 +f 1719//1 1742//1 1720//1 +f 1742//1 1743//1 1720//1 +f 1720//1 1743//1 1721//1 +f 1743//1 1744//1 1721//1 +f 1721//1 1744//1 1722//1 +f 1744//1 1745//1 1722//1 +f 1722//1 1745//1 1723//1 +f 1745//1 1746//1 1723//1 +f 1723//1 1746//1 1724//1 +f 1746//1 1747//1 1724//1 +f 1724//1 1747//1 1725//1 +f 1747//1 1748//1 1725//1 +f 1725//1 1748//1 1726//1 +f 1748//1 1749//1 1726//1 +f 1726//1 1749//1 1727//1 +f 1749//1 1750//1 1727//1 +f 1727//1 1750//1 1728//1 +f 1750//1 1751//1 1728//1 +f 1728//1 1751//1 1729//1 +f 1751//1 1752//1 1729//1 +f 1729//1 1752//1 1730//1 +f 1752//1 1753//1 1730//1 +f 1730//1 1753//1 1731//1 +f 1753//1 1754//1 1731//1 +f 1731//1 1754//1 1732//1 +f 1754//1 1755//1 1732//1 +f 1732//1 1755//1 32//1 +f 1755//1 31//1 32//1 +f 78//1 1756//1 1733//1 +f 1756//1 1757//1 1733//1 +f 1733//1 1757//1 1734//1 +f 1757//1 1758//1 1734//1 +f 1734//1 1758//1 1735//1 +f 1758//1 1759//1 1735//1 +f 1735//1 1759//1 1736//1 +f 1759//1 1760//1 1736//1 +f 1736//1 1760//1 1737//1 +f 1760//1 1761//1 1737//1 +f 1737//1 1761//1 1738//1 +f 1761//1 1762//1 1738//1 +f 1738//1 1762//1 1739//1 +f 1762//1 1763//1 1739//1 +f 1739//1 1763//1 1740//1 +f 1763//1 1764//1 1740//1 +f 1740//1 1764//1 1741//1 +f 1764//1 1765//1 1741//1 +f 1741//1 1765//1 1742//1 +f 1765//1 1766//1 1742//1 +f 1742//1 1766//1 1743//1 +f 1766//1 1767//1 1743//1 +f 1743//1 1767//1 1744//1 +f 1767//1 1768//1 1744//1 +f 1744//1 1768//1 1745//1 +f 1768//1 1769//1 1745//1 +f 1745//1 1769//1 1746//1 +f 1769//1 1770//1 1746//1 +f 1746//1 1770//1 1747//1 +f 1770//1 1771//1 1747//1 +f 1747//1 1771//1 1748//1 +f 1771//1 1772//1 1748//1 +f 1748//1 1772//1 1749//1 +f 1772//1 1773//1 1749//1 +f 1749//1 1773//1 1750//1 +f 1773//1 1774//1 1750//1 +f 1750//1 1774//1 1751//1 +f 1774//1 1775//1 1751//1 +f 1751//1 1775//1 1752//1 +f 1775//1 1776//1 1752//1 +f 1752//1 1776//1 1753//1 +f 1776//1 1777//1 1753//1 +f 1753//1 1777//1 1754//1 +f 1777//1 1778//1 1754//1 +f 1754//1 1778//1 1755//1 +f 1778//1 1779//1 1755//1 +f 1755//1 1779//1 31//1 +f 1779//1 30//1 31//1 +f 79//1 1780//1 1756//1 +f 1780//1 1781//1 1756//1 +f 1756//1 1781//1 1757//1 +f 1781//1 1782//1 1757//1 +f 1757//1 1782//1 1758//1 +f 1782//1 1783//1 1758//1 +f 1758//1 1783//1 1759//1 +f 1783//1 1784//1 1759//1 +f 1759//1 1784//1 1760//1 +f 1784//1 1785//1 1760//1 +f 1760//1 1785//1 1761//1 +f 1785//1 1786//1 1761//1 +f 1761//1 1786//1 1762//1 +f 1786//1 1787//1 1762//1 +f 1762//1 1787//1 1763//1 +f 1787//1 1788//1 1763//1 +f 1763//1 1788//1 1764//1 +f 1788//1 1789//1 1764//1 +f 1764//1 1789//1 1765//1 +f 1789//1 1790//1 1765//1 +f 1765//1 1790//1 1766//1 +f 1790//1 1791//1 1766//1 +f 1766//1 1791//1 1767//1 +f 1791//1 1792//1 1767//1 +f 1767//1 1792//1 1768//1 +f 1792//1 1793//1 1768//1 +f 1768//1 1793//1 1769//1 +f 1793//1 1794//1 1769//1 +f 1769//1 1794//1 1770//1 +f 1794//1 1795//1 1770//1 +f 1770//1 1795//1 1771//1 +f 1795//1 1796//1 1771//1 +f 1771//1 1796//1 1772//1 +f 1796//1 1797//1 1772//1 +f 1772//1 1797//1 1773//1 +f 1797//1 1798//1 1773//1 +f 1773//1 1798//1 1774//1 +f 1798//1 1799//1 1774//1 +f 1774//1 1799//1 1775//1 +f 1799//1 1800//1 1775//1 +f 1775//1 1800//1 1776//1 +f 1800//1 1801//1 1776//1 +f 1776//1 1801//1 1777//1 +f 1801//1 1802//1 1777//1 +f 1777//1 1802//1 1778//1 +f 1802//1 1803//1 1778//1 +f 1778//1 1803//1 1779//1 +f 1803//1 1804//1 1779//1 +f 1779//1 1804//1 30//1 +f 1804//1 29//1 30//1 +f 80//1 1805//1 1780//1 +f 1805//1 1806//1 1780//1 +f 1780//1 1806//1 1781//1 +f 1806//1 1807//1 1781//1 +f 1781//1 1807//1 1782//1 +f 1807//1 1808//1 1782//1 +f 1782//1 1808//1 1783//1 +f 1808//1 1809//1 1783//1 +f 1783//1 1809//1 1784//1 +f 1809//1 1810//1 1784//1 +f 1784//1 1810//1 1785//1 +f 1810//1 1811//1 1785//1 +f 1785//1 1811//1 1786//1 +f 1811//1 1812//1 1786//1 +f 1786//1 1812//1 1787//1 +f 1812//1 1813//1 1787//1 +f 1787//1 1813//1 1788//1 +f 1813//1 1814//1 1788//1 +f 1788//1 1814//1 1789//1 +f 1814//1 1815//1 1789//1 +f 1789//1 1815//1 1790//1 +f 1815//1 1816//1 1790//1 +f 1790//1 1816//1 1791//1 +f 1816//1 1817//1 1791//1 +f 1791//1 1817//1 1792//1 +f 1817//1 1818//1 1792//1 +f 1792//1 1818//1 1793//1 +f 1818//1 1819//1 1793//1 +f 1793//1 1819//1 1794//1 +f 1819//1 1820//1 1794//1 +f 1794//1 1820//1 1795//1 +f 1820//1 1821//1 1795//1 +f 1795//1 1821//1 1796//1 +f 1821//1 1822//1 1796//1 +f 1796//1 1822//1 1797//1 +f 1822//1 1823//1 1797//1 +f 1797//1 1823//1 1798//1 +f 1823//1 1824//1 1798//1 +f 1798//1 1824//1 1799//1 +f 1824//1 1825//1 1799//1 +f 1799//1 1825//1 1800//1 +f 1825//1 1826//1 1800//1 +f 1800//1 1826//1 1801//1 +f 1826//1 1827//1 1801//1 +f 1801//1 1827//1 1802//1 +f 1827//1 1828//1 1802//1 +f 1802//1 1828//1 1803//1 +f 1828//1 1829//1 1803//1 +f 1803//1 1829//1 1804//1 +f 1829//1 1830//1 1804//1 +f 1804//1 1830//1 29//1 +f 1830//1 28//1 29//1 +f 81//1 1831//1 1805//1 +f 1831//1 1832//1 1805//1 +f 1805//1 1832//1 1806//1 +f 1832//1 1833//1 1806//1 +f 1806//1 1833//1 1807//1 +f 1833//1 1834//1 1807//1 +f 1807//1 1834//1 1808//1 +f 1834//1 1835//1 1808//1 +f 1808//1 1835//1 1809//1 +f 1835//1 1836//1 1809//1 +f 1809//1 1836//1 1810//1 +f 1836//1 1837//1 1810//1 +f 1810//1 1837//1 1811//1 +f 1837//1 1838//1 1811//1 +f 1811//1 1838//1 1812//1 +f 1838//1 1839//1 1812//1 +f 1812//1 1839//1 1813//1 +f 1839//1 1840//1 1813//1 +f 1813//1 1840//1 1814//1 +f 1840//1 1841//1 1814//1 +f 1814//1 1841//1 1815//1 +f 1841//1 1842//1 1815//1 +f 1815//1 1842//1 1816//1 +f 1842//1 1843//1 1816//1 +f 1816//1 1843//1 1817//1 +f 1843//1 1844//1 1817//1 +f 1817//1 1844//1 1818//1 +f 1844//1 1845//1 1818//1 +f 1818//1 1845//1 1819//1 +f 1845//1 1846//1 1819//1 +f 1819//1 1846//1 1820//1 +f 1846//1 1847//1 1820//1 +f 1820//1 1847//1 1821//1 +f 1847//1 1848//1 1821//1 +f 1821//1 1848//1 1822//1 +f 1848//1 1849//1 1822//1 +f 1822//1 1849//1 1823//1 +f 1849//1 1850//1 1823//1 +f 1823//1 1850//1 1824//1 +f 1850//1 1851//1 1824//1 +f 1824//1 1851//1 1825//1 +f 1851//1 1852//1 1825//1 +f 1825//1 1852//1 1826//1 +f 1852//1 1853//1 1826//1 +f 1826//1 1853//1 1827//1 +f 1853//1 1854//1 1827//1 +f 1827//1 1854//1 1828//1 +f 1854//1 1855//1 1828//1 +f 1828//1 1855//1 1829//1 +f 1855//1 1856//1 1829//1 +f 1829//1 1856//1 1830//1 +f 1856//1 1857//1 1830//1 +f 1830//1 1857//1 28//1 +f 1857//1 27//1 28//1 +f 82//1 1858//1 1831//1 +f 1858//1 1859//1 1831//1 +f 1831//1 1859//1 1832//1 +f 1859//1 1860//1 1832//1 +f 1832//1 1860//1 1833//1 +f 1860//1 1861//1 1833//1 +f 1833//1 1861//1 1834//1 +f 1861//1 1862//1 1834//1 +f 1834//1 1862//1 1835//1 +f 1862//1 1863//1 1835//1 +f 1835//1 1863//1 1836//1 +f 1863//1 1864//1 1836//1 +f 1836//1 1864//1 1837//1 +f 1864//1 1865//1 1837//1 +f 1837//1 1865//1 1838//1 +f 1865//1 1866//1 1838//1 +f 1838//1 1866//1 1839//1 +f 1866//1 1867//1 1839//1 +f 1839//1 1867//1 1840//1 +f 1867//1 1868//1 1840//1 +f 1840//1 1868//1 1841//1 +f 1868//1 1869//1 1841//1 +f 1841//1 1869//1 1842//1 +f 1869//1 1870//1 1842//1 +f 1842//1 1870//1 1843//1 +f 1870//1 1871//1 1843//1 +f 1843//1 1871//1 1844//1 +f 1871//1 1872//1 1844//1 +f 1844//1 1872//1 1845//1 +f 1872//1 1873//1 1845//1 +f 1845//1 1873//1 1846//1 +f 1873//1 1874//1 1846//1 +f 1846//1 1874//1 1847//1 +f 1874//1 1875//1 1847//1 +f 1847//1 1875//1 1848//1 +f 1875//1 1876//1 1848//1 +f 1848//1 1876//1 1849//1 +f 1876//1 1877//1 1849//1 +f 1849//1 1877//1 1850//1 +f 1877//1 1878//1 1850//1 +f 1850//1 1878//1 1851//1 +f 1878//1 1879//1 1851//1 +f 1851//1 1879//1 1852//1 +f 1879//1 1880//1 1852//1 +f 1852//1 1880//1 1853//1 +f 1880//1 1881//1 1853//1 +f 1853//1 1881//1 1854//1 +f 1881//1 1882//1 1854//1 +f 1854//1 1882//1 1855//1 +f 1882//1 1883//1 1855//1 +f 1855//1 1883//1 1856//1 +f 1883//1 1884//1 1856//1 +f 1856//1 1884//1 1857//1 +f 1884//1 1885//1 1857//1 +f 1857//1 1885//1 27//1 +f 1885//1 26//1 27//1 +f 83//1 1886//1 1858//1 +f 1886//1 1887//1 1858//1 +f 1858//1 1887//1 1859//1 +f 1887//1 1888//1 1859//1 +f 1859//1 1888//1 1860//1 +f 1888//1 1889//1 1860//1 +f 1860//1 1889//1 1861//1 +f 1889//1 1890//1 1861//1 +f 1861//1 1890//1 1862//1 +f 1890//1 1891//1 1862//1 +f 1862//1 1891//1 1863//1 +f 1891//1 1892//1 1863//1 +f 1863//1 1892//1 1864//1 +f 1892//1 1893//1 1864//1 +f 1864//1 1893//1 1865//1 +f 1893//1 1894//1 1865//1 +f 1865//1 1894//1 1866//1 +f 1894//1 1895//1 1866//1 +f 1866//1 1895//1 1867//1 +f 1895//1 1896//1 1867//1 +f 1867//1 1896//1 1868//1 +f 1896//1 1897//1 1868//1 +f 1868//1 1897//1 1869//1 +f 1897//1 1898//1 1869//1 +f 1869//1 1898//1 1870//1 +f 1898//1 1899//1 1870//1 +f 1870//1 1899//1 1871//1 +f 1899//1 1900//1 1871//1 +f 1871//1 1900//1 1872//1 +f 1900//1 1901//1 1872//1 +f 1872//1 1901//1 1873//1 +f 1901//1 1902//1 1873//1 +f 1873//1 1902//1 1874//1 +f 1902//1 1903//1 1874//1 +f 1874//1 1903//1 1875//1 +f 1903//1 1904//1 1875//1 +f 1875//1 1904//1 1876//1 +f 1904//1 1905//1 1876//1 +f 1876//1 1905//1 1877//1 +f 1905//1 1906//1 1877//1 +f 1877//1 1906//1 1878//1 +f 1906//1 1907//1 1878//1 +f 1878//1 1907//1 1879//1 +f 1907//1 1908//1 1879//1 +f 1879//1 1908//1 1880//1 +f 1908//1 1909//1 1880//1 +f 1880//1 1909//1 1881//1 +f 1909//1 1910//1 1881//1 +f 1881//1 1910//1 1882//1 +f 1910//1 1911//1 1882//1 +f 1882//1 1911//1 1883//1 +f 1911//1 1912//1 1883//1 +f 1883//1 1912//1 1884//1 +f 1912//1 1913//1 1884//1 +f 1884//1 1913//1 1885//1 +f 1913//1 1914//1 1885//1 +f 1885//1 1914//1 26//1 +f 1914//1 25//1 26//1 +f 84//1 1915//1 1886//1 +f 1915//1 1916//1 1886//1 +f 1886//1 1916//1 1887//1 +f 1916//1 1917//1 1887//1 +f 1887//1 1917//1 1888//1 +f 1917//1 1918//1 1888//1 +f 1888//1 1918//1 1889//1 +f 1918//1 1919//1 1889//1 +f 1889//1 1919//1 1890//1 +f 1919//1 1920//1 1890//1 +f 1890//1 1920//1 1891//1 +f 1920//1 1921//1 1891//1 +f 1891//1 1921//1 1892//1 +f 1921//1 1922//1 1892//1 +f 1892//1 1922//1 1893//1 +f 1922//1 1923//1 1893//1 +f 1893//1 1923//1 1894//1 +f 1923//1 1924//1 1894//1 +f 1894//1 1924//1 1895//1 +f 1924//1 1925//1 1895//1 +f 1895//1 1925//1 1896//1 +f 1925//1 1926//1 1896//1 +f 1896//1 1926//1 1897//1 +f 1926//1 1927//1 1897//1 +f 1897//1 1927//1 1898//1 +f 1927//1 1928//1 1898//1 +f 1898//1 1928//1 1899//1 +f 1928//1 1929//1 1899//1 +f 1899//1 1929//1 1900//1 +f 1929//1 1930//1 1900//1 +f 1900//1 1930//1 1901//1 +f 1930//1 1931//1 1901//1 +f 1901//1 1931//1 1902//1 +f 1931//1 1932//1 1902//1 +f 1902//1 1932//1 1903//1 +f 1932//1 1933//1 1903//1 +f 1903//1 1933//1 1904//1 +f 1933//1 1934//1 1904//1 +f 1904//1 1934//1 1905//1 +f 1934//1 1935//1 1905//1 +f 1905//1 1935//1 1906//1 +f 1935//1 1936//1 1906//1 +f 1906//1 1936//1 1907//1 +f 1936//1 1937//1 1907//1 +f 1907//1 1937//1 1908//1 +f 1937//1 1938//1 1908//1 +f 1908//1 1938//1 1909//1 +f 1938//1 1939//1 1909//1 +f 1909//1 1939//1 1910//1 +f 1939//1 1940//1 1910//1 +f 1910//1 1940//1 1911//1 +f 1940//1 1941//1 1911//1 +f 1911//1 1941//1 1912//1 +f 1941//1 1942//1 1912//1 +f 1912//1 1942//1 1913//1 +f 1942//1 1943//1 1913//1 +f 1913//1 1943//1 1914//1 +f 1943//1 1944//1 1914//1 +f 1914//1 1944//1 25//1 +f 1944//1 24//1 25//1 +f 85//1 1945//1 1915//1 +f 1945//1 1946//1 1915//1 +f 1915//1 1946//1 1916//1 +f 1946//1 1947//1 1916//1 +f 1916//1 1947//1 1917//1 +f 1947//1 1948//1 1917//1 +f 1917//1 1948//1 1918//1 +f 1948//1 1949//1 1918//1 +f 1918//1 1949//1 1919//1 +f 1949//1 1950//1 1919//1 +f 1919//1 1950//1 1920//1 +f 1950//1 1951//1 1920//1 +f 1920//1 1951//1 1921//1 +f 1951//1 1952//1 1921//1 +f 1921//1 1952//1 1922//1 +f 1952//1 1953//1 1922//1 +f 1922//1 1953//1 1923//1 +f 1953//1 1954//1 1923//1 +f 1923//1 1954//1 1924//1 +f 1954//1 1955//1 1924//1 +f 1924//1 1955//1 1925//1 +f 1955//1 1956//1 1925//1 +f 1925//1 1956//1 1926//1 +f 1956//1 1957//1 1926//1 +f 1926//1 1957//1 1927//1 +f 1957//1 1958//1 1927//1 +f 1927//1 1958//1 1928//1 +f 1958//1 1959//1 1928//1 +f 1928//1 1959//1 1929//1 +f 1959//1 1960//1 1929//1 +f 1929//1 1960//1 1930//1 +f 1960//1 1961//1 1930//1 +f 1930//1 1961//1 1931//1 +f 1961//1 1962//1 1931//1 +f 1931//1 1962//1 1932//1 +f 1962//1 1963//1 1932//1 +f 1932//1 1963//1 1933//1 +f 1963//1 1964//1 1933//1 +f 1933//1 1964//1 1934//1 +f 1964//1 1965//1 1934//1 +f 1934//1 1965//1 1935//1 +f 1965//1 1966//1 1935//1 +f 1935//1 1966//1 1936//1 +f 1966//1 1967//1 1936//1 +f 1936//1 1967//1 1937//1 +f 1967//1 1968//1 1937//1 +f 1937//1 1968//1 1938//1 +f 1968//1 1969//1 1938//1 +f 1938//1 1969//1 1939//1 +f 1969//1 1970//1 1939//1 +f 1939//1 1970//1 1940//1 +f 1970//1 1971//1 1940//1 +f 1940//1 1971//1 1941//1 +f 1971//1 1972//1 1941//1 +f 1941//1 1972//1 1942//1 +f 1972//1 1973//1 1942//1 +f 1942//1 1973//1 1943//1 +f 1973//1 1974//1 1943//1 +f 1943//1 1974//1 1944//1 +f 1974//1 1975//1 1944//1 +f 1944//1 1975//1 24//1 +f 1975//1 23//1 24//1 +f 86//1 1976//1 1945//1 +f 1976//1 1977//1 1945//1 +f 1945//1 1977//1 1946//1 +f 1977//1 1978//1 1946//1 +f 1946//1 1978//1 1947//1 +f 1978//1 1979//1 1947//1 +f 1947//1 1979//1 1948//1 +f 1979//1 1980//1 1948//1 +f 1948//1 1980//1 1949//1 +f 1980//1 1981//1 1949//1 +f 1949//1 1981//1 1950//1 +f 1981//1 1982//1 1950//1 +f 1950//1 1982//1 1951//1 +f 1982//1 1983//1 1951//1 +f 1951//1 1983//1 1952//1 +f 1983//1 1984//1 1952//1 +f 1952//1 1984//1 1953//1 +f 1984//1 1985//1 1953//1 +f 1953//1 1985//1 1954//1 +f 1985//1 1986//1 1954//1 +f 1954//1 1986//1 1955//1 +f 1986//1 1987//1 1955//1 +f 1955//1 1987//1 1956//1 +f 1987//1 1988//1 1956//1 +f 1956//1 1988//1 1957//1 +f 1988//1 1989//1 1957//1 +f 1957//1 1989//1 1958//1 +f 1989//1 1990//1 1958//1 +f 1958//1 1990//1 1959//1 +f 1990//1 1991//1 1959//1 +f 1959//1 1991//1 1960//1 +f 1991//1 1992//1 1960//1 +f 1960//1 1992//1 1961//1 +f 1992//1 1993//1 1961//1 +f 1961//1 1993//1 1962//1 +f 1993//1 1994//1 1962//1 +f 1962//1 1994//1 1963//1 +f 1994//1 1995//1 1963//1 +f 1963//1 1995//1 1964//1 +f 1995//1 1996//1 1964//1 +f 1964//1 1996//1 1965//1 +f 1996//1 1997//1 1965//1 +f 1965//1 1997//1 1966//1 +f 1997//1 1998//1 1966//1 +f 1966//1 1998//1 1967//1 +f 1998//1 1999//1 1967//1 +f 1967//1 1999//1 1968//1 +f 1999//1 2000//1 1968//1 +f 1968//1 2000//1 1969//1 +f 2000//1 2001//1 1969//1 +f 1969//1 2001//1 1970//1 +f 2001//1 2002//1 1970//1 +f 1970//1 2002//1 1971//1 +f 2002//1 2003//1 1971//1 +f 1971//1 2003//1 1972//1 +f 2003//1 2004//1 1972//1 +f 1972//1 2004//1 1973//1 +f 2004//1 2005//1 1973//1 +f 1973//1 2005//1 1974//1 +f 2005//1 2006//1 1974//1 +f 1974//1 2006//1 1975//1 +f 2006//1 2007//1 1975//1 +f 1975//1 2007//1 23//1 +f 2007//1 22//1 23//1 +f 87//1 2008//1 1976//1 +f 2008//1 2009//1 1976//1 +f 1976//1 2009//1 1977//1 +f 2009//1 2010//1 1977//1 +f 1977//1 2010//1 1978//1 +f 2010//1 2011//1 1978//1 +f 1978//1 2011//1 1979//1 +f 2011//1 2012//1 1979//1 +f 1979//1 2012//1 1980//1 +f 2012//1 2013//1 1980//1 +f 1980//1 2013//1 1981//1 +f 2013//1 2014//1 1981//1 +f 1981//1 2014//1 1982//1 +f 2014//1 2015//1 1982//1 +f 1982//1 2015//1 1983//1 +f 2015//1 2016//1 1983//1 +f 1983//1 2016//1 1984//1 +f 2016//1 2017//1 1984//1 +f 1984//1 2017//1 1985//1 +f 2017//1 2018//1 1985//1 +f 1985//1 2018//1 1986//1 +f 2018//1 2019//1 1986//1 +f 1986//1 2019//1 1987//1 +f 2019//1 2020//1 1987//1 +f 1987//1 2020//1 1988//1 +f 2020//1 2021//1 1988//1 +f 1988//1 2021//1 1989//1 +f 2021//1 2022//1 1989//1 +f 1989//1 2022//1 1990//1 +f 2022//1 2023//1 1990//1 +f 1990//1 2023//1 1991//1 +f 2023//1 2024//1 1991//1 +f 1991//1 2024//1 1992//1 +f 2024//1 2025//1 1992//1 +f 1992//1 2025//1 1993//1 +f 2025//1 2026//1 1993//1 +f 1993//1 2026//1 1994//1 +f 2026//1 2027//1 1994//1 +f 1994//1 2027//1 1995//1 +f 2027//1 2028//1 1995//1 +f 1995//1 2028//1 1996//1 +f 2028//1 2029//1 1996//1 +f 1996//1 2029//1 1997//1 +f 2029//1 2030//1 1997//1 +f 1997//1 2030//1 1998//1 +f 2030//1 2031//1 1998//1 +f 1998//1 2031//1 1999//1 +f 2031//1 2032//1 1999//1 +f 1999//1 2032//1 2000//1 +f 2032//1 2033//1 2000//1 +f 2000//1 2033//1 2001//1 +f 2033//1 2034//1 2001//1 +f 2001//1 2034//1 2002//1 +f 2034//1 2035//1 2002//1 +f 2002//1 2035//1 2003//1 +f 2035//1 2036//1 2003//1 +f 2003//1 2036//1 2004//1 +f 2036//1 2037//1 2004//1 +f 2004//1 2037//1 2005//1 +f 2037//1 2038//1 2005//1 +f 2005//1 2038//1 2006//1 +f 2038//1 2039//1 2006//1 +f 2006//1 2039//1 2007//1 +f 2039//1 2040//1 2007//1 +f 2007//1 2040//1 22//1 +f 2040//1 21//1 22//1 +f 88//1 2041//1 2008//1 +f 2041//1 2042//1 2008//1 +f 2008//1 2042//1 2009//1 +f 2042//1 2043//1 2009//1 +f 2009//1 2043//1 2010//1 +f 2043//1 2044//1 2010//1 +f 2010//1 2044//1 2011//1 +f 2044//1 2045//1 2011//1 +f 2011//1 2045//1 2012//1 +f 2045//1 2046//1 2012//1 +f 2012//1 2046//1 2013//1 +f 2046//1 2047//1 2013//1 +f 2013//1 2047//1 2014//1 +f 2047//1 2048//1 2014//1 +f 2014//1 2048//1 2015//1 +f 2048//1 2049//1 2015//1 +f 2015//1 2049//1 2016//1 +f 2049//1 2050//1 2016//1 +f 2016//1 2050//1 2017//1 +f 2050//1 2051//1 2017//1 +f 2017//1 2051//1 2018//1 +f 2051//1 2052//1 2018//1 +f 2018//1 2052//1 2019//1 +f 2052//1 2053//1 2019//1 +f 2019//1 2053//1 2020//1 +f 2053//1 2054//1 2020//1 +f 2020//1 2054//1 2021//1 +f 2054//1 2055//1 2021//1 +f 2021//1 2055//1 2022//1 +f 2055//1 2056//1 2022//1 +f 2022//1 2056//1 2023//1 +f 2056//1 2057//1 2023//1 +f 2023//1 2057//1 2024//1 +f 2057//1 2058//1 2024//1 +f 2024//1 2058//1 2025//1 +f 2058//1 2059//1 2025//1 +f 2025//1 2059//1 2026//1 +f 2059//1 2060//1 2026//1 +f 2026//1 2060//1 2027//1 +f 2060//1 2061//1 2027//1 +f 2027//1 2061//1 2028//1 +f 2061//1 2062//1 2028//1 +f 2028//1 2062//1 2029//1 +f 2062//1 2063//1 2029//1 +f 2029//1 2063//1 2030//1 +f 2063//1 2064//1 2030//1 +f 2030//1 2064//1 2031//1 +f 2064//1 2065//1 2031//1 +f 2031//1 2065//1 2032//1 +f 2065//1 2066//1 2032//1 +f 2032//1 2066//1 2033//1 +f 2066//1 2067//1 2033//1 +f 2033//1 2067//1 2034//1 +f 2067//1 2068//1 2034//1 +f 2034//1 2068//1 2035//1 +f 2068//1 2069//1 2035//1 +f 2035//1 2069//1 2036//1 +f 2069//1 2070//1 2036//1 +f 2036//1 2070//1 2037//1 +f 2070//1 2071//1 2037//1 +f 2037//1 2071//1 2038//1 +f 2071//1 2072//1 2038//1 +f 2038//1 2072//1 2039//1 +f 2072//1 2073//1 2039//1 +f 2039//1 2073//1 2040//1 +f 2073//1 2074//1 2040//1 +f 2040//1 2074//1 21//1 +f 2074//1 20//1 21//1 +f 89//1 2075//1 2041//1 +f 2075//1 2076//1 2041//1 +f 2041//1 2076//1 2042//1 +f 2076//1 2077//1 2042//1 +f 2042//1 2077//1 2043//1 +f 2077//1 2078//1 2043//1 +f 2043//1 2078//1 2044//1 +f 2078//1 2079//1 2044//1 +f 2044//1 2079//1 2045//1 +f 2079//1 2080//1 2045//1 +f 2045//1 2080//1 2046//1 +f 2080//1 2081//1 2046//1 +f 2046//1 2081//1 2047//1 +f 2081//1 2082//1 2047//1 +f 2047//1 2082//1 2048//1 +f 2082//1 2083//1 2048//1 +f 2048//1 2083//1 2049//1 +f 2083//1 2084//1 2049//1 +f 2049//1 2084//1 2050//1 +f 2084//1 2085//1 2050//1 +f 2050//1 2085//1 2051//1 +f 2085//1 2086//1 2051//1 +f 2051//1 2086//1 2052//1 +f 2086//1 2087//1 2052//1 +f 2052//1 2087//1 2053//1 +f 2087//1 2088//1 2053//1 +f 2053//1 2088//1 2054//1 +f 2088//1 2089//1 2054//1 +f 2054//1 2089//1 2055//1 +f 2089//1 2090//1 2055//1 +f 2055//1 2090//1 2056//1 +f 2090//1 2091//1 2056//1 +f 2056//1 2091//1 2057//1 +f 2091//1 2092//1 2057//1 +f 2057//1 2092//1 2058//1 +f 2092//1 2093//1 2058//1 +f 2058//1 2093//1 2059//1 +f 2093//1 2094//1 2059//1 +f 2059//1 2094//1 2060//1 +f 2094//1 2095//1 2060//1 +f 2060//1 2095//1 2061//1 +f 2095//1 2096//1 2061//1 +f 2061//1 2096//1 2062//1 +f 2096//1 2097//1 2062//1 +f 2062//1 2097//1 2063//1 +f 2097//1 2098//1 2063//1 +f 2063//1 2098//1 2064//1 +f 2098//1 2099//1 2064//1 +f 2064//1 2099//1 2065//1 +f 2099//1 2100//1 2065//1 +f 2065//1 2100//1 2066//1 +f 2100//1 2101//1 2066//1 +f 2066//1 2101//1 2067//1 +f 2101//1 2102//1 2067//1 +f 2067//1 2102//1 2068//1 +f 2102//1 2103//1 2068//1 +f 2068//1 2103//1 2069//1 +f 2103//1 2104//1 2069//1 +f 2069//1 2104//1 2070//1 +f 2104//1 2105//1 2070//1 +f 2070//1 2105//1 2071//1 +f 2105//1 2106//1 2071//1 +f 2071//1 2106//1 2072//1 +f 2106//1 2107//1 2072//1 +f 2072//1 2107//1 2073//1 +f 2107//1 2108//1 2073//1 +f 2073//1 2108//1 2074//1 +f 2108//1 2109//1 2074//1 +f 2074//1 2109//1 20//1 +f 2109//1 19//1 20//1 +f 90//1 2110//1 2075//1 +f 2110//1 2111//1 2075//1 +f 2075//1 2111//1 2076//1 +f 2111//1 2112//1 2076//1 +f 2076//1 2112//1 2077//1 +f 2112//1 2113//1 2077//1 +f 2077//1 2113//1 2078//1 +f 2113//1 2114//1 2078//1 +f 2078//1 2114//1 2079//1 +f 2114//1 2115//1 2079//1 +f 2079//1 2115//1 2080//1 +f 2115//1 2116//1 2080//1 +f 2080//1 2116//1 2081//1 +f 2116//1 2117//1 2081//1 +f 2081//1 2117//1 2082//1 +f 2117//1 2118//1 2082//1 +f 2082//1 2118//1 2083//1 +f 2118//1 2119//1 2083//1 +f 2083//1 2119//1 2084//1 +f 2119//1 2120//1 2084//1 +f 2084//1 2120//1 2085//1 +f 2120//1 2121//1 2085//1 +f 2085//1 2121//1 2086//1 +f 2121//1 2122//1 2086//1 +f 2086//1 2122//1 2087//1 +f 2122//1 2123//1 2087//1 +f 2087//1 2123//1 2088//1 +f 2123//1 2124//1 2088//1 +f 2088//1 2124//1 2089//1 +f 2124//1 2125//1 2089//1 +f 2089//1 2125//1 2090//1 +f 2125//1 2126//1 2090//1 +f 2090//1 2126//1 2091//1 +f 2126//1 2127//1 2091//1 +f 2091//1 2127//1 2092//1 +f 2127//1 2128//1 2092//1 +f 2092//1 2128//1 2093//1 +f 2128//1 2129//1 2093//1 +f 2093//1 2129//1 2094//1 +f 2129//1 2130//1 2094//1 +f 2094//1 2130//1 2095//1 +f 2130//1 2131//1 2095//1 +f 2095//1 2131//1 2096//1 +f 2131//1 2132//1 2096//1 +f 2096//1 2132//1 2097//1 +f 2132//1 2133//1 2097//1 +f 2097//1 2133//1 2098//1 +f 2133//1 2134//1 2098//1 +f 2098//1 2134//1 2099//1 +f 2134//1 2135//1 2099//1 +f 2099//1 2135//1 2100//1 +f 2135//1 2136//1 2100//1 +f 2100//1 2136//1 2101//1 +f 2136//1 2137//1 2101//1 +f 2101//1 2137//1 2102//1 +f 2137//1 2138//1 2102//1 +f 2102//1 2138//1 2103//1 +f 2138//1 2139//1 2103//1 +f 2103//1 2139//1 2104//1 +f 2139//1 2140//1 2104//1 +f 2104//1 2140//1 2105//1 +f 2140//1 2141//1 2105//1 +f 2105//1 2141//1 2106//1 +f 2141//1 2142//1 2106//1 +f 2106//1 2142//1 2107//1 +f 2142//1 2143//1 2107//1 +f 2107//1 2143//1 2108//1 +f 2143//1 2144//1 2108//1 +f 2108//1 2144//1 2109//1 +f 2144//1 2145//1 2109//1 +f 2109//1 2145//1 19//1 +f 2145//1 18//1 19//1 +f 91//1 2146//1 2110//1 +f 2146//1 2147//1 2110//1 +f 2110//1 2147//1 2111//1 +f 2147//1 2148//1 2111//1 +f 2111//1 2148//1 2112//1 +f 2148//1 2149//1 2112//1 +f 2112//1 2149//1 2113//1 +f 2149//1 2150//1 2113//1 +f 2113//1 2150//1 2114//1 +f 2150//1 2151//1 2114//1 +f 2114//1 2151//1 2115//1 +f 2151//1 2152//1 2115//1 +f 2115//1 2152//1 2116//1 +f 2152//1 2153//1 2116//1 +f 2116//1 2153//1 2117//1 +f 2153//1 2154//1 2117//1 +f 2117//1 2154//1 2118//1 +f 2154//1 2155//1 2118//1 +f 2118//1 2155//1 2119//1 +f 2155//1 2156//1 2119//1 +f 2119//1 2156//1 2120//1 +f 2156//1 2157//1 2120//1 +f 2120//1 2157//1 2121//1 +f 2157//1 2158//1 2121//1 +f 2121//1 2158//1 2122//1 +f 2158//1 2159//1 2122//1 +f 2122//1 2159//1 2123//1 +f 2159//1 2160//1 2123//1 +f 2123//1 2160//1 2124//1 +f 2160//1 2161//1 2124//1 +f 2124//1 2161//1 2125//1 +f 2161//1 2162//1 2125//1 +f 2125//1 2162//1 2126//1 +f 2162//1 2163//1 2126//1 +f 2126//1 2163//1 2127//1 +f 2163//1 2164//1 2127//1 +f 2127//1 2164//1 2128//1 +f 2164//1 2165//1 2128//1 +f 2128//1 2165//1 2129//1 +f 2165//1 2166//1 2129//1 +f 2129//1 2166//1 2130//1 +f 2166//1 2167//1 2130//1 +f 2130//1 2167//1 2131//1 +f 2167//1 2168//1 2131//1 +f 2131//1 2168//1 2132//1 +f 2168//1 2169//1 2132//1 +f 2132//1 2169//1 2133//1 +f 2169//1 2170//1 2133//1 +f 2133//1 2170//1 2134//1 +f 2170//1 2171//1 2134//1 +f 2134//1 2171//1 2135//1 +f 2171//1 2172//1 2135//1 +f 2135//1 2172//1 2136//1 +f 2172//1 2173//1 2136//1 +f 2136//1 2173//1 2137//1 +f 2173//1 2174//1 2137//1 +f 2137//1 2174//1 2138//1 +f 2174//1 2175//1 2138//1 +f 2138//1 2175//1 2139//1 +f 2175//1 2176//1 2139//1 +f 2139//1 2176//1 2140//1 +f 2176//1 2177//1 2140//1 +f 2140//1 2177//1 2141//1 +f 2177//1 2178//1 2141//1 +f 2141//1 2178//1 2142//1 +f 2178//1 2179//1 2142//1 +f 2142//1 2179//1 2143//1 +f 2179//1 2180//1 2143//1 +f 2143//1 2180//1 2144//1 +f 2180//1 2181//1 2144//1 +f 2144//1 2181//1 2145//1 +f 2181//1 2182//1 2145//1 +f 2145//1 2182//1 18//1 +f 2182//1 17//1 18//1 +f 92//1 2183//1 2146//1 +f 2183//1 2184//1 2146//1 +f 2146//1 2184//1 2147//1 +f 2184//1 2185//1 2147//1 +f 2147//1 2185//1 2148//1 +f 2185//1 2186//1 2148//1 +f 2148//1 2186//1 2149//1 +f 2186//1 2187//1 2149//1 +f 2149//1 2187//1 2150//1 +f 2187//1 2188//1 2150//1 +f 2150//1 2188//1 2151//1 +f 2188//1 2189//1 2151//1 +f 2151//1 2189//1 2152//1 +f 2189//1 2190//1 2152//1 +f 2152//1 2190//1 2153//1 +f 2190//1 2191//1 2153//1 +f 2153//1 2191//1 2154//1 +f 2191//1 2192//1 2154//1 +f 2154//1 2192//1 2155//1 +f 2192//1 2193//1 2155//1 +f 2155//1 2193//1 2156//1 +f 2193//1 2194//1 2156//1 +f 2156//1 2194//1 2157//1 +f 2194//1 2195//1 2157//1 +f 2157//1 2195//1 2158//1 +f 2195//1 2196//1 2158//1 +f 2158//1 2196//1 2159//1 +f 2196//1 2197//1 2159//1 +f 2159//1 2197//1 2160//1 +f 2197//1 2198//1 2160//1 +f 2160//1 2198//1 2161//1 +f 2198//1 2199//1 2161//1 +f 2161//1 2199//1 2162//1 +f 2199//1 2200//1 2162//1 +f 2162//1 2200//1 2163//1 +f 2200//1 2201//1 2163//1 +f 2163//1 2201//1 2164//1 +f 2201//1 2202//1 2164//1 +f 2164//1 2202//1 2165//1 +f 2202//1 2203//1 2165//1 +f 2165//1 2203//1 2166//1 +f 2203//1 2204//1 2166//1 +f 2166//1 2204//1 2167//1 +f 2204//1 2205//1 2167//1 +f 2167//1 2205//1 2168//1 +f 2205//1 2206//1 2168//1 +f 2168//1 2206//1 2169//1 +f 2206//1 2207//1 2169//1 +f 2169//1 2207//1 2170//1 +f 2207//1 2208//1 2170//1 +f 2170//1 2208//1 2171//1 +f 2208//1 2209//1 2171//1 +f 2171//1 2209//1 2172//1 +f 2209//1 2210//1 2172//1 +f 2172//1 2210//1 2173//1 +f 2210//1 2211//1 2173//1 +f 2173//1 2211//1 2174//1 +f 2211//1 2212//1 2174//1 +f 2174//1 2212//1 2175//1 +f 2212//1 2213//1 2175//1 +f 2175//1 2213//1 2176//1 +f 2213//1 2214//1 2176//1 +f 2176//1 2214//1 2177//1 +f 2214//1 2215//1 2177//1 +f 2177//1 2215//1 2178//1 +f 2215//1 2216//1 2178//1 +f 2178//1 2216//1 2179//1 +f 2216//1 2217//1 2179//1 +f 2179//1 2217//1 2180//1 +f 2217//1 2218//1 2180//1 +f 2180//1 2218//1 2181//1 +f 2218//1 2219//1 2181//1 +f 2181//1 2219//1 2182//1 +f 2219//1 2220//1 2182//1 +f 2182//1 2220//1 17//1 +f 2220//1 16//1 17//1 +f 93//1 2221//1 2183//1 +f 2221//1 2222//1 2183//1 +f 2183//1 2222//1 2184//1 +f 2222//1 2223//1 2184//1 +f 2184//1 2223//1 2185//1 +f 2223//1 2224//1 2185//1 +f 2185//1 2224//1 2186//1 +f 2224//1 2225//1 2186//1 +f 2186//1 2225//1 2187//1 +f 2225//1 2226//1 2187//1 +f 2187//1 2226//1 2188//1 +f 2226//1 2227//1 2188//1 +f 2188//1 2227//1 2189//1 +f 2227//1 2228//1 2189//1 +f 2189//1 2228//1 2190//1 +f 2228//1 2229//1 2190//1 +f 2190//1 2229//1 2191//1 +f 2229//1 2230//1 2191//1 +f 2191//1 2230//1 2192//1 +f 2230//1 2231//1 2192//1 +f 2192//1 2231//1 2193//1 +f 2231//1 2232//1 2193//1 +f 2193//1 2232//1 2194//1 +f 2232//1 2233//1 2194//1 +f 2194//1 2233//1 2195//1 +f 2233//1 2234//1 2195//1 +f 2195//1 2234//1 2196//1 +f 2234//1 2235//1 2196//1 +f 2196//1 2235//1 2197//1 +f 2235//1 2236//1 2197//1 +f 2197//1 2236//1 2198//1 +f 2236//1 2237//1 2198//1 +f 2198//1 2237//1 2199//1 +f 2237//1 2238//1 2199//1 +f 2199//1 2238//1 2200//1 +f 2238//1 2239//1 2200//1 +f 2200//1 2239//1 2201//1 +f 2239//1 2240//1 2201//1 +f 2201//1 2240//1 2202//1 +f 2240//1 2241//1 2202//1 +f 2202//1 2241//1 2203//1 +f 2241//1 2242//1 2203//1 +f 2203//1 2242//1 2204//1 +f 2242//1 2243//1 2204//1 +f 2204//1 2243//1 2205//1 +f 2243//1 2244//1 2205//1 +f 2205//1 2244//1 2206//1 +f 2244//1 2245//1 2206//1 +f 2206//1 2245//1 2207//1 +f 2245//1 2246//1 2207//1 +f 2207//1 2246//1 2208//1 +f 2246//1 2247//1 2208//1 +f 2208//1 2247//1 2209//1 +f 2247//1 2248//1 2209//1 +f 2209//1 2248//1 2210//1 +f 2248//1 2249//1 2210//1 +f 2210//1 2249//1 2211//1 +f 2249//1 2250//1 2211//1 +f 2211//1 2250//1 2212//1 +f 2250//1 2251//1 2212//1 +f 2212//1 2251//1 2213//1 +f 2251//1 2252//1 2213//1 +f 2213//1 2252//1 2214//1 +f 2252//1 2253//1 2214//1 +f 2214//1 2253//1 2215//1 +f 2253//1 2254//1 2215//1 +f 2215//1 2254//1 2216//1 +f 2254//1 2255//1 2216//1 +f 2216//1 2255//1 2217//1 +f 2255//1 2256//1 2217//1 +f 2217//1 2256//1 2218//1 +f 2256//1 2257//1 2218//1 +f 2218//1 2257//1 2219//1 +f 2257//1 2258//1 2219//1 +f 2219//1 2258//1 2220//1 +f 2258//1 2259//1 2220//1 +f 2220//1 2259//1 16//1 +f 2259//1 15//1 16//1 +f 94//1 2260//1 2221//1 +f 2260//1 2261//1 2221//1 +f 2221//1 2261//1 2222//1 +f 2261//1 2262//1 2222//1 +f 2222//1 2262//1 2223//1 +f 2262//1 2263//1 2223//1 +f 2223//1 2263//1 2224//1 +f 2263//1 2264//1 2224//1 +f 2224//1 2264//1 2225//1 +f 2264//1 2265//1 2225//1 +f 2225//1 2265//1 2226//1 +f 2265//1 2266//1 2226//1 +f 2226//1 2266//1 2227//1 +f 2266//1 2267//1 2227//1 +f 2227//1 2267//1 2228//1 +f 2267//1 2268//1 2228//1 +f 2228//1 2268//1 2229//1 +f 2268//1 2269//1 2229//1 +f 2229//1 2269//1 2230//1 +f 2269//1 2270//1 2230//1 +f 2230//1 2270//1 2231//1 +f 2270//1 2271//1 2231//1 +f 2231//1 2271//1 2232//1 +f 2271//1 2272//1 2232//1 +f 2232//1 2272//1 2233//1 +f 2272//1 2273//1 2233//1 +f 2233//1 2273//1 2234//1 +f 2273//1 2274//1 2234//1 +f 2234//1 2274//1 2235//1 +f 2274//1 2275//1 2235//1 +f 2235//1 2275//1 2236//1 +f 2275//1 2276//1 2236//1 +f 2236//1 2276//1 2237//1 +f 2276//1 2277//1 2237//1 +f 2237//1 2277//1 2238//1 +f 2277//1 2278//1 2238//1 +f 2238//1 2278//1 2239//1 +f 2278//1 2279//1 2239//1 +f 2239//1 2279//1 2240//1 +f 2279//1 2280//1 2240//1 +f 2240//1 2280//1 2241//1 +f 2280//1 2281//1 2241//1 +f 2241//1 2281//1 2242//1 +f 2281//1 2282//1 2242//1 +f 2242//1 2282//1 2243//1 +f 2282//1 2283//1 2243//1 +f 2243//1 2283//1 2244//1 +f 2283//1 2284//1 2244//1 +f 2244//1 2284//1 2245//1 +f 2284//1 2285//1 2245//1 +f 2245//1 2285//1 2246//1 +f 2285//1 2286//1 2246//1 +f 2246//1 2286//1 2247//1 +f 2286//1 2287//1 2247//1 +f 2247//1 2287//1 2248//1 +f 2287//1 2288//1 2248//1 +f 2248//1 2288//1 2249//1 +f 2288//1 2289//1 2249//1 +f 2249//1 2289//1 2250//1 +f 2289//1 2290//1 2250//1 +f 2250//1 2290//1 2251//1 +f 2290//1 2291//1 2251//1 +f 2251//1 2291//1 2252//1 +f 2291//1 2292//1 2252//1 +f 2252//1 2292//1 2253//1 +f 2292//1 2293//1 2253//1 +f 2253//1 2293//1 2254//1 +f 2293//1 2294//1 2254//1 +f 2254//1 2294//1 2255//1 +f 2294//1 2295//1 2255//1 +f 2255//1 2295//1 2256//1 +f 2295//1 2296//1 2256//1 +f 2256//1 2296//1 2257//1 +f 2296//1 2297//1 2257//1 +f 2257//1 2297//1 2258//1 +f 2297//1 2298//1 2258//1 +f 2258//1 2298//1 2259//1 +f 2298//1 2299//1 2259//1 +f 2259//1 2299//1 15//1 +f 2299//1 14//1 15//1 +f 95//1 2300//1 2260//1 +f 2300//1 2301//1 2260//1 +f 2260//1 2301//1 2261//1 +f 2301//1 2302//1 2261//1 +f 2261//1 2302//1 2262//1 +f 2302//1 2303//1 2262//1 +f 2262//1 2303//1 2263//1 +f 2303//1 2304//1 2263//1 +f 2263//1 2304//1 2264//1 +f 2304//1 2305//1 2264//1 +f 2264//1 2305//1 2265//1 +f 2305//1 2306//1 2265//1 +f 2265//1 2306//1 2266//1 +f 2306//1 2307//1 2266//1 +f 2266//1 2307//1 2267//1 +f 2307//1 2308//1 2267//1 +f 2267//1 2308//1 2268//1 +f 2308//1 2309//1 2268//1 +f 2268//1 2309//1 2269//1 +f 2309//1 2310//1 2269//1 +f 2269//1 2310//1 2270//1 +f 2310//1 2311//1 2270//1 +f 2270//1 2311//1 2271//1 +f 2311//1 2312//1 2271//1 +f 2271//1 2312//1 2272//1 +f 2312//1 2313//1 2272//1 +f 2272//1 2313//1 2273//1 +f 2313//1 2314//1 2273//1 +f 2273//1 2314//1 2274//1 +f 2314//1 2315//1 2274//1 +f 2274//1 2315//1 2275//1 +f 2315//1 2316//1 2275//1 +f 2275//1 2316//1 2276//1 +f 2316//1 2317//1 2276//1 +f 2276//1 2317//1 2277//1 +f 2317//1 2318//1 2277//1 +f 2277//1 2318//1 2278//1 +f 2318//1 2319//1 2278//1 +f 2278//1 2319//1 2279//1 +f 2319//1 2320//1 2279//1 +f 2279//1 2320//1 2280//1 +f 2320//1 2321//1 2280//1 +f 2280//1 2321//1 2281//1 +f 2321//1 2322//1 2281//1 +f 2281//1 2322//1 2282//1 +f 2322//1 2323//1 2282//1 +f 2282//1 2323//1 2283//1 +f 2323//1 2324//1 2283//1 +f 2283//1 2324//1 2284//1 +f 2324//1 2325//1 2284//1 +f 2284//1 2325//1 2285//1 +f 2325//1 2326//1 2285//1 +f 2285//1 2326//1 2286//1 +f 2326//1 2327//1 2286//1 +f 2286//1 2327//1 2287//1 +f 2327//1 2328//1 2287//1 +f 2287//1 2328//1 2288//1 +f 2328//1 2329//1 2288//1 +f 2288//1 2329//1 2289//1 +f 2329//1 2330//1 2289//1 +f 2289//1 2330//1 2290//1 +f 2330//1 2331//1 2290//1 +f 2290//1 2331//1 2291//1 +f 2331//1 2332//1 2291//1 +f 2291//1 2332//1 2292//1 +f 2332//1 2333//1 2292//1 +f 2292//1 2333//1 2293//1 +f 2333//1 2334//1 2293//1 +f 2293//1 2334//1 2294//1 +f 2334//1 2335//1 2294//1 +f 2294//1 2335//1 2295//1 +f 2335//1 2336//1 2295//1 +f 2295//1 2336//1 2296//1 +f 2336//1 2337//1 2296//1 +f 2296//1 2337//1 2297//1 +f 2337//1 2338//1 2297//1 +f 2297//1 2338//1 2298//1 +f 2338//1 2339//1 2298//1 +f 2298//1 2339//1 2299//1 +f 2339//1 2340//1 2299//1 +f 2299//1 2340//1 14//1 +f 2340//1 13//1 14//1 +f 96//1 2341//1 2300//1 +f 2341//1 2342//1 2300//1 +f 2300//1 2342//1 2301//1 +f 2342//1 2343//1 2301//1 +f 2301//1 2343//1 2302//1 +f 2343//1 2344//1 2302//1 +f 2302//1 2344//1 2303//1 +f 2344//1 2345//1 2303//1 +f 2303//1 2345//1 2304//1 +f 2345//1 2346//1 2304//1 +f 2304//1 2346//1 2305//1 +f 2346//1 2347//1 2305//1 +f 2305//1 2347//1 2306//1 +f 2347//1 2348//1 2306//1 +f 2306//1 2348//1 2307//1 +f 2348//1 2349//1 2307//1 +f 2307//1 2349//1 2308//1 +f 2349//1 2350//1 2308//1 +f 2308//1 2350//1 2309//1 +f 2350//1 2351//1 2309//1 +f 2309//1 2351//1 2310//1 +f 2351//1 2352//1 2310//1 +f 2310//1 2352//1 2311//1 +f 2352//1 2353//1 2311//1 +f 2311//1 2353//1 2312//1 +f 2353//1 2354//1 2312//1 +f 2312//1 2354//1 2313//1 +f 2354//1 2355//1 2313//1 +f 2313//1 2355//1 2314//1 +f 2355//1 2356//1 2314//1 +f 2314//1 2356//1 2315//1 +f 2356//1 2357//1 2315//1 +f 2315//1 2357//1 2316//1 +f 2357//1 2358//1 2316//1 +f 2316//1 2358//1 2317//1 +f 2358//1 2359//1 2317//1 +f 2317//1 2359//1 2318//1 +f 2359//1 2360//1 2318//1 +f 2318//1 2360//1 2319//1 +f 2360//1 2361//1 2319//1 +f 2319//1 2361//1 2320//1 +f 2361//1 2362//1 2320//1 +f 2320//1 2362//1 2321//1 +f 2362//1 2363//1 2321//1 +f 2321//1 2363//1 2322//1 +f 2363//1 2364//1 2322//1 +f 2322//1 2364//1 2323//1 +f 2364//1 2365//1 2323//1 +f 2323//1 2365//1 2324//1 +f 2365//1 2366//1 2324//1 +f 2324//1 2366//1 2325//1 +f 2366//1 2367//1 2325//1 +f 2325//1 2367//1 2326//1 +f 2367//1 2368//1 2326//1 +f 2326//1 2368//1 2327//1 +f 2368//1 2369//1 2327//1 +f 2327//1 2369//1 2328//1 +f 2369//1 2370//1 2328//1 +f 2328//1 2370//1 2329//1 +f 2370//1 2371//1 2329//1 +f 2329//1 2371//1 2330//1 +f 2371//1 2372//1 2330//1 +f 2330//1 2372//1 2331//1 +f 2372//1 2373//1 2331//1 +f 2331//1 2373//1 2332//1 +f 2373//1 2374//1 2332//1 +f 2332//1 2374//1 2333//1 +f 2374//1 2375//1 2333//1 +f 2333//1 2375//1 2334//1 +f 2375//1 2376//1 2334//1 +f 2334//1 2376//1 2335//1 +f 2376//1 2377//1 2335//1 +f 2335//1 2377//1 2336//1 +f 2377//1 2378//1 2336//1 +f 2336//1 2378//1 2337//1 +f 2378//1 2379//1 2337//1 +f 2337//1 2379//1 2338//1 +f 2379//1 2380//1 2338//1 +f 2338//1 2380//1 2339//1 +f 2380//1 2381//1 2339//1 +f 2339//1 2381//1 2340//1 +f 2381//1 2382//1 2340//1 +f 2340//1 2382//1 13//1 +f 2382//1 12//1 13//1 +f 97//1 2383//1 2341//1 +f 2383//1 2384//1 2341//1 +f 2341//1 2384//1 2342//1 +f 2384//1 2385//1 2342//1 +f 2342//1 2385//1 2343//1 +f 2385//1 2386//1 2343//1 +f 2343//1 2386//1 2344//1 +f 2386//1 2387//1 2344//1 +f 2344//1 2387//1 2345//1 +f 2387//1 2388//1 2345//1 +f 2345//1 2388//1 2346//1 +f 2388//1 2389//1 2346//1 +f 2346//1 2389//1 2347//1 +f 2389//1 2390//1 2347//1 +f 2347//1 2390//1 2348//1 +f 2390//1 2391//1 2348//1 +f 2348//1 2391//1 2349//1 +f 2391//1 2392//1 2349//1 +f 2349//1 2392//1 2350//1 +f 2392//1 2393//1 2350//1 +f 2350//1 2393//1 2351//1 +f 2393//1 2394//1 2351//1 +f 2351//1 2394//1 2352//1 +f 2394//1 2395//1 2352//1 +f 2352//1 2395//1 2353//1 +f 2395//1 2396//1 2353//1 +f 2353//1 2396//1 2354//1 +f 2396//1 2397//1 2354//1 +f 2354//1 2397//1 2355//1 +f 2397//1 2398//1 2355//1 +f 2355//1 2398//1 2356//1 +f 2398//1 2399//1 2356//1 +f 2356//1 2399//1 2357//1 +f 2399//1 2400//1 2357//1 +f 2357//1 2400//1 2358//1 +f 2400//1 2401//1 2358//1 +f 2358//1 2401//1 2359//1 +f 2401//1 2402//1 2359//1 +f 2359//1 2402//1 2360//1 +f 2402//1 2403//1 2360//1 +f 2360//1 2403//1 2361//1 +f 2403//1 2404//1 2361//1 +f 2361//1 2404//1 2362//1 +f 2404//1 2405//1 2362//1 +f 2362//1 2405//1 2363//1 +f 2405//1 2406//1 2363//1 +f 2363//1 2406//1 2364//1 +f 2406//1 2407//1 2364//1 +f 2364//1 2407//1 2365//1 +f 2407//1 2408//1 2365//1 +f 2365//1 2408//1 2366//1 +f 2408//1 2409//1 2366//1 +f 2366//1 2409//1 2367//1 +f 2409//1 2410//1 2367//1 +f 2367//1 2410//1 2368//1 +f 2410//1 2411//1 2368//1 +f 2368//1 2411//1 2369//1 +f 2411//1 2412//1 2369//1 +f 2369//1 2412//1 2370//1 +f 2412//1 2413//1 2370//1 +f 2370//1 2413//1 2371//1 +f 2413//1 2414//1 2371//1 +f 2371//1 2414//1 2372//1 +f 2414//1 2415//1 2372//1 +f 2372//1 2415//1 2373//1 +f 2415//1 2416//1 2373//1 +f 2373//1 2416//1 2374//1 +f 2416//1 2417//1 2374//1 +f 2374//1 2417//1 2375//1 +f 2417//1 2418//1 2375//1 +f 2375//1 2418//1 2376//1 +f 2418//1 2419//1 2376//1 +f 2376//1 2419//1 2377//1 +f 2419//1 2420//1 2377//1 +f 2377//1 2420//1 2378//1 +f 2420//1 2421//1 2378//1 +f 2378//1 2421//1 2379//1 +f 2421//1 2422//1 2379//1 +f 2379//1 2422//1 2380//1 +f 2422//1 2423//1 2380//1 +f 2380//1 2423//1 2381//1 +f 2423//1 2424//1 2381//1 +f 2381//1 2424//1 2382//1 +f 2424//1 2425//1 2382//1 +f 2382//1 2425//1 12//1 +f 2425//1 11//1 12//1 +f 98//1 2426//1 2383//1 +f 2426//1 2427//1 2383//1 +f 2383//1 2427//1 2384//1 +f 2427//1 2428//1 2384//1 +f 2384//1 2428//1 2385//1 +f 2428//1 2429//1 2385//1 +f 2385//1 2429//1 2386//1 +f 2429//1 2430//1 2386//1 +f 2386//1 2430//1 2387//1 +f 2430//1 2431//1 2387//1 +f 2387//1 2431//1 2388//1 +f 2431//1 2432//1 2388//1 +f 2388//1 2432//1 2389//1 +f 2432//1 2433//1 2389//1 +f 2389//1 2433//1 2390//1 +f 2433//1 2434//1 2390//1 +f 2390//1 2434//1 2391//1 +f 2434//1 2435//1 2391//1 +f 2391//1 2435//1 2392//1 +f 2435//1 2436//1 2392//1 +f 2392//1 2436//1 2393//1 +f 2436//1 2437//1 2393//1 +f 2393//1 2437//1 2394//1 +f 2437//1 2438//1 2394//1 +f 2394//1 2438//1 2395//1 +f 2438//1 2439//1 2395//1 +f 2395//1 2439//1 2396//1 +f 2439//1 2440//1 2396//1 +f 2396//1 2440//1 2397//1 +f 2440//1 2441//1 2397//1 +f 2397//1 2441//1 2398//1 +f 2441//1 2442//1 2398//1 +f 2398//1 2442//1 2399//1 +f 2442//1 2443//1 2399//1 +f 2399//1 2443//1 2400//1 +f 2443//1 2444//1 2400//1 +f 2400//1 2444//1 2401//1 +f 2444//1 2445//1 2401//1 +f 2401//1 2445//1 2402//1 +f 2445//1 2446//1 2402//1 +f 2402//1 2446//1 2403//1 +f 2446//1 2447//1 2403//1 +f 2403//1 2447//1 2404//1 +f 2447//1 2448//1 2404//1 +f 2404//1 2448//1 2405//1 +f 2448//1 2449//1 2405//1 +f 2405//1 2449//1 2406//1 +f 2449//1 2450//1 2406//1 +f 2406//1 2450//1 2407//1 +f 2450//1 2451//1 2407//1 +f 2407//1 2451//1 2408//1 +f 2451//1 2452//1 2408//1 +f 2408//1 2452//1 2409//1 +f 2452//1 2453//1 2409//1 +f 2409//1 2453//1 2410//1 +f 2453//1 2454//1 2410//1 +f 2410//1 2454//1 2411//1 +f 2454//1 2455//1 2411//1 +f 2411//1 2455//1 2412//1 +f 2455//1 2456//1 2412//1 +f 2412//1 2456//1 2413//1 +f 2456//1 2457//1 2413//1 +f 2413//1 2457//1 2414//1 +f 2457//1 2458//1 2414//1 +f 2414//1 2458//1 2415//1 +f 2458//1 2459//1 2415//1 +f 2415//1 2459//1 2416//1 +f 2459//1 2460//1 2416//1 +f 2416//1 2460//1 2417//1 +f 2460//1 2461//1 2417//1 +f 2417//1 2461//1 2418//1 +f 2461//1 2462//1 2418//1 +f 2418//1 2462//1 2419//1 +f 2462//1 2463//1 2419//1 +f 2419//1 2463//1 2420//1 +f 2463//1 2464//1 2420//1 +f 2420//1 2464//1 2421//1 +f 2464//1 2465//1 2421//1 +f 2421//1 2465//1 2422//1 +f 2465//1 2466//1 2422//1 +f 2422//1 2466//1 2423//1 +f 2466//1 2467//1 2423//1 +f 2423//1 2467//1 2424//1 +f 2467//1 2468//1 2424//1 +f 2424//1 2468//1 2425//1 +f 2468//1 2469//1 2425//1 +f 2425//1 2469//1 11//1 +f 2469//1 10//1 11//1 +f 99//1 2470//1 2426//1 +f 2470//1 2471//1 2426//1 +f 2426//1 2471//1 2427//1 +f 2471//1 2472//1 2427//1 +f 2427//1 2472//1 2428//1 +f 2472//1 2473//1 2428//1 +f 2428//1 2473//1 2429//1 +f 2473//1 2474//1 2429//1 +f 2429//1 2474//1 2430//1 +f 2474//1 2475//1 2430//1 +f 2430//1 2475//1 2431//1 +f 2475//1 2476//1 2431//1 +f 2431//1 2476//1 2432//1 +f 2476//1 2477//1 2432//1 +f 2432//1 2477//1 2433//1 +f 2477//1 2478//1 2433//1 +f 2433//1 2478//1 2434//1 +f 2478//1 2479//1 2434//1 +f 2434//1 2479//1 2435//1 +f 2479//1 2480//1 2435//1 +f 2435//1 2480//1 2436//1 +f 2480//1 2481//1 2436//1 +f 2436//1 2481//1 2437//1 +f 2481//1 2482//1 2437//1 +f 2437//1 2482//1 2438//1 +f 2482//1 2483//1 2438//1 +f 2438//1 2483//1 2439//1 +f 2483//1 2484//1 2439//1 +f 2439//1 2484//1 2440//1 +f 2484//1 2485//1 2440//1 +f 2440//1 2485//1 2441//1 +f 2485//1 2486//1 2441//1 +f 2441//1 2486//1 2442//1 +f 2486//1 2487//1 2442//1 +f 2442//1 2487//1 2443//1 +f 2487//1 2488//1 2443//1 +f 2443//1 2488//1 2444//1 +f 2488//1 2489//1 2444//1 +f 2444//1 2489//1 2445//1 +f 2489//1 2490//1 2445//1 +f 2445//1 2490//1 2446//1 +f 2490//1 2491//1 2446//1 +f 2446//1 2491//1 2447//1 +f 2491//1 2492//1 2447//1 +f 2447//1 2492//1 2448//1 +f 2492//1 2493//1 2448//1 +f 2448//1 2493//1 2449//1 +f 2493//1 2494//1 2449//1 +f 2449//1 2494//1 2450//1 +f 2494//1 2495//1 2450//1 +f 2450//1 2495//1 2451//1 +f 2495//1 2496//1 2451//1 +f 2451//1 2496//1 2452//1 +f 2496//1 2497//1 2452//1 +f 2452//1 2497//1 2453//1 +f 2497//1 2498//1 2453//1 +f 2453//1 2498//1 2454//1 +f 2498//1 2499//1 2454//1 +f 2454//1 2499//1 2455//1 +f 2499//1 2500//1 2455//1 +f 2455//1 2500//1 2456//1 +f 2500//1 2501//1 2456//1 +f 2456//1 2501//1 2457//1 +f 2501//1 2502//1 2457//1 +f 2457//1 2502//1 2458//1 +f 2502//1 2503//1 2458//1 +f 2458//1 2503//1 2459//1 +f 2503//1 2504//1 2459//1 +f 2459//1 2504//1 2460//1 +f 2504//1 2505//1 2460//1 +f 2460//1 2505//1 2461//1 +f 2505//1 2506//1 2461//1 +f 2461//1 2506//1 2462//1 +f 2506//1 2507//1 2462//1 +f 2462//1 2507//1 2463//1 +f 2507//1 2508//1 2463//1 +f 2463//1 2508//1 2464//1 +f 2508//1 2509//1 2464//1 +f 2464//1 2509//1 2465//1 +f 2509//1 2510//1 2465//1 +f 2465//1 2510//1 2466//1 +f 2510//1 2511//1 2466//1 +f 2466//1 2511//1 2467//1 +f 2511//1 2512//1 2467//1 +f 2467//1 2512//1 2468//1 +f 2512//1 2513//1 2468//1 +f 2468//1 2513//1 2469//1 +f 2513//1 2514//1 2469//1 +f 2469//1 2514//1 10//1 +f 2514//1 9//1 10//1 +f 100//1 2515//1 2470//1 +f 2515//1 2516//1 2470//1 +f 2470//1 2516//1 2471//1 +f 2516//1 2517//1 2471//1 +f 2471//1 2517//1 2472//1 +f 2517//1 2518//1 2472//1 +f 2472//1 2518//1 2473//1 +f 2518//1 2519//1 2473//1 +f 2473//1 2519//1 2474//1 +f 2519//1 2520//1 2474//1 +f 2474//1 2520//1 2475//1 +f 2520//1 2521//1 2475//1 +f 2475//1 2521//1 2476//1 +f 2521//1 2522//1 2476//1 +f 2476//1 2522//1 2477//1 +f 2522//1 2523//1 2477//1 +f 2477//1 2523//1 2478//1 +f 2523//1 2524//1 2478//1 +f 2478//1 2524//1 2479//1 +f 2524//1 2525//1 2479//1 +f 2479//1 2525//1 2480//1 +f 2525//1 2526//1 2480//1 +f 2480//1 2526//1 2481//1 +f 2526//1 2527//1 2481//1 +f 2481//1 2527//1 2482//1 +f 2527//1 2528//1 2482//1 +f 2482//1 2528//1 2483//1 +f 2528//1 2529//1 2483//1 +f 2483//1 2529//1 2484//1 +f 2529//1 2530//1 2484//1 +f 2484//1 2530//1 2485//1 +f 2530//1 2531//1 2485//1 +f 2485//1 2531//1 2486//1 +f 2531//1 2532//1 2486//1 +f 2486//1 2532//1 2487//1 +f 2532//1 2533//1 2487//1 +f 2487//1 2533//1 2488//1 +f 2533//1 2534//1 2488//1 +f 2488//1 2534//1 2489//1 +f 2534//1 2535//1 2489//1 +f 2489//1 2535//1 2490//1 +f 2535//1 2536//1 2490//1 +f 2490//1 2536//1 2491//1 +f 2536//1 2537//1 2491//1 +f 2491//1 2537//1 2492//1 +f 2537//1 2538//1 2492//1 +f 2492//1 2538//1 2493//1 +f 2538//1 2539//1 2493//1 +f 2493//1 2539//1 2494//1 +f 2539//1 2540//1 2494//1 +f 2494//1 2540//1 2495//1 +f 2540//1 2541//1 2495//1 +f 2495//1 2541//1 2496//1 +f 2541//1 2542//1 2496//1 +f 2496//1 2542//1 2497//1 +f 2542//1 2543//1 2497//1 +f 2497//1 2543//1 2498//1 +f 2543//1 2544//1 2498//1 +f 2498//1 2544//1 2499//1 +f 2544//1 2545//1 2499//1 +f 2499//1 2545//1 2500//1 +f 2545//1 2546//1 2500//1 +f 2500//1 2546//1 2501//1 +f 2546//1 2547//1 2501//1 +f 2501//1 2547//1 2502//1 +f 2547//1 2548//1 2502//1 +f 2502//1 2548//1 2503//1 +f 2548//1 2549//1 2503//1 +f 2503//1 2549//1 2504//1 +f 2549//1 2550//1 2504//1 +f 2504//1 2550//1 2505//1 +f 2550//1 2551//1 2505//1 +f 2505//1 2551//1 2506//1 +f 2551//1 2552//1 2506//1 +f 2506//1 2552//1 2507//1 +f 2552//1 2553//1 2507//1 +f 2507//1 2553//1 2508//1 +f 2553//1 2554//1 2508//1 +f 2508//1 2554//1 2509//1 +f 2554//1 2555//1 2509//1 +f 2509//1 2555//1 2510//1 +f 2555//1 2556//1 2510//1 +f 2510//1 2556//1 2511//1 +f 2556//1 2557//1 2511//1 +f 2511//1 2557//1 2512//1 +f 2557//1 2558//1 2512//1 +f 2512//1 2558//1 2513//1 +f 2558//1 2559//1 2513//1 +f 2513//1 2559//1 2514//1 +f 2559//1 2560//1 2514//1 +f 2514//1 2560//1 9//1 +f 2560//1 8//1 9//1 +f 101//1 2561//1 2515//1 +f 2561//1 2562//1 2515//1 +f 2515//1 2562//1 2516//1 +f 2562//1 2563//1 2516//1 +f 2516//1 2563//1 2517//1 +f 2563//1 2564//1 2517//1 +f 2517//1 2564//1 2518//1 +f 2564//1 2565//1 2518//1 +f 2518//1 2565//1 2519//1 +f 2565//1 2566//1 2519//1 +f 2519//1 2566//1 2520//1 +f 2566//1 2567//1 2520//1 +f 2520//1 2567//1 2521//1 +f 2567//1 2568//1 2521//1 +f 2521//1 2568//1 2522//1 +f 2568//1 2569//1 2522//1 +f 2522//1 2569//1 2523//1 +f 2569//1 2570//1 2523//1 +f 2523//1 2570//1 2524//1 +f 2570//1 2571//1 2524//1 +f 2524//1 2571//1 2525//1 +f 2571//1 2572//1 2525//1 +f 2525//1 2572//1 2526//1 +f 2572//1 2573//1 2526//1 +f 2526//1 2573//1 2527//1 +f 2573//1 2574//1 2527//1 +f 2527//1 2574//1 2528//1 +f 2574//1 2575//1 2528//1 +f 2528//1 2575//1 2529//1 +f 2575//1 2576//1 2529//1 +f 2529//1 2576//1 2530//1 +f 2576//1 2577//1 2530//1 +f 2530//1 2577//1 2531//1 +f 2577//1 2578//1 2531//1 +f 2531//1 2578//1 2532//1 +f 2578//1 2579//1 2532//1 +f 2532//1 2579//1 2533//1 +f 2579//1 2580//1 2533//1 +f 2533//1 2580//1 2534//1 +f 2580//1 2581//1 2534//1 +f 2534//1 2581//1 2535//1 +f 2581//1 2582//1 2535//1 +f 2535//1 2582//1 2536//1 +f 2582//1 2583//1 2536//1 +f 2536//1 2583//1 2537//1 +f 2583//1 2584//1 2537//1 +f 2537//1 2584//1 2538//1 +f 2584//1 2585//1 2538//1 +f 2538//1 2585//1 2539//1 +f 2585//1 2586//1 2539//1 +f 2539//1 2586//1 2540//1 +f 2586//1 2587//1 2540//1 +f 2540//1 2587//1 2541//1 +f 2587//1 2588//1 2541//1 +f 2541//1 2588//1 2542//1 +f 2588//1 2589//1 2542//1 +f 2542//1 2589//1 2543//1 +f 2589//1 2590//1 2543//1 +f 2543//1 2590//1 2544//1 +f 2590//1 2591//1 2544//1 +f 2544//1 2591//1 2545//1 +f 2591//1 2592//1 2545//1 +f 2545//1 2592//1 2546//1 +f 2592//1 2593//1 2546//1 +f 2546//1 2593//1 2547//1 +f 2593//1 2594//1 2547//1 +f 2547//1 2594//1 2548//1 +f 2594//1 2595//1 2548//1 +f 2548//1 2595//1 2549//1 +f 2595//1 2596//1 2549//1 +f 2549//1 2596//1 2550//1 +f 2596//1 2597//1 2550//1 +f 2550//1 2597//1 2551//1 +f 2597//1 2598//1 2551//1 +f 2551//1 2598//1 2552//1 +f 2598//1 2599//1 2552//1 +f 2552//1 2599//1 2553//1 +f 2599//1 2600//1 2553//1 +f 2553//1 2600//1 2554//1 +f 2600//1 2601//1 2554//1 +f 2554//1 2601//1 2555//1 +f 2601//1 2602//1 2555//1 +f 2555//1 2602//1 2556//1 +f 2602//1 2603//1 2556//1 +f 2556//1 2603//1 2557//1 +f 2603//1 2604//1 2557//1 +f 2557//1 2604//1 2558//1 +f 2604//1 2605//1 2558//1 +f 2558//1 2605//1 2559//1 +f 2605//1 2606//1 2559//1 +f 2559//1 2606//1 2560//1 +f 2606//1 2607//1 2560//1 +f 2560//1 2607//1 8//1 +f 2607//1 7//1 8//1 +f 102//1 2608//1 2561//1 +f 2608//1 2609//1 2561//1 +f 2561//1 2609//1 2562//1 +f 2609//1 2610//1 2562//1 +f 2562//1 2610//1 2563//1 +f 2610//1 2611//1 2563//1 +f 2563//1 2611//1 2564//1 +f 2611//1 2612//1 2564//1 +f 2564//1 2612//1 2565//1 +f 2612//1 2613//1 2565//1 +f 2565//1 2613//1 2566//1 +f 2613//1 2614//1 2566//1 +f 2566//1 2614//1 2567//1 +f 2614//1 2615//1 2567//1 +f 2567//1 2615//1 2568//1 +f 2615//1 2616//1 2568//1 +f 2568//1 2616//1 2569//1 +f 2616//1 2617//1 2569//1 +f 2569//1 2617//1 2570//1 +f 2617//1 2618//1 2570//1 +f 2570//1 2618//1 2571//1 +f 2618//1 2619//1 2571//1 +f 2571//1 2619//1 2572//1 +f 2619//1 2620//1 2572//1 +f 2572//1 2620//1 2573//1 +f 2620//1 2621//1 2573//1 +f 2573//1 2621//1 2574//1 +f 2621//1 2622//1 2574//1 +f 2574//1 2622//1 2575//1 +f 2622//1 2623//1 2575//1 +f 2575//1 2623//1 2576//1 +f 2623//1 2624//1 2576//1 +f 2576//1 2624//1 2577//1 +f 2624//1 2625//1 2577//1 +f 2577//1 2625//1 2578//1 +f 2625//1 2626//1 2578//1 +f 2578//1 2626//1 2579//1 +f 2626//1 2627//1 2579//1 +f 2579//1 2627//1 2580//1 +f 2627//1 2628//1 2580//1 +f 2580//1 2628//1 2581//1 +f 2628//1 2629//1 2581//1 +f 2581//1 2629//1 2582//1 +f 2629//1 2630//1 2582//1 +f 2582//1 2630//1 2583//1 +f 2630//1 2631//1 2583//1 +f 2583//1 2631//1 2584//1 +f 2631//1 2632//1 2584//1 +f 2584//1 2632//1 2585//1 +f 2632//1 2633//1 2585//1 +f 2585//1 2633//1 2586//1 +f 2633//1 2634//1 2586//1 +f 2586//1 2634//1 2587//1 +f 2634//1 2635//1 2587//1 +f 2587//1 2635//1 2588//1 +f 2635//1 2636//1 2588//1 +f 2588//1 2636//1 2589//1 +f 2636//1 2637//1 2589//1 +f 2589//1 2637//1 2590//1 +f 2637//1 2638//1 2590//1 +f 2590//1 2638//1 2591//1 +f 2638//1 2639//1 2591//1 +f 2591//1 2639//1 2592//1 +f 2639//1 2640//1 2592//1 +f 2592//1 2640//1 2593//1 +f 2640//1 2641//1 2593//1 +f 2593//1 2641//1 2594//1 +f 2641//1 2642//1 2594//1 +f 2594//1 2642//1 2595//1 +f 2642//1 2643//1 2595//1 +f 2595//1 2643//1 2596//1 +f 2643//1 2644//1 2596//1 +f 2596//1 2644//1 2597//1 +f 2644//1 2645//1 2597//1 +f 2597//1 2645//1 2598//1 +f 2645//1 2646//1 2598//1 +f 2598//1 2646//1 2599//1 +f 2646//1 2647//1 2599//1 +f 2599//1 2647//1 2600//1 +f 2647//1 2648//1 2600//1 +f 2600//1 2648//1 2601//1 +f 2648//1 2649//1 2601//1 +f 2601//1 2649//1 2602//1 +f 2649//1 2650//1 2602//1 +f 2602//1 2650//1 2603//1 +f 2650//1 2651//1 2603//1 +f 2603//1 2651//1 2604//1 +f 2651//1 2652//1 2604//1 +f 2604//1 2652//1 2605//1 +f 2652//1 2653//1 2605//1 +f 2605//1 2653//1 2606//1 +f 2653//1 2654//1 2606//1 +f 2606//1 2654//1 2607//1 +f 2654//1 2655//1 2607//1 +f 2607//1 2655//1 7//1 +f 2655//1 6//1 7//1 +f 103//1 2656//1 2608//1 +f 2656//1 2657//1 2608//1 +f 2608//1 2657//1 2609//1 +f 2657//1 2658//1 2609//1 +f 2609//1 2658//1 2610//1 +f 2658//1 2659//1 2610//1 +f 2610//1 2659//1 2611//1 +f 2659//1 2660//1 2611//1 +f 2611//1 2660//1 2612//1 +f 2660//1 2661//1 2612//1 +f 2612//1 2661//1 2613//1 +f 2661//1 2662//1 2613//1 +f 2613//1 2662//1 2614//1 +f 2662//1 2663//1 2614//1 +f 2614//1 2663//1 2615//1 +f 2663//1 2664//1 2615//1 +f 2615//1 2664//1 2616//1 +f 2664//1 2665//1 2616//1 +f 2616//1 2665//1 2617//1 +f 2665//1 2666//1 2617//1 +f 2617//1 2666//1 2618//1 +f 2666//1 2667//1 2618//1 +f 2618//1 2667//1 2619//1 +f 2667//1 2668//1 2619//1 +f 2619//1 2668//1 2620//1 +f 2668//1 2669//1 2620//1 +f 2620//1 2669//1 2621//1 +f 2669//1 2670//1 2621//1 +f 2621//1 2670//1 2622//1 +f 2670//1 2671//1 2622//1 +f 2622//1 2671//1 2623//1 +f 2671//1 2672//1 2623//1 +f 2623//1 2672//1 2624//1 +f 2672//1 2673//1 2624//1 +f 2624//1 2673//1 2625//1 +f 2673//1 2674//1 2625//1 +f 2625//1 2674//1 2626//1 +f 2674//1 2675//1 2626//1 +f 2626//1 2675//1 2627//1 +f 2675//1 2676//1 2627//1 +f 2627//1 2676//1 2628//1 +f 2676//1 2677//1 2628//1 +f 2628//1 2677//1 2629//1 +f 2677//1 2678//1 2629//1 +f 2629//1 2678//1 2630//1 +f 2678//1 2679//1 2630//1 +f 2630//1 2679//1 2631//1 +f 2679//1 2680//1 2631//1 +f 2631//1 2680//1 2632//1 +f 2680//1 2681//1 2632//1 +f 2632//1 2681//1 2633//1 +f 2681//1 2682//1 2633//1 +f 2633//1 2682//1 2634//1 +f 2682//1 2683//1 2634//1 +f 2634//1 2683//1 2635//1 +f 2683//1 2684//1 2635//1 +f 2635//1 2684//1 2636//1 +f 2684//1 2685//1 2636//1 +f 2636//1 2685//1 2637//1 +f 2685//1 2686//1 2637//1 +f 2637//1 2686//1 2638//1 +f 2686//1 2687//1 2638//1 +f 2638//1 2687//1 2639//1 +f 2687//1 2688//1 2639//1 +f 2639//1 2688//1 2640//1 +f 2688//1 2689//1 2640//1 +f 2640//1 2689//1 2641//1 +f 2689//1 2690//1 2641//1 +f 2641//1 2690//1 2642//1 +f 2690//1 2691//1 2642//1 +f 2642//1 2691//1 2643//1 +f 2691//1 2692//1 2643//1 +f 2643//1 2692//1 2644//1 +f 2692//1 2693//1 2644//1 +f 2644//1 2693//1 2645//1 +f 2693//1 2694//1 2645//1 +f 2645//1 2694//1 2646//1 +f 2694//1 2695//1 2646//1 +f 2646//1 2695//1 2647//1 +f 2695//1 2696//1 2647//1 +f 2647//1 2696//1 2648//1 +f 2696//1 2697//1 2648//1 +f 2648//1 2697//1 2649//1 +f 2697//1 2698//1 2649//1 +f 2649//1 2698//1 2650//1 +f 2698//1 2699//1 2650//1 +f 2650//1 2699//1 2651//1 +f 2699//1 2700//1 2651//1 +f 2651//1 2700//1 2652//1 +f 2700//1 2701//1 2652//1 +f 2652//1 2701//1 2653//1 +f 2701//1 2702//1 2653//1 +f 2653//1 2702//1 2654//1 +f 2702//1 2703//1 2654//1 +f 2654//1 2703//1 2655//1 +f 2703//1 2704//1 2655//1 +f 2655//1 2704//1 6//1 +f 2704//1 5//1 6//1 +f 104//1 254//1 2656//1 +f 254//1 253//1 2656//1 +f 2656//1 253//1 2657//1 +f 253//1 252//1 2657//1 +f 2657//1 252//1 2658//1 +f 252//1 251//1 2658//1 +f 2658//1 251//1 2659//1 +f 251//1 250//1 2659//1 +f 2659//1 250//1 2660//1 +f 250//1 249//1 2660//1 +f 2660//1 249//1 2661//1 +f 249//1 248//1 2661//1 +f 2661//1 248//1 2662//1 +f 248//1 247//1 2662//1 +f 2662//1 247//1 2663//1 +f 247//1 246//1 2663//1 +f 2663//1 246//1 2664//1 +f 246//1 245//1 2664//1 +f 2664//1 245//1 2665//1 +f 245//1 244//1 2665//1 +f 2665//1 244//1 2666//1 +f 244//1 243//1 2666//1 +f 2666//1 243//1 2667//1 +f 243//1 242//1 2667//1 +f 2667//1 242//1 2668//1 +f 242//1 241//1 2668//1 +f 2668//1 241//1 2669//1 +f 241//1 240//1 2669//1 +f 2669//1 240//1 2670//1 +f 240//1 239//1 2670//1 +f 2670//1 239//1 2671//1 +f 239//1 238//1 2671//1 +f 2671//1 238//1 2672//1 +f 238//1 237//1 2672//1 +f 2672//1 237//1 2673//1 +f 237//1 236//1 2673//1 +f 2673//1 236//1 2674//1 +f 236//1 235//1 2674//1 +f 2674//1 235//1 2675//1 +f 235//1 234//1 2675//1 +f 2675//1 234//1 2676//1 +f 234//1 233//1 2676//1 +f 2676//1 233//1 2677//1 +f 233//1 232//1 2677//1 +f 2677//1 232//1 2678//1 +f 232//1 231//1 2678//1 +f 2678//1 231//1 2679//1 +f 231//1 230//1 2679//1 +f 2679//1 230//1 2680//1 +f 230//1 229//1 2680//1 +f 2680//1 229//1 2681//1 +f 229//1 228//1 2681//1 +f 2681//1 228//1 2682//1 +f 228//1 227//1 2682//1 +f 2682//1 227//1 2683//1 +f 227//1 226//1 2683//1 +f 2683//1 226//1 2684//1 +f 226//1 225//1 2684//1 +f 2684//1 225//1 2685//1 +f 225//1 224//1 2685//1 +f 2685//1 224//1 2686//1 +f 224//1 223//1 2686//1 +f 2686//1 223//1 2687//1 +f 223//1 222//1 2687//1 +f 2687//1 222//1 2688//1 +f 222//1 221//1 2688//1 +f 2688//1 221//1 2689//1 +f 221//1 220//1 2689//1 +f 2689//1 220//1 2690//1 +f 220//1 219//1 2690//1 +f 2690//1 219//1 2691//1 +f 219//1 218//1 2691//1 +f 2691//1 218//1 2692//1 +f 218//1 217//1 2692//1 +f 2692//1 217//1 2693//1 +f 217//1 216//1 2693//1 +f 2693//1 216//1 2694//1 +f 216//1 215//1 2694//1 +f 2694//1 215//1 2695//1 +f 215//1 214//1 2695//1 +f 2695//1 214//1 2696//1 +f 214//1 213//1 2696//1 +f 2696//1 213//1 2697//1 +f 213//1 212//1 2697//1 +f 2697//1 212//1 2698//1 +f 212//1 211//1 2698//1 +f 2698//1 211//1 2699//1 +f 211//1 210//1 2699//1 +f 2699//1 210//1 2700//1 +f 210//1 209//1 2700//1 +f 2700//1 209//1 2701//1 +f 209//1 208//1 2701//1 +f 2701//1 208//1 2702//1 +f 208//1 207//1 2702//1 +f 2702//1 207//1 2703//1 +f 207//1 206//1 2703//1 +f 2703//1 206//1 2704//1 +f 206//1 205//1 2704//1 +f 2704//1 205//1 5//1 +f 205//1 3//1 5//1 +o Torus +v 1.269537 0.006289 1.359776 +v 1.258843 0.006289 1.196618 +v 1.225636 0.131289 1.200990 +v 1.236043 0.131289 1.359776 +v 1.134912 0.222796 1.212934 +v 1.144537 0.222796 1.359776 +v 1.010982 0.256289 1.229250 +v 1.019537 0.256289 1.359776 +v 0.887051 0.222796 1.245565 +v 0.894537 0.222796 1.359776 +v 0.796328 0.131289 1.257509 +v 0.803031 0.131289 1.359776 +v 0.763121 0.006289 1.261881 +v 0.769537 0.006289 1.359776 +v 0.796328 -0.118711 1.257509 +v 0.803031 -0.118711 1.359776 +v 0.887051 -0.210217 1.245565 +v 0.894537 -0.210217 1.359776 +v 1.010982 -0.243711 1.229250 +v 1.019537 -0.243711 1.359776 +v 1.134912 -0.210217 1.212934 +v 1.144537 -0.210217 1.359776 +v 1.225636 -0.118711 1.200990 +v 1.236043 -0.118711 1.359776 +v 1.226944 0.006289 1.036252 +v 1.194592 0.131289 1.044921 +v 1.106204 0.222796 1.068604 +v 0.985463 0.256289 1.100957 +v 0.864722 0.222796 1.133309 +v 0.776334 0.131289 1.156993 +v 0.743981 0.006289 1.165661 +v 0.776334 -0.118711 1.156993 +v 0.864722 -0.210217 1.133309 +v 0.985463 -0.243711 1.100957 +v 1.106204 -0.210217 1.068604 +v 1.194592 -0.118711 1.044921 +v 1.174387 0.006289 0.881421 +v 1.143442 0.131289 0.894239 +v 1.058902 0.222796 0.929257 +v 0.943417 0.256289 0.977092 +v 0.827932 0.222796 1.024928 +v 0.743391 0.131289 1.059946 +v 0.712447 0.006289 1.072763 +v 0.743391 -0.118711 1.059946 +v 0.827932 -0.210217 1.024928 +v 0.943417 -0.243711 0.977092 +v 1.058902 -0.210217 0.929257 +v 1.143442 -0.118711 0.894239 +v 1.102069 0.006289 0.734776 +v 1.073062 0.131289 0.751522 +v 0.993815 0.222796 0.797276 +v 0.885562 0.256289 0.859776 +v 0.777309 0.222796 0.922276 +v 0.698062 0.131289 0.968029 +v 0.669056 0.006289 0.984776 +v 0.698062 -0.118711 0.968029 +v 0.777309 -0.210217 0.922276 +v 0.885562 -0.243711 0.859776 +v 0.993815 -0.210217 0.797276 +v 1.073062 -0.118711 0.751522 +v 1.011229 0.006289 0.598824 +v 0.984656 0.131289 0.619214 +v 0.912059 0.222796 0.674919 +v 0.812890 0.256289 0.751014 +v 0.713721 0.222796 0.827109 +v 0.641124 0.131289 0.882815 +v 0.614552 0.006289 0.903205 +v 0.641124 -0.118711 0.882815 +v 0.713721 -0.210217 0.827109 +v 0.812890 -0.243711 0.751014 +v 0.912059 -0.210217 0.674919 +v 0.984656 -0.118711 0.619214 +v 0.903420 0.006289 0.475892 +v 0.879737 0.131289 0.499576 +v 0.815032 0.222796 0.564281 +v 0.726644 0.256289 0.652669 +v 0.638255 0.222796 0.741057 +v 0.573551 0.131289 0.805762 +v 0.549867 0.006289 0.829446 +v 0.573551 -0.118711 0.805762 +v 0.638255 -0.210217 0.741057 +v 0.726644 -0.243711 0.652669 +v 0.815032 -0.210217 0.564281 +v 0.879737 -0.118711 0.499576 +v 0.780489 0.006289 0.368084 +v 0.760099 0.131289 0.394656 +v 0.704394 0.222796 0.467253 +v 0.628298 0.256289 0.566423 +v 0.552203 0.222796 0.665592 +v 0.496498 0.131289 0.738188 +v 0.476108 0.006289 0.764761 +v 0.496498 -0.118711 0.738188 +v 0.552203 -0.210217 0.665592 +v 0.628298 -0.243711 0.566423 +v 0.704394 -0.210217 0.467253 +v 0.760099 -0.118711 0.394656 +v 0.644537 0.006289 0.277244 +v 0.627790 0.131289 0.306250 +v 0.582037 0.222796 0.385497 +v 0.519537 0.256289 0.493750 +v 0.457037 0.222796 0.602003 +v 0.411284 0.131289 0.681250 +v 0.394537 0.006289 0.710257 +v 0.411284 -0.118711 0.681250 +v 0.457037 -0.210217 0.602003 +v 0.519537 -0.243711 0.493750 +v 0.582037 -0.210217 0.385497 +v 0.627790 -0.118711 0.306250 +v 0.497891 0.006289 0.204926 +v 0.485074 0.131289 0.235871 +v 0.450056 0.222796 0.320411 +v 0.402221 0.256289 0.435896 +v 0.354385 0.222796 0.551381 +v 0.319367 0.131289 0.635922 +v 0.306550 0.006289 0.666866 +v 0.319367 -0.118711 0.635922 +v 0.354385 -0.210217 0.551381 +v 0.402221 -0.243711 0.435896 +v 0.450056 -0.210217 0.320411 +v 0.485074 -0.118711 0.235871 +v 0.343061 0.006289 0.152368 +v 0.334392 0.131289 0.184721 +v 0.310708 0.222796 0.273109 +v 0.278356 0.256289 0.393850 +v 0.246004 0.222796 0.514591 +v 0.222320 0.131289 0.602979 +v 0.213651 0.006289 0.635331 +v 0.222320 -0.118711 0.602979 +v 0.246004 -0.210217 0.514591 +v 0.278356 -0.243711 0.393850 +v 0.310708 -0.210217 0.273109 +v 0.334392 -0.118711 0.184721 +v 0.182694 0.006289 0.120470 +v 0.178323 0.131289 0.153677 +v 0.166379 0.222796 0.244400 +v 0.150063 0.256289 0.368331 +v 0.133747 0.222796 0.492261 +v 0.121803 0.131289 0.582985 +v 0.117431 0.006289 0.616192 +v 0.121803 -0.118711 0.582985 +v 0.133747 -0.210217 0.492261 +v 0.150063 -0.243711 0.368331 +v 0.166379 -0.210217 0.244400 +v 0.178323 -0.118711 0.153677 +v 0.019537 0.006289 0.109776 +v 0.019537 0.131289 0.143269 +v 0.019537 0.222796 0.234776 +v 0.019537 0.256289 0.359776 +v 0.019537 0.222796 0.484776 +v 0.019537 0.131289 0.576282 +v 0.019537 0.006289 0.609776 +v 0.019537 -0.118711 0.576282 +v 0.019537 -0.210217 0.484776 +v 0.019537 -0.243711 0.359776 +v 0.019537 -0.210217 0.234776 +v 0.019537 -0.118711 0.143269 +v -0.143621 0.006289 0.120470 +v -0.139249 0.131289 0.153677 +v -0.127305 0.222796 0.244400 +v -0.110989 0.256289 0.368331 +v -0.094674 0.222796 0.492261 +v -0.082730 0.131289 0.582985 +v -0.078358 0.006289 0.616192 +v -0.082730 -0.118711 0.582985 +v -0.094674 -0.210217 0.492261 +v -0.110989 -0.243711 0.368331 +v -0.127305 -0.210217 0.244400 +v -0.139249 -0.118711 0.153677 +v -0.303987 0.006289 0.152368 +v -0.295318 0.131289 0.184721 +v -0.271634 0.222796 0.273109 +v -0.239282 0.256289 0.393850 +v -0.206930 0.222796 0.514590 +v -0.183246 0.131289 0.602979 +v -0.174577 0.006289 0.635331 +v -0.183246 -0.118711 0.602979 +v -0.206930 -0.210217 0.514590 +v -0.239282 -0.243711 0.393850 +v -0.271634 -0.210217 0.273109 +v -0.295318 -0.118711 0.184721 +v -0.458818 0.006289 0.204926 +v -0.446000 0.131289 0.235870 +v -0.410982 0.222796 0.320411 +v -0.363147 0.256289 0.435896 +v -0.315311 0.222796 0.551381 +v -0.280293 0.131289 0.635922 +v -0.267476 0.006289 0.666866 +v -0.280293 -0.118711 0.635922 +v -0.315311 -0.210217 0.551381 +v -0.363147 -0.243711 0.435896 +v -0.410982 -0.210217 0.320411 +v -0.446000 -0.118711 0.235870 +v -0.605463 0.006289 0.277244 +v -0.588716 0.131289 0.306250 +v -0.542963 0.222796 0.385497 +v -0.480463 0.256289 0.493750 +v -0.417963 0.222796 0.602003 +v -0.372210 0.131289 0.681250 +v -0.355463 0.006289 0.710257 +v -0.372210 -0.118711 0.681250 +v -0.417963 -0.210217 0.602003 +v -0.480463 -0.243711 0.493750 +v -0.542963 -0.210217 0.385497 +v -0.588716 -0.118711 0.306250 +v -0.741415 0.006289 0.368084 +v -0.721025 0.131289 0.394656 +v -0.665320 0.222796 0.467253 +v -0.589225 0.256289 0.566422 +v -0.513129 0.222796 0.665592 +v -0.457424 0.131289 0.738188 +v -0.437034 0.006289 0.764761 +v -0.457424 -0.118711 0.738188 +v -0.513129 -0.210217 0.665592 +v -0.589225 -0.243711 0.566422 +v -0.665320 -0.210217 0.467253 +v -0.721025 -0.118711 0.394656 +v -0.864347 0.006289 0.475893 +v -0.840663 0.131289 0.499576 +v -0.775958 0.222796 0.564281 +v -0.687570 0.256289 0.652669 +v -0.599182 0.222796 0.741057 +v -0.534477 0.131289 0.805762 +v -0.510793 0.006289 0.829446 +v -0.534477 -0.118711 0.805762 +v -0.599182 -0.210217 0.741057 +v -0.687570 -0.243711 0.652669 +v -0.775958 -0.210217 0.564281 +v -0.840663 -0.118711 0.499576 +v -0.972155 0.006289 0.598824 +v -0.945583 0.131289 0.619214 +v -0.872986 0.222796 0.674919 +v -0.773816 0.256289 0.751014 +v -0.674647 0.222796 0.827109 +v -0.602050 0.131289 0.882815 +v -0.575478 0.006289 0.903205 +v -0.602050 -0.118711 0.882815 +v -0.674647 -0.210217 0.827109 +v -0.773816 -0.243711 0.751014 +v -0.872986 -0.210217 0.674919 +v -0.945583 -0.118711 0.619214 +v -1.062995 0.006289 0.734775 +v -1.033988 0.131289 0.751522 +v -0.954742 0.222796 0.797275 +v -0.846488 0.256289 0.859775 +v -0.738235 0.222796 0.922275 +v -0.658988 0.131289 0.968029 +v -0.629982 0.006289 0.984775 +v -0.658988 -0.118711 0.968029 +v -0.738235 -0.210217 0.922275 +v -0.846488 -0.243711 0.859775 +v -0.954742 -0.210217 0.797275 +v -1.033988 -0.118711 0.751522 +v -1.135312 0.006289 0.881421 +v -1.104368 0.131289 0.894239 +v -1.019827 0.222796 0.929257 +v -0.904343 0.256289 0.977092 +v -0.788858 0.222796 1.024928 +v -0.704317 0.131289 1.059946 +v -0.673373 0.006289 1.072763 +v -0.704317 -0.118711 1.059946 +v -0.788858 -0.210217 1.024928 +v -0.904343 -0.243711 0.977092 +v -1.019827 -0.210217 0.929257 +v -1.104368 -0.118711 0.894239 +v -1.187871 0.006289 1.036252 +v -1.155518 0.131289 1.044921 +v -1.067130 0.222796 1.068604 +v -0.946389 0.256289 1.100957 +v -0.825648 0.222796 1.133309 +v -0.737260 0.131289 1.156993 +v -0.704908 0.006289 1.165662 +v -0.737260 -0.118711 1.156993 +v -0.825648 -0.210217 1.133309 +v -0.946389 -0.243711 1.100957 +v -1.067130 -0.210217 1.068604 +v -1.155518 -0.118711 1.044921 +v -1.219769 0.006289 1.196618 +v -1.186562 0.131289 1.200990 +v -1.095839 0.222796 1.212934 +v -0.971908 0.256289 1.229249 +v -0.847977 0.222796 1.245565 +v -0.757254 0.131289 1.257509 +v -0.724047 0.006289 1.261881 +v -0.757254 -0.118711 1.257509 +v -0.847977 -0.210217 1.245565 +v -0.971908 -0.243711 1.229249 +v -1.095839 -0.210217 1.212934 +v -1.186562 -0.118711 1.200990 +v -1.230463 0.006289 1.359776 +v -1.196970 0.131289 1.359776 +v -1.105463 0.222796 1.359776 +v -0.980463 0.256289 1.359776 +v -0.855463 0.222796 1.359776 +v -0.763957 0.131289 1.359776 +v -0.730463 0.006289 1.359776 +v -0.763957 -0.118711 1.359776 +v -0.855463 -0.210217 1.359776 +v -0.980463 -0.243711 1.359776 +v -1.105463 -0.210217 1.359776 +v -1.196970 -0.118711 1.359776 +v -1.219769 0.006289 1.522934 +v -1.186562 0.131289 1.518562 +v -1.095839 0.222796 1.506618 +v -0.971908 0.256289 1.490302 +v -0.847977 0.222796 1.473986 +v -0.757254 0.131289 1.462042 +v -0.724047 0.006289 1.457670 +v -0.757254 -0.118711 1.462042 +v -0.847977 -0.210217 1.473986 +v -0.971908 -0.243711 1.490302 +v -1.095839 -0.210217 1.506618 +v -1.186562 -0.118711 1.518562 +v -1.187871 0.006289 1.683299 +v -1.155518 0.131289 1.674631 +v -1.067130 0.222796 1.650947 +v -0.946389 0.256289 1.618595 +v -0.825648 0.222796 1.586242 +v -0.737260 0.131289 1.562559 +v -0.704908 0.006289 1.553890 +v -0.737260 -0.118711 1.562559 +v -0.825648 -0.210217 1.586242 +v -0.946389 -0.243711 1.618595 +v -1.067130 -0.210217 1.650947 +v -1.155518 -0.118711 1.674631 +v -1.135313 0.006289 1.838130 +v -1.104369 0.131289 1.825312 +v -1.019828 0.222796 1.790294 +v -0.904343 0.256289 1.742459 +v -0.788858 0.222796 1.694623 +v -0.704317 0.131289 1.659605 +v -0.673373 0.006289 1.646788 +v -0.704317 -0.118711 1.659605 +v -0.788858 -0.210217 1.694623 +v -0.904343 -0.243711 1.742459 +v -1.019828 -0.210217 1.790294 +v -1.104369 -0.118711 1.825312 +v -1.062995 0.006289 1.984776 +v -1.033989 0.131289 1.968029 +v -0.954742 0.222796 1.922276 +v -0.846489 0.256289 1.859776 +v -0.738235 0.222796 1.797276 +v -0.658989 0.131289 1.751522 +v -0.629982 0.006289 1.734776 +v -0.658989 -0.118711 1.751522 +v -0.738235 -0.210217 1.797276 +v -0.846489 -0.243711 1.859776 +v -0.954742 -0.210217 1.922276 +v -1.033989 -0.118711 1.968029 +v -0.972155 0.006289 2.120728 +v -0.945583 0.131289 2.100338 +v -0.872986 0.222796 2.044632 +v -0.773816 0.256289 1.968537 +v -0.674647 0.222796 1.892442 +v -0.602050 0.131289 1.836736 +v -0.575478 0.006289 1.816347 +v -0.602050 -0.118711 1.836736 +v -0.674647 -0.210217 1.892442 +v -0.773816 -0.243711 1.968537 +v -0.872986 -0.210217 2.044632 +v -0.945583 -0.118711 2.100338 +v -0.864347 0.006289 2.243659 +v -0.840663 0.131289 2.219975 +v -0.775958 0.222796 2.155271 +v -0.687570 0.256289 2.066882 +v -0.599182 0.222796 1.978494 +v -0.534477 0.131289 1.913789 +v -0.510793 0.006289 1.890106 +v -0.534477 -0.118711 1.913789 +v -0.599182 -0.210217 1.978494 +v -0.687570 -0.243711 2.066882 +v -0.775958 -0.210217 2.155271 +v -0.840663 -0.118711 2.219975 +v -0.741416 0.006289 2.351467 +v -0.721026 0.131289 2.324895 +v -0.665320 0.222796 2.252298 +v -0.589225 0.256289 2.153129 +v -0.513130 0.222796 2.053960 +v -0.457424 0.131289 1.981363 +v -0.437034 0.006289 1.954791 +v -0.457424 -0.118711 1.981363 +v -0.513130 -0.210217 2.053960 +v -0.589225 -0.243711 2.153129 +v -0.665320 -0.210217 2.252298 +v -0.721026 -0.118711 2.324895 +v -0.605463 0.006289 2.442308 +v -0.588716 0.131289 2.413301 +v -0.542963 0.222796 2.334054 +v -0.480463 0.256289 2.225801 +v -0.417963 0.222796 2.117548 +v -0.372210 0.131289 2.038301 +v -0.355463 0.006289 2.009295 +v -0.372210 -0.118711 2.038301 +v -0.417963 -0.210217 2.117548 +v -0.480463 -0.243711 2.225801 +v -0.542963 -0.210217 2.334054 +v -0.588716 -0.118711 2.413301 +v -0.458818 0.006289 2.514625 +v -0.446000 0.131289 2.483681 +v -0.410982 0.222796 2.399140 +v -0.363147 0.256289 2.283655 +v -0.315311 0.222796 2.168170 +v -0.280293 0.131289 2.083629 +v -0.267476 0.006289 2.052685 +v -0.280293 -0.118711 2.083629 +v -0.315311 -0.210217 2.168170 +v -0.363147 -0.243711 2.283655 +v -0.410982 -0.210217 2.399140 +v -0.446000 -0.118711 2.483681 +v -0.303987 0.006289 2.567183 +v -0.295318 0.131289 2.534830 +v -0.271635 0.222796 2.446442 +v -0.239282 0.256289 2.325701 +v -0.206930 0.222796 2.204961 +v -0.183246 0.131289 2.116572 +v -0.174578 0.006289 2.084220 +v -0.183246 -0.118711 2.116572 +v -0.206930 -0.210217 2.204961 +v -0.239282 -0.243711 2.325701 +v -0.271635 -0.210217 2.446442 +v -0.295318 -0.118711 2.534830 +v -0.143622 0.006289 2.599082 +v -0.139250 0.131289 2.565874 +v -0.127306 0.222796 2.475151 +v -0.110990 0.256289 2.351220 +v -0.094674 0.222796 2.227290 +v -0.082730 0.131289 2.136566 +v -0.078358 0.006289 2.103359 +v -0.082730 -0.118711 2.136566 +v -0.094674 -0.210217 2.227290 +v -0.110990 -0.243711 2.351220 +v -0.127306 -0.210217 2.475151 +v -0.139250 -0.118711 2.565874 +v 0.019537 0.006289 2.609776 +v 0.019537 0.131289 2.576282 +v 0.019537 0.222796 2.484776 +v 0.019537 0.256289 2.359776 +v 0.019537 0.222796 2.234776 +v 0.019537 0.131289 2.143269 +v 0.019537 0.006289 2.109776 +v 0.019537 -0.118711 2.143269 +v 0.019537 -0.210217 2.234776 +v 0.019537 -0.243711 2.359776 +v 0.019537 -0.210217 2.484776 +v 0.019537 -0.118711 2.576282 +v 0.182694 0.006289 2.599082 +v 0.178323 0.131289 2.565875 +v 0.166379 0.222796 2.475151 +v 0.150063 0.256289 2.351221 +v 0.133747 0.222796 2.227290 +v 0.121803 0.131289 2.136566 +v 0.117431 0.006289 2.103359 +v 0.121803 -0.118711 2.136566 +v 0.133747 -0.210217 2.227290 +v 0.150063 -0.243711 2.351221 +v 0.166379 -0.210217 2.475151 +v 0.178323 -0.118711 2.565875 +v 0.343060 0.006289 2.567183 +v 0.334391 0.131289 2.534831 +v 0.310708 0.222796 2.446442 +v 0.278356 0.256289 2.325702 +v 0.246003 0.222796 2.204961 +v 0.222320 0.131289 2.116573 +v 0.213651 0.006289 2.084220 +v 0.222320 -0.118711 2.116573 +v 0.246003 -0.210217 2.204961 +v 0.278356 -0.243711 2.325702 +v 0.310708 -0.210217 2.446442 +v 0.334391 -0.118711 2.534831 +v 0.497891 0.006289 2.514625 +v 0.485074 0.131289 2.483681 +v 0.450056 0.222796 2.399140 +v 0.402221 0.256289 2.283655 +v 0.354385 0.222796 2.168170 +v 0.319367 0.131289 2.083629 +v 0.306550 0.006289 2.052685 +v 0.319367 -0.118711 2.083629 +v 0.354385 -0.210217 2.168170 +v 0.402221 -0.243711 2.283655 +v 0.450056 -0.210217 2.399140 +v 0.485074 -0.118711 2.483681 +v 0.644537 0.006289 2.442307 +v 0.627790 0.131289 2.413301 +v 0.582037 0.222796 2.334054 +v 0.519537 0.256289 2.225801 +v 0.457037 0.222796 2.117548 +v 0.411284 0.131289 2.038301 +v 0.394537 0.006289 2.009295 +v 0.411284 -0.118711 2.038301 +v 0.457037 -0.210217 2.117548 +v 0.519537 -0.243711 2.225801 +v 0.582037 -0.210217 2.334054 +v 0.627790 -0.118711 2.413301 +v 0.780488 0.006289 2.351468 +v 0.760099 0.131289 2.324895 +v 0.704393 0.222796 2.252298 +v 0.628298 0.256289 2.153129 +v 0.552203 0.222796 2.053960 +v 0.496497 0.131289 1.981363 +v 0.476108 0.006289 1.954791 +v 0.496497 -0.118711 1.981363 +v 0.552203 -0.210217 2.053960 +v 0.628298 -0.243711 2.153129 +v 0.704393 -0.210217 2.252298 +v 0.760099 -0.118711 2.324895 +v 0.903420 0.006289 2.243660 +v 0.879736 0.131289 2.219976 +v 0.815032 0.222796 2.155271 +v 0.726643 0.256289 2.066883 +v 0.638255 0.222796 1.978495 +v 0.573550 0.131289 1.913790 +v 0.549867 0.006289 1.890106 +v 0.573550 -0.118711 1.913790 +v 0.638255 -0.210217 1.978495 +v 0.726643 -0.243711 2.066883 +v 0.815032 -0.210217 2.155271 +v 0.879736 -0.118711 2.219976 +v 1.011229 0.006289 2.120727 +v 0.984656 0.131289 2.100338 +v 0.912059 0.222796 2.044632 +v 0.812890 0.256289 1.968537 +v 0.713721 0.222796 1.892442 +v 0.641124 0.131289 1.836736 +v 0.614552 0.006289 1.816347 +v 0.641124 -0.118711 1.836736 +v 0.713721 -0.210217 1.892442 +v 0.812890 -0.243711 1.968537 +v 0.912059 -0.210217 2.044632 +v 0.984656 -0.118711 2.100338 +v 1.102069 0.006289 1.984776 +v 1.073062 0.131289 1.968029 +v 0.993815 0.222796 1.922276 +v 0.885562 0.256289 1.859776 +v 0.777309 0.222796 1.797276 +v 0.698062 0.131289 1.751523 +v 0.669056 0.006289 1.734776 +v 0.698062 -0.118711 1.751523 +v 0.777309 -0.210217 1.797276 +v 0.885562 -0.243711 1.859776 +v 0.993815 -0.210217 1.922276 +v 1.073062 -0.118711 1.968029 +v 1.174386 0.006289 1.838130 +v 1.143442 0.131289 1.825313 +v 1.058901 0.222796 1.790295 +v 0.943416 0.256289 1.742460 +v 0.827931 0.222796 1.694624 +v 0.743391 0.131289 1.659606 +v 0.712446 0.006289 1.646789 +v 0.743391 -0.118711 1.659606 +v 0.827931 -0.210217 1.694624 +v 0.943416 -0.243711 1.742460 +v 1.058901 -0.210217 1.790295 +v 1.143442 -0.118711 1.825313 +v 1.226944 0.006289 1.683299 +v 1.194592 0.131289 1.674630 +v 1.106204 0.222796 1.650947 +v 0.985463 0.256289 1.618594 +v 0.864722 0.222796 1.586242 +v 0.776334 0.131289 1.562559 +v 0.743981 0.006289 1.553890 +v 0.776334 -0.118711 1.562559 +v 0.864722 -0.210217 1.586242 +v 0.985463 -0.243711 1.618594 +v 1.106204 -0.210217 1.650947 +v 1.194592 -0.118711 1.674630 +v 1.258843 0.006289 1.522933 +v 1.225636 0.131289 1.518562 +v 1.134912 0.222796 1.506618 +v 1.010982 0.256289 1.490302 +v 0.887051 0.222796 1.473986 +v 0.796328 0.131289 1.462042 +v 0.763121 0.006289 1.457670 +v 0.796328 -0.118711 1.462042 +v 0.887051 -0.210217 1.473986 +v 1.010982 -0.243711 1.490302 +v 1.134912 -0.210217 1.506618 +v 1.225636 -0.118711 1.518562 +vn 0.9640 0.2583 -0.0632 +vn 0.7064 0.7063 -0.0463 +vn 0.2588 0.9658 -0.0170 +vn -0.2588 0.9658 0.0170 +vn -0.7064 0.7063 0.0463 +vn -0.9640 0.2583 0.0632 +vn -0.9640 -0.2583 0.0632 +vn -0.7063 -0.7063 0.0463 +vn -0.2588 -0.9658 0.0170 +vn 0.2588 -0.9658 -0.0170 +vn 0.7063 -0.7064 -0.0463 +vn 0.9640 -0.2583 -0.0632 +vn 0.9475 0.2583 -0.1885 +vn 0.6943 0.7063 -0.1381 +vn 0.2543 0.9658 -0.0506 +vn -0.2543 0.9658 0.0506 +vn -0.6943 0.7063 0.1381 +vn -0.9475 0.2583 0.1885 +vn -0.9475 -0.2583 0.1885 +vn -0.6943 -0.7063 0.1381 +vn -0.2544 -0.9658 0.0506 +vn 0.2544 -0.9658 -0.0506 +vn 0.6943 -0.7063 -0.1381 +vn 0.9475 -0.2583 -0.1885 +vn 0.9148 0.2583 -0.3105 +vn 0.6703 0.7063 -0.2275 +vn 0.2456 0.9658 -0.0834 +vn -0.2456 0.9658 0.0834 +vn -0.6703 0.7063 0.2275 +vn -0.9148 0.2583 0.3105 +vn -0.9148 -0.2583 0.3105 +vn -0.6703 -0.7064 0.2275 +vn -0.2456 -0.9658 0.0834 +vn 0.2456 -0.9658 -0.0834 +vn 0.6703 -0.7063 -0.2275 +vn 0.9148 -0.2583 -0.3105 +vn 0.8664 0.2583 -0.4273 +vn 0.6349 0.7063 -0.3131 +vn 0.2326 0.9658 -0.1147 +vn -0.2326 0.9658 0.1147 +vn -0.6349 0.7063 0.3131 +vn -0.8664 0.2583 0.4273 +vn -0.8664 -0.2583 0.4273 +vn -0.6349 -0.7064 0.3131 +vn -0.2326 -0.9658 0.1147 +vn 0.2326 -0.9658 -0.1147 +vn 0.6349 -0.7064 -0.3131 +vn 0.8664 -0.2583 -0.4273 +vn 0.8033 0.2583 -0.5367 +vn 0.5886 0.7063 -0.3933 +vn 0.2156 0.9658 -0.1441 +vn -0.2156 0.9658 0.1441 +vn -0.5886 0.7063 0.3933 +vn -0.8033 0.2583 0.5367 +vn -0.8033 -0.2583 0.5367 +vn -0.5886 -0.7064 0.3933 +vn -0.2156 -0.9658 0.1441 +vn 0.2156 -0.9658 -0.1441 +vn 0.5886 -0.7063 -0.3933 +vn 0.8033 -0.2583 -0.5367 +vn 0.7263 0.2583 -0.6370 +vn 0.5322 0.7063 -0.4667 +vn 0.1950 0.9658 -0.1710 +vn -0.1950 0.9658 0.1710 +vn -0.5322 0.7063 0.4667 +vn -0.7263 0.2583 0.6370 +vn -0.7263 -0.2583 0.6370 +vn -0.5322 -0.7064 0.4667 +vn -0.1950 -0.9658 0.1710 +vn 0.1950 -0.9658 -0.1710 +vn 0.5322 -0.7063 -0.4667 +vn 0.7263 -0.2583 -0.6370 +vn 0.6370 0.2583 -0.7263 +vn 0.4667 0.7063 -0.5322 +vn 0.1710 0.9658 -0.1950 +vn -0.1710 0.9658 0.1950 +vn -0.4667 0.7063 0.5322 +vn -0.6370 0.2583 0.7263 +vn -0.6370 -0.2583 0.7263 +vn -0.4667 -0.7063 0.5322 +vn -0.1710 -0.9658 0.1950 +vn 0.1710 -0.9658 -0.1950 +vn 0.4667 -0.7064 -0.5322 +vn 0.6370 -0.2583 -0.7263 +vn 0.5367 0.2583 -0.8033 +vn 0.3933 0.7063 -0.5886 +vn 0.1441 0.9658 -0.2156 +vn -0.1441 0.9658 0.2156 +vn -0.3933 0.7063 0.5886 +vn -0.5367 0.2583 0.8033 +vn -0.5367 -0.2583 0.8033 +vn -0.3933 -0.7063 0.5886 +vn -0.1441 -0.9658 0.2156 +vn 0.1441 -0.9658 -0.2156 +vn 0.3933 -0.7063 -0.5886 +vn 0.5367 -0.2583 -0.8033 +vn 0.4273 0.2583 -0.8664 +vn 0.3131 0.7063 -0.6349 +vn 0.1147 0.9658 -0.2326 +vn -0.1147 0.9658 0.2326 +vn -0.3131 0.7063 0.6349 +vn -0.4273 0.2583 0.8664 +vn -0.4273 -0.2583 0.8664 +vn -0.3131 -0.7064 0.6349 +vn -0.1147 -0.9658 0.2326 +vn 0.1147 -0.9658 -0.2326 +vn 0.3131 -0.7063 -0.6349 +vn 0.4273 -0.2583 -0.8664 +vn 0.3105 0.2583 -0.9148 +vn 0.2275 0.7063 -0.6703 +vn 0.0834 0.9658 -0.2456 +vn -0.0834 0.9658 0.2456 +vn -0.2275 0.7063 0.6703 +vn -0.3105 0.2583 0.9148 +vn -0.3105 -0.2583 0.9148 +vn -0.2275 -0.7064 0.6703 +vn -0.0834 -0.9658 0.2456 +vn 0.0834 -0.9658 -0.2456 +vn 0.2275 -0.7063 -0.6703 +vn 0.3105 -0.2583 -0.9148 +vn 0.1885 0.2583 -0.9475 +vn 0.1381 0.7063 -0.6943 +vn 0.0506 0.9658 -0.2543 +vn -0.0506 0.9658 0.2543 +vn -0.1381 0.7063 0.6943 +vn -0.1885 0.2583 0.9475 +vn -0.1885 -0.2583 0.9475 +vn -0.1381 -0.7064 0.6943 +vn -0.0506 -0.9658 0.2544 +vn 0.0506 -0.9658 -0.2544 +vn 0.1381 -0.7063 -0.6943 +vn 0.1885 -0.2583 -0.9475 +vn 0.0632 0.2583 -0.9640 +vn 0.0463 0.7063 -0.7064 +vn 0.0170 0.9658 -0.2588 +vn -0.0170 0.9658 0.2588 +vn -0.0463 0.7063 0.7064 +vn -0.0632 0.2583 0.9640 +vn -0.0632 -0.2583 0.9640 +vn -0.0463 -0.7064 0.7063 +vn -0.0170 -0.9658 0.2588 +vn 0.0170 -0.9658 -0.2588 +vn 0.0463 -0.7064 -0.7063 +vn 0.0632 -0.2583 -0.9640 +vn -0.0632 0.2583 -0.9640 +vn -0.0463 0.7063 -0.7064 +vn -0.0170 0.9658 -0.2588 +vn 0.0170 0.9658 0.2588 +vn 0.0463 0.7063 0.7064 +vn 0.0632 0.2583 0.9640 +vn 0.0632 -0.2583 0.9640 +vn 0.0463 -0.7064 0.7063 +vn 0.0170 -0.9658 0.2588 +vn -0.0170 -0.9658 -0.2588 +vn -0.0463 -0.7064 -0.7063 +vn -0.0632 -0.2583 -0.9640 +vn -0.1885 0.2583 -0.9475 +vn -0.1381 0.7063 -0.6943 +vn -0.0506 0.9658 -0.2543 +vn 0.0506 0.9658 0.2544 +vn 0.1381 0.7063 0.6943 +vn 0.1885 0.2583 0.9475 +vn 0.1885 -0.2583 0.9475 +vn 0.1381 -0.7064 0.6943 +vn 0.0506 -0.9658 0.2544 +vn -0.0506 -0.9658 -0.2544 +vn -0.1381 -0.7063 -0.6943 +vn -0.1885 -0.2583 -0.9475 +vn -0.3105 0.2583 -0.9148 +vn -0.2275 0.7063 -0.6703 +vn -0.0834 0.9658 -0.2456 +vn 0.0834 0.9658 0.2456 +vn 0.2275 0.7063 0.6703 +vn 0.3105 0.2583 0.9148 +vn 0.3105 -0.2583 0.9148 +vn 0.2275 -0.7064 0.6703 +vn 0.0834 -0.9658 0.2456 +vn -0.0834 -0.9658 -0.2456 +vn -0.2275 -0.7063 -0.6703 +vn -0.3105 -0.2583 -0.9148 +vn -0.4273 0.2583 -0.8664 +vn -0.3131 0.7063 -0.6349 +vn -0.1147 0.9658 -0.2326 +vn 0.1147 0.9658 0.2326 +vn 0.3131 0.7063 0.6349 +vn 0.4273 0.2583 0.8664 +vn 0.4273 -0.2583 0.8664 +vn 0.3131 -0.7064 0.6349 +vn 0.1147 -0.9658 0.2326 +vn -0.1147 -0.9658 -0.2326 +vn -0.3131 -0.7064 -0.6349 +vn -0.4273 -0.2583 -0.8664 +vn -0.5367 0.2583 -0.8033 +vn -0.3933 0.7063 -0.5886 +vn -0.1441 0.9658 -0.2156 +vn 0.1441 0.9658 0.2156 +vn 0.3933 0.7063 0.5886 +vn 0.5367 0.2583 0.8033 +vn 0.5367 -0.2583 0.8033 +vn 0.3933 -0.7063 0.5886 +vn 0.1441 -0.9658 0.2156 +vn -0.1441 -0.9658 -0.2156 +vn -0.3933 -0.7063 -0.5886 +vn -0.5367 -0.2583 -0.8033 +vn -0.6370 0.2583 -0.7263 +vn -0.4667 0.7063 -0.5322 +vn -0.1710 0.9658 -0.1950 +vn 0.1710 0.9658 0.1950 +vn 0.4667 0.7063 0.5322 +vn 0.6370 0.2583 0.7263 +vn 0.6370 -0.2583 0.7263 +vn 0.4667 -0.7063 0.5322 +vn 0.1710 -0.9658 0.1950 +vn -0.1710 -0.9658 -0.1950 +vn -0.4667 -0.7063 -0.5322 +vn -0.6370 -0.2583 -0.7263 +vn -0.7263 0.2583 -0.6370 +vn -0.5322 0.7063 -0.4667 +vn -0.1950 0.9658 -0.1710 +vn 0.1950 0.9658 0.1710 +vn 0.5322 0.7063 0.4667 +vn 0.7263 0.2583 0.6370 +vn 0.7263 -0.2583 0.6370 +vn 0.5322 -0.7064 0.4667 +vn 0.1950 -0.9658 0.1710 +vn -0.1950 -0.9658 -0.1710 +vn -0.5322 -0.7063 -0.4667 +vn -0.7263 -0.2583 -0.6370 +vn -0.8033 0.2583 -0.5367 +vn -0.5886 0.7063 -0.3933 +vn -0.2156 0.9658 -0.1441 +vn 0.2156 0.9658 0.1441 +vn 0.5886 0.7063 0.3933 +vn 0.8033 0.2583 0.5367 +vn 0.8033 -0.2583 0.5367 +vn 0.5886 -0.7064 0.3933 +vn 0.2156 -0.9658 0.1441 +vn -0.2156 -0.9658 -0.1441 +vn -0.5886 -0.7063 -0.3933 +vn -0.8033 -0.2583 -0.5367 +vn -0.8664 0.2583 -0.4273 +vn -0.6349 0.7063 -0.3131 +vn -0.2326 0.9658 -0.1147 +vn 0.2326 0.9658 0.1147 +vn 0.6349 0.7063 0.3131 +vn 0.8664 0.2583 0.4273 +vn 0.8664 -0.2583 0.4273 +vn 0.6349 -0.7064 0.3131 +vn 0.2326 -0.9658 0.1147 +vn -0.2326 -0.9658 -0.1147 +vn -0.6349 -0.7063 -0.3131 +vn -0.8664 -0.2583 -0.4273 +vn -0.9148 0.2583 -0.3105 +vn -0.6703 0.7063 -0.2275 +vn -0.2456 0.9658 -0.0834 +vn 0.2456 0.9658 0.0834 +vn 0.6703 0.7063 0.2275 +vn 0.9148 0.2583 0.3105 +vn 0.9148 -0.2583 0.3105 +vn 0.6703 -0.7064 0.2275 +vn 0.2456 -0.9658 0.0834 +vn -0.2456 -0.9658 -0.0834 +vn -0.6703 -0.7063 -0.2275 +vn -0.9148 -0.2583 -0.3105 +vn -0.9475 0.2583 -0.1885 +vn -0.6943 0.7063 -0.1381 +vn -0.2543 0.9658 -0.0506 +vn 0.2543 0.9658 0.0506 +vn 0.6943 0.7063 0.1381 +vn 0.9475 0.2583 0.1885 +vn 0.9475 -0.2583 0.1885 +vn 0.6943 -0.7063 0.1381 +vn 0.2544 -0.9658 0.0506 +vn -0.2544 -0.9658 -0.0506 +vn -0.6943 -0.7063 -0.1381 +vn -0.9475 -0.2583 -0.1885 +vn -0.9640 0.2583 -0.0632 +vn -0.7064 0.7063 -0.0463 +vn -0.2588 0.9658 -0.0170 +vn 0.2588 0.9658 0.0170 +vn 0.7064 0.7063 0.0463 +vn 0.9640 0.2583 0.0632 +vn 0.9640 -0.2583 0.0632 +vn 0.7063 -0.7063 0.0463 +vn 0.2588 -0.9658 0.0170 +vn -0.2588 -0.9658 -0.0170 +vn -0.7063 -0.7064 -0.0463 +vn -0.9640 -0.2583 -0.0632 +vn 0.7063 -0.7063 -0.0463 +vn -0.7063 -0.7064 0.0463 +vn 0.6349 -0.7063 -0.3131 +vn 0.5886 -0.7064 -0.3933 +vn 0.5322 -0.7064 -0.4667 +vn -0.4667 -0.7064 0.5322 +vn 0.3933 -0.7064 -0.5886 +vn -0.3933 -0.7064 0.5886 +vn 0.3131 -0.7064 -0.6349 +vn 0.2275 -0.7064 -0.6703 +vn -0.2275 -0.7063 0.6703 +vn 0.0506 0.9658 -0.2544 +vn 0.1381 -0.7064 -0.6943 +vn -0.1381 -0.7063 0.6943 +vn 0.0463 0.7063 -0.7063 +vn -0.0463 -0.7063 0.7063 +vn -0.0463 0.7063 -0.7063 +vn -0.3933 -0.7064 -0.5886 +vn 0.3933 -0.7064 0.5886 +vn -0.4667 -0.7064 -0.5322 +vn 0.4667 -0.7064 0.5322 +vn -0.5322 -0.7064 -0.4667 +vn -0.5886 -0.7064 -0.3933 +vn 0.6703 -0.7063 0.2275 +vn 0.2544 0.9658 0.0506 +vn 0.6943 -0.7064 0.1381 +vn -0.7063 -0.7063 -0.0463 +vn 0.7063 -0.7064 0.0463 +usemtl None +s 1 +f 2705//2 2706//2 2707//2 2708//2 +f 2708//3 2707//3 2709//3 2710//3 +f 2710//4 2709//4 2711//4 2712//4 +f 2712//5 2711//5 2713//5 2714//5 +f 2714//6 2713//6 2715//6 2716//6 +f 2716//7 2715//7 2717//7 2718//7 +f 2718//8 2717//8 2719//8 2720//8 +f 2720//9 2719//9 2721//9 2722//9 +f 2722//10 2721//10 2723//10 2724//10 +f 2724//11 2723//11 2725//11 2726//11 +f 2726//12 2725//12 2727//12 2728//12 +f 2705//13 2728//13 2727//13 2706//13 +f 2706//14 2729//14 2730//14 2707//14 +f 2707//15 2730//15 2731//15 2709//15 +f 2709//16 2731//16 2732//16 2711//16 +f 2711//17 2732//17 2733//17 2713//17 +f 2713//18 2733//18 2734//18 2715//18 +f 2715//19 2734//19 2735//19 2717//19 +f 2717//20 2735//20 2736//20 2719//20 +f 2719//21 2736//21 2737//21 2721//21 +f 2721//22 2737//22 2738//22 2723//22 +f 2723//23 2738//23 2739//23 2725//23 +f 2725//24 2739//24 2740//24 2727//24 +f 2727//25 2740//25 2729//25 2706//25 +f 2729//26 2741//26 2742//26 2730//26 +f 2730//27 2742//27 2743//27 2731//27 +f 2731//28 2743//28 2744//28 2732//28 +f 2732//29 2744//29 2745//29 2733//29 +f 2733//30 2745//30 2746//30 2734//30 +f 2734//31 2746//31 2747//31 2735//31 +f 2735//32 2747//32 2748//32 2736//32 +f 2736//33 2748//33 2749//33 2737//33 +f 2737//34 2749//34 2750//34 2738//34 +f 2738//35 2750//35 2751//35 2739//35 +f 2739//36 2751//36 2752//36 2740//36 +f 2740//37 2752//37 2741//37 2729//37 +f 2741//38 2753//38 2754//38 2742//38 +f 2742//39 2754//39 2755//39 2743//39 +f 2743//40 2755//40 2756//40 2744//40 +f 2744//41 2756//41 2757//41 2745//41 +f 2745//42 2757//42 2758//42 2746//42 +f 2746//43 2758//43 2759//43 2747//43 +f 2747//44 2759//44 2760//44 2748//44 +f 2748//45 2760//45 2761//45 2749//45 +f 2749//46 2761//46 2762//46 2750//46 +f 2750//47 2762//47 2763//47 2751//47 +f 2751//48 2763//48 2764//48 2752//48 +f 2752//49 2764//49 2753//49 2741//49 +f 2753//50 2765//50 2766//50 2754//50 +f 2754//51 2766//51 2767//51 2755//51 +f 2755//52 2767//52 2768//52 2756//52 +f 2756//53 2768//53 2769//53 2757//53 +f 2757//54 2769//54 2770//54 2758//54 +f 2758//55 2770//55 2771//55 2759//55 +f 2759//56 2771//56 2772//56 2760//56 +f 2760//57 2772//57 2773//57 2761//57 +f 2761//58 2773//58 2774//58 2762//58 +f 2762//59 2774//59 2775//59 2763//59 +f 2763//60 2775//60 2776//60 2764//60 +f 2764//61 2776//61 2765//61 2753//61 +f 2765//62 2777//62 2778//62 2766//62 +f 2766//63 2778//63 2779//63 2767//63 +f 2767//64 2779//64 2780//64 2768//64 +f 2768//65 2780//65 2781//65 2769//65 +f 2769//66 2781//66 2782//66 2770//66 +f 2770//67 2782//67 2783//67 2771//67 +f 2771//68 2783//68 2784//68 2772//68 +f 2772//69 2784//69 2785//69 2773//69 +f 2773//70 2785//70 2786//70 2774//70 +f 2774//71 2786//71 2787//71 2775//71 +f 2775//72 2787//72 2788//72 2776//72 +f 2776//73 2788//73 2777//73 2765//73 +f 2777//74 2789//74 2790//74 2778//74 +f 2778//75 2790//75 2791//75 2779//75 +f 2779//76 2791//76 2792//76 2780//76 +f 2780//77 2792//77 2793//77 2781//77 +f 2781//78 2793//78 2794//78 2782//78 +f 2782//79 2794//79 2795//79 2783//79 +f 2783//80 2795//80 2796//80 2784//80 +f 2784//81 2796//81 2797//81 2785//81 +f 2785//82 2797//82 2798//82 2786//82 +f 2786//83 2798//83 2799//83 2787//83 +f 2787//84 2799//84 2800//84 2788//84 +f 2788//85 2800//85 2789//85 2777//85 +f 2789//86 2801//86 2802//86 2790//86 +f 2790//87 2802//87 2803//87 2791//87 +f 2791//88 2803//88 2804//88 2792//88 +f 2792//89 2804//89 2805//89 2793//89 +f 2793//90 2805//90 2806//90 2794//90 +f 2794//91 2806//91 2807//91 2795//91 +f 2795//92 2807//92 2808//92 2796//92 +f 2796//93 2808//93 2809//93 2797//93 +f 2797//94 2809//94 2810//94 2798//94 +f 2798//95 2810//95 2811//95 2799//95 +f 2799//96 2811//96 2812//96 2800//96 +f 2800//97 2812//97 2801//97 2789//97 +f 2801//98 2813//98 2814//98 2802//98 +f 2802//99 2814//99 2815//99 2803//99 +f 2803//100 2815//100 2816//100 2804//100 +f 2804//101 2816//101 2817//101 2805//101 +f 2805//102 2817//102 2818//102 2806//102 +f 2806//103 2818//103 2819//103 2807//103 +f 2807//104 2819//104 2820//104 2808//104 +f 2808//105 2820//105 2821//105 2809//105 +f 2809//106 2821//106 2822//106 2810//106 +f 2810//107 2822//107 2823//107 2811//107 +f 2811//108 2823//108 2824//108 2812//108 +f 2812//109 2824//109 2813//109 2801//109 +f 2813//110 2825//110 2826//110 2814//110 +f 2814//111 2826//111 2827//111 2815//111 +f 2815//112 2827//112 2828//112 2816//112 +f 2816//113 2828//113 2829//113 2817//113 +f 2817//114 2829//114 2830//114 2818//114 +f 2818//115 2830//115 2831//115 2819//115 +f 2819//116 2831//116 2832//116 2820//116 +f 2820//117 2832//117 2833//117 2821//117 +f 2821//118 2833//118 2834//118 2822//118 +f 2822//119 2834//119 2835//119 2823//119 +f 2823//120 2835//120 2836//120 2824//120 +f 2824//121 2836//121 2825//121 2813//121 +f 2825//122 2837//122 2838//122 2826//122 +f 2826//123 2838//123 2839//123 2827//123 +f 2827//124 2839//124 2840//124 2828//124 +f 2828//125 2840//125 2841//125 2829//125 +f 2829//126 2841//126 2842//126 2830//126 +f 2830//127 2842//127 2843//127 2831//127 +f 2831//128 2843//128 2844//128 2832//128 +f 2832//129 2844//129 2845//129 2833//129 +f 2833//130 2845//130 2846//130 2834//130 +f 2834//131 2846//131 2847//131 2835//131 +f 2835//132 2847//132 2848//132 2836//132 +f 2836//133 2848//133 2837//133 2825//133 +f 2837//134 2849//134 2850//134 2838//134 +f 2838//135 2850//135 2851//135 2839//135 +f 2839//136 2851//136 2852//136 2840//136 +f 2840//137 2852//137 2853//137 2841//137 +f 2841//138 2853//138 2854//138 2842//138 +f 2842//139 2854//139 2855//139 2843//139 +f 2843//140 2855//140 2856//140 2844//140 +f 2844//141 2856//141 2857//141 2845//141 +f 2845//142 2857//142 2858//142 2846//142 +f 2846//143 2858//143 2859//143 2847//143 +f 2847//144 2859//144 2860//144 2848//144 +f 2848//145 2860//145 2849//145 2837//145 +f 2849//146 2861//146 2862//146 2850//146 +f 2850//147 2862//147 2863//147 2851//147 +f 2851//148 2863//148 2864//148 2852//148 +f 2852//149 2864//149 2865//149 2853//149 +f 2853//150 2865//150 2866//150 2854//150 +f 2854//151 2866//151 2867//151 2855//151 +f 2855//152 2867//152 2868//152 2856//152 +f 2856//153 2868//153 2869//153 2857//153 +f 2857//154 2869//154 2870//154 2858//154 +f 2858//155 2870//155 2871//155 2859//155 +f 2859//156 2871//156 2872//156 2860//156 +f 2860//157 2872//157 2861//157 2849//157 +f 2861//158 2873//158 2874//158 2862//158 +f 2862//159 2874//159 2875//159 2863//159 +f 2863//160 2875//160 2876//160 2864//160 +f 2864//161 2876//161 2877//161 2865//161 +f 2865//162 2877//162 2878//162 2866//162 +f 2866//163 2878//163 2879//163 2867//163 +f 2867//164 2879//164 2880//164 2868//164 +f 2868//165 2880//165 2881//165 2869//165 +f 2869//166 2881//166 2882//166 2870//166 +f 2870//167 2882//167 2883//167 2871//167 +f 2871//168 2883//168 2884//168 2872//168 +f 2872//169 2884//169 2873//169 2861//169 +f 2873//170 2885//170 2886//170 2874//170 +f 2874//171 2886//171 2887//171 2875//171 +f 2875//172 2887//172 2888//172 2876//172 +f 2876//173 2888//173 2889//173 2877//173 +f 2877//174 2889//174 2890//174 2878//174 +f 2878//175 2890//175 2891//175 2879//175 +f 2879//176 2891//176 2892//176 2880//176 +f 2880//177 2892//177 2893//177 2881//177 +f 2881//178 2893//178 2894//178 2882//178 +f 2882//179 2894//179 2895//179 2883//179 +f 2883//180 2895//180 2896//180 2884//180 +f 2884//181 2896//181 2885//181 2873//181 +f 2885//182 2897//182 2898//182 2886//182 +f 2886//183 2898//183 2899//183 2887//183 +f 2887//184 2899//184 2900//184 2888//184 +f 2888//185 2900//185 2901//185 2889//185 +f 2889//186 2901//186 2902//186 2890//186 +f 2890//187 2902//187 2903//187 2891//187 +f 2891//188 2903//188 2904//188 2892//188 +f 2892//189 2904//189 2905//189 2893//189 +f 2893//190 2905//190 2906//190 2894//190 +f 2894//191 2906//191 2907//191 2895//191 +f 2895//192 2907//192 2908//192 2896//192 +f 2896//193 2908//193 2897//193 2885//193 +f 2897//194 2909//194 2910//194 2898//194 +f 2898//195 2910//195 2911//195 2899//195 +f 2899//196 2911//196 2912//196 2900//196 +f 2900//197 2912//197 2913//197 2901//197 +f 2901//198 2913//198 2914//198 2902//198 +f 2902//199 2914//199 2915//199 2903//199 +f 2903//200 2915//200 2916//200 2904//200 +f 2904//201 2916//201 2917//201 2905//201 +f 2905//202 2917//202 2918//202 2906//202 +f 2906//203 2918//203 2919//203 2907//203 +f 2907//204 2919//204 2920//204 2908//204 +f 2908//205 2920//205 2909//205 2897//205 +f 2909//206 2921//206 2922//206 2910//206 +f 2910//207 2922//207 2923//207 2911//207 +f 2911//208 2923//208 2924//208 2912//208 +f 2912//209 2924//209 2925//209 2913//209 +f 2913//210 2925//210 2926//210 2914//210 +f 2914//211 2926//211 2927//211 2915//211 +f 2915//212 2927//212 2928//212 2916//212 +f 2916//213 2928//213 2929//213 2917//213 +f 2917//214 2929//214 2930//214 2918//214 +f 2918//215 2930//215 2931//215 2919//215 +f 2919//216 2931//216 2932//216 2920//216 +f 2920//217 2932//217 2921//217 2909//217 +f 2921//218 2933//218 2934//218 2922//218 +f 2922//219 2934//219 2935//219 2923//219 +f 2923//220 2935//220 2936//220 2924//220 +f 2924//221 2936//221 2937//221 2925//221 +f 2925//222 2937//222 2938//222 2926//222 +f 2926//223 2938//223 2939//223 2927//223 +f 2927//224 2939//224 2940//224 2928//224 +f 2928//225 2940//225 2941//225 2929//225 +f 2929//226 2941//226 2942//226 2930//226 +f 2930//227 2942//227 2943//227 2931//227 +f 2931//228 2943//228 2944//228 2932//228 +f 2932//229 2944//229 2933//229 2921//229 +f 2933//230 2945//230 2946//230 2934//230 +f 2934//231 2946//231 2947//231 2935//231 +f 2935//232 2947//232 2948//232 2936//232 +f 2936//233 2948//233 2949//233 2937//233 +f 2937//234 2949//234 2950//234 2938//234 +f 2938//235 2950//235 2951//235 2939//235 +f 2939//236 2951//236 2952//236 2940//236 +f 2940//237 2952//237 2953//237 2941//237 +f 2941//238 2953//238 2954//238 2942//238 +f 2942//239 2954//239 2955//239 2943//239 +f 2943//240 2955//240 2956//240 2944//240 +f 2944//241 2956//241 2945//241 2933//241 +f 2945//242 2957//242 2958//242 2946//242 +f 2946//243 2958//243 2959//243 2947//243 +f 2947//244 2959//244 2960//244 2948//244 +f 2948//245 2960//245 2961//245 2949//245 +f 2949//246 2961//246 2962//246 2950//246 +f 2950//247 2962//247 2963//247 2951//247 +f 2951//248 2963//248 2964//248 2952//248 +f 2952//249 2964//249 2965//249 2953//249 +f 2953//250 2965//250 2966//250 2954//250 +f 2954//251 2966//251 2967//251 2955//251 +f 2955//252 2967//252 2968//252 2956//252 +f 2956//253 2968//253 2957//253 2945//253 +f 2957//254 2969//254 2970//254 2958//254 +f 2958//255 2970//255 2971//255 2959//255 +f 2959//256 2971//256 2972//256 2960//256 +f 2960//257 2972//257 2973//257 2961//257 +f 2961//258 2973//258 2974//258 2962//258 +f 2962//259 2974//259 2975//259 2963//259 +f 2963//260 2975//260 2976//260 2964//260 +f 2964//261 2976//261 2977//261 2965//261 +f 2965//262 2977//262 2978//262 2966//262 +f 2966//263 2978//263 2979//263 2967//263 +f 2967//264 2979//264 2980//264 2968//264 +f 2968//265 2980//265 2969//265 2957//265 +f 2969//266 2981//266 2982//266 2970//266 +f 2970//267 2982//267 2983//267 2971//267 +f 2971//268 2983//268 2984//268 2972//268 +f 2972//269 2984//269 2985//269 2973//269 +f 2973//270 2985//270 2986//270 2974//270 +f 2974//271 2986//271 2987//271 2975//271 +f 2975//272 2987//272 2988//272 2976//272 +f 2976//273 2988//273 2989//273 2977//273 +f 2977//274 2989//274 2990//274 2978//274 +f 2978//275 2990//275 2991//275 2979//275 +f 2979//276 2991//276 2992//276 2980//276 +f 2980//277 2992//277 2981//277 2969//277 +f 2981//278 2993//278 2994//278 2982//278 +f 2982//279 2994//279 2995//279 2983//279 +f 2983//280 2995//280 2996//280 2984//280 +f 2984//281 2996//281 2997//281 2985//281 +f 2985//282 2997//282 2998//282 2986//282 +f 2986//283 2998//283 2999//283 2987//283 +f 2987//284 2999//284 3000//284 2988//284 +f 2988//285 3000//285 3001//285 2989//285 +f 2989//286 3001//286 3002//286 2990//286 +f 2990//287 3002//287 3003//287 2991//287 +f 2991//288 3003//288 3004//288 2992//288 +f 2992//289 3004//289 2993//289 2981//289 +f 2993//7 3005//7 3006//7 2994//7 +f 2994//6 3006//6 3007//6 2995//6 +f 2995//5 3007//5 3008//5 2996//5 +f 2996//4 3008//4 3009//4 2997//4 +f 2997//3 3009//3 3010//3 2998//3 +f 2998//2 3010//2 3011//2 2999//2 +f 2999//13 3011//13 3012//13 3000//13 +f 3000//290 3012//290 3013//290 3001//290 +f 3001//11 3013//11 3014//11 3002//11 +f 3002//10 3014//10 3015//10 3003//10 +f 3003//291 3015//291 3016//291 3004//291 +f 3004//8 3016//8 3005//8 2993//8 +f 3005//19 3017//19 3018//19 3006//19 +f 3006//18 3018//18 3019//18 3007//18 +f 3007//17 3019//17 3020//17 3008//17 +f 3008//16 3020//16 3021//16 3009//16 +f 3009//15 3021//15 3022//15 3010//15 +f 3010//14 3022//14 3023//14 3011//14 +f 3011//25 3023//25 3024//25 3012//25 +f 3012//24 3024//24 3025//24 3013//24 +f 3013//23 3025//23 3026//23 3014//23 +f 3014//22 3026//22 3027//22 3015//22 +f 3015//21 3027//21 3028//21 3016//21 +f 3016//20 3028//20 3017//20 3005//20 +f 3017//31 3029//31 3030//31 3018//31 +f 3018//30 3030//30 3031//30 3019//30 +f 3019//29 3031//29 3032//29 3020//29 +f 3020//28 3032//28 3033//28 3021//28 +f 3021//27 3033//27 3034//27 3022//27 +f 3022//26 3034//26 3035//26 3023//26 +f 3023//37 3035//37 3036//37 3024//37 +f 3024//36 3036//36 3037//36 3025//36 +f 3025//35 3037//35 3038//35 3026//35 +f 3026//34 3038//34 3039//34 3027//34 +f 3027//33 3039//33 3040//33 3028//33 +f 3028//32 3040//32 3029//32 3017//32 +f 3029//43 3041//43 3042//43 3030//43 +f 3030//42 3042//42 3043//42 3031//42 +f 3031//41 3043//41 3044//41 3032//41 +f 3032//40 3044//40 3045//40 3033//40 +f 3033//39 3045//39 3046//39 3034//39 +f 3034//38 3046//38 3047//38 3035//38 +f 3035//49 3047//49 3048//49 3036//49 +f 3036//292 3048//292 3049//292 3037//292 +f 3037//47 3049//47 3050//47 3038//47 +f 3038//46 3050//46 3051//46 3039//46 +f 3039//45 3051//45 3052//45 3040//45 +f 3040//44 3052//44 3041//44 3029//44 +f 3041//55 3053//55 3054//55 3042//55 +f 3042//54 3054//54 3055//54 3043//54 +f 3043//53 3055//53 3056//53 3044//53 +f 3044//52 3056//52 3057//52 3045//52 +f 3045//51 3057//51 3058//51 3046//51 +f 3046//50 3058//50 3059//50 3047//50 +f 3047//61 3059//61 3060//61 3048//61 +f 3048//293 3060//293 3061//293 3049//293 +f 3049//59 3061//59 3062//59 3050//59 +f 3050//58 3062//58 3063//58 3051//58 +f 3051//57 3063//57 3064//57 3052//57 +f 3052//56 3064//56 3053//56 3041//56 +f 3053//67 3065//67 3066//67 3054//67 +f 3054//66 3066//66 3067//66 3055//66 +f 3055//65 3067//65 3068//65 3056//65 +f 3056//64 3068//64 3069//64 3057//64 +f 3057//63 3069//63 3070//63 3058//63 +f 3058//62 3070//62 3071//62 3059//62 +f 3059//73 3071//73 3072//73 3060//73 +f 3060//294 3072//294 3073//294 3061//294 +f 3061//71 3073//71 3074//71 3062//71 +f 3062//70 3074//70 3075//70 3063//70 +f 3063//69 3075//69 3076//69 3064//69 +f 3064//68 3076//68 3065//68 3053//68 +f 3065//79 3077//79 3078//79 3066//79 +f 3066//78 3078//78 3079//78 3067//78 +f 3067//77 3079//77 3080//77 3068//77 +f 3068//76 3080//76 3081//76 3069//76 +f 3069//75 3081//75 3082//75 3070//75 +f 3070//74 3082//74 3083//74 3071//74 +f 3071//85 3083//85 3084//85 3072//85 +f 3072//84 3084//84 3085//84 3073//84 +f 3073//83 3085//83 3086//83 3074//83 +f 3074//82 3086//82 3087//82 3075//82 +f 3075//295 3087//295 3088//295 3076//295 +f 3076//80 3088//80 3077//80 3065//80 +f 3077//91 3089//91 3090//91 3078//91 +f 3078//90 3090//90 3091//90 3079//90 +f 3079//89 3091//89 3092//89 3080//89 +f 3080//88 3092//88 3093//88 3081//88 +f 3081//87 3093//87 3094//87 3082//87 +f 3082//86 3094//86 3095//86 3083//86 +f 3083//97 3095//97 3096//97 3084//97 +f 3084//296 3096//296 3097//296 3085//296 +f 3085//95 3097//95 3098//95 3086//95 +f 3086//94 3098//94 3099//94 3087//94 +f 3087//297 3099//297 3100//297 3088//297 +f 3088//92 3100//92 3089//92 3077//92 +f 3089//103 3101//103 3102//103 3090//103 +f 3090//102 3102//102 3103//102 3091//102 +f 3091//101 3103//101 3104//101 3092//101 +f 3092//100 3104//100 3105//100 3093//100 +f 3093//99 3105//99 3106//99 3094//99 +f 3094//98 3106//98 3107//98 3095//98 +f 3095//109 3107//109 3108//109 3096//109 +f 3096//298 3108//298 3109//298 3097//298 +f 3097//107 3109//107 3110//107 3098//107 +f 3098//106 3110//106 3111//106 3099//106 +f 3099//105 3111//105 3112//105 3100//105 +f 3100//104 3112//104 3101//104 3089//104 +f 3101//115 3113//115 3114//115 3102//115 +f 3102//114 3114//114 3115//114 3103//114 +f 3103//113 3115//113 3116//113 3104//113 +f 3104//112 3116//112 3117//112 3105//112 +f 3105//111 3117//111 3118//111 3106//111 +f 3106//110 3118//110 3119//110 3107//110 +f 3107//121 3119//121 3120//121 3108//121 +f 3108//299 3120//299 3121//299 3109//299 +f 3109//119 3121//119 3122//119 3110//119 +f 3110//118 3122//118 3123//118 3111//118 +f 3111//300 3123//300 3124//300 3112//300 +f 3112//116 3124//116 3113//116 3101//116 +f 3113//127 3125//127 3126//127 3114//127 +f 3114//126 3126//126 3127//126 3115//126 +f 3115//125 3127//125 3128//125 3116//125 +f 3116//301 3128//301 3129//301 3117//301 +f 3117//123 3129//123 3130//123 3118//123 +f 3118//122 3130//122 3131//122 3119//122 +f 3119//133 3131//133 3132//133 3120//133 +f 3120//302 3132//302 3133//302 3121//302 +f 3121//131 3133//131 3134//131 3122//131 +f 3122//130 3134//130 3135//130 3123//130 +f 3123//303 3135//303 3136//303 3124//303 +f 3124//128 3136//128 3125//128 3113//128 +f 3125//139 3137//139 3138//139 3126//139 +f 3126//138 3138//138 3139//138 3127//138 +f 3127//137 3139//137 3140//137 3128//137 +f 3128//136 3140//136 3141//136 3129//136 +f 3129//304 3141//304 3142//304 3130//304 +f 3130//134 3142//134 3143//134 3131//134 +f 3131//145 3143//145 3144//145 3132//145 +f 3132//144 3144//144 3145//144 3133//144 +f 3133//143 3145//143 3146//143 3134//143 +f 3134//142 3146//142 3147//142 3135//142 +f 3135//305 3147//305 3148//305 3136//305 +f 3136//140 3148//140 3137//140 3125//140 +f 3137//151 3149//151 3150//151 3138//151 +f 3138//150 3150//150 3151//150 3139//150 +f 3139//149 3151//149 3152//149 3140//149 +f 3140//148 3152//148 3153//148 3141//148 +f 3141//306 3153//306 3154//306 3142//306 +f 3142//146 3154//146 3155//146 3143//146 +f 3143//157 3155//157 3156//157 3144//157 +f 3144//156 3156//156 3157//156 3145//156 +f 3145//155 3157//155 3158//155 3146//155 +f 3146//154 3158//154 3159//154 3147//154 +f 3147//153 3159//153 3160//153 3148//153 +f 3148//152 3160//152 3149//152 3137//152 +f 3149//163 3161//163 3162//163 3150//163 +f 3150//162 3162//162 3163//162 3151//162 +f 3151//161 3163//161 3164//161 3152//161 +f 3152//160 3164//160 3165//160 3153//160 +f 3153//159 3165//159 3166//159 3154//159 +f 3154//158 3166//158 3167//158 3155//158 +f 3155//169 3167//169 3168//169 3156//169 +f 3156//168 3168//168 3169//168 3157//168 +f 3157//167 3169//167 3170//167 3158//167 +f 3158//166 3170//166 3171//166 3159//166 +f 3159//165 3171//165 3172//165 3160//165 +f 3160//164 3172//164 3161//164 3149//164 +f 3161//175 3173//175 3174//175 3162//175 +f 3162//174 3174//174 3175//174 3163//174 +f 3163//173 3175//173 3176//173 3164//173 +f 3164//172 3176//172 3177//172 3165//172 +f 3165//171 3177//171 3178//171 3166//171 +f 3166//170 3178//170 3179//170 3167//170 +f 3167//181 3179//181 3180//181 3168//181 +f 3168//180 3180//180 3181//180 3169//180 +f 3169//179 3181//179 3182//179 3170//179 +f 3170//178 3182//178 3183//178 3171//178 +f 3171//177 3183//177 3184//177 3172//177 +f 3172//176 3184//176 3173//176 3161//176 +f 3173//187 3185//187 3186//187 3174//187 +f 3174//186 3186//186 3187//186 3175//186 +f 3175//185 3187//185 3188//185 3176//185 +f 3176//184 3188//184 3189//184 3177//184 +f 3177//183 3189//183 3190//183 3178//183 +f 3178//182 3190//182 3191//182 3179//182 +f 3179//193 3191//193 3192//193 3180//193 +f 3180//192 3192//192 3193//192 3181//192 +f 3181//191 3193//191 3194//191 3182//191 +f 3182//190 3194//190 3195//190 3183//190 +f 3183//189 3195//189 3196//189 3184//189 +f 3184//188 3196//188 3185//188 3173//188 +f 3185//199 3197//199 3198//199 3186//199 +f 3186//198 3198//198 3199//198 3187//198 +f 3187//197 3199//197 3200//197 3188//197 +f 3188//196 3200//196 3201//196 3189//196 +f 3189//195 3201//195 3202//195 3190//195 +f 3190//194 3202//194 3203//194 3191//194 +f 3191//205 3203//205 3204//205 3192//205 +f 3192//307 3204//307 3205//307 3193//307 +f 3193//203 3205//203 3206//203 3194//203 +f 3194//202 3206//202 3207//202 3195//202 +f 3195//308 3207//308 3208//308 3196//308 +f 3196//200 3208//200 3197//200 3185//200 +f 3197//211 3209//211 3210//211 3198//211 +f 3198//210 3210//210 3211//210 3199//210 +f 3199//209 3211//209 3212//209 3200//209 +f 3200//208 3212//208 3213//208 3201//208 +f 3201//207 3213//207 3214//207 3202//207 +f 3202//206 3214//206 3215//206 3203//206 +f 3203//217 3215//217 3216//217 3204//217 +f 3204//309 3216//309 3217//309 3205//309 +f 3205//215 3217//215 3218//215 3206//215 +f 3206//214 3218//214 3219//214 3207//214 +f 3207//310 3219//310 3220//310 3208//310 +f 3208//212 3220//212 3209//212 3197//212 +f 3209//223 3221//223 3222//223 3210//223 +f 3210//222 3222//222 3223//222 3211//222 +f 3211//221 3223//221 3224//221 3212//221 +f 3212//220 3224//220 3225//220 3213//220 +f 3213//219 3225//219 3226//219 3214//219 +f 3214//218 3226//218 3227//218 3215//218 +f 3215//229 3227//229 3228//229 3216//229 +f 3216//311 3228//311 3229//311 3217//311 +f 3217//227 3229//227 3230//227 3218//227 +f 3218//226 3230//226 3231//226 3219//226 +f 3219//225 3231//225 3232//225 3220//225 +f 3220//224 3232//224 3221//224 3209//224 +f 3221//235 3233//235 3234//235 3222//235 +f 3222//234 3234//234 3235//234 3223//234 +f 3223//233 3235//233 3236//233 3224//233 +f 3224//232 3236//232 3237//232 3225//232 +f 3225//231 3237//231 3238//231 3226//231 +f 3226//230 3238//230 3239//230 3227//230 +f 3227//241 3239//241 3240//241 3228//241 +f 3228//312 3240//312 3241//312 3229//312 +f 3229//239 3241//239 3242//239 3230//239 +f 3230//238 3242//238 3243//238 3231//238 +f 3231//237 3243//237 3244//237 3232//237 +f 3232//236 3244//236 3233//236 3221//236 +f 3233//247 3245//247 3246//247 3234//247 +f 3234//246 3246//246 3247//246 3235//246 +f 3235//245 3247//245 3248//245 3236//245 +f 3236//244 3248//244 3249//244 3237//244 +f 3237//243 3249//243 3250//243 3238//243 +f 3238//242 3250//242 3251//242 3239//242 +f 3239//253 3251//253 3252//253 3240//253 +f 3240//252 3252//252 3253//252 3241//252 +f 3241//251 3253//251 3254//251 3242//251 +f 3242//250 3254//250 3255//250 3243//250 +f 3243//249 3255//249 3256//249 3244//249 +f 3244//248 3256//248 3245//248 3233//248 +f 3245//259 3257//259 3258//259 3246//259 +f 3246//258 3258//258 3259//258 3247//258 +f 3247//257 3259//257 3260//257 3248//257 +f 3248//256 3260//256 3261//256 3249//256 +f 3249//255 3261//255 3262//255 3250//255 +f 3250//254 3262//254 3263//254 3251//254 +f 3251//265 3263//265 3264//265 3252//265 +f 3252//264 3264//264 3265//264 3253//264 +f 3253//263 3265//263 3266//263 3254//263 +f 3254//262 3266//262 3267//262 3255//262 +f 3255//313 3267//313 3268//313 3256//313 +f 3256//260 3268//260 3257//260 3245//260 +f 3257//271 3269//271 3270//271 3258//271 +f 3258//270 3270//270 3271//270 3259//270 +f 3259//314 3271//314 3272//314 3260//314 +f 3260//268 3272//268 3273//268 3261//268 +f 3261//267 3273//267 3274//267 3262//267 +f 3262//266 3274//266 3275//266 3263//266 +f 3263//277 3275//277 3276//277 3264//277 +f 3264//276 3276//276 3277//276 3265//276 +f 3265//275 3277//275 3278//275 3266//275 +f 3266//274 3278//274 3279//274 3267//274 +f 3267//315 3279//315 3280//315 3268//315 +f 3268//272 3280//272 3269//272 3257//272 +f 3269//283 2705//283 2708//283 3270//283 +f 3270//282 2708//282 2710//282 3271//282 +f 3271//281 2710//281 2712//281 3272//281 +f 3272//280 2712//280 2714//280 3273//280 +f 3273//279 2714//279 2716//279 3274//279 +f 3274//278 2716//278 2718//278 3275//278 +f 3275//289 2718//289 2720//289 3276//289 +f 3276//316 2720//316 2722//316 3277//316 +f 3277//287 2722//287 2724//287 3278//287 +f 3278//286 2724//286 2726//286 3279//286 +f 3279//317 2726//317 2728//317 3280//317 +f 3280//284 2728//284 2705//284 3269//284 diff --git a/data/torus/torus_with_plane.urdf b/data/torus/torus_with_plane.urdf new file mode 100644 index 000000000..3db35dec2 --- /dev/null +++ b/data/torus/torus_with_plane.urdf @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/data/torus/torus_with_separate_plane.urdf b/data/torus/torus_with_separate_plane.urdf new file mode 100644 index 000000000..050301f4a --- /dev/null +++ b/data/torus/torus_with_separate_plane.urdf @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/data/tray/tray.jpg b/data/tray/tray.jpg new file mode 100644 index 000000000..2ce198fb6 Binary files /dev/null and b/data/tray/tray.jpg differ diff --git a/data/tray/tray_textured2.mtl b/data/tray/tray_textured2.mtl new file mode 100644 index 000000000..4689a463a --- /dev/null +++ b/data/tray/tray_textured2.mtl @@ -0,0 +1,13 @@ +# Blender MTL File: 'tray_textured2.blend' +# Material Count: 1 + +newmtl None +Ns 0.000000 +Ka 0.000000 0.000000 0.000000 +Kd 0.800000 0.800000 0.800000 +Ks 0.800000 0.800000 0.800000 +Ke 0.000000 0.000000 0.000000 +Ni 1.000000 +d 1.000000 +illum 2 +map_Kd tray.jpg diff --git a/data/tray/tray_textured2.obj b/data/tray/tray_textured2.obj new file mode 100644 index 000000000..98a8962c6 --- /dev/null +++ b/data/tray/tray_textured2.obj @@ -0,0 +1,255 @@ +# Blender v2.78 (sub 0) OBJ File: 'tray_textured2.blend' +# www.blender.org +mtllib tray_textured2.mtl +o edge_1_Cube.003 +v 0.580000 0.590083 0.250354 +v -0.419960 0.426691 -0.001860 +v -0.580000 0.590083 0.250354 +v 0.580000 0.573309 0.261247 +v 0.420014 0.426691 -0.001059 +v -0.580000 0.573309 0.261247 +v 0.420014 0.409917 0.009834 +v -0.419960 0.409917 0.009033 +vt 0.8346 0.9187 +vt 0.2203 0.8574 +vt 0.1480 0.9187 +vt 0.8346 0.9129 +vt 0.7623 0.8574 +vt 0.1480 0.9129 +vt 0.7623 0.8511 +vt 0.2203 0.8511 +vn 0.0004 0.8386 -0.5448 +vn 0.0001 0.8391 -0.5439 +vn -0.0000 0.8393 -0.5437 +vn 0.8823 -0.2564 -0.3948 +vn -0.0004 -0.8392 0.5439 +vn -0.0001 -0.8386 0.5447 +vn 0.0000 -0.8385 0.5449 +vn -0.8826 -0.2560 -0.3942 +vn 0.0008 -0.5446 -0.8387 +vn -0.0000 0.5446 0.8387 +vn 0.0005 0.8383 -0.5452 +vn -0.0005 -0.8394 0.5435 +usemtl None +s 1 +f 1/1/1 2/2/2 3/3/3 +f 4/4/4 5/5/4 1/1/4 +f 6/6/5 7/7/6 4/4/7 +f 3/3/8 8/8/8 6/6/8 +f 5/5/9 8/8/9 2/2/9 +f 4/4/10 3/3/10 6/6/10 +f 1/1/1 5/5/11 2/2/2 +f 4/4/4 7/7/4 5/5/4 +f 6/6/5 8/8/12 7/7/6 +f 3/3/8 2/2/8 8/8/8 +f 5/5/9 7/7/9 8/8/9 +f 4/4/10 1/1/10 3/3/10 +o edge_2_Cube +v 0.590083 0.580000 0.250354 +v 0.409917 0.420060 0.009390 +v 0.573309 0.580000 0.261247 +v 0.590083 -0.580000 0.250354 +v 0.426691 0.420060 -0.001503 +v 0.573309 -0.580000 0.261247 +v 0.426691 -0.419158 -0.002053 +v 0.409917 -0.419158 0.008840 +vt 0.9410 0.8520 +vt 0.7523 0.8566 +vt 0.9234 0.8524 +vt 0.8896 0.1426 +vt 0.7698 0.8562 +vt 0.8721 0.1430 +vt 0.7185 0.1468 +vt 0.7009 0.1472 +vn -0.2561 0.8826 -0.3943 +vn 0.8394 0.0003 -0.5435 +vn 0.8390 0.0001 -0.5441 +vn 0.8389 0.0000 -0.5442 +vn -0.2569 -0.8818 -0.3956 +vn -0.8390 -0.0003 0.5441 +vn -0.8394 -0.0001 0.5436 +vn -0.8395 -0.0000 0.5434 +vn -0.5446 0.0005 -0.8387 +vn 0.5446 -0.0000 0.8387 +vn 0.8396 0.0004 -0.5433 +vn -0.8388 -0.0004 0.5444 +usemtl None +s 1 +f 9/9/13 10/10/13 11/11/13 +f 12/12/14 13/13/15 9/9/16 +f 14/14/17 15/15/17 12/12/17 +f 11/11/18 16/16/19 14/14/20 +f 13/13/21 16/16/21 10/10/21 +f 12/12/22 11/11/22 14/14/22 +f 9/9/13 13/13/13 10/10/13 +f 12/12/14 15/15/23 13/13/15 +f 14/14/17 16/16/17 15/15/17 +f 11/11/18 10/10/24 16/16/19 +f 13/13/21 15/15/21 16/16/21 +f 12/12/22 9/9/22 11/11/22 +o edge_3_Cube.002 +v 0.580000 -0.573309 0.261247 +v -0.419400 -0.409917 0.008678 +v -0.580000 -0.573309 0.261247 +v 0.580000 -0.590083 0.250354 +v 0.419883 -0.409917 0.009162 +v -0.580000 -0.590083 0.250354 +v 0.419883 -0.426691 -0.001731 +v -0.419400 -0.426691 -0.002215 +vt 0.8690 0.1040 +vt 0.1365 0.1739 +vt 0.0188 0.1040 +vt 0.8690 0.0968 +vt 0.7517 0.1739 +vt 0.0188 0.0968 +vt 0.7517 0.1668 +vt 0.1365 0.1668 +vn -0.0002 0.8392 0.5438 +vn -0.0000 0.8395 0.5433 +vn -0.0000 0.8396 0.5432 +vn 0.8825 0.2562 -0.3945 +vn 0.0002 -0.8396 -0.5433 +vn 0.0000 -0.8392 -0.5438 +vn 0.0000 -0.8391 -0.5439 +vn -0.8821 0.2565 -0.3950 +vn 0.0005 0.5446 -0.8387 +vn 0.0000 -0.5446 0.8387 +vn -0.0003 0.8391 0.5440 +vn 0.0003 -0.8397 -0.5430 +usemtl None +s 1 +f 17/17/25 18/18/26 19/19/27 +f 20/20/28 21/21/28 17/17/28 +f 22/22/29 23/23/30 20/20/31 +f 19/19/32 24/24/32 22/22/32 +f 21/21/33 24/24/33 18/18/33 +f 20/20/34 19/19/34 22/22/34 +f 17/17/25 21/21/35 18/18/26 +f 20/20/28 23/23/28 21/21/28 +f 22/22/29 24/24/36 23/23/30 +f 19/19/32 18/18/32 24/24/32 +f 21/21/33 23/23/33 24/24/33 +f 20/20/34 17/17/34 19/19/34 +o edge_5_Cube.005 +v -0.153309 0.580000 0.261247 +v -0.006691 0.419400 -0.002214 +v -0.170083 0.580000 0.250354 +v -0.153309 -0.580000 0.261247 +v 0.010083 0.419400 0.008679 +v -0.170083 -0.580000 0.250354 +v 0.010083 -0.419883 0.009732 +v -0.006691 -0.419883 -0.001161 +vt 0.0506 0.8517 +vt 0.1935 0.8492 +vt 0.0342 0.8520 +vt 0.0164 0.1914 +vt 0.2099 0.8489 +vt 0.0001 0.1917 +vt 0.1757 0.1886 +vt 0.1594 0.1889 +vn 0.2565 0.8821 -0.3950 +vn 0.8387 0.0005 0.5446 +vn 0.8394 0.0001 0.5434 +vn 0.8396 0.0000 0.5432 +vn 0.2565 -0.8822 -0.3950 +vn -0.8395 -0.0005 -0.5434 +vn -0.8388 -0.0001 -0.5445 +vn -0.8386 -0.0000 -0.5448 +vn 0.5446 -0.0011 -0.8387 +vn -0.5446 -0.0000 0.8387 +vn 0.8384 0.0007 0.5451 +vn -0.8398 -0.0007 -0.5429 +usemtl None +s 1 +f 25/25/37 26/26/37 27/27/37 +f 28/28/38 29/29/39 25/25/40 +f 30/30/41 31/31/41 28/28/41 +f 27/27/42 32/32/43 30/30/44 +f 29/29/45 32/32/45 26/26/45 +f 28/28/46 27/27/46 30/30/46 +f 25/25/37 29/29/37 26/26/37 +f 28/28/38 31/31/47 29/29/39 +f 30/30/41 32/32/41 31/31/41 +f 27/27/42 26/26/48 32/32/43 +f 29/29/45 31/31/45 32/32/45 +f 28/28/46 25/25/46 27/27/46 +o edge_4_Cube.001 +v -0.573309 0.580000 0.261247 +v -0.426691 0.419400 -0.002214 +v -0.590083 0.580000 0.250354 +v -0.573309 -0.580000 0.261247 +v -0.409917 0.419400 0.008679 +v -0.590083 -0.580000 0.250354 +v -0.409917 -0.419400 0.009162 +v -0.426691 -0.419400 -0.001731 +vt 0.9046 0.2397 +vt 0.7929 0.2434 +vt 0.9174 0.2393 +vt 0.9537 0.7559 +vt 0.7801 0.2438 +vt 0.9664 0.7554 +vt 0.8291 0.7599 +vt 0.8419 0.7595 +vn 0.2565 0.8821 -0.3950 +vn 0.8392 0.0002 0.5438 +vn 0.8395 0.0000 0.5433 +vn 0.8396 0.0000 0.5432 +vn 0.2568 -0.8819 -0.3954 +vn -0.8396 -0.0002 -0.5433 +vn -0.8392 -0.0000 -0.5438 +vn -0.8391 -0.0000 -0.5439 +vn 0.5446 -0.0005 -0.8387 +vn -0.5446 -0.0000 0.8387 +vn 0.8391 0.0003 0.5440 +vn -0.8397 -0.0003 -0.5430 +usemtl None +s 1 +f 33/33/49 34/34/49 35/35/49 +f 36/36/50 37/37/51 33/33/52 +f 38/38/53 39/39/53 36/36/53 +f 35/35/54 40/40/55 38/38/56 +f 37/37/57 40/40/57 34/34/57 +f 36/36/58 35/35/58 38/38/58 +f 33/33/49 37/37/49 34/34/49 +f 36/36/50 39/39/59 37/37/51 +f 38/38/53 40/40/53 39/39/53 +f 35/35/54 34/34/60 40/40/55 +f 37/37/57 39/39/57 40/40/57 +f 36/36/58 33/33/58 35/35/58 +o base_Cube.004 +v 0.420000 0.420000 0.010000 +v -0.420000 0.420000 -0.010000 +v -0.420000 0.420000 0.010000 +v 0.420000 -0.420000 0.010000 +v 0.420000 0.420000 -0.010000 +v -0.420000 -0.420000 0.010000 +v 0.420000 -0.420000 -0.010000 +v -0.420000 -0.420000 -0.010000 +vt 0.7524 0.8072 +vt -0.3038 0.8371 +vt -0.3038 0.8371 +vt 0.7012 0.1905 +vt 0.7524 0.8072 +vt -0.3550 0.2204 +vt 0.7012 0.1905 +vt -0.3550 0.2204 +vn -0.0000 1.0000 0.0000 +vn 1.0000 0.0000 0.0000 +vn 0.0000 -1.0000 0.0000 +vn -1.0000 -0.0000 0.0000 +vn -0.0000 0.0000 -1.0000 +vn 0.0000 -0.0000 1.0000 +usemtl None +s 1 +f 41/41/61 42/42/61 43/43/61 +f 44/44/62 45/45/62 41/41/62 +f 46/46/63 47/47/63 44/44/63 +f 43/43/64 48/48/64 46/46/64 +f 45/45/65 48/48/65 42/42/65 +f 44/44/66 43/43/66 46/46/66 +f 41/41/61 45/45/61 42/42/61 +f 44/44/62 47/47/62 45/45/62 +f 46/46/63 48/48/63 47/47/63 +f 43/43/64 42/42/64 48/48/64 +f 45/45/65 47/47/65 48/48/65 +f 44/44/66 41/41/66 43/43/66 diff --git a/data/tray/tray_textured2.urdf b/data/tray/tray_textured2.urdf new file mode 100644 index 000000000..8b89b015c --- /dev/null +++ b/data/tray/tray_textured2.urdf @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/pybullet_quickstartguide.pdf b/docs/pybullet_quickstartguide.pdf new file mode 100644 index 000000000..d1e10cca7 Binary files /dev/null and b/docs/pybullet_quickstartguide.pdf differ diff --git a/examples/BasicDemo/premake4.lua b/examples/BasicDemo/premake4.lua index dd924249e..2faa974cd 100644 --- a/examples/BasicDemo/premake4.lua +++ b/examples/BasicDemo/premake4.lua @@ -18,6 +18,7 @@ language "C++" files { "**.cpp", "**.h", + "../CommonInterfaces/*", } @@ -49,6 +50,7 @@ files { "../ExampleBrowser/OpenGLGuiHelper.cpp", "../ExampleBrowser/GL_ShapeDrawer.cpp", "../ExampleBrowser/CollisionShape2TriangleMesh.cpp", + "../CommonInterfaces/*", "../Utils/b3Clock.cpp", "../Utils/b3Clock.h", } @@ -90,6 +92,7 @@ files { "../ExampleBrowser/OpenGLGuiHelper.cpp", "../ExampleBrowser/GL_ShapeDrawer.cpp", "../ExampleBrowser/CollisionShape2TriangleMesh.cpp", + "../CommonInterfaces/*", "../TinyRenderer/geometry.cpp", "../TinyRenderer/model.cpp", "../TinyRenderer/tgaimage.cpp", @@ -130,6 +133,7 @@ files { "*.h", "../StandaloneMain/main_tinyrenderer_single_example.cpp", "../ExampleBrowser/CollisionShape2TriangleMesh.cpp", + "../CommonInterfaces/*", "../OpenGLWindow/SimpleCamera.cpp", "../TinyRenderer/geometry.cpp", "../TinyRenderer/model.cpp", @@ -175,6 +179,7 @@ files { "BasicExample.cpp", "*.h", "../StandaloneMain/hellovr_opengl_main.cpp", + "../CommonInterfaces/*", "../ExampleBrowser/OpenGLGuiHelper.cpp", "../ExampleBrowser/GL_ShapeDrawer.cpp", "../ExampleBrowser/CollisionShape2TriangleMesh.cpp", @@ -200,4 +205,4 @@ if os.is("MacOSX") then links{"Cocoa.framework"} end -end \ No newline at end of file +end diff --git a/examples/Benchmarks/BenchmarkDemo.cpp b/examples/Benchmarks/BenchmarkDemo.cpp index f659d017c..00ac36b9c 100644 --- a/examples/Benchmarks/BenchmarkDemo.cpp +++ b/examples/Benchmarks/BenchmarkDemo.cpp @@ -32,10 +32,12 @@ subject to the following restrictions: #include "LinearMath/btAlignedObjectArray.h" #include "LinearMath/btTransform.h" +#include "../MultiThreadedDemo/ParallelFor.h" class btDynamicsWorld; #define NUMRAYS 500 +#define USE_PARALLEL_RAYCASTS 1 class btRigidBody; class btBroadphaseInterface; @@ -47,11 +49,11 @@ struct btCollisionAlgorithmCreateFunc; class btDefaultCollisionConfiguration; -#include "../CommonInterfaces/CommonRigidBodyBase.h" +#include "../MultiThreadedDemo/CommonRigidBodyMTBase.h" -class BenchmarkDemo : public CommonRigidBodyBase +class BenchmarkDemo : public CommonRigidBodyMTBase { //keep the collision shapes, for deletion/cleanup @@ -91,7 +93,7 @@ class BenchmarkDemo : public CommonRigidBodyBase public: BenchmarkDemo(struct GUIHelperInterface* helper, int benchmark) - :CommonRigidBodyBase(helper), + :CommonRigidBodyMTBase(helper), m_benchmark(benchmark) { } @@ -204,7 +206,39 @@ public: sign = -1.0; } - void cast (btCollisionWorld* cw) + void castRays( btCollisionWorld* cw, int iBegin, int iEnd ) + { + for ( int i = iBegin; i < iEnd; ++i ) + { + btCollisionWorld::ClosestRayResultCallback cb(source[i], dest[i]); + + cw->rayTest (source[i], dest[i], cb); + if (cb.hasHit ()) + { + hit[i] = cb.m_hitPointWorld; + normal[i] = cb.m_hitNormalWorld; + normal[i].normalize (); + } else { + hit[i] = dest[i]; + normal[i] = btVector3(1.0, 0.0, 0.0); + } + + } + } + + struct CastRaysLoopBody + { + btRaycastBar2* mRaycasts; + btCollisionWorld* mWorld; + CastRaysLoopBody(btCollisionWorld* cw, btRaycastBar2* rb) : mWorld(cw), mRaycasts(rb) {} + + void forLoop( int iBegin, int iEnd ) const + { + mRaycasts->castRays(mWorld, iBegin, iEnd); + } + }; + + void cast (btCollisionWorld* cw, bool multiThreading = false) { #ifdef USE_BT_CLOCK frame_timer.reset (); @@ -228,22 +262,19 @@ public: normal[i].normalize (); } #else - for (int i = 0; i < NUMRAYS; i++) - { - btCollisionWorld::ClosestRayResultCallback cb(source[i], dest[i]); - - cw->rayTest (source[i], dest[i], cb); - if (cb.hasHit ()) - { - hit[i] = cb.m_hitPointWorld; - normal[i] = cb.m_hitNormalWorld; - normal[i].normalize (); - } else { - hit[i] = dest[i]; - normal[i] = btVector3(1.0, 0.0, 0.0); - } - - } +#if USE_PARALLEL_RAYCASTS + if ( multiThreading ) + { + CastRaysLoopBody rayLooper(cw, this); + int grainSize = 20; // number of raycasts per task + parallelFor( 0, NUMRAYS, grainSize, rayLooper ); + } + else +#endif // USE_PARALLEL_RAYCASTS + { + // single threaded + castRays(cw, 0, NUMRAYS); + } #ifdef USE_BT_CLOCK ms += frame_timer.getTimeMilliseconds (); #endif //USE_BT_CLOCK @@ -354,42 +385,43 @@ void BenchmarkDemo::initPhysics() setCameraDistance(btScalar(100.)); - ///collision configuration contains default setup for memory, collision setup - btDefaultCollisionConstructionInfo cci; - cci.m_defaultMaxPersistentManifoldPoolSize = 32768; - m_collisionConfiguration = new btDefaultCollisionConfiguration(cci); + createEmptyDynamicsWorld(); + /////collision configuration contains default setup for memory, collision setup + //btDefaultCollisionConstructionInfo cci; + //cci.m_defaultMaxPersistentManifoldPoolSize = 32768; + //m_collisionConfiguration = new btDefaultCollisionConfiguration(cci); - ///use the default collision dispatcher. For parallel processing you can use a diffent dispatcher (see Extras/BulletMultiThreaded) - m_dispatcher = new btCollisionDispatcher(m_collisionConfiguration); - - m_dispatcher->setDispatcherFlags(btCollisionDispatcher::CD_DISABLE_CONTACTPOOL_DYNAMIC_ALLOCATION); + /////use the default collision dispatcher. For parallel processing you can use a diffent dispatcher (see Extras/BulletMultiThreaded) + //m_dispatcher = new btCollisionDispatcher(m_collisionConfiguration); + // + //m_dispatcher->setDispatcherFlags(btCollisionDispatcher::CD_DISABLE_CONTACTPOOL_DYNAMIC_ALLOCATION); - ///the maximum size of the collision world. Make sure objects stay within these boundaries - ///Don't make the world AABB size too large, it will harm simulation quality and performance - btVector3 worldAabbMin(-1000,-1000,-1000); - btVector3 worldAabbMax(1000,1000,1000); - - btHashedOverlappingPairCache* pairCache = new btHashedOverlappingPairCache(); - m_broadphase = new btAxisSweep3(worldAabbMin,worldAabbMax,3500,pairCache); + /////the maximum size of the collision world. Make sure objects stay within these boundaries + /////Don't make the world AABB size too large, it will harm simulation quality and performance + //btVector3 worldAabbMin(-1000,-1000,-1000); + //btVector3 worldAabbMax(1000,1000,1000); + // + //btHashedOverlappingPairCache* pairCache = new btHashedOverlappingPairCache(); + //m_broadphase = new btAxisSweep3(worldAabbMin,worldAabbMax,3500,pairCache); // m_broadphase = new btSimpleBroadphase(); // m_broadphase = new btDbvtBroadphase(); ///the default constraint solver. For parallel processing you can use a different solver (see Extras/BulletMultiThreaded) - btSequentialImpulseConstraintSolver* sol = new btSequentialImpulseConstraintSolver; + //btSequentialImpulseConstraintSolver* sol = new btSequentialImpulseConstraintSolver; - m_solver = sol; + //m_solver = sol; - btDiscreteDynamicsWorld* dynamicsWorld; - m_dynamicsWorld = dynamicsWorld = new btDiscreteDynamicsWorld(m_dispatcher,m_broadphase,m_solver,m_collisionConfiguration); + //btDiscreteDynamicsWorld* dynamicsWorld; + //m_dynamicsWorld = dynamicsWorld = new btDiscreteDynamicsWorld(m_dispatcher,m_broadphase,m_solver,m_collisionConfiguration); ///the following 3 lines increase the performance dramatically, with a little bit of loss of quality m_dynamicsWorld->getSolverInfo().m_solverMode |=SOLVER_ENABLE_FRICTION_DIRECTION_CACHING; //don't recalculate friction values each frame - dynamicsWorld->getSolverInfo().m_numIterations = 5; //few solver iterations + m_dynamicsWorld->getSolverInfo().m_numIterations = 5; //few solver iterations //m_defaultContactProcessingThreshold = 0.f;//used when creating bodies: body->setContactProcessingThreshold(...); m_guiHelper->createPhysicsDebugDrawer(m_dynamicsWorld); @@ -1242,7 +1274,7 @@ void BenchmarkDemo::initRays() void BenchmarkDemo::castRays() { - raycastBar.cast (m_dynamicsWorld); + raycastBar.cast (m_dynamicsWorld, m_multithreadedWorld); } void BenchmarkDemo::createTest7() @@ -1264,7 +1296,7 @@ void BenchmarkDemo::exitPhysics() } m_ragdolls.clear(); - CommonRigidBodyBase::exitPhysics(); + CommonRigidBodyMTBase::exitPhysics(); } diff --git a/examples/CommonInterfaces/CommonGUIHelperInterface.h b/examples/CommonInterfaces/CommonGUIHelperInterface.h index baea8daf4..01f7b3728 100644 --- a/examples/CommonInterfaces/CommonGUIHelperInterface.h +++ b/examples/CommonInterfaces/CommonGUIHelperInterface.h @@ -69,6 +69,12 @@ struct GUIHelperInterface virtual void drawText3D( const char* txt, float posX, float posZY, float posZ, float size)=0; + + virtual int addUserDebugText3D( const char* txt, const double posisionXYZ[3], const double textColorRGB[3], double size, double lifeTime)=0; + virtual int addUserDebugLine(const double debugLineFromXYZ[3], const double debugLineToXYZ[3], const double debugLineColorRGB[3], double lineWidth, double lifeTime )=0; + virtual void removeUserDebugItem( int debugItemUniqueId)=0; + virtual void removeAllUserDebugItems( )=0; + }; @@ -141,7 +147,22 @@ struct DummyGUIHelper : public GUIHelperInterface virtual void drawText3D( const char* txt, float posX, float posZY, float posZ, float size) { } - + + virtual int addUserDebugText3D( const char* txt, const double positionXYZ[3], const double textColorRGB[3], double size, double lifeTime) + { + return -1; + } + virtual int addUserDebugLine(const double debugLineFromXYZ[3], const double debugLineToXYZ[3], const double debugLineColorRGB[3], double lineWidth, double lifeTime ) + { + return -1; + } + virtual void removeUserDebugItem( int debugItemUniqueId) + { + } + virtual void removeAllUserDebugItems( ) + { + } + }; #endif //GUI_HELPER_INTERFACE_H diff --git a/examples/CommonInterfaces/CommonGraphicsAppInterface.h b/examples/CommonInterfaces/CommonGraphicsAppInterface.h index 674807de8..31f0f51ce 100644 --- a/examples/CommonInterfaces/CommonGraphicsAppInterface.h +++ b/examples/CommonInterfaces/CommonGraphicsAppInterface.h @@ -120,7 +120,7 @@ struct CommonGraphicsApp virtual int getUpAxis() const = 0; virtual void swapBuffer() = 0; - virtual void drawText( const char* txt, int posX, int posY) = 0; + virtual void drawText( const char* txt, int posX, int posY, float size = 1.0f) = 0; virtual void drawText3D( const char* txt, float posX, float posZY, float posZ, float size)=0; virtual void drawTexturedRect(float x0, float y0, float x1, float y1, float color[4], float u0,float v0, float u1, float v1, int useRGBA)=0; virtual int registerCubeShape(float halfExtentsX,float halfExtentsY, float halfExtentsZ, int textureIndex = -1, float textureScaling = 1)=0; diff --git a/examples/CommonInterfaces/CommonParameterInterface.h b/examples/CommonInterfaces/CommonParameterInterface.h index 3bb2f50c8..e2334108c 100644 --- a/examples/CommonInterfaces/CommonParameterInterface.h +++ b/examples/CommonInterfaces/CommonParameterInterface.h @@ -4,7 +4,7 @@ #pragma once -typedef void (*SliderParamChangedCallback) (float newVal); +typedef void (*SliderParamChangedCallback) (float newVal, void* userPointer); #include "LinearMath/btScalar.h" struct SliderParams @@ -16,6 +16,7 @@ struct SliderParams btScalar* m_paramValuePointer; void* m_userPointer; bool m_clampToNotches; + bool m_clampToIntegers; bool m_showValues; SliderParams(const char* name, btScalar* targetValuePointer) @@ -26,6 +27,7 @@ struct SliderParams m_paramValuePointer(targetValuePointer), m_userPointer(0), m_clampToNotches(true), + m_clampToIntegers(false), m_showValues(true) { } diff --git a/examples/Evolution/NN3DWalkers.cpp b/examples/Evolution/NN3DWalkers.cpp index 3a4eb32fc..67718c970 100755 --- a/examples/Evolution/NN3DWalkers.cpp +++ b/examples/Evolution/NN3DWalkers.cpp @@ -950,9 +950,9 @@ bool NN3DWalkersExample::keyboardCallback(int key, int state) case ']': gWalkerMotorStrength *= 1.1f; return true; -// case 'l': + case 'l': // printWalkerConfigs(); -// return true; + return true; default: break; } diff --git a/examples/Evolution/NN3DWalkersTimeWarpBase.h b/examples/Evolution/NN3DWalkersTimeWarpBase.h index 98385d00a..31142ed07 100644 --- a/examples/Evolution/NN3DWalkersTimeWarpBase.h +++ b/examples/Evolution/NN3DWalkersTimeWarpBase.h @@ -138,19 +138,15 @@ static btScalar gCFMSingularityAvoidance = 0; //GUI related parameter changing helpers -inline void floorSliderValues(float notUsed) { // floor values that should be ints - gSolverIterations = floor(gSolverIterations); -} - -inline void twxChangePhysicsStepsPerSecond(float physicsStepsPerSecond) { // function to change simulation physics steps per second +inline void twxChangePhysicsStepsPerSecond(float physicsStepsPerSecond, void*) { // function to change simulation physics steps per second gPhysicsStepsPerSecond = physicsStepsPerSecond; } -inline void twxChangeFPS(float framesPerSecond) { +inline void twxChangeFPS(float framesPerSecond, void*) { gFramesPerSecond = framesPerSecond; } -inline void twxChangeERPCFM(float notUsed) { // function to change ERP/CFM appropriately +inline void twxChangeERPCFM(float notUsed, void*) { // function to change ERP/CFM appropriately gChangeErpCfm = true; } @@ -166,13 +162,12 @@ inline void changeSolver(int comboboxId, const char* item, void* userPointer) { } -inline void twxChangeSolverIterations(float notUsed){ // change the solver iterations +inline void twxChangeSolverIterations(float notUsed, void* userPtr) { // change the solver iterations - floorSliderValues(0); // floor the values set by slider } -inline void clampToCustomSpeedNotches(float speed) { // function to clamp to custom speed notches +inline void clampToCustomSpeedNotches(float speed, void*) { // function to clamp to custom speed notches double minSpeed = 0; double minSpeedDist = SimulationSpeeds::MAX_SPEED; for (int i = 0; i < SimulationSpeeds::NUM_SPEEDS; i++) { @@ -200,7 +195,7 @@ inline void switchMaximumSpeed(int buttonId, bool buttonState, void* userPointer // b3Printf("Run maximum speed %s", gMaximumSpeed?"on":"off"); } -inline void setApplicationTick(float frequency){ // set internal application tick +inline void setApplicationTick(float frequency, void*){ // set internal application tick gApplicationTick = 1000.0f/frequency; } @@ -384,7 +379,7 @@ struct NN3DWalkersTimeWarpBase: public CommonRigidBodyBase { slider.m_minVal = 0; slider.m_maxVal = 1000; slider.m_callback = twxChangePhysicsStepsPerSecond; - slider.m_clampToNotches = false; + slider.m_clampToIntegers = true; m_guiHelper->getParameterInterface()->registerSliderFloatParameter( slider); } diff --git a/examples/ExampleBrowser/CMakeLists.txt b/examples/ExampleBrowser/CMakeLists.txt index 024d928d3..0096560b6 100644 --- a/examples/ExampleBrowser/CMakeLists.txt +++ b/examples/ExampleBrowser/CMakeLists.txt @@ -108,6 +108,29 @@ ELSE(WIN32) ENDIF(APPLE) ENDIF(WIN32) +IF (BULLET2_MULTITHREADED_OPEN_MP_DEMO) + ADD_DEFINITIONS("-DBT_USE_OPENMP=1") + IF (MSVC) + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /openmp") + ELSE (MSVC) + # GCC, Clang + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fopenmp") + ENDIF (MSVC) +ENDIF (BULLET2_MULTITHREADED_OPEN_MP_DEMO) + +IF (BULLET2_MULTITHREADED_PPL_DEMO) + ADD_DEFINITIONS("-DBT_USE_PPL=1") +ENDIF (BULLET2_MULTITHREADED_PPL_DEMO) + +IF (BULLET2_MULTITHREADED_TBB_DEMO) + SET (BULLET2_TBB_INCLUDE_DIR "not found" CACHE PATH "Directory for Intel TBB includes.") + SET (BULLET2_TBB_LIB_DIR "not found" CACHE PATH "Directory for Intel TBB libraries.") + find_library(TBB_LIBRARY tbb PATHS ${BULLET2_TBB_LIB_DIR}) + find_library(TBBMALLOC_LIBRARY tbbmalloc PATHS ${BULLET2_TBB_LIB_DIR}) + ADD_DEFINITIONS("-DBT_USE_TBB=1") + INCLUDE_DIRECTORIES( ${BULLET2_TBB_INCLUDE_DIR} ) + LINK_LIBRARIES( ${TBB_LIBRARY} ${TBBMALLOC_LIBRARY} ) +ENDIF (BULLET2_MULTITHREADED_TBB_DEMO) SET(ExtendedTutorialsSources ../ExtendedTutorials/Chain.cpp @@ -146,6 +169,7 @@ SET(BulletExampleBrowser_SRCS ../SharedMemory/PhysicsServer.cpp ../SharedMemory/PhysicsClientSharedMemory.cpp + ../SharedMemory/PhysicsClientSharedMemory_C_API.cpp ../SharedMemory/PhysicsClient.cpp ../SharedMemory/PhysicsClientC_API.cpp ../SharedMemory/PhysicsServerExample.cpp @@ -173,6 +197,11 @@ SET(BulletExampleBrowser_SRCS ../InverseKinematics/InverseKinematicsExample.h ../ForkLift/ForkLiftDemo.cpp ../ForkLift/ForkLiftDemo.h + ../MultiThreadedDemo/MultiThreadedDemo.cpp + ../MultiThreadedDemo/MultiThreadedDemo.h + ../MultiThreadedDemo/CommonRigidBodyMTBase.cpp + ../MultiThreadedDemo/CommonRigidBodyMTBase.h + ../MultiThreadedDemo/ParallelFor.h ../Tutorial/Tutorial.cpp ../Tutorial/Tutorial.h ../Tutorial/Dof6ConstraintTutorial.cpp @@ -346,9 +375,26 @@ ADD_CUSTOM_COMMAND( COMMAND ${CMAKE_COMMAND} ARGS -E copy_directory ${BULLET_PHYSICS_SOURCE_DIR}/data ${PROJECT_BINARY_DIR}/data ) +IF (BULLET2_MULTITHREADED_TBB_DEMO AND WIN32) + # add a post build command to copy some dlls to the executable directory + set(TBB_VC_VER "vc12") + set(TBB_VC_ARCH "ia32") + # assume 32-bit build in VC12 for now + # checks can be added here at a later time + ADD_CUSTOM_COMMAND(TARGET App_ExampleBrowser POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different + "${BULLET2_TBB_INCLUDE_DIR}/../bin/${TBB_VC_ARCH}/${TBB_VC_VER}/tbb.dll" + $) + ADD_CUSTOM_COMMAND(TARGET App_ExampleBrowser POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different + "${BULLET2_TBB_INCLUDE_DIR}/../bin/${TBB_VC_ARCH}/${TBB_VC_VER}/tbbmalloc.dll" + $) +ENDIF (BULLET2_MULTITHREADED_TBB_DEMO AND WIN32) + IF (INTERNAL_ADD_POSTFIX_EXECUTABLE_NAMES) SET_TARGET_PROPERTIES(App_ExampleBrowser PROPERTIES DEBUG_POSTFIX "_Debug") SET_TARGET_PROPERTIES(App_ExampleBrowser PROPERTIES MINSIZEREL_POSTFIX "_MinsizeRel") SET_TARGET_PROPERTIES(App_ExampleBrowser PROPERTIES RELWITHDEBINFO_POSTFIX "_RelWithDebugInfo") ENDIF(INTERNAL_ADD_POSTFIX_EXECUTABLE_NAMES) + diff --git a/examples/ExampleBrowser/ExampleEntries.cpp b/examples/ExampleBrowser/ExampleEntries.cpp index 87382fbc8..f6af39031 100644 --- a/examples/ExampleBrowser/ExampleEntries.cpp +++ b/examples/ExampleBrowser/ExampleEntries.cpp @@ -8,6 +8,7 @@ #include "../RenderingExamples/TinyRendererSetup.h" #include "../RenderingExamples/DynamicTexturedCubeDemo.h" #include "../ForkLift/ForkLiftDemo.h" +#include "../MultiThreadedDemo/MultiThreadedDemo.h" #include "../BasicDemo/BasicExample.h" #include "../Planar2D/Planar2D.h" #include "../Benchmarks/BenchmarkDemo.h" @@ -269,6 +270,7 @@ static ExampleEntry gDefaultExamples[]= ExampleEntry(1,"Two Point Grasp","Grasp experiment with two point contact to test rolling friction", GripperGraspExampleCreateFunc, eTWO_POINT_GRASP), ExampleEntry(1,"One Motor Gripper Grasp","Grasp experiment with a gripper with one motor to test slider constraint for closed loop structure", GripperGraspExampleCreateFunc, eONE_MOTOR_GRASP), ExampleEntry(1,"Grasp Soft Body","Grasp soft body experiment", GripperGraspExampleCreateFunc, eGRASP_SOFT_BODY), + ExampleEntry(1,"Softbody Multibody Coupling","Two way coupling between soft body and multibody experiment", GripperGraspExampleCreateFunc, eSOFTBODY_MULTIBODY_COUPLING), #ifdef ENABLE_LUA @@ -284,7 +286,13 @@ static ExampleEntry gDefaultExamples[]= ExampleEntry(1,"Fracture demo", "Create a basic custom implementation to model fracturing objects, based on a btCompoundShape. It explicitly propagates the collision impulses and breaks the rigid body into multiple rigid bodies. Press F to toggle fracture and glue mode.", FractureDemoCreateFunc), ExampleEntry(1,"Planar 2D","Show the use of 2D collision shapes and rigid body simulation. The collision shape is wrapped into a btConvex2dShape. The rigid bodies are restricted in a plane using the 'setAngularFactor' and 'setLinearFactor' API call.",Planar2DCreateFunc), - +#if BT_USE_OPENMP || BT_USE_TBB || BT_USE_PPL + // only enable MultiThreaded demo if a task scheduler is available + ExampleEntry( 1, "Multithreaded Demo", + "Stacks of boxes that do not sleep. Good for testing performance with large numbers of bodies and contacts. Sliders can be used to change the number of stacks (restart needed after each change)." + , + MultiThreadedDemoCreateFunc ), +#endif ExampleEntry(0,"Rendering"), diff --git a/examples/ExampleBrowser/GL_ShapeDrawer.cpp b/examples/ExampleBrowser/GL_ShapeDrawer.cpp index 99b6421d6..2b730af5b 100644 --- a/examples/ExampleBrowser/GL_ShapeDrawer.cpp +++ b/examples/ExampleBrowser/GL_ShapeDrawer.cpp @@ -782,7 +782,7 @@ GL_ShapeDrawer::~GL_ShapeDrawer() } } -void GL_ShapeDrawer::drawSceneInternal(const btDiscreteDynamicsWorld* dynamicsWorld, int pass) +void GL_ShapeDrawer::drawSceneInternal(const btDiscreteDynamicsWorld* dynamicsWorld, int pass, int cameraUpAxis) { btAssert(dynamicsWorld); @@ -849,7 +849,12 @@ void GL_ShapeDrawer::drawSceneInternal(const btDiscreteDynamicsWorld* dynamicsWo //if (!(getDebugMode()& btIDebugDraw::DBG_DrawWireframe)) int debugMode = 0;//getDebugMode() //btVector3 m_sundirection(-1,-1,-1); + btVector3 m_sundirection(btVector3(1,-2,1)*1000); + if (cameraUpAxis==2) + { + m_sundirection = btVector3(1,1,-2)*1000; + } switch(pass) { @@ -861,9 +866,12 @@ void GL_ShapeDrawer::drawSceneInternal(const btDiscreteDynamicsWorld* dynamicsWo } -void GL_ShapeDrawer::drawScene(const btDiscreteDynamicsWorld* dynamicsWorld, bool useShadows) +//this GL_ShapeDrawer will be removed, in the meanwhile directly access this global 'useShadoMaps' +extern bool useShadowMap; +void GL_ShapeDrawer::drawScene(const btDiscreteDynamicsWorld* dynamicsWorld, bool useShadows1, int cameraUpAxis) { + bool useShadows = useShadowMap; GLfloat light_ambient[] = { btScalar(0.2), btScalar(0.2), btScalar(0.2), btScalar(1.0) }; GLfloat light_diffuse[] = { btScalar(1.0), btScalar(1.0), btScalar(1.0), btScalar(1.0) }; GLfloat light_specular[] = { btScalar(1.0), btScalar(1.0), btScalar(1.0), btScalar(1.0 )}; @@ -897,7 +905,7 @@ void GL_ShapeDrawer::drawScene(const btDiscreteDynamicsWorld* dynamicsWorld, boo { glClear(GL_STENCIL_BUFFER_BIT); glEnable(GL_CULL_FACE); - drawSceneInternal(dynamicsWorld,0); + drawSceneInternal(dynamicsWorld,0, cameraUpAxis); glDisable(GL_LIGHTING); glDepthMask(GL_FALSE); @@ -907,10 +915,10 @@ void GL_ShapeDrawer::drawScene(const btDiscreteDynamicsWorld* dynamicsWorld, boo glStencilFunc(GL_ALWAYS,1,0xFFFFFFFFL); glFrontFace(GL_CCW); glStencilOp(GL_KEEP,GL_KEEP,GL_INCR); - drawSceneInternal(dynamicsWorld,1); + drawSceneInternal(dynamicsWorld,1,cameraUpAxis); glFrontFace(GL_CW); glStencilOp(GL_KEEP,GL_KEEP,GL_DECR); - drawSceneInternal(dynamicsWorld,1); + drawSceneInternal(dynamicsWorld,1,cameraUpAxis); glFrontFace(GL_CCW); glPolygonMode(GL_FRONT,GL_FILL); @@ -929,7 +937,7 @@ void GL_ShapeDrawer::drawScene(const btDiscreteDynamicsWorld* dynamicsWorld, boo glStencilFunc( GL_NOTEQUAL, 0, 0xFFFFFFFFL ); glStencilOp( GL_KEEP, GL_KEEP, GL_KEEP ); glDisable(GL_LIGHTING); - drawSceneInternal(dynamicsWorld,2); + drawSceneInternal(dynamicsWorld,2,cameraUpAxis); glEnable(GL_LIGHTING); glDepthFunc(GL_LESS); glDisable(GL_STENCIL_TEST); @@ -938,6 +946,6 @@ void GL_ShapeDrawer::drawScene(const btDiscreteDynamicsWorld* dynamicsWorld, boo else { glDisable(GL_CULL_FACE); - drawSceneInternal(dynamicsWorld,0); + drawSceneInternal(dynamicsWorld,0,cameraUpAxis); } } \ No newline at end of file diff --git a/examples/ExampleBrowser/GL_ShapeDrawer.h b/examples/ExampleBrowser/GL_ShapeDrawer.h index 4d9ce701a..e004420c4 100644 --- a/examples/ExampleBrowser/GL_ShapeDrawer.h +++ b/examples/ExampleBrowser/GL_ShapeDrawer.h @@ -44,7 +44,7 @@ protected: ShapeCache* cache(btConvexShape*); - virtual void drawSceneInternal(const btDiscreteDynamicsWorld* world, int pass); + virtual void drawSceneInternal(const btDiscreteDynamicsWorld* world, int pass, int cameraUpAxis); public: GL_ShapeDrawer(); @@ -53,7 +53,7 @@ public: - virtual void drawScene(const btDiscreteDynamicsWorld* world, bool useShadows); + virtual void drawScene(const btDiscreteDynamicsWorld* world, bool useShadows, int cameraUpAxis); ///drawOpenGL might allocate temporary memoty, stores pointer in shape userpointer virtual void drawOpenGL(btScalar* m, const btCollisionShape* shape, const btVector3& color,int debugMode,const btVector3& worldBoundsMin,const btVector3& worldBoundsMax); diff --git a/examples/ExampleBrowser/GwenGUISupport/GwenParameterInterface.cpp b/examples/ExampleBrowser/GwenGUISupport/GwenParameterInterface.cpp index 449f27e0a..aa8c0b871 100644 --- a/examples/ExampleBrowser/GwenGUISupport/GwenParameterInterface.cpp +++ b/examples/ExampleBrowser/GwenGUISupport/GwenParameterInterface.cpp @@ -28,18 +28,20 @@ template struct MySliderEventHandler : public Gwen::Event::Handler { SliderParamChangedCallback m_callback; + void* m_userPointer; Gwen::Controls::TextBox* m_label; Gwen::Controls::Slider* m_pSlider; char m_variableName[1024]; T* m_targetValue; bool m_showValue; - MySliderEventHandler(const char* varName, Gwen::Controls::TextBox* label, Gwen::Controls::Slider* pSlider,T* target,SliderParamChangedCallback callback) + MySliderEventHandler(const char* varName, Gwen::Controls::TextBox* label, Gwen::Controls::Slider* pSlider,T* target, SliderParamChangedCallback callback, void* userPtr) :m_label(label), m_pSlider(pSlider), m_targetValue(target), m_showValue(true), - m_callback(callback) + m_callback(callback), + m_userPointer(userPtr) { memcpy(m_variableName,varName,strlen(varName)+1); } @@ -55,7 +57,7 @@ struct MySliderEventHandler : public Gwen::Event::Handler if (m_callback) { - (*m_callback)(v); + (*m_callback)(v, m_userPointer); } } @@ -223,12 +225,20 @@ void GwenParameterInterface::registerSliderFloatParameter(SliderParams& params) pSlider->SetPos( 10, m_gwenInternalData->m_curYposition ); pSlider->SetSize( 200, 20 ); pSlider->SetRange( params.m_minVal, params.m_maxVal); - pSlider->SetNotchCount(16);//float(params.m_maxVal-params.m_minVal)/100.f); - pSlider->SetClampToNotches( params.m_clampToNotches ); + if (params.m_clampToIntegers) + { + pSlider->SetNotchCount( int( params.m_maxVal - params.m_minVal ) ); + pSlider->SetClampToNotches( params.m_clampToNotches ); + } + else + { + pSlider->SetNotchCount( 16 );//float(params.m_maxVal-params.m_minVal)/100.f); + pSlider->SetClampToNotches( params.m_clampToNotches ); + } pSlider->SetValue( *params.m_paramValuePointer);//dimensions[i] ); char labelName[1024]; sprintf(labelName,"%s",params.m_name);//axisNames[0]); - MySliderEventHandler* handler = new MySliderEventHandler(labelName,label,pSlider,params.m_paramValuePointer,params.m_callback); + MySliderEventHandler* handler = new MySliderEventHandler(labelName,label,pSlider,params.m_paramValuePointer,params.m_callback, params.m_userPointer); handler->m_showValue = params.m_showValues; m_paramInternalData->m_sliderEventHandlers.push_back(handler); diff --git a/examples/ExampleBrowser/OpenGLExampleBrowser.cpp b/examples/ExampleBrowser/OpenGLExampleBrowser.cpp index 70e717159..ca86cda97 100644 --- a/examples/ExampleBrowser/OpenGLExampleBrowser.cpp +++ b/examples/ExampleBrowser/OpenGLExampleBrowser.cpp @@ -134,9 +134,9 @@ int gSharedMemoryKey=-1; int gPreferredOpenCLDeviceIndex=-1; int gPreferredOpenCLPlatformIndex=-1; -int gGpuArraySizeX=15; -int gGpuArraySizeY=15; -int gGpuArraySizeZ=15; +int gGpuArraySizeX=45; +int gGpuArraySizeY=55; +int gGpuArraySizeZ=45; //#include //unsigned int fp_control_state = _controlfp(_EM_INEXACT, _MCW_EM); @@ -1167,7 +1167,7 @@ void OpenGLExampleBrowser::update(float deltaTime) } BT_PROFILE("Render Scene"); sCurrentDemo->renderScene(); - } + } else { B3_PROFILE("physicsDebugDraw"); glPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); diff --git a/examples/ExampleBrowser/OpenGLGuiHelper.cpp b/examples/ExampleBrowser/OpenGLGuiHelper.cpp index 4a4277b2d..0194b4f4e 100644 --- a/examples/ExampleBrowser/OpenGLGuiHelper.cpp +++ b/examples/ExampleBrowser/OpenGLGuiHelper.cpp @@ -338,7 +338,7 @@ void OpenGLGuiHelper::render(const btDiscreteDynamicsWorld* rbWorld) if (m_data->m_gl2ShapeDrawer && rbWorld) { m_data->m_gl2ShapeDrawer->enableTexture(true); - m_data->m_gl2ShapeDrawer->drawScene(rbWorld,true); + m_data->m_gl2ShapeDrawer->drawScene(rbWorld,true, m_data->m_glApp->getUpAxis()); } } void OpenGLGuiHelper::createPhysicsDebugDrawer(btDiscreteDynamicsWorld* rbWorld) diff --git a/examples/ExampleBrowser/OpenGLGuiHelper.h b/examples/ExampleBrowser/OpenGLGuiHelper.h index eaa72a7be..d0c9cdb2b 100644 --- a/examples/ExampleBrowser/OpenGLGuiHelper.h +++ b/examples/ExampleBrowser/OpenGLGuiHelper.h @@ -55,9 +55,27 @@ struct OpenGLGuiHelper : public GUIHelperInterface virtual void drawText3D( const char* txt, float posX, float posY, float posZ, float size); + virtual int addUserDebugText3D( const char* txt, const double positionXYZ[3], const double textColorRGB[3], double size, double lifeTime) + { + return -1; + } + virtual int addUserDebugLine(const double debugLineFromXYZ[3], const double debugLineToXYZ[3], const double debugLineColorRGB[3], double lineWidth, double lifeTime ) + { + return -1; + } + virtual void removeUserDebugItem( int debugItemUniqueId) + { + } + virtual void removeAllUserDebugItems( ) + { + } + + void renderInternalGl2(int pass, const btDiscreteDynamicsWorld* dynamicsWorld); void setVRMode(bool vrMode); + + }; #endif //OPENGL_GUI_HELPER_H diff --git a/examples/ExampleBrowser/main.cpp b/examples/ExampleBrowser/main.cpp index d0f132c1a..05985d41e 100644 --- a/examples/ExampleBrowser/main.cpp +++ b/examples/ExampleBrowser/main.cpp @@ -15,6 +15,8 @@ #include "../Importers/ImportURDFDemo/ImportURDFSetup.h" #include "../Importers/ImportSDFDemo/ImportSDFSetup.h" #include "../Importers/ImportSTLDemo/ImportSTLSetup.h" +#include "../Importers/ImportBullet/SerializeSetup.h" + #include "LinearMath/btAlignedAllocator.h" @@ -34,6 +36,8 @@ int main(int argc, char* argv[]) exampleBrowser->registerFileImporter(".sdf", ImportSDFCreateFunc); exampleBrowser->registerFileImporter(".obj", ImportObjCreateFunc); exampleBrowser->registerFileImporter(".stl", ImportSTLCreateFunc); + exampleBrowser->registerFileImporter(".bullet", SerializeBulletCreateFunc); + clock.reset(); if (init) diff --git a/examples/ExampleBrowser/premake4.lua b/examples/ExampleBrowser/premake4.lua index c28ae0e5a..ac184dedc 100644 --- a/examples/ExampleBrowser/premake4.lua +++ b/examples/ExampleBrowser/premake4.lua @@ -63,6 +63,14 @@ project "App_BulletExampleBrowser" "../SharedMemory/PhysicsServer.cpp", "../SharedMemory/PhysicsServerSharedMemory.cpp", "../SharedMemory/PhysicsClientSharedMemory.cpp", + "../SharedMemory/PhysicsClientSharedMemory_C_API.cpp", + "../SharedMemory/PhysicsClientSharedMemory_C_API.h", + "../SharedMemory/PhysicsClientSharedMemory2.cpp", + "../SharedMemory/PhysicsClientSharedMemory2.h", + "../SharedMemory/PhysicsClientSharedMemory2_C_API.cpp", + "../SharedMemory/PhysicsClientSharedMemory2_C_API.h", + "../SharedMemory/SharedMemoryCommandProcessor.cpp", + "../SharedMemory/SharedMemoryCommandProcessor.h", "../SharedMemory/SharedMemoryInProcessPhysicsC_API.cpp", "../SharedMemory/PhysicsClient.cpp", "../SharedMemory/PosixSharedMemory.cpp", @@ -95,7 +103,8 @@ project "App_BulletExampleBrowser" "../RoboticsLearning/*", "../Collision/Internal/*", "../Benchmarks/*", - "../CommonInterfaces/*", + "../MultiThreadedDemo/*", + "../CommonInterfaces/*.h", "../ForkLift/ForkLiftDemo.*", "../Importers/**", "../../Extras/Serialize/BulletWorldImporter/*", diff --git a/examples/ExtendedTutorials/InclinedPlane.cpp b/examples/ExtendedTutorials/InclinedPlane.cpp index dceafdbe8..2c36f8ffa 100644 --- a/examples/ExtendedTutorials/InclinedPlane.cpp +++ b/examples/ExtendedTutorials/InclinedPlane.cpp @@ -69,19 +69,19 @@ struct InclinedPlaneExample : public CommonRigidBodyBase }; -void onBoxFrictionChanged(float friction); +void onBoxFrictionChanged(float friction, void* userPtr); -void onBoxRestitutionChanged(float restitution); +void onBoxRestitutionChanged(float restitution, void* userPtr); -void onSphereFrictionChanged(float friction); +void onSphereFrictionChanged(float friction, void* userPtr); -void onSphereRestitutionChanged(float restitution); +void onSphereRestitutionChanged(float restitution, void* userPtr); -void onRampInclinationChanged(float inclination); +void onRampInclinationChanged(float inclination, void* userPtr); -void onRampFrictionChanged(float friction); +void onRampFrictionChanged(float friction, void* userPtr); -void onRampRestitutionChanged(float restitution); +void onRampRestitutionChanged(float restitution, void* userPtr); void InclinedPlaneExample::initPhysics() { @@ -306,35 +306,35 @@ bool InclinedPlaneExample::keyboardCallback(int key, int state) { // GUI parameter modifiers -void onBoxFrictionChanged(float friction){ +void onBoxFrictionChanged(float friction, void*){ if(gBox){ gBox->setFriction(friction); // b3Printf("Friction of box changed to %f",friction ); } } -void onBoxRestitutionChanged(float restitution){ +void onBoxRestitutionChanged(float restitution, void*){ if(gBox){ gBox->setRestitution(restitution); //b3Printf("Restitution of box changed to %f",restitution); } } -void onSphereFrictionChanged(float friction){ +void onSphereFrictionChanged(float friction, void*){ if(gSphere){ gSphere->setFriction(friction); //b3Printf("Friction of sphere changed to %f",friction ); } } -void onSphereRestitutionChanged(float restitution){ +void onSphereRestitutionChanged(float restitution, void*){ if(gSphere){ gSphere->setRestitution(restitution); //b3Printf("Restitution of sphere changed to %f",restitution); } } -void onRampInclinationChanged(float inclination){ +void onRampInclinationChanged(float inclination, void*){ if(ramp){ btTransform startTransform; startTransform.setIdentity(); @@ -351,14 +351,14 @@ void onRampInclinationChanged(float inclination){ } } -void onRampFrictionChanged(float friction){ +void onRampFrictionChanged(float friction, void*){ if(ramp){ ramp->setFriction(friction); //b3Printf("Friction of ramp changed to %f \n",friction ); } } -void onRampRestitutionChanged(float restitution){ +void onRampRestitutionChanged(float restitution, void*){ if(ramp){ ramp->setRestitution(restitution); //b3Printf("Restitution of ramp changed to %f \n",restitution); diff --git a/examples/ExtendedTutorials/MultiPendulum.cpp b/examples/ExtendedTutorials/MultiPendulum.cpp index 038aab3ec..b45eee755 100644 --- a/examples/ExtendedTutorials/MultiPendulum.cpp +++ b/examples/ExtendedTutorials/MultiPendulum.cpp @@ -71,11 +71,9 @@ struct MultiPendulumExample: public CommonRigidBodyBase { static MultiPendulumExample* mex = NULL; // Handle to the example to access it via functions. Do not use this in your simulation! -void onMultiPendulaLengthChanged(float pendulaLength); // Change the pendula length +void onMultiPendulaLengthChanged(float pendulaLength, void*); // Change the pendula length -void onMultiPendulaRestitutionChanged(float pendulaRestitution); // change the pendula restitution - -void floorMSliderValue(float notUsed); // floor the slider values which should be integers +void onMultiPendulaRestitutionChanged(float pendulaRestitution, void*); // change the pendula restitution void applyMForceWithForceScalar(float forceScalar); @@ -85,8 +83,7 @@ void MultiPendulumExample::initPhysics() { // Setup your physics scene SliderParams slider("Number of Pendula", &gPendulaQty); slider.m_minVal = 1; slider.m_maxVal = 50; - slider.m_callback = floorMSliderValue; // hack to get integer values - slider.m_clampToNotches = false; + slider.m_clampToIntegers = true; m_guiHelper->getParameterInterface()->registerSliderFloatParameter( slider); } @@ -95,8 +92,7 @@ void MultiPendulumExample::initPhysics() { // Setup your physics scene SliderParams slider("Number of Displaced Pendula", &gDisplacedPendula); slider.m_minVal = 0; slider.m_maxVal = 49; - slider.m_callback = floorMSliderValue; // hack to get integer values - slider.m_clampToNotches = false; + slider.m_clampToIntegers = true; m_guiHelper->getParameterInterface()->registerSliderFloatParameter( slider); } @@ -397,7 +393,7 @@ void MultiPendulumExample::applyPendulumForce(btScalar pendulumForce){ // GUI parameter modifiers -void onMultiPendulaLengthChanged(float pendulaLength) { // Change the pendula length +void onMultiPendulaLengthChanged(float pendulaLength, void*) { // Change the pendula length if (mex){ mex->changePendulaLength(pendulaLength); } @@ -405,18 +401,13 @@ void onMultiPendulaLengthChanged(float pendulaLength) { // Change the pendula le } -void onMultiPendulaRestitutionChanged(float pendulaRestitution) { // change the pendula restitution +void onMultiPendulaRestitutionChanged(float pendulaRestitution, void*) { // change the pendula restitution if (mex){ mex->changePendulaRestitution(pendulaRestitution); } } -void floorMSliderValue(float notUsed) { // floor the slider values which should be integers - gPendulaQty = floor(gPendulaQty); - gDisplacedPendula = floor(gDisplacedPendula); -} - void applyMForceWithForceScalar(float forceScalar) { if(mex){ btScalar appliedForce = forceScalar * gDisplacementForce; diff --git a/examples/ExtendedTutorials/NewtonsCradle.cpp b/examples/ExtendedTutorials/NewtonsCradle.cpp index 0d4c52095..54be8367a 100644 --- a/examples/ExtendedTutorials/NewtonsCradle.cpp +++ b/examples/ExtendedTutorials/NewtonsCradle.cpp @@ -71,11 +71,9 @@ struct NewtonsCradleExample: public CommonRigidBodyBase { static NewtonsCradleExample* nex = NULL; -void onPendulaLengthChanged(float pendulaLength); // Change the pendula length +void onPendulaLengthChanged(float pendulaLength, void* userPtr); // Change the pendula length -void onPendulaRestitutionChanged(float pendulaRestitution); // change the pendula restitution - -void floorSliderValue(float notUsed); // floor the slider values which should be integers +void onPendulaRestitutionChanged(float pendulaRestitution, void* userPtr); // change the pendula restitution void applyForceWithForceScalar(float forceScalar); @@ -85,8 +83,7 @@ void NewtonsCradleExample::initPhysics() { SliderParams slider("Number of Pendula", &gPendulaQty); slider.m_minVal = 1; slider.m_maxVal = 50; - slider.m_callback = floorSliderValue; // hack to get integer values - slider.m_clampToNotches = false; + slider.m_clampToIntegers = true; m_guiHelper->getParameterInterface()->registerSliderFloatParameter( slider); } @@ -95,8 +92,7 @@ void NewtonsCradleExample::initPhysics() { SliderParams slider("Number of Displaced Pendula", &gDisplacedPendula); slider.m_minVal = 0; slider.m_maxVal = 49; - slider.m_callback = floorSliderValue; // hack to get integer values - slider.m_clampToNotches = false; + slider.m_clampToIntegers = true; m_guiHelper->getParameterInterface()->registerSliderFloatParameter( slider); } @@ -343,25 +339,19 @@ void NewtonsCradleExample::applyPendulumForce(btScalar pendulumForce){ // GUI parameter modifiers -void onPendulaLengthChanged(float pendulaLength) { +void onPendulaLengthChanged(float pendulaLength, void*) { if (nex){ nex->changePendulaLength(pendulaLength); //b3Printf("Pendula length changed to %f \n",sliderValue ); } } -void onPendulaRestitutionChanged(float pendulaRestitution) { +void onPendulaRestitutionChanged(float pendulaRestitution, void*) { if (nex){ nex->changePendulaRestitution(pendulaRestitution); } } -void floorSliderValue(float notUsed) { - gPendulaQty = floor(gPendulaQty); - gDisplacedPendula = floor(gDisplacedPendula); - -} - void applyForceWithForceScalar(float forceScalar) { if(nex){ btScalar appliedForce = forceScalar * gDisplacementForce; diff --git a/examples/ExtendedTutorials/NewtonsRopeCradle.cpp b/examples/ExtendedTutorials/NewtonsRopeCradle.cpp index 94c96a71f..76eb115ea 100644 --- a/examples/ExtendedTutorials/NewtonsRopeCradle.cpp +++ b/examples/ExtendedTutorials/NewtonsRopeCradle.cpp @@ -105,9 +105,7 @@ struct NewtonsRopeCradleExample : public CommonRigidBodyBase { static NewtonsRopeCradleExample* nex = NULL; -void onRopePendulaRestitutionChanged(float pendulaRestitution); - -void floorRSliderValue(float notUsed); +void onRopePendulaRestitutionChanged(float pendulaRestitution, void*); void applyRForceWithForceScalar(float forceScalar); @@ -118,8 +116,7 @@ void NewtonsRopeCradleExample::initPhysics() SliderParams slider("Number of Pendula", &gPendulaQty); slider.m_minVal = 1; slider.m_maxVal = 50; - slider.m_callback = floorRSliderValue; // hack to get integer values - slider.m_clampToNotches = false; + slider.m_clampToIntegers = true; m_guiHelper->getParameterInterface()->registerSliderFloatParameter( slider); } @@ -128,8 +125,7 @@ void NewtonsRopeCradleExample::initPhysics() SliderParams slider("Number of Displaced Pendula", &gDisplacedPendula); slider.m_minVal = 0; slider.m_maxVal = 49; - slider.m_callback = floorRSliderValue; // hack to get integer values - slider.m_clampToNotches = false; + slider.m_clampToIntegers = true; m_guiHelper->getParameterInterface()->registerSliderFloatParameter( slider); } @@ -148,8 +144,7 @@ void NewtonsRopeCradleExample::initPhysics() SliderParams slider("Rope Resolution", &gRopeResolution); slider.m_minVal = 1; slider.m_maxVal = 20; - slider.m_clampToNotches = false; - slider.m_callback = floorRSliderValue; + slider.m_clampToIntegers = true; m_guiHelper->getParameterInterface()->registerSliderFloatParameter( slider); } @@ -357,18 +352,12 @@ void NewtonsRopeCradleExample::applyPendulumForce(btScalar pendulumForce){ // GUI parameter modifiers -void onRopePendulaRestitutionChanged(float pendulaRestitution) { +void onRopePendulaRestitutionChanged(float pendulaRestitution, void*) { if (nex){ nex->changePendulaRestitution(pendulaRestitution); } } -void floorRSliderValue(float notUsed) { - gPendulaQty = floor(gPendulaQty); - gDisplacedPendula = floor(gDisplacedPendula); - gRopeResolution = floor(gRopeResolution); -} - void applyRForceWithForceScalar(float forceScalar) { if(nex){ btScalar appliedForce = forceScalar * gDisplacementForce; diff --git a/examples/ExtendedTutorials/premake4.lua b/examples/ExtendedTutorials/premake4.lua index 41126e0af..bbfa7c224 100644 --- a/examples/ExtendedTutorials/premake4.lua +++ b/examples/ExtendedTutorials/premake4.lua @@ -17,6 +17,7 @@ language "C++" files { "RigidBodyFromObj.cpp", + "../CommonInterfaces/*", "**.h", "../StandaloneMain/main_console_single_example.cpp", "../Utils/b3ResourcePath.cpp", @@ -68,6 +69,7 @@ files { "RigidBodyFromObj.cpp", "*.h", "../StandaloneMain/main_opengl_single_example.cpp", + "../CommonInterfaces/*", "../ExampleBrowser/OpenGLGuiHelper.cpp", "../ExampleBrowser/GL_ShapeDrawer.cpp", "../ExampleBrowser/CollisionShape2TriangleMesh.cpp", @@ -132,6 +134,7 @@ files { "../ExampleBrowser/OpenGLGuiHelper.cpp", "../ExampleBrowser/GL_ShapeDrawer.cpp", "../ExampleBrowser/CollisionShape2TriangleMesh.cpp", + "../CommonInterfaces/*", "../TinyRenderer/geometry.cpp", "../TinyRenderer/model.cpp", "../TinyRenderer/tgaimage.cpp", @@ -193,6 +196,7 @@ files { "../StandaloneMain/main_tinyrenderer_single_example.cpp", "../OpenGLWindow/SimpleCamera.cpp", "../ExampleBrowser/CollisionShape2TriangleMesh.cpp", + "../CommonInterfaces/*", "../TinyRenderer/geometry.cpp", "../TinyRenderer/model.cpp", "../TinyRenderer/tgaimage.cpp", diff --git a/examples/Importers/ImportMJCFDemo/ImportMJCFSetup.cpp b/examples/Importers/ImportMJCFDemo/ImportMJCFSetup.cpp new file mode 100644 index 000000000..f4259f77e --- /dev/null +++ b/examples/Importers/ImportMJCFDemo/ImportMJCFSetup.cpp @@ -0,0 +1,236 @@ + +#include "ImportMJCFSetup.h" +#include "BulletDynamics/ConstraintSolver/btGeneric6DofSpring2Constraint.h" +//#define TEST_MULTIBODY_SERIALIZATION 1 + +#include "BulletDynamics/Featherstone/btMultiBodyLinkCollider.h" +#include "Bullet3Common/b3FileUtils.h" + +#include "BulletDynamics/Featherstone/btMultiBodyJointMotor.h" +#include "BulletDynamics/Featherstone/btMultiBodyDynamicsWorld.h" +#include "../CommonInterfaces/CommonParameterInterface.h" +#include "../../Utils/b3ResourcePath.h" + +#include "../CommonInterfaces/CommonMultiBodyBase.h" + +#include "../ImportURDFDemo/MyMultiBodyCreator.h" + +class ImportMJCFSetup : public CommonMultiBodyBase +{ + char m_fileName[1024]; + + struct ImportMJCFInternalData* m_data; + bool m_useMultiBody; + btAlignedObjectArray m_nameMemory; + btScalar m_grav; + int m_upAxis; +public: + ImportMJCFSetup(struct GUIHelperInterface* helper, int option, const char* fileName); + virtual ~ImportMJCFSetup(); + + virtual void initPhysics(); + virtual void stepSimulation(float deltaTime); + + void setFileName(const char* mjcfFileName); + + virtual void resetCamera() + { + float dist = 3.5; + float pitch = -136; + float yaw = 28; + float targetPos[3]={0.47,0,-0.64}; + m_guiHelper->resetCamera(dist,pitch,yaw,targetPos[0],targetPos[1],targetPos[2]); + } +}; + + +static btAlignedObjectArray gMCFJFileNameArray; + + +#define MAX_NUM_MOTORS 1024 + +struct ImportMJCFInternalData +{ + ImportMJCFInternalData() + :m_numMotors(0), + m_mb(0) + { + for (int i=0;i=numFileNames) + { + count=0; + } + sprintf(m_fileName,"%s",gMCFJFileNameArray[count++].c_str()); + } +} + +ImportMJCFSetup::~ImportMJCFSetup() +{ + for (int i=0;isetUpAxis(m_upAxis); + + this->createEmptyDynamicsWorld(); + //m_dynamicsWorld->getSolverInfo().m_numIterations = 100; + m_guiHelper->createPhysicsDebugDrawer(m_dynamicsWorld); + m_dynamicsWorld->getDebugDrawer()->setDebugMode( + btIDebugDraw::DBG_DrawConstraints + +btIDebugDraw::DBG_DrawContactPoints + +btIDebugDraw::DBG_DrawAabb + );//+btIDebugDraw::DBG_DrawConstraintLimits); + + + if (m_guiHelper->getParameterInterface()) + { + SliderParams slider("Gravity", &m_grav); + slider.m_minVal = -10; + slider.m_maxVal = 10; + m_guiHelper->getParameterInterface()->registerSliderFloatParameter(slider); + } + + + +} + + + +void ImportMJCFSetup::stepSimulation(float deltaTime) +{ + if (m_dynamicsWorld) + { + btVector3 gravity(0, 0, 0); + gravity[m_upAxis] = m_grav; + m_dynamicsWorld->setGravity(gravity); + + for (int i=0;im_numMotors;i++) + { + if (m_data->m_jointMotors[i]) + { + m_data->m_jointMotors[i]->setVelocityTarget(m_data->m_motorTargetVelocities[i]); + } + if (m_data->m_generic6DofJointMotors[i]) + { + GenericConstraintUserInfo* jointInfo = (GenericConstraintUserInfo*)m_data->m_generic6DofJointMotors[i]->getUserConstraintPtr(); + m_data->m_generic6DofJointMotors[i]->setTargetVelocity(jointInfo->m_jointAxisIndex,m_data->m_motorTargetVelocities[i]); + //jointInfo-> + } + } + + //the maximal coordinates/iterative MLCP solver requires a smallish timestep to converge + m_dynamicsWorld->stepSimulation(deltaTime,10,1./240.); + } +} + +class CommonExampleInterface* ImportMJCFCreateFunc(struct CommonExampleOptions& options) +{ + + return new ImportMJCFSetup(options.m_guiHelper, options.m_option,options.m_fileName); +} diff --git a/examples/Importers/ImportMJCFDemo/ImportMJCFSetup.h b/examples/Importers/ImportMJCFDemo/ImportMJCFSetup.h new file mode 100644 index 000000000..52b399426 --- /dev/null +++ b/examples/Importers/ImportMJCFDemo/ImportMJCFSetup.h @@ -0,0 +1,8 @@ +#ifndef IMPORT_MJCF_SETUP_H +#define IMPORT_MJCF_SETUP_H + + +class CommonExampleInterface* ImportMJCFCreateFunc(struct CommonExampleOptions& options); + + +#endif //IMPORT_MJCF_SETUP_H diff --git a/examples/Importers/ImportURDFDemo/ImportURDFSetup.cpp b/examples/Importers/ImportURDFDemo/ImportURDFSetup.cpp index 3dfe17dd0..aba0b3e03 100644 --- a/examples/Importers/ImportURDFDemo/ImportURDFSetup.cpp +++ b/examples/Importers/ImportURDFDemo/ImportURDFSetup.cpp @@ -135,7 +135,7 @@ ImportUrdfSetup::ImportUrdfSetup(struct GUIHelperInterface* helper, int option, if (gFileNameArray.size()==0) { - gFileNameArray.push_back("r2d2.urdf"); + gFileNameArray.push_back("quadruped/quadruped.urdf"); } diff --git a/examples/Importers/ImportURDFDemo/URDF2Bullet.cpp b/examples/Importers/ImportURDFDemo/URDF2Bullet.cpp index d9e58ef5a..7c0f2c86a 100644 --- a/examples/Importers/ImportURDFDemo/URDF2Bullet.cpp +++ b/examples/Importers/ImportURDFDemo/URDF2Bullet.cpp @@ -143,6 +143,34 @@ void InitURDF2BulletCache(const URDFImporterInterface& u2b, URDF2BulletCachedDat } +void processContactParameters(const URDFLinkContactInfo& contactInfo, btCollisionObject* col) +{ + if ((contactInfo.m_flags & URDF_CONTACT_HAS_LATERAL_FRICTION) != 0) + { + col->setFriction(contactInfo.m_lateralFriction); + } + if ((contactInfo.m_flags & URDF_CONTACT_HAS_RESTITUTION) != 0) + { + col->setRestitution(contactInfo.m_restitution); + } + + if ((contactInfo.m_flags & URDF_CONTACT_HAS_ROLLING_FRICTION) != 0) + { + col->setRollingFriction(contactInfo.m_rollingFriction); + } + if ((contactInfo.m_flags & URDF_CONTACT_HAS_SPINNING_FRICTION) != 0) + { + col->setSpinningFriction(contactInfo.m_spinningFriction); + } + if ((contactInfo.m_flags & URDF_CONTACT_HAS_STIFFNESS_DAMPING) != 0) + { + col->setContactStiffnessAndDamping(contactInfo.m_contactStiffness, contactInfo.m_contactDamping); + } +} + + + + void ConvertURDF2BulletInternal( const URDFImporterInterface& u2b, MultiBodyCreationInterface& creation, URDF2BulletCachedData& cache, int urdfLinkIndex, @@ -258,11 +286,18 @@ void ConvertURDF2BulletInternal( world1->addRigidBody(body); + compoundShape->setUserIndex(graphicsIndex); + URDFLinkContactInfo contactInfo; + u2b.getLinkContactInfo(urdfLinkIndex, contactInfo); + + processContactParameters(contactInfo, body); creation.createRigidBodyGraphicsInstance(urdfLinkIndex, body, color, graphicsIndex); cache.registerRigidBody(urdfLinkIndex, body, inertialFrameInWorldSpace, mass, localInertiaDiagonal, compoundShape, localInertialFrame); + + //untested: u2b.convertLinkVisualShapes2(urdfLinkIndex,pathPrefix,localInertialFrame,body); } else { @@ -413,22 +448,7 @@ void ConvertURDF2BulletInternal( URDFLinkContactInfo contactInfo; u2b.getLinkContactInfo(urdfLinkIndex,contactInfo); - if ((contactInfo.m_flags & URDF_CONTACT_HAS_LATERAL_FRICTION)!=0) - { - col->setFriction(contactInfo.m_lateralFriction); - } - if ((contactInfo.m_flags & URDF_CONTACT_HAS_ROLLING_FRICTION)!=0) - { - col->setRollingFriction(contactInfo.m_rollingFriction); - } - if ((contactInfo.m_flags & URDF_CONTACT_HAS_SPINNING_FRICTION)!=0) - { - col->setSpinningFriction(contactInfo.m_spinningFriction); - } - if ((contactInfo.m_flags & URDF_CONTACT_HAS_STIFFNESS_DAMPING)!=0) - { - col->setContactStiffnessAndDamping(contactInfo.m_contactStiffness,contactInfo.m_contactDamping); - } + processContactParameters(contactInfo, col); if (mbLinkIndex>=0) //???? double-check +/- 1 { diff --git a/examples/Importers/ImportURDFDemo/URDFJointTypes.h b/examples/Importers/ImportURDFDemo/URDFJointTypes.h index 88912cb1a..2bcb53214 100644 --- a/examples/Importers/ImportURDFDemo/URDFJointTypes.h +++ b/examples/Importers/ImportURDFDemo/URDFJointTypes.h @@ -22,6 +22,7 @@ enum URDF_LinkContactFlags URDF_CONTACT_HAS_STIFFNESS_DAMPING=16, URDF_CONTACT_HAS_ROLLING_FRICTION=32, URDF_CONTACT_HAS_SPINNING_FRICTION=64, + URDF_CONTACT_HAS_RESTITUTION=128, }; @@ -30,6 +31,7 @@ struct URDFLinkContactInfo btScalar m_lateralFriction; btScalar m_rollingFriction; btScalar m_spinningFriction; + btScalar m_restitution; btScalar m_inertiaScaling; btScalar m_contactCfm; btScalar m_contactErp; @@ -42,6 +44,7 @@ struct URDFLinkContactInfo :m_lateralFriction(0.5), m_rollingFriction(0), m_spinningFriction(0), + m_restitution(0), m_inertiaScaling(1), m_contactCfm(0), m_contactErp(0), diff --git a/examples/Importers/ImportURDFDemo/UrdfParser.cpp b/examples/Importers/ImportURDFDemo/UrdfParser.cpp index 817cb0ce5..bcac5eec7 100644 --- a/examples/Importers/ImportURDFDemo/UrdfParser.cpp +++ b/examples/Importers/ImportURDFDemo/UrdfParser.cpp @@ -672,6 +672,31 @@ bool UrdfParser::parseLink(UrdfModel& model, UrdfLink& link, TiXmlElement *confi } } } + + { + TiXmlElement *restitution_xml = ci->FirstChildElement("restitution"); + if (restitution_xml) + { + if (m_parseSDF) + { + link.m_contactInfo.m_restitution = urdfLexicalCast(restitution_xml->GetText()); + link.m_contactInfo.m_flags |= URDF_CONTACT_HAS_RESTITUTION; + } + else + { + if (!restitution_xml->Attribute("value")) + { + logger->reportError("Link/contact: restitution element must have value attribute"); + return false; + } + + link.m_contactInfo.m_restitution = urdfLexicalCast(restitution_xml->Attribute("value")); + link.m_contactInfo.m_flags |= URDF_CONTACT_HAS_RESTITUTION; + + } + } + } + { TiXmlElement *spinning_xml = ci->FirstChildElement("spinning_friction"); if (spinning_xml) diff --git a/examples/MultiThreadedDemo/CommonRigidBodyMTBase.cpp b/examples/MultiThreadedDemo/CommonRigidBodyMTBase.cpp new file mode 100644 index 000000000..8375489ee --- /dev/null +++ b/examples/MultiThreadedDemo/CommonRigidBodyMTBase.cpp @@ -0,0 +1,868 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#include "btBulletDynamicsCommon.h" +#include "LinearMath/btIDebugDraw.h" + +#include +#include + +class btCollisionShape; + +#include "CommonRigidBodyMTBase.h" +#include "../CommonInterfaces/CommonParameterInterface.h" +#include "ParallelFor.h" +#include "LinearMath/btAlignedObjectArray.h" +#include "LinearMath/btPoolAllocator.h" +#include "btBulletCollisionCommon.h" +#include "BulletDynamics/Dynamics/btSimulationIslandManagerMt.h" // for setSplitIslands() +#include "BulletDynamics/Dynamics/btDiscreteDynamicsWorldMt.h" +#include "BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.h" + +TaskManager gTaskMgr; + +#define USE_PARALLEL_NARROWPHASE 1 // detect collisions in parallel +#define USE_PARALLEL_ISLAND_SOLVER 1 // solve simulation islands in parallel +#define USE_PARALLEL_CREATE_PREDICTIVE_CONTACTS 1 +#define USE_PARALLEL_INTEGRATE_TRANSFORMS 1 +#define USE_PARALLEL_PREDICT_UNCONSTRAINED_MOTION 1 + +#if defined (_MSC_VER) && _MSC_VER >= 1600 +// give us a compile error if any signatures of overriden methods is changed +#define BT_OVERRIDE override +#else +#define BT_OVERRIDE +#endif + + +class Profiler +{ +public: + enum RecordType + { + kRecordInternalTimeStep, + kRecordDispatchAllCollisionPairs, + kRecordDispatchIslands, + kRecordPredictUnconstrainedMotion, + kRecordCreatePredictiveContacts, + kRecordIntegrateTransforms, + kRecordCount + }; + +private: + btClock mClock; + + struct Record + { + int mCallCount; + unsigned long long mAccum; + unsigned int mStartTime; + unsigned int mHistory[8]; + + void begin(unsigned int curTime) + { + mStartTime = curTime; + } + void end(unsigned int curTime) + { + unsigned int endTime = curTime; + unsigned int elapsed = endTime - mStartTime; + mAccum += elapsed; + mHistory[ mCallCount & 7 ] = elapsed; + ++mCallCount; + } + float getAverageTime() const + { + int count = btMin( 8, mCallCount ); + if ( count > 0 ) + { + unsigned int sum = 0; + for ( int i = 0; i < count; ++i ) + { + sum += mHistory[ i ]; + } + float avg = float( sum ) / float( count ); + return avg; + } + return 0.0; + } + }; + Record mRecords[ kRecordCount ]; + +public: + void begin(RecordType rt) + { + mRecords[rt].begin(mClock.getTimeMicroseconds()); + } + void end(RecordType rt) + { + mRecords[rt].end(mClock.getTimeMicroseconds()); + } + float getAverageTime(RecordType rt) const + { + return mRecords[rt].getAverageTime(); + } +}; + + +Profiler gProfiler; + +class ProfileHelper +{ + Profiler::RecordType mRecType; +public: + ProfileHelper(Profiler::RecordType rt) + { + mRecType = rt; + gProfiler.begin( mRecType ); + } + ~ProfileHelper() + { + gProfiler.end( mRecType ); + } +}; + +int gThreadsRunningCounter = 0; +btSpinMutex gThreadsRunningCounterMutex; + +void btPushThreadsAreRunning() +{ + gThreadsRunningCounterMutex.lock(); + gThreadsRunningCounter++; + gThreadsRunningCounterMutex.unlock(); +} + +void btPopThreadsAreRunning() +{ + gThreadsRunningCounterMutex.lock(); + gThreadsRunningCounter--; + gThreadsRunningCounterMutex.unlock(); +} + +bool btThreadsAreRunning() +{ + return gThreadsRunningCounter != 0; +} + + +#if USE_PARALLEL_NARROWPHASE + +class MyCollisionDispatcher : public btCollisionDispatcher +{ + btSpinMutex m_manifoldPtrsMutex; + +public: + MyCollisionDispatcher( btCollisionConfiguration* config ) : btCollisionDispatcher( config ) + { + } + + virtual ~MyCollisionDispatcher() + { + } + + btPersistentManifold* getNewManifold( const btCollisionObject* body0, const btCollisionObject* body1 ) BT_OVERRIDE + { + // added spin-locks + //optional relative contact breaking threshold, turned on by default (use setDispatcherFlags to switch off feature for improved performance) + + btScalar contactBreakingThreshold = ( m_dispatcherFlags & btCollisionDispatcher::CD_USE_RELATIVE_CONTACT_BREAKING_THRESHOLD ) ? + btMin( body0->getCollisionShape()->getContactBreakingThreshold( gContactBreakingThreshold ), body1->getCollisionShape()->getContactBreakingThreshold( gContactBreakingThreshold ) ) + : gContactBreakingThreshold; + + btScalar contactProcessingThreshold = btMin( body0->getContactProcessingThreshold(), body1->getContactProcessingThreshold() ); + + void* mem = m_persistentManifoldPoolAllocator->allocate( sizeof( btPersistentManifold ) ); + if (NULL == mem) + { + //we got a pool memory overflow, by default we fallback to dynamically allocate memory. If we require a contiguous contact pool then assert. + if ( ( m_dispatcherFlags&CD_DISABLE_CONTACTPOOL_DYNAMIC_ALLOCATION ) == 0 ) + { + mem = btAlignedAlloc( sizeof( btPersistentManifold ), 16 ); + } + else + { + btAssert( 0 ); + //make sure to increase the m_defaultMaxPersistentManifoldPoolSize in the btDefaultCollisionConstructionInfo/btDefaultCollisionConfiguration + return 0; + } + } + btPersistentManifold* manifold = new(mem) btPersistentManifold( body0, body1, 0, contactBreakingThreshold, contactProcessingThreshold ); + m_manifoldPtrsMutex.lock(); + manifold->m_index1a = m_manifoldsPtr.size(); + m_manifoldsPtr.push_back( manifold ); + m_manifoldPtrsMutex.unlock(); + + return manifold; + } + + void releaseManifold( btPersistentManifold* manifold ) BT_OVERRIDE + { + clearManifold( manifold ); + + m_manifoldPtrsMutex.lock(); + int findIndex = manifold->m_index1a; + btAssert( findIndex < m_manifoldsPtr.size() ); + m_manifoldsPtr.swap( findIndex, m_manifoldsPtr.size() - 1 ); + m_manifoldsPtr[ findIndex ]->m_index1a = findIndex; + m_manifoldsPtr.pop_back(); + m_manifoldPtrsMutex.unlock(); + + manifold->~btPersistentManifold(); + if ( m_persistentManifoldPoolAllocator->validPtr( manifold ) ) + { + m_persistentManifoldPoolAllocator->freeMemory( manifold ); + } + else + { + btAlignedFree( manifold ); + } + } + + struct Updater + { + btBroadphasePair* mPairArray; + btNearCallback mCallback; + btCollisionDispatcher* mDispatcher; + const btDispatcherInfo* mInfo; + + Updater() + { + mPairArray = NULL; + mCallback = NULL; + mDispatcher = NULL; + mInfo = NULL; + } + void forLoop( int iBegin, int iEnd ) const + { + for ( int i = iBegin; i < iEnd; ++i ) + { + btBroadphasePair* pair = &mPairArray[ i ]; + mCallback( *pair, *mDispatcher, *mInfo ); + } + } + }; + + virtual void dispatchAllCollisionPairs( btOverlappingPairCache* pairCache, const btDispatcherInfo& info, btDispatcher* dispatcher ) BT_OVERRIDE + { + ProfileHelper prof(Profiler::kRecordDispatchAllCollisionPairs); + int grainSize = 40; // iterations per task + int pairCount = pairCache->getNumOverlappingPairs(); + Updater updater; + updater.mCallback = getNearCallback(); + updater.mPairArray = pairCount > 0 ? pairCache->getOverlappingPairArrayPtr() : NULL; + updater.mDispatcher = this; + updater.mInfo = &info; + + btPushThreadsAreRunning(); + parallelFor( 0, pairCount, grainSize, updater ); + btPopThreadsAreRunning(); + + if (m_manifoldsPtr.size() < 1) + return; + + // reconstruct the manifolds array to ensure determinism + m_manifoldsPtr.resizeNoInitialize(0); + btBroadphasePair* pairs = pairCache->getOverlappingPairArrayPtr(); + for (int i = 0; i < pairCount; ++i) + { + btCollisionAlgorithm* algo = pairs[i].m_algorithm; + if (algo) algo->getAllContactManifolds(m_manifoldsPtr); + } + + // update the indices (used when releasing manifolds) + for (int i = 0; i < m_manifoldsPtr.size(); ++i) + m_manifoldsPtr[i]->m_index1a = i; + } +}; + +#endif + + +#if USE_PARALLEL_ISLAND_SOLVER +/// +/// MyConstraintSolverPool - masquerades as a constraint solver, but really it is a threadsafe pool of them. +/// +/// Each solver in the pool is protected by a mutex. When solveGroup is called from a thread, +/// the pool looks for a solver that isn't being used by another thread, locks it, and dispatches the +/// call to the solver. +/// So long as there are at least as many solvers as there are hardware threads, it should never need to +/// spin wait. +/// +class MyConstraintSolverPool : public btConstraintSolver +{ + const static size_t kCacheLineSize = 128; + struct ThreadSolver + { + btConstraintSolver* solver; + btSpinMutex mutex; + char _cachelinePadding[ kCacheLineSize - sizeof( btSpinMutex ) - sizeof( void* ) ]; // keep mutexes from sharing a cache line + }; + btAlignedObjectArray m_solvers; + btConstraintSolverType m_solverType; + + ThreadSolver* getAndLockThreadSolver() + { + while ( true ) + { + for ( int i = 0; i < m_solvers.size(); ++i ) + { + ThreadSolver& solver = m_solvers[ i ]; + if ( solver.mutex.tryLock() ) + { + return &solver; + } + } + } + return NULL; + } + void init( btConstraintSolver** solvers, int numSolvers ) + { + m_solverType = BT_SEQUENTIAL_IMPULSE_SOLVER; + m_solvers.resize( numSolvers ); + for ( int i = 0; i < numSolvers; ++i ) + { + m_solvers[ i ].solver = solvers[ i ]; + } + if ( numSolvers > 0 ) + { + m_solverType = solvers[ 0 ]->getSolverType(); + } + } +public: + // create the solvers for me + explicit MyConstraintSolverPool( int numSolvers ) + { + btAlignedObjectArray solvers; + solvers.reserve( numSolvers ); + for ( int i = 0; i < numSolvers; ++i ) + { + btConstraintSolver* solver = new btSequentialImpulseConstraintSolver(); + solvers.push_back( solver ); + } + init( &solvers[ 0 ], numSolvers ); + } + + // pass in fully constructed solvers (destructor will delete them) + MyConstraintSolverPool( btConstraintSolver** solvers, int numSolvers ) + { + init( solvers, numSolvers ); + } + virtual ~MyConstraintSolverPool() + { + // delete all solvers + for ( int i = 0; i < m_solvers.size(); ++i ) + { + ThreadSolver& solver = m_solvers[ i ]; + delete solver.solver; + solver.solver = NULL; + } + } + + //virtual void prepareSolve( int /* numBodies */, int /* numManifolds */ ) { ; } // does nothing + + ///solve a group of constraints + virtual btScalar solveGroup( btCollisionObject** bodies, + int numBodies, + btPersistentManifold** manifolds, + int numManifolds, + btTypedConstraint** constraints, + int numConstraints, + const btContactSolverInfo& info, + btIDebugDraw* debugDrawer, + btDispatcher* dispatcher + ) + { + ThreadSolver* solver = getAndLockThreadSolver(); + solver->solver->solveGroup( bodies, numBodies, manifolds, numManifolds, constraints, numConstraints, info, debugDrawer, dispatcher ); + solver->mutex.unlock(); + return 0.0f; + } + + //virtual void allSolved( const btContactSolverInfo& /* info */, class btIDebugDraw* /* debugDrawer */ ) { ; } // does nothing + + ///clear internal cached data and reset random seed + virtual void reset() + { + for ( int i = 0; i < m_solvers.size(); ++i ) + { + ThreadSolver& solver = m_solvers[ i ]; + solver.mutex.lock(); + solver.solver->reset(); + solver.mutex.unlock(); + } + } + + virtual btConstraintSolverType getSolverType() const + { + return m_solverType; + } +}; + +struct UpdateIslandDispatcher +{ + btAlignedObjectArray* islandsPtr; + btSimulationIslandManagerMt::IslandCallback* callback; + + void forLoop( int iBegin, int iEnd ) const + { + for ( int i = iBegin; i < iEnd; ++i ) + { + btSimulationIslandManagerMt::Island* island = ( *islandsPtr )[ i ]; + btPersistentManifold** manifolds = island->manifoldArray.size() ? &island->manifoldArray[ 0 ] : NULL; + btTypedConstraint** constraintsPtr = island->constraintArray.size() ? &island->constraintArray[ 0 ] : NULL; + callback->processIsland( &island->bodyArray[ 0 ], + island->bodyArray.size(), + manifolds, + island->manifoldArray.size(), + constraintsPtr, + island->constraintArray.size(), + island->id + ); + } + } +}; + +static int gNumIslands = 0; + +void parallelIslandDispatch( btAlignedObjectArray* islandsPtr, btSimulationIslandManagerMt::IslandCallback* callback ) +{ + ProfileHelper prof(Profiler::kRecordDispatchIslands); + gNumIslands = islandsPtr->size(); + int grainSize = 1; // iterations per task + UpdateIslandDispatcher dispatcher; + dispatcher.islandsPtr = islandsPtr; + dispatcher.callback = callback; + btPushThreadsAreRunning(); + parallelFor( 0, islandsPtr->size(), grainSize, dispatcher ); + btPopThreadsAreRunning(); +} +#endif //#if USE_PARALLEL_ISLAND_SOLVER + + +void profileBeginCallback(btDynamicsWorld *world, btScalar timeStep) +{ + gProfiler.begin(Profiler::kRecordInternalTimeStep); +} + +void profileEndCallback(btDynamicsWorld *world, btScalar timeStep) +{ + gProfiler.end(Profiler::kRecordInternalTimeStep); +} + +/// +/// MyDiscreteDynamicsWorld +/// +/// Should function exactly like btDiscreteDynamicsWorld. +/// 3 methods that iterate over all of the rigidbodies can run in parallel: +/// - predictUnconstraintMotion +/// - integrateTransforms +/// - createPredictiveContacts +/// +ATTRIBUTE_ALIGNED16( class ) MyDiscreteDynamicsWorld : public btDiscreteDynamicsWorldMt +{ + typedef btDiscreteDynamicsWorld ParentClass; + +protected: +#if USE_PARALLEL_PREDICT_UNCONSTRAINED_MOTION + struct UpdaterUnconstrainedMotion + { + btScalar timeStep; + btRigidBody** rigidBodies; + + void forLoop( int iBegin, int iEnd ) const + { + for ( int i = iBegin; i < iEnd; ++i ) + { + btRigidBody* body = rigidBodies[ i ]; + if ( !body->isStaticOrKinematicObject() ) + { + //don't integrate/update velocities here, it happens in the constraint solver + body->applyDamping( timeStep ); + body->predictIntegratedTransform( timeStep, body->getInterpolationWorldTransform() ); + } + } + } + }; + + virtual void predictUnconstraintMotion( btScalar timeStep ) BT_OVERRIDE + { + ProfileHelper prof( Profiler::kRecordPredictUnconstrainedMotion ); + BT_PROFILE( "predictUnconstraintMotion" ); + int grainSize = 50; // num of iterations per task for TBB + int bodyCount = m_nonStaticRigidBodies.size(); + UpdaterUnconstrainedMotion update; + update.timeStep = timeStep; + update.rigidBodies = bodyCount ? &m_nonStaticRigidBodies[ 0 ] : NULL; + btPushThreadsAreRunning(); + parallelFor( 0, bodyCount, grainSize, update ); + btPopThreadsAreRunning(); + } +#endif // #if USE_PARALLEL_PREDICT_UNCONSTRAINED_MOTION + +#if USE_PARALLEL_CREATE_PREDICTIVE_CONTACTS + struct UpdaterCreatePredictiveContacts + { + btScalar timeStep; + btRigidBody** rigidBodies; + MyDiscreteDynamicsWorld* world; + + void forLoop( int iBegin, int iEnd ) const + { + world->createPredictiveContactsInternal( &rigidBodies[ iBegin ], iEnd - iBegin, timeStep ); + } + }; + + virtual void createPredictiveContacts( btScalar timeStep ) + { + ProfileHelper prof( Profiler::kRecordCreatePredictiveContacts ); + releasePredictiveContacts(); + int grainSize = 50; // num of iterations per task for TBB or OPENMP + if ( int bodyCount = m_nonStaticRigidBodies.size() ) + { + UpdaterCreatePredictiveContacts update; + update.world = this; + update.timeStep = timeStep; + update.rigidBodies = &m_nonStaticRigidBodies[ 0 ]; + btPushThreadsAreRunning(); + parallelFor( 0, bodyCount, grainSize, update ); + btPopThreadsAreRunning(); + } + } +#endif // #if USE_PARALLEL_CREATE_PREDICTIVE_CONTACTS + +#if USE_PARALLEL_INTEGRATE_TRANSFORMS + struct UpdaterIntegrateTransforms + { + btScalar timeStep; + btRigidBody** rigidBodies; + MyDiscreteDynamicsWorld* world; + + void forLoop( int iBegin, int iEnd ) const + { + world->integrateTransformsInternal( &rigidBodies[ iBegin ], iEnd - iBegin, timeStep ); + } + }; + + virtual void integrateTransforms( btScalar timeStep ) BT_OVERRIDE + { + ProfileHelper prof( Profiler::kRecordIntegrateTransforms ); + BT_PROFILE( "integrateTransforms" ); + int grainSize = 50; // num of iterations per task for TBB or OPENMP + if ( int bodyCount = m_nonStaticRigidBodies.size() ) + { + UpdaterIntegrateTransforms update; + update.world = this; + update.timeStep = timeStep; + update.rigidBodies = &m_nonStaticRigidBodies[ 0 ]; + btPushThreadsAreRunning(); + parallelFor( 0, bodyCount, grainSize, update ); + btPopThreadsAreRunning(); + } + } +#endif // #if USE_PARALLEL_INTEGRATE_TRANSFORMS + +public: + BT_DECLARE_ALIGNED_ALLOCATOR(); + + MyDiscreteDynamicsWorld( btDispatcher* dispatcher, + btBroadphaseInterface* pairCache, + btConstraintSolver* constraintSolver, + btCollisionConfiguration* collisionConfiguration + ) : + btDiscreteDynamicsWorldMt( dispatcher, pairCache, constraintSolver, collisionConfiguration ) + { + } + +}; + +static bool gMultithreadedWorld = false; +static bool gDisplayProfileInfo = false; +static btScalar gSliderNumThreads = 1.0f; // should be int +static btScalar gSliderSolverIterations = 10.0f; // should be int + + +//////////////////////////////////// +CommonRigidBodyMTBase::CommonRigidBodyMTBase( struct GUIHelperInterface* helper ) + :m_broadphase( 0 ), + m_dispatcher( 0 ), + m_solver( 0 ), + m_collisionConfiguration( 0 ), + m_dynamicsWorld( 0 ), + m_pickedBody( 0 ), + m_pickedConstraint( 0 ), + m_guiHelper( helper ) +{ + m_multithreadedWorld = false; + m_multithreadCapable = false; + gTaskMgr.init(); +} + +CommonRigidBodyMTBase::~CommonRigidBodyMTBase() +{ + gTaskMgr.shutdown(); +} + +void boolPtrButtonCallback(int buttonId, bool buttonState, void* userPointer) +{ + if (bool* val = static_cast(userPointer)) + { + *val = ! *val; + } +} + +void apiSelectButtonCallback(int buttonId, bool buttonState, void* userPointer) +{ + gTaskMgr.setApi(static_cast(buttonId)); + if (gTaskMgr.getApi()==TaskManager::apiNone) + { + gSliderNumThreads = 1.0f; + } + else + { + gSliderNumThreads = float(gTaskMgr.getNumThreads()); + } +} + +void setThreadCountCallback(float val, void* userPtr) +{ + if (gTaskMgr.getApi()==TaskManager::apiNone) + { + gSliderNumThreads = 1.0f; + } + else + { + gTaskMgr.setNumThreads( int( gSliderNumThreads ) ); + } +} + +void setSolverIterationCountCallback(float val, void* userPtr) +{ + if (btDiscreteDynamicsWorld* world = reinterpret_cast(userPtr)) + { + world->getSolverInfo().m_numIterations = btMax(1, int(gSliderSolverIterations)); + } +} + +void CommonRigidBodyMTBase::createEmptyDynamicsWorld() +{ + gNumIslands = 0; +#if BT_THREADSAFE && (BT_USE_OPENMP || BT_USE_PPL || BT_USE_TBB) + m_multithreadCapable = true; +#endif + if ( gMultithreadedWorld ) + { + m_dispatcher = NULL; + btDefaultCollisionConstructionInfo cci; + cci.m_defaultMaxPersistentManifoldPoolSize = 80000; + cci.m_defaultMaxCollisionAlgorithmPoolSize = 80000; + m_collisionConfiguration = new btDefaultCollisionConfiguration( cci ); + +#if USE_PARALLEL_NARROWPHASE + m_dispatcher = new MyCollisionDispatcher( m_collisionConfiguration ); +#else + m_dispatcher = new btCollisionDispatcher( m_collisionConfiguration ); +#endif //USE_PARALLEL_NARROWPHASE + + m_broadphase = new btDbvtBroadphase(); + +#if USE_PARALLEL_ISLAND_SOLVER + m_solver = new MyConstraintSolverPool( TaskManager::getMaxNumThreads() ); +#else + m_solver = new btSequentialImpulseConstraintSolver(); +#endif //#if USE_PARALLEL_ISLAND_SOLVER + btDiscreteDynamicsWorld* world = new MyDiscreteDynamicsWorld( m_dispatcher, m_broadphase, m_solver, m_collisionConfiguration ); + m_dynamicsWorld = world; + +#if USE_PARALLEL_ISLAND_SOLVER + if ( btSimulationIslandManagerMt* islandMgr = dynamic_cast( world->getSimulationIslandManager() ) ) + { + islandMgr->setIslandDispatchFunction( parallelIslandDispatch ); + m_multithreadedWorld = true; + } +#endif //#if USE_PARALLEL_ISLAND_SOLVER + } + else + { + // single threaded world + m_multithreadedWorld = false; + + ///collision configuration contains default setup for memory, collision setup + m_collisionConfiguration = new btDefaultCollisionConfiguration(); + //m_collisionConfiguration->setConvexConvexMultipointIterations(); + + ///use the default collision dispatcher. For parallel processing you can use a diffent dispatcher (see Extras/BulletMultiThreaded) + m_dispatcher = new btCollisionDispatcher( m_collisionConfiguration ); + + m_broadphase = new btDbvtBroadphase(); + + ///the default constraint solver. For parallel processing you can use a different solver (see Extras/BulletMultiThreaded) + btSequentialImpulseConstraintSolver* sol = new btSequentialImpulseConstraintSolver; + m_solver = sol; + + m_dynamicsWorld = new btDiscreteDynamicsWorld( m_dispatcher, m_broadphase, m_solver, m_collisionConfiguration ); + } + m_dynamicsWorld->setInternalTickCallback( profileBeginCallback, NULL, true ); + m_dynamicsWorld->setInternalTickCallback( profileEndCallback, NULL, false ); + m_dynamicsWorld->setGravity( btVector3( 0, -10, 0 ) ); + createDefaultParameters(); +} + + +void CommonRigidBodyMTBase::createDefaultParameters() +{ + if (m_multithreadCapable) + { + // create a button to toggle multithreaded world + ButtonParams button( "Multithreaded world enable", 0, true ); + button.m_userPointer = &gMultithreadedWorld; + button.m_callback = boolPtrButtonCallback; + m_guiHelper->getParameterInterface()->registerButtonParameter( button ); + } + { + // create a button to toggle profile printing + ButtonParams button( "Display profile timings", 0, true ); + button.m_userPointer = &gDisplayProfileInfo; + button.m_callback = boolPtrButtonCallback; + m_guiHelper->getParameterInterface()->registerButtonParameter( button ); + } + { + SliderParams slider( "Solver iterations", &gSliderSolverIterations ); + slider.m_minVal = 1.0f; + slider.m_maxVal = 30.0f; + slider.m_callback = setSolverIterationCountCallback; + slider.m_userPointer = m_dynamicsWorld; + slider.m_clampToIntegers = true; + m_guiHelper->getParameterInterface()->registerSliderFloatParameter( slider ); + } + if (m_multithreadedWorld) + { + // create a button for each supported threading API + for (int iApi = 0; iApi < TaskManager::apiCount; ++iApi) + { + TaskManager::Api api = static_cast(iApi); + if (gTaskMgr.isSupported(api)) + { + char str[1024]; + sprintf(str, "API %s", gTaskMgr.getApiName(api)); + ButtonParams button( str, iApi, false ); + button.m_callback = apiSelectButtonCallback; + m_guiHelper->getParameterInterface()->registerButtonParameter( button ); + } + } + { + // create a slider to set the number of threads to use + gSliderNumThreads = float(gTaskMgr.getNumThreads()); + SliderParams slider("Thread count", &gSliderNumThreads); + slider.m_minVal = 1.0f; + slider.m_maxVal = float(gTaskMgr.getMaxNumThreads()*2); + slider.m_callback = setThreadCountCallback; + slider.m_clampToIntegers = true; + m_guiHelper->getParameterInterface()->registerSliderFloatParameter( slider ); + } + } +} + +void CommonRigidBodyMTBase::physicsDebugDraw(int debugFlags) +{ + if (m_dynamicsWorld && m_dynamicsWorld->getDebugDrawer()) + { + m_dynamicsWorld->getDebugDrawer()->setDebugMode(debugFlags); + m_dynamicsWorld->debugDrawWorld(); + } + char msg[ 1024 ]; + int xCoord = 400; + int yCoord = 30; + int yStep = 30; + if (m_multithreadCapable) + { + if ( m_multithreadedWorld != gMultithreadedWorld ) + { + sprintf( msg, "restart example to begin in %s mode", + gMultithreadedWorld ? "multithreaded" : "single threaded" + ); + m_guiHelper->getAppInterface()->drawText( msg, 300, yCoord, 0.4f ); + yCoord += yStep; + } + } + if (gDisplayProfileInfo) + { + if ( m_multithreadedWorld ) + { + int numManifolds = m_dispatcher->getNumManifolds(); + int numContacts = 0; + for ( int i = 0; i < numManifolds; ++i ) + { + const btPersistentManifold* man = m_dispatcher->getManifoldByIndexInternal( i ); + numContacts += man->getNumContacts(); + } + const char* mtApi = TaskManager::getApiName( gTaskMgr.getApi() ); + sprintf( msg, "islands=%d bodies=%d manifolds=%d contacts=%d [%s] threads=%d", + gNumIslands, + m_dynamicsWorld->getNumCollisionObjects(), + numManifolds, + numContacts, + mtApi, + gTaskMgr.getApi() == TaskManager::apiNone ? 1 : gTaskMgr.getNumThreads() + ); + m_guiHelper->getAppInterface()->drawText( msg, 100, yCoord, 0.4f ); + yCoord += yStep; + } + + sprintf( msg, "internalSimStep %5.3f ms", + gProfiler.getAverageTime( Profiler::kRecordInternalTimeStep )*0.001f + ); + m_guiHelper->getAppInterface()->drawText( msg, xCoord, yCoord, 0.4f ); + yCoord += yStep; + + if ( m_multithreadedWorld ) + { + sprintf( msg, + "DispatchCollisionPairs %5.3f ms", + gProfiler.getAverageTime( Profiler::kRecordDispatchAllCollisionPairs )*0.001f + ); + m_guiHelper->getAppInterface()->drawText( msg, xCoord, yCoord, 0.4f ); + yCoord += yStep; + + sprintf( msg, + "SolveAllIslands %5.3f ms", + gProfiler.getAverageTime( Profiler::kRecordDispatchIslands )*0.001f + ); + m_guiHelper->getAppInterface()->drawText( msg, xCoord, yCoord, 0.4f ); + yCoord += yStep; + + sprintf( msg, + "PredictUnconstrainedMotion %5.3f ms", + gProfiler.getAverageTime( Profiler::kRecordPredictUnconstrainedMotion )*0.001f + ); + m_guiHelper->getAppInterface()->drawText( msg, xCoord, yCoord, 0.4f ); + yCoord += yStep; + + sprintf( msg, + "CreatePredictiveContacts %5.3f ms", + gProfiler.getAverageTime( Profiler::kRecordCreatePredictiveContacts )*0.001f + ); + m_guiHelper->getAppInterface()->drawText( msg, xCoord, yCoord, 0.4f ); + yCoord += yStep; + + sprintf( msg, + "IntegrateTransforms %5.3f ms", + gProfiler.getAverageTime( Profiler::kRecordIntegrateTransforms )*0.001f + ); + m_guiHelper->getAppInterface()->drawText( msg, xCoord, yCoord, 0.4f ); + yCoord += yStep; + } + } +} + diff --git a/examples/MultiThreadedDemo/CommonRigidBodyMTBase.h b/examples/MultiThreadedDemo/CommonRigidBodyMTBase.h new file mode 100644 index 000000000..7b19bdeaf --- /dev/null +++ b/examples/MultiThreadedDemo/CommonRigidBodyMTBase.h @@ -0,0 +1,438 @@ + +#ifndef COMMON_RIGID_BODY_MT_BASE_H +#define COMMON_RIGID_BODY_MT_BASE_H + + +#include "btBulletDynamicsCommon.h" +#include "../CommonInterfaces/CommonExampleInterface.h" +#include "../CommonInterfaces/CommonGUIHelperInterface.h" +#include "../CommonInterfaces/CommonRenderInterface.h" +#include "../CommonInterfaces/CommonCameraInterface.h" +#include "../CommonInterfaces/CommonGraphicsAppInterface.h" +#include "../CommonInterfaces/CommonWindowInterface.h" + +struct CommonRigidBodyMTBase : public CommonExampleInterface +{ + //keep the collision shapes, for deletion/cleanup + btAlignedObjectArray m_collisionShapes; + btBroadphaseInterface* m_broadphase; + btCollisionDispatcher* m_dispatcher; + btConstraintSolver* m_solver; + btDefaultCollisionConfiguration* m_collisionConfiguration; + btDiscreteDynamicsWorld* m_dynamicsWorld; + bool m_multithreadedWorld; + bool m_multithreadCapable; + + //data for picking objects + class btRigidBody* m_pickedBody; + class btTypedConstraint* m_pickedConstraint; + int m_savedState; + btVector3 m_oldPickingPos; + btVector3 m_hitPos; + btScalar m_oldPickingDist; + struct GUIHelperInterface* m_guiHelper; + + CommonRigidBodyMTBase(struct GUIHelperInterface* helper); + virtual ~CommonRigidBodyMTBase(); + + + btDiscreteDynamicsWorld* getDynamicsWorld() + { + return m_dynamicsWorld; + } + + virtual void createDefaultParameters(); + virtual void createEmptyDynamicsWorld(); + + virtual void stepSimulation(float deltaTime) + { + if (m_dynamicsWorld) + { + m_dynamicsWorld->stepSimulation(deltaTime); + } + } + + virtual void physicsDebugDraw(int debugFlags); + + virtual void exitPhysics() + { + removePickingConstraint(); + //cleanup in the reverse order of creation/initialization + + //remove the rigidbodies from the dynamics world and delete them + + if (m_dynamicsWorld) + { + + int i; + for (i = m_dynamicsWorld->getNumConstraints() - 1; i >= 0; i--) + { + m_dynamicsWorld->removeConstraint(m_dynamicsWorld->getConstraint(i)); + } + for (i = m_dynamicsWorld->getNumCollisionObjects() - 1; i >= 0; i--) + { + btCollisionObject* obj = m_dynamicsWorld->getCollisionObjectArray()[i]; + btRigidBody* body = btRigidBody::upcast(obj); + if (body && body->getMotionState()) + { + delete body->getMotionState(); + } + m_dynamicsWorld->removeCollisionObject(obj); + delete obj; + } + } + //delete collision shapes + for (int j = 0; jgetDebugDrawer()) + { + m_dynamicsWorld->getDebugDrawer()->setDebugMode(debugDrawFlags); + } + m_dynamicsWorld->debugDrawWorld(); + } + + } + + virtual bool keyboardCallback(int key, int state) + { + if ((key==B3G_F3) && state && m_dynamicsWorld) + { + btDefaultSerializer* serializer = new btDefaultSerializer(); + m_dynamicsWorld->serialize(serializer); + + FILE* file = fopen("testFile.bullet","wb"); + fwrite(serializer->getBufferPointer(),serializer->getCurrentBufferSize(),1, file); + fclose(file); + //b3Printf("btDefaultSerializer wrote testFile.bullet"); + delete serializer; + return true; + + } + return false;//don't handle this key + } + + + btVector3 getRayTo(int x,int y) + { + CommonRenderInterface* renderer = m_guiHelper->getRenderInterface(); + + if (!renderer) + { + btAssert(0); + return btVector3(0,0,0); + } + + float top = 1.f; + float bottom = -1.f; + float nearPlane = 1.f; + float tanFov = (top-bottom)*0.5f / nearPlane; + float fov = btScalar(2.0) * btAtan(tanFov); + + btVector3 camPos,camTarget; + + renderer->getActiveCamera()->getCameraPosition(camPos); + renderer->getActiveCamera()->getCameraTargetPosition(camTarget); + + btVector3 rayFrom = camPos; + btVector3 rayForward = (camTarget-camPos); + rayForward.normalize(); + float farPlane = 10000.f; + rayForward*= farPlane; + + btVector3 rightOffset; + btVector3 cameraUp=btVector3(0,0,0); + cameraUp[m_guiHelper->getAppInterface()->getUpAxis()]=1; + + btVector3 vertical = cameraUp; + + btVector3 hor; + hor = rayForward.cross(vertical); + hor.safeNormalize(); + vertical = hor.cross(rayForward); + vertical.safeNormalize(); + + float tanfov = tanf(0.5f*fov); + + + hor *= 2.f * farPlane * tanfov; + vertical *= 2.f * farPlane * tanfov; + + btScalar aspect; + float width = float(renderer->getScreenWidth()); + float height = float (renderer->getScreenHeight()); + + aspect = width / height; + + hor*=aspect; + + + btVector3 rayToCenter = rayFrom + rayForward; + btVector3 dHor = hor * 1.f/width; + btVector3 dVert = vertical * 1.f/height; + + + btVector3 rayTo = rayToCenter - 0.5f * hor + 0.5f * vertical; + rayTo += btScalar(x) * dHor; + rayTo -= btScalar(y) * dVert; + return rayTo; + } + + virtual bool mouseMoveCallback(float x,float y) + { + CommonRenderInterface* renderer = m_guiHelper->getRenderInterface(); + + if (!renderer) + { + btAssert(0); + return false; + } + + btVector3 rayTo = getRayTo(int(x), int(y)); + btVector3 rayFrom; + renderer->getActiveCamera()->getCameraPosition(rayFrom); + movePickedBody(rayFrom,rayTo); + + return false; + } + + virtual bool mouseButtonCallback(int button, int state, float x, float y) + { + CommonRenderInterface* renderer = m_guiHelper->getRenderInterface(); + + if (!renderer) + { + btAssert(0); + return false; + } + + CommonWindowInterface* window = m_guiHelper->getAppInterface()->m_window; + +#if 0 + if (window->isModifierKeyPressed(B3G_ALT)) + { + printf("ALT pressed\n"); + } else + { + printf("NO ALT pressed\n"); + } + + if (window->isModifierKeyPressed(B3G_SHIFT)) + { + printf("SHIFT pressed\n"); + } else + { + printf("NO SHIFT pressed\n"); + } + + if (window->isModifierKeyPressed(B3G_CONTROL)) + { + printf("CONTROL pressed\n"); + } else + { + printf("NO CONTROL pressed\n"); + } +#endif + + + if (state==1) + { + if(button==0 && (!window->isModifierKeyPressed(B3G_ALT) && !window->isModifierKeyPressed(B3G_CONTROL) )) + { + btVector3 camPos; + renderer->getActiveCamera()->getCameraPosition(camPos); + + btVector3 rayFrom = camPos; + btVector3 rayTo = getRayTo(int(x),int(y)); + + pickBody(rayFrom, rayTo); + + + } + } else + { + if (button==0) + { + removePickingConstraint(); + //remove p2p + } + } + + //printf("button=%d, state=%d\n",button,state); + return false; + } + + + virtual bool pickBody(const btVector3& rayFromWorld, const btVector3& rayToWorld) + { + if (m_dynamicsWorld==0) + return false; + + btCollisionWorld::ClosestRayResultCallback rayCallback(rayFromWorld, rayToWorld); + + m_dynamicsWorld->rayTest(rayFromWorld, rayToWorld, rayCallback); + if (rayCallback.hasHit()) + { + + btVector3 pickPos = rayCallback.m_hitPointWorld; + btRigidBody* body = (btRigidBody*)btRigidBody::upcast(rayCallback.m_collisionObject); + if (body) + { + //other exclusions? + if (!(body->isStaticObject() || body->isKinematicObject())) + { + m_pickedBody = body; + m_savedState = m_pickedBody->getActivationState(); + m_pickedBody->setActivationState(DISABLE_DEACTIVATION); + //printf("pickPos=%f,%f,%f\n",pickPos.getX(),pickPos.getY(),pickPos.getZ()); + btVector3 localPivot = body->getCenterOfMassTransform().inverse() * pickPos; + btPoint2PointConstraint* p2p = new btPoint2PointConstraint(*body, localPivot); + m_dynamicsWorld->addConstraint(p2p, true); + m_pickedConstraint = p2p; + btScalar mousePickClamping = 30.f; + p2p->m_setting.m_impulseClamp = mousePickClamping; + //very weak constraint for picking + p2p->m_setting.m_tau = 0.001f; + } + } + + + // pickObject(pickPos, rayCallback.m_collisionObject); + m_oldPickingPos = rayToWorld; + m_hitPos = pickPos; + m_oldPickingDist = (pickPos - rayFromWorld).length(); + // printf("hit !\n"); + //add p2p + } + return false; + } + virtual bool movePickedBody(const btVector3& rayFromWorld, const btVector3& rayToWorld) + { + if (m_pickedBody && m_pickedConstraint) + { + btPoint2PointConstraint* pickCon = static_cast(m_pickedConstraint); + if (pickCon) + { + //keep it at the same picking distance + + btVector3 newPivotB; + + btVector3 dir = rayToWorld - rayFromWorld; + dir.normalize(); + dir *= m_oldPickingDist; + + newPivotB = rayFromWorld + dir; + pickCon->setPivotB(newPivotB); + return true; + } + } + return false; + } + virtual void removePickingConstraint() + { + if (m_pickedConstraint) + { + m_pickedBody->forceActivationState(m_savedState); + m_pickedBody->activate(); + m_dynamicsWorld->removeConstraint(m_pickedConstraint); + delete m_pickedConstraint; + m_pickedConstraint = 0; + m_pickedBody = 0; + } + } + + + + btBoxShape* createBoxShape(const btVector3& halfExtents) + { + btBoxShape* box = new btBoxShape(halfExtents); + return box; + } + + btRigidBody* createRigidBody(float mass, const btTransform& startTransform, btCollisionShape* shape, const btVector4& color = btVector4(1, 0, 0, 1)) + { + btAssert((!shape || shape->getShapeType() != INVALID_SHAPE_PROXYTYPE)); + + //rigidbody is dynamic if and only if mass is non zero, otherwise static + bool isDynamic = (mass != 0.f); + + btVector3 localInertia(0, 0, 0); + if (isDynamic) + shape->calculateLocalInertia(mass, localInertia); + + //using motionstate is recommended, it provides interpolation capabilities, and only synchronizes 'active' objects + +#define USE_MOTIONSTATE 1 +#ifdef USE_MOTIONSTATE + btDefaultMotionState* myMotionState = new btDefaultMotionState(startTransform); + + btRigidBody::btRigidBodyConstructionInfo cInfo(mass, myMotionState, shape, localInertia); + + btRigidBody* body = new btRigidBody(cInfo); + //body->setContactProcessingThreshold(m_defaultContactProcessingThreshold); + +#else + btRigidBody* body = new btRigidBody(mass, 0, shape, localInertia); + body->setWorldTransform(startTransform); +#endif// + + body->setUserIndex(-1); + m_dynamicsWorld->addRigidBody(body); + return body; + } + + btRigidBody* createKinematicBody(const btTransform& startTransform, btCollisionShape* shape) + { + btAssert( ( !shape || shape->getShapeType() != INVALID_SHAPE_PROXYTYPE ) ); + + btRigidBody* body = new btRigidBody( 0.0f, NULL, shape ); + body->setWorldTransform( startTransform ); + body->setCollisionFlags( body->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT ); + body->setUserIndex( -1 ); + m_dynamicsWorld->addRigidBody( body ); + return body; + } + + + virtual void renderScene() + { + { + + m_guiHelper->syncPhysicsToGraphics(m_dynamicsWorld); + } + + { + + m_guiHelper->render(m_dynamicsWorld); + } + } +}; + +#endif //#define COMMON_RIGID_BODY_MT_BASE_H + + diff --git a/examples/MultiThreadedDemo/MultiThreadedDemo.cpp b/examples/MultiThreadedDemo/MultiThreadedDemo.cpp new file mode 100644 index 000000000..3dff09ae8 --- /dev/null +++ b/examples/MultiThreadedDemo/MultiThreadedDemo.cpp @@ -0,0 +1,281 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#include "btBulletDynamicsCommon.h" +#include "LinearMath/btQuickprof.h" +#include "LinearMath/btIDebugDraw.h" +#include "../CommonInterfaces/CommonParameterInterface.h" +#include //printf debugging +#include + +class btCollisionShape; + +#include "CommonRigidBodyMTBase.h" +#include "MultiThreadedDemo.h" +#include "LinearMath/btAlignedObjectArray.h" +#include "btBulletCollisionCommon.h" + + +#define BT_OVERRIDE + +static btScalar gSliderStackRows = 8.0f; +static btScalar gSliderStackColumns = 6.0f; +static btScalar gSliderStackHeight = 15.0f; +static btScalar gSliderGroundHorizontalAmplitude = 0.0f; +static btScalar gSliderGroundVerticalAmplitude = 0.0f; + + +/// MultiThreadedDemo shows how to setup and use multithreading +class MultiThreadedDemo : public CommonRigidBodyMTBase +{ + static const int kUpAxis = 1; + + btRigidBody* localCreateRigidBody(btScalar mass, const btTransform& worldTransform, btCollisionShape* colSape); + + btVector3 m_cameraTargetPos; + float m_cameraPitch; + float m_cameraYaw; + float m_cameraDist; + btRigidBody* m_groundBody; + btTransform m_groundStartXf; + float m_groundMovePhase; + + void createStack( const btVector3& pos, btCollisionShape* boxShape, const btVector3& halfBoxSize, int size ); + void createSceneObjects(); + void destroySceneObjects(); + +public: + BT_DECLARE_ALIGNED_ALLOCATOR(); + + MultiThreadedDemo( struct GUIHelperInterface* helper ); + + virtual ~MultiThreadedDemo() {} + + virtual void stepSimulation( float deltaTime ) BT_OVERRIDE + { + if ( m_dynamicsWorld ) + { + if (m_groundBody) + { + // update ground + const float cyclesPerSecond = 1.0f; + m_groundMovePhase += cyclesPerSecond * deltaTime; + m_groundMovePhase -= floor( m_groundMovePhase ); // keep phase between 0 and 1 + btTransform xf = m_groundStartXf; + float gndHOffset = btSin(m_groundMovePhase * SIMD_2_PI) * gSliderGroundHorizontalAmplitude; + float gndHVel = btCos(m_groundMovePhase * SIMD_2_PI) * gSliderGroundHorizontalAmplitude * cyclesPerSecond * SIMD_2_PI; // d(gndHOffset)/dt + float gndVOffset = btSin(m_groundMovePhase * SIMD_2_PI) * gSliderGroundVerticalAmplitude; + float gndVVel = btCos(m_groundMovePhase * SIMD_2_PI) * gSliderGroundVerticalAmplitude * cyclesPerSecond * SIMD_2_PI; // d(gndVOffset)/dt + btVector3 offset(0,0,0); + btVector3 vel(0,0,0); + int horizAxis = 2; + offset[horizAxis] = gndHOffset; + vel[horizAxis] = gndHVel; + offset[kUpAxis] = gndVOffset; + vel[kUpAxis] = gndVVel; + xf.setOrigin(xf.getOrigin() + offset); + m_groundBody->setWorldTransform( xf ); + m_groundBody->setLinearVelocity( vel ); + } + // always step by 1/60 for benchmarking + m_dynamicsWorld->stepSimulation( 1.0f / 60.0f, 0 ); + } + } + + virtual void initPhysics() BT_OVERRIDE; + virtual void resetCamera() BT_OVERRIDE + { + m_guiHelper->resetCamera( m_cameraDist, + m_cameraPitch, + m_cameraYaw, + m_cameraTargetPos.x(), + m_cameraTargetPos.y(), + m_cameraTargetPos.z() + ); + } + +}; + + +MultiThreadedDemo::MultiThreadedDemo(struct GUIHelperInterface* helper) + : CommonRigidBodyMTBase( helper ) +{ + m_groundBody = NULL; + m_groundMovePhase = 0.0f; + m_cameraTargetPos = btVector3( 0.0f, 0.0f, 0.0f ); + m_cameraPitch = 90.0f; + m_cameraYaw = 30.0f; + m_cameraDist = 48.0f; + helper->setUpAxis( kUpAxis ); +} + + +void MultiThreadedDemo::initPhysics() +{ + createEmptyDynamicsWorld(); + + m_dynamicsWorld->setGravity( btVector3( 0, -10, 0 ) ); + + { + SliderParams slider( "Stack height", &gSliderStackHeight ); + slider.m_minVal = 1.0f; + slider.m_maxVal = 30.0f; + slider.m_clampToIntegers = true; + m_guiHelper->getParameterInterface()->registerSliderFloatParameter( slider ); + } + { + SliderParams slider( "Stack rows", &gSliderStackRows ); + slider.m_minVal = 1.0f; + slider.m_maxVal = 20.0f; + slider.m_clampToIntegers = true; + m_guiHelper->getParameterInterface()->registerSliderFloatParameter( slider ); + } + { + SliderParams slider( "Stack columns", &gSliderStackColumns ); + slider.m_minVal = 1.0f; + slider.m_maxVal = 20.0f; + slider.m_clampToIntegers = true; + m_guiHelper->getParameterInterface()->registerSliderFloatParameter( slider ); + } + { + // horizontal ground shake + SliderParams slider( "Ground horiz amp", &gSliderGroundHorizontalAmplitude ); + slider.m_minVal = 0.0f; + slider.m_maxVal = 1.0f; + slider.m_clampToNotches = false; + m_guiHelper->getParameterInterface()->registerSliderFloatParameter( slider ); + } + { + // vertical ground shake + SliderParams slider( "Ground vert amp", &gSliderGroundVerticalAmplitude ); + slider.m_minVal = 0.0f; + slider.m_maxVal = 1.0f; + slider.m_clampToNotches = false; + m_guiHelper->getParameterInterface()->registerSliderFloatParameter( slider ); + } + + createSceneObjects(); + + m_guiHelper->createPhysicsDebugDrawer( m_dynamicsWorld ); +} + + + +btRigidBody* MultiThreadedDemo::localCreateRigidBody(btScalar mass, const btTransform& startTransform, btCollisionShape* shape) +{ + btRigidBody* body = createRigidBody(mass, startTransform, shape); + if ( mass > 0.0f ) + { + // prevent bodies from sleeping to make profiling/benchmarking easier + body->forceActivationState( DISABLE_DEACTIVATION ); + } + return body; +} + + +void MultiThreadedDemo::createStack( const btVector3& center, btCollisionShape* boxShape, const btVector3& halfBoxSize, int size ) +{ + btTransform trans; + trans.setIdentity(); + float halfBoxHeight = halfBoxSize.y(); + float halfBoxWidth = halfBoxSize.x(); + + for ( int i = 0; isetFriction(1.0f); + } + } +} + + +void MultiThreadedDemo::createSceneObjects() +{ + { + // create ground box + btTransform tr; + tr.setIdentity(); + tr.setOrigin( btVector3( 0.f, -3.f, 0.f ) ); + m_groundStartXf = tr; + + //either use heightfield or triangle mesh + + btVector3 groundExtents( 400, 400, 400 ); + groundExtents[ kUpAxis ] = 3; + btCollisionShape* groundShape = new btBoxShape( groundExtents ); + m_collisionShapes.push_back( groundShape ); + + //create ground object + m_groundBody = createKinematicBody( m_groundStartXf, groundShape ); + m_groundBody->forceActivationState( DISABLE_DEACTIVATION ); + m_groundBody->setFriction(1.0f); + } + + { + // create walls of cubes + const btVector3 halfExtents = btVector3( 0.5f, 0.25f, 0.5f ); + int numStackRows = btMax(1, int(gSliderStackRows)); + int numStackCols = btMax(1, int(gSliderStackColumns)); + int stackHeight = 15; + float stackZSpacing = 3.0f; + float stackXSpacing = 20.0f; + + btBoxShape* boxShape = new btBoxShape( halfExtents ); + m_collisionShapes.push_back( boxShape ); + + for ( int iX = 0; iX < numStackCols; ++iX ) + { + for ( int iZ = 0; iZ < numStackRows; ++iZ ) + { + btVector3 center = btVector3( iX * stackXSpacing, 0.0f, ( iZ - numStackRows / 2 ) * stackZSpacing ); + createStack( center, boxShape, halfExtents, stackHeight ); + } + } + } +#if 0 + if ( false ) + { + // destroyer ball + btTransform sphereTrans; + sphereTrans.setIdentity(); + sphereTrans.setOrigin( btVector3( 0, 2, 40 ) ); + btSphereShape* ball = new btSphereShape( 2.f ); + m_collisionShapes.push_back( ball ); + btRigidBody* ballBody = localCreateRigidBody( 10000.f, sphereTrans, ball ); + ballBody->setLinearVelocity( btVector3( 0, 0, -10 ) ); + } +#endif + m_guiHelper->autogenerateGraphicsObjects( m_dynamicsWorld ); + +} + + +CommonExampleInterface* MultiThreadedDemoCreateFunc( struct CommonExampleOptions& options ) +{ + return new MultiThreadedDemo(options.m_guiHelper); +} + diff --git a/examples/MultiThreadedDemo/MultiThreadedDemo.h b/examples/MultiThreadedDemo/MultiThreadedDemo.h new file mode 100644 index 000000000..0075e81e7 --- /dev/null +++ b/examples/MultiThreadedDemo/MultiThreadedDemo.h @@ -0,0 +1,22 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ +#ifndef MULTITHREADED_DEMO_H +#define MULTITHREADED_DEMO_H + +class CommonExampleInterface* MultiThreadedDemoCreateFunc(struct CommonExampleOptions& options); + +#endif // MULTITHREADED_DEMO_H + + diff --git a/examples/MultiThreadedDemo/ParallelFor.h b/examples/MultiThreadedDemo/ParallelFor.h new file mode 100644 index 000000000..77f6dfe39 --- /dev/null +++ b/examples/MultiThreadedDemo/ParallelFor.h @@ -0,0 +1,336 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#include //printf debugging +#include + + +// choose threading providers: +#if BT_USE_TBB +#define USE_TBB 1 // use Intel Threading Building Blocks for thread management +#endif + +#if BT_USE_PPL +#define USE_PPL 1 // use Microsoft Parallel Patterns Library (installed with Visual Studio 2010 and later) +#endif // BT_USE_PPL + +#if BT_USE_OPENMP +#define USE_OPENMP 1 // use OpenMP (also need to change compiler options for OpenMP support) +#endif + + +#if USE_OPENMP + +#include + +#endif // #if USE_OPENMP + + +#if USE_PPL + +#include // if you get a compile error here, check whether your version of Visual Studio includes PPL +// Visual Studio 2010 and later should come with it +#include // for GetProcessorCount() +#endif // #if USE_PPL + + +#if USE_TBB + +#define __TBB_NO_IMPLICIT_LINKAGE 1 +#include +#include +#include +#include + +#endif // #if USE_TBB + + + +class TaskManager +{ +public: + enum Api + { + apiNone, + apiOpenMP, + apiTbb, + apiPpl, + apiCount + }; + static const char* getApiName( Api api ) + { + switch ( api ) + { + case apiNone: return "None"; + case apiOpenMP: return "OpenMP"; + case apiTbb: return "Intel TBB"; + case apiPpl: return "MS PPL"; + default: return "unknown"; + } + } + + TaskManager() + { + m_api = apiNone; + m_numThreads = 0; +#if USE_TBB + m_tbbSchedulerInit = NULL; +#endif // #if USE_TBB + } + + Api getApi() const + { + return m_api; + } + + bool isSupported( Api api ) const + { +#if USE_OPENMP + if ( api == apiOpenMP ) + { + return true; + } +#endif +#if USE_TBB + if ( api == apiTbb ) + { + return true; + } +#endif +#if USE_PPL + if ( api == apiPpl ) + { + return true; + } +#endif + // apiNone is always "supported" + return api == apiNone; + } + + void setApi( Api api ) + { + if (isSupported(api)) + { + m_api = api; + } + else + { + // no compile time support for selected API, fallback to "none" + m_api = apiNone; + } + } + + static int getMaxNumThreads() + { +#if USE_OPENMP + return omp_get_max_threads(); +#elif USE_PPL + return concurrency::GetProcessorCount(); +#elif USE_TBB + return tbb::task_scheduler_init::default_num_threads(); +#endif + return 1; + } + + int getNumThreads() const + { + return m_numThreads; + } + + int setNumThreads( int numThreads ) + { + m_numThreads = ( std::max )( 1, numThreads ); + +#if USE_OPENMP + omp_set_num_threads( m_numThreads ); +#endif + +#if USE_PPL + { + using namespace concurrency; + if ( CurrentScheduler::Id() != -1 ) + { + CurrentScheduler::Detach(); + } + SchedulerPolicy policy; + policy.SetConcurrencyLimits( m_numThreads, m_numThreads ); + CurrentScheduler::Create( policy ); + } +#endif + +#if USE_TBB + if ( m_tbbSchedulerInit ) + { + delete m_tbbSchedulerInit; + m_tbbSchedulerInit = NULL; + } + m_tbbSchedulerInit = new tbb::task_scheduler_init( m_numThreads ); +#endif + return m_numThreads; + } + + void init() + { + if (m_numThreads == 0) + { +#if USE_PPL + setApi( apiPpl ); +#endif +#if USE_TBB + setApi( apiTbb ); +#endif +#if USE_OPENMP + setApi( apiOpenMP ); +#endif + setNumThreads(getMaxNumThreads()); + } + else + { + setNumThreads(m_numThreads); + } + } + + void shutdown() + { +#if USE_TBB + if ( m_tbbSchedulerInit ) + { + delete m_tbbSchedulerInit; + m_tbbSchedulerInit = NULL; + } +#endif + } + +private: + Api m_api; + int m_numThreads; +#if USE_TBB + tbb::task_scheduler_init* m_tbbSchedulerInit; +#endif // #if USE_TBB +}; + +extern TaskManager gTaskMgr; + + +static void initTaskScheduler() +{ + gTaskMgr.init(); +} + +static void cleanupTaskScheduler() +{ + gTaskMgr.shutdown(); +} + + +#if USE_TBB +/// +/// TbbBodyAdapter -- Converts a body object that implements the +/// "forLoop(int iBegin, int iEnd) const" function +/// into a TBB compatible object that takes a tbb::blocked_range type. +/// +template +struct TbbBodyAdapter +{ + const TBody* mBody; + + void operator()( const tbb::blocked_range& range ) const + { + mBody->forLoop( range.begin(), range.end() ); + } +}; +#endif // #if USE_TBB + +#if USE_PPL +/// +/// PplBodyAdapter -- Converts a body object that implements the +/// "forLoop(int iBegin, int iEnd) const" function +/// into a PPL compatible object that implements "void operator()( int ) const" +/// +template +struct PplBodyAdapter +{ + const TBody* mBody; + int mGrainSize; + int mIndexEnd; + + void operator()( int i ) const + { + mBody->forLoop( i, (std::min)(i + mGrainSize, mIndexEnd) ); + } +}; +#endif // #if USE_PPL + + +/// +/// parallelFor -- interface for submitting work expressed as a for loop to the worker threads +/// +template +void parallelFor( int iBegin, int iEnd, int grainSize, const TBody& body ) +{ +#if USE_OPENMP + if ( gTaskMgr.getApi() == TaskManager::apiOpenMP ) + { +#pragma omp parallel for schedule(static, 1) + for ( int i = iBegin; i < iEnd; i += grainSize ) + { + body.forLoop( i, (std::min)( i + grainSize, iEnd ) ); + } + return; + } +#endif // #if USE_OPENMP + +#if USE_PPL + if ( gTaskMgr.getApi() == TaskManager::apiPpl ) + { + // PPL dispatch + PplBodyAdapter pplBody; + pplBody.mBody = &body; + pplBody.mGrainSize = grainSize; + pplBody.mIndexEnd = iEnd; + // note: MSVC 2010 doesn't support partitioner args, so avoid them + concurrency::parallel_for( iBegin, + iEnd, + grainSize, + pplBody + ); + return; + } +#endif //#if USE_PPL + +#if USE_TBB + if ( gTaskMgr.getApi() == TaskManager::apiTbb ) + { + // TBB dispatch + TbbBodyAdapter tbbBody; + tbbBody.mBody = &body; + tbb::parallel_for( tbb::blocked_range( iBegin, iEnd, grainSize ), + tbbBody, + tbb::simple_partitioner() + ); + return; + } +#endif // #if USE_TBB + + { + // run on main thread + body.forLoop( iBegin, iEnd ); + } + +} + + + + diff --git a/examples/MultiThreading/MultiThreadingExample.cpp b/examples/MultiThreading/MultiThreadingExample.cpp index 1969912b9..33eb0e751 100644 --- a/examples/MultiThreading/MultiThreadingExample.cpp +++ b/examples/MultiThreading/MultiThreadingExample.cpp @@ -11,6 +11,7 @@ #include "stb_image/stb_image.h" #include "Bullet3Common/b3Quaternion.h" #include "Bullet3Common/b3Matrix3x3.h" +#include "../Utils/b3Clock.h" #include "../CommonInterfaces/CommonParameterInterface.h" #include "LinearMath/btAlignedObjectArray.h" @@ -134,6 +135,8 @@ void SampleThreadFunc(void* userPtr,void* lsMemory) job->executeJob(localStorage->threadId); } + b3Clock::usleep(250); + args->m_cs->lock(); int exitMagicNumber = args->m_cs->getSharedParam(1); requestExit = (exitMagicNumber==MAGIC_RESET_NUMBER); diff --git a/examples/OpenCL/rigidbody/GpuRigidBodyDemo.cpp b/examples/OpenCL/rigidbody/GpuRigidBodyDemo.cpp index d2ee9794a..c7b821dbf 100644 --- a/examples/OpenCL/rigidbody/GpuRigidBodyDemo.cpp +++ b/examples/OpenCL/rigidbody/GpuRigidBodyDemo.cpp @@ -80,7 +80,18 @@ m_window(0) m_window = helper->getAppInterface()->m_window; m_data = new GpuRigidBodyDemoInternalData; + m_data->m_guiHelper = helper; } + +void GpuRigidBodyDemo::resetCamera() +{ + float dist = 114; + float pitch = 52; + float yaw = 35; + float targetPos[3]={0,0,0}; + m_data->m_guiHelper->resetCamera(dist,pitch,yaw,targetPos[0],targetPos[1],targetPos[2]); +} + GpuRigidBodyDemo::~GpuRigidBodyDemo() { diff --git a/examples/OpenCL/rigidbody/GpuRigidBodyDemo.h b/examples/OpenCL/rigidbody/GpuRigidBodyDemo.h index 7e58b9e7d..a62fdab9e 100644 --- a/examples/OpenCL/rigidbody/GpuRigidBodyDemo.h +++ b/examples/OpenCL/rigidbody/GpuRigidBodyDemo.h @@ -31,7 +31,8 @@ public: virtual void renderScene(); - + void resetCamera(); + virtual void stepSimulation(float deltaTime); //for picking diff --git a/examples/OpenCL/rigidbody/GpuRigidBodyDemoInternalData.h b/examples/OpenCL/rigidbody/GpuRigidBodyDemoInternalData.h index 9147a5080..8c7b5f5bb 100644 --- a/examples/OpenCL/rigidbody/GpuRigidBodyDemoInternalData.h +++ b/examples/OpenCL/rigidbody/GpuRigidBodyDemoInternalData.h @@ -32,6 +32,7 @@ struct GpuRigidBodyDemoInternalData int m_pickGraphicsShapeIndex; int m_pickGraphicsShapeInstance; b3Config m_config; + GUIHelperInterface* m_guiHelper; GpuRigidBodyDemoInternalData() :m_instancePosOrnColor(0), @@ -45,7 +46,8 @@ struct GpuRigidBodyDemoInternalData m_pickGraphicsShapeInstance(-1), m_pickBody(-1), m_altPressed(0), - m_controlPressed(0) + m_controlPressed(0), + m_guiHelper(0) { } diff --git a/examples/OpenGLWindow/GLInstancingRenderer.cpp b/examples/OpenGLWindow/GLInstancingRenderer.cpp index 718a9fc60..c6f620bab 100644 --- a/examples/OpenGLWindow/GLInstancingRenderer.cpp +++ b/examples/OpenGLWindow/GLInstancingRenderer.cpp @@ -17,9 +17,9 @@ subject to the following restrictions: ///todo: make this configurable in the gui bool useShadowMap = true;// true;//false;//true; -int shadowMapWidth= 2048; -int shadowMapHeight= 2048; -float shadowMapWorldSize=5; +int shadowMapWidth= 4096; +int shadowMapHeight= 4096; +float shadowMapWorldSize=10; #define MAX_POINTS_IN_BATCH 1024 #define MAX_LINES_IN_BATCH 1024 @@ -1539,7 +1539,7 @@ void GLInstancingRenderer::renderSceneInternal(int renderMode) b3Assert(glGetError() ==GL_NO_ERROR); } else { - //glDisable(GL_CULL_FACE); + glEnable(GL_CULL_FACE); glCullFace(GL_BACK); } diff --git a/examples/OpenGLWindow/SimpleOpenGL2App.cpp b/examples/OpenGLWindow/SimpleOpenGL2App.cpp index 62f8aba16..710b9fdab 100644 --- a/examples/OpenGLWindow/SimpleOpenGL2App.cpp +++ b/examples/OpenGLWindow/SimpleOpenGL2App.cpp @@ -70,6 +70,11 @@ struct SimpleOpenGL2AppInternalData { GLuint m_fontTextureId; GLuint m_largeFontTextureId; + int m_upAxis; + SimpleOpenGL2AppInternalData() + :m_upAxis(1) + { + } }; static GLuint BindFont2(const CTexFont *_Font) @@ -268,10 +273,11 @@ void SimpleOpenGL2App::drawGrid(DrawGridData data) } void SimpleOpenGL2App::setUpAxis(int axis) { + this->m_data->m_upAxis = axis; } int SimpleOpenGL2App::getUpAxis() const { - return 1; + return this->m_data->m_upAxis; } void SimpleOpenGL2App::swapBuffer() @@ -280,7 +286,7 @@ void SimpleOpenGL2App::swapBuffer() m_window->startRendering(); } -void SimpleOpenGL2App::drawText( const char* txt, int posX, int posY) +void SimpleOpenGL2App::drawText( const char* txt, int posX, int posY, float size) { } diff --git a/examples/OpenGLWindow/SimpleOpenGL2App.h b/examples/OpenGLWindow/SimpleOpenGL2App.h index 960dc1d07..3b8a54a5b 100644 --- a/examples/OpenGLWindow/SimpleOpenGL2App.h +++ b/examples/OpenGLWindow/SimpleOpenGL2App.h @@ -17,7 +17,7 @@ public: virtual int getUpAxis() const; virtual void swapBuffer(); - virtual void drawText( const char* txt, int posX, int posY); + virtual void drawText( const char* txt, int posX, int posY, float size); virtual void drawTexturedRect(float x0, float y0, float x1, float y1, float color[4], float u0,float v0, float u1, float v1, int useRGBA){}; virtual void setBackgroundColor(float red, float green, float blue); virtual int registerCubeShape(float halfExtentsX,float halfExtentsY, float halfExtentsZ, int textureIndex = -1, float textureScaling = 1) diff --git a/examples/OpenGLWindow/SimpleOpenGL2Renderer.cpp b/examples/OpenGLWindow/SimpleOpenGL2Renderer.cpp index 050ec447e..d69b63d54 100644 --- a/examples/OpenGLWindow/SimpleOpenGL2Renderer.cpp +++ b/examples/OpenGLWindow/SimpleOpenGL2Renderer.cpp @@ -33,6 +33,7 @@ void SimpleOpenGL2Renderer::updateCamera(int upAxis) float projection[16]; float view[16]; m_camera.setAspectRatio((float)m_width/(float)m_height); + m_camera.setCameraUpAxis(upAxis); m_camera.update(); m_camera.getCameraProjectionMatrix(projection); m_camera.getCameraViewMatrix(view); diff --git a/examples/OpenGLWindow/SimpleOpenGL3App.cpp b/examples/OpenGLWindow/SimpleOpenGL3App.cpp index 6abcd2185..aea665019 100644 --- a/examples/OpenGLWindow/SimpleOpenGL3App.cpp +++ b/examples/OpenGLWindow/SimpleOpenGL3App.cpp @@ -352,7 +352,7 @@ void SimpleOpenGL3App::drawText3D( const char* txt, float worldPosX, float world } -void SimpleOpenGL3App::drawText( const char* txt, int posXi, int posYi) +void SimpleOpenGL3App::drawText( const char* txt, int posXi, int posYi, float size) { float posX = (float)posXi; @@ -374,7 +374,7 @@ void SimpleOpenGL3App::drawText( const char* txt, int posXi, int posYi) { bool measureOnly = false; - float fontSize= 64;//512;//128; + float fontSize= 64*size;//512;//128; sth_draw_text(m_data->m_fontStash, m_data->m_droidRegular,fontSize,posX,posY, txt,&dx, this->m_instancingRenderer->getScreenWidth(), diff --git a/examples/OpenGLWindow/SimpleOpenGL3App.h b/examples/OpenGLWindow/SimpleOpenGL3App.h index 8a3f477f6..6902dacf8 100644 --- a/examples/OpenGLWindow/SimpleOpenGL3App.h +++ b/examples/OpenGLWindow/SimpleOpenGL3App.h @@ -31,7 +31,7 @@ struct SimpleOpenGL3App : public CommonGraphicsApp virtual int getUpAxis() const; virtual void swapBuffer(); - virtual void drawText( const char* txt, int posX, int posY); + virtual void drawText( const char* txt, int posX, int posY, float size=1.0f); virtual void drawText3D( const char* txt, float posX, float posZY, float posZ, float size); virtual void drawTexturedRect(float x0, float y0, float x1, float y1, float color[4], float u0,float v0, float u1, float v1, int useRGBA); struct sth_stash* getFontStash(); diff --git a/examples/Raycast/RaytestDemo.cpp b/examples/Raycast/RaytestDemo.cpp index fa07a9942..5bf458d7e 100644 --- a/examples/Raycast/RaytestDemo.cpp +++ b/examples/Raycast/RaytestDemo.cpp @@ -200,7 +200,6 @@ void RaytestDemo::initPhysics() btDefaultMotionState* myMotionState = new btDefaultMotionState(groundTransform); btRigidBody::btRigidBodyConstructionInfo rbInfo(mass,myMotionState,groundShape,localInertia); btRigidBody* body = new btRigidBody(rbInfo); - body->setRollingFriction(1); body->setFriction(1); //add the body to the dynamics world m_dynamicsWorld->addRigidBody(body); @@ -269,6 +268,7 @@ void RaytestDemo::initPhysics() rbInfo.m_startWorldTransform = startTransform; btRigidBody* body = new btRigidBody(rbInfo); body->setRollingFriction(0.03); + body->setSpinningFriction(0.03); body->setFriction(1); body->setAnisotropicFriction(colShape->getAnisotropicRollingFrictionDirection(),btCollisionObject::CF_ANISOTROPIC_ROLLING_FRICTION); diff --git a/examples/RenderingExamples/TinyRendererSetup.cpp b/examples/RenderingExamples/TinyRendererSetup.cpp index a38b13abd..caec7c41a 100644 --- a/examples/RenderingExamples/TinyRendererSetup.cpp +++ b/examples/RenderingExamples/TinyRendererSetup.cpp @@ -23,6 +23,7 @@ struct TinyRendererSetupInternalData TGAImage m_rgbColorBuffer; b3AlignedObjectArray m_depthBuffer; + b3AlignedObjectArray m_shadowBuffer; b3AlignedObjectArray m_segmentationMaskBuffer; @@ -53,6 +54,7 @@ struct TinyRendererSetupInternalData m_animateRenderer(0) { m_depthBuffer.resize(m_width*m_height); + m_shadowBuffer.resize(m_width*m_height); // m_segmentationMaskBuffer.resize(m_width*m_height); } @@ -152,7 +154,7 @@ TinyRendererSetup::TinyRendererSetup(struct GUIHelperInterface* gui) const char* fileName = "textured_sphere_smooth.obj"; fileName = "cube.obj"; - + fileName = "torus/torus_with_plane.obj"; { @@ -188,6 +190,7 @@ TinyRendererSetup::TinyRendererSetup(struct GUIHelperInterface* gui) TinyRenderObjectData* ob = new TinyRenderObjectData( m_internalData->m_rgbColorBuffer, m_internalData->m_depthBuffer, + &m_internalData->m_shadowBuffer, &m_internalData->m_segmentationMaskBuffer, m_internalData->m_renderObjects.size()); @@ -328,6 +331,7 @@ void TinyRendererSetup::stepSimulation(float deltaTime) { m_internalData->m_rgbColorBuffer.set(x,y,clearColor); m_internalData->m_depthBuffer[x+y*m_internalData->m_width] = -1e30f; + m_internalData->m_shadowBuffer[x+y*m_internalData->m_width] = -1e30f; } } @@ -339,7 +343,46 @@ void TinyRendererSetup::stepSimulation(float deltaTime) render->getActiveCamera()->getCameraViewMatrix(viewMat); render->getActiveCamera()->getCameraProjectionMatrix(projMat); - + for (int o=0;om_internalData->m_renderObjects.size();o++) + { + + const btTransform& tr = m_internalData->m_transforms[o]; + tr.getOpenGLMatrix(modelMat2); + + + for (int i=0;i<4;i++) + { + for (int j=0;j<4;j++) + { + m_internalData->m_renderObjects[o]->m_modelMatrix[i][j] = float(modelMat2[i+4*j]); + m_internalData->m_renderObjects[o]->m_viewMatrix[i][j] = viewMat[i+4*j]; + m_internalData->m_renderObjects[o]->m_projectionMatrix[i][j] = projMat[i+4*j]; + + btVector3 lightDirWorld; + switch (m_app->getUpAxis()) + { + case 1: + lightDirWorld = btVector3(-50.f,100,30); + break; + case 2: + lightDirWorld = btVector3(-50.f,30,100); + break; + default:{} + }; + + m_internalData->m_renderObjects[o]->m_lightDirWorld = lightDirWorld.normalized(); + + btVector3 lightColor(1.0,1.0,1.0); + m_internalData->m_renderObjects[o]->m_lightColor = lightColor; + + m_internalData->m_renderObjects[o]->m_lightDistance = 10.0; + m_internalData->m_renderObjects[o]->m_lightAmbientCoeff = 0.6; + m_internalData->m_renderObjects[o]->m_lightDiffuseCoeff = 0.35; + m_internalData->m_renderObjects[o]->m_lightSpecularCoeff = 0.05; + } + } + TinyRenderer::renderObjectDepth(*m_internalData->m_renderObjects[o]); + } for (int o=0;om_internalData->m_renderObjects.size();o++) { @@ -369,6 +412,14 @@ void TinyRendererSetup::stepSimulation(float deltaTime) }; m_internalData->m_renderObjects[o]->m_lightDirWorld = lightDirWorld.normalized(); + + btVector3 lightColor(1.0,1.0,1.0); + m_internalData->m_renderObjects[o]->m_lightColor = lightColor; + + m_internalData->m_renderObjects[o]->m_lightDistance = 10.0; + m_internalData->m_renderObjects[o]->m_lightAmbientCoeff = 0.6; + m_internalData->m_renderObjects[o]->m_lightDiffuseCoeff = 0.35; + m_internalData->m_renderObjects[o]->m_lightSpecularCoeff = 0.05; } } diff --git a/examples/RoboticsLearning/GripperGraspExample.cpp b/examples/RoboticsLearning/GripperGraspExample.cpp index 37e6c06a0..71e32924d 100644 --- a/examples/RoboticsLearning/GripperGraspExample.cpp +++ b/examples/RoboticsLearning/GripperGraspExample.cpp @@ -343,7 +343,6 @@ public: slider.m_maxVal=1; m_guiHelper->getParameterInterface()->registerSliderFloatParameter(slider); } - if (1) { b3RobotSimLoadFileArgs args(""); args.m_fileName = "gripper/wsg50_one_motor_gripper_new.sdf"; @@ -374,12 +373,10 @@ public: } } - - if (1) { b3RobotSimLoadFileArgs args(""); args.m_fileName = "plane.urdf"; - args.m_startPosition.setValue(0,0,0); + args.m_startPosition.setValue(0,0,-0.2); args.m_startOrientation.setEulerZYX(0,0,0); args.m_forceOverrideFixedBase = true; args.m_useMultiBody = true; @@ -388,7 +385,7 @@ public: } m_robotSim.setGravity(b3MakeVector3(0,0,-10)); - m_robotSim.loadBunny(); + m_robotSim.loadBunny(0.1,0.1,0.02); b3JointInfo revoluteJoint1; revoluteJoint1.m_parentFrame[0] = -0.055; @@ -431,6 +428,46 @@ public: m_robotSim.createJoint(0, 2, 0, 4, &revoluteJoint1); m_robotSim.createJoint(0, 3, 0, 6, &revoluteJoint2); } + + if ((m_options & eSOFTBODY_MULTIBODY_COUPLING)!=0) + { + { + b3RobotSimLoadFileArgs args(""); + args.m_fileName = "kuka_iiwa/model_free_base.urdf"; + args.m_startPosition.setValue(0,1.0,2.0); + args.m_startOrientation.setEulerZYX(0,0,1.57); + args.m_forceOverrideFixedBase = false; + args.m_useMultiBody = true; + b3RobotSimLoadFileResults results; + m_robotSim.loadFile(args,results); + + int kukaId = results.m_uniqueObjectIds[0]; + int numJoints = m_robotSim.getNumJoints(kukaId); + b3Printf("numJoints = %d",numJoints); + + for (int i=0;im_physicsClient)); if (b3CanSubmitCommand(m_data->m_physicsClient)) { - statusHandle = b3SubmitClientCommandAndWaitStatus(m_data->m_physicsClient, b3CreateJoint(m_data->m_physicsClient, parentBodyIndex, parentJointIndex, childBodyIndex, childJointIndex, jointInfo)); + statusHandle = b3SubmitClientCommandAndWaitStatus(m_data->m_physicsClient, b3InitCreateUserConstraintCommand(m_data->m_physicsClient, parentBodyIndex, parentJointIndex, childBodyIndex, childJointIndex, jointInfo)); } } @@ -893,7 +910,8 @@ bool b3RobotSimAPI::connect(GUIHelperInterface* guiHelper) } else { - m_data->m_clientServerDirect = new PhysicsDirect(); + PhysicsServerCommandProcessor* sdk = new PhysicsServerCommandProcessor; + m_data->m_clientServerDirect = new PhysicsDirect(sdk); bool connected = m_data->m_clientServerDirect->connect(guiHelper); m_data->m_physicsClient = (b3PhysicsClientHandle)m_data->m_clientServerDirect; @@ -1000,8 +1018,11 @@ void b3RobotSimAPI::getLinkState(int bodyUniqueId, int linkIndex, double* worldP } } -void b3RobotSimAPI::loadBunny() +void b3RobotSimAPI::loadBunny(double scale, double mass, double collisionMargin) { b3SharedMemoryCommandHandle command = b3LoadBunnyCommandInit(m_data->m_physicsClient); + b3LoadBunnySetScale(command, scale); + b3LoadBunnySetMass(command, mass); + b3LoadBunnySetCollisionMargin(command, collisionMargin); b3SubmitClientCommand(m_data->m_physicsClient, command); -} \ No newline at end of file +} diff --git a/examples/RoboticsLearning/b3RobotSimAPI.h b/examples/RoboticsLearning/b3RobotSimAPI.h index 882817384..886aafcad 100644 --- a/examples/RoboticsLearning/b3RobotSimAPI.h +++ b/examples/RoboticsLearning/b3RobotSimAPI.h @@ -165,7 +165,7 @@ public: void getLinkState(int bodyUniqueId, int linkIndex, double* worldPosition, double* worldOrientation); - void loadBunny(); + void loadBunny(double scale, double mass, double collisionMargin); }; #endif //B3_ROBOT_SIM_API_H diff --git a/examples/RollingFrictionDemo/RollingFrictionDemo.cpp b/examples/RollingFrictionDemo/RollingFrictionDemo.cpp index 7e53be9b0..65a2404d3 100644 --- a/examples/RollingFrictionDemo/RollingFrictionDemo.cpp +++ b/examples/RollingFrictionDemo/RollingFrictionDemo.cpp @@ -123,8 +123,8 @@ void RollingFrictionDemo::initPhysics() btDefaultMotionState* myMotionState = new btDefaultMotionState(groundTransform); btRigidBody::btRigidBodyConstructionInfo rbInfo(mass,myMotionState,groundShape,localInertia); btRigidBody* body = new btRigidBody(rbInfo); - body->setFriction(1); - body->setRollingFriction(1); + body->setFriction(.5); + //add the body to the dynamics world m_dynamicsWorld->addRigidBody(body); } @@ -153,8 +153,7 @@ void RollingFrictionDemo::initPhysics() btDefaultMotionState* myMotionState = new btDefaultMotionState(groundTransform); btRigidBody::btRigidBodyConstructionInfo rbInfo(mass,myMotionState,groundShape,localInertia); btRigidBody* body = new btRigidBody(rbInfo); - body->setFriction(1); - body->setRollingFriction(1); + body->setFriction(.1); //add the body to the dynamics world m_dynamicsWorld->addRigidBody(body); } @@ -217,7 +216,8 @@ void RollingFrictionDemo::initPhysics() btRigidBody::btRigidBodyConstructionInfo rbInfo(mass,myMotionState,colShape,localInertia); btRigidBody* body = new btRigidBody(rbInfo); body->setFriction(1.f); - body->setRollingFriction(.3); + body->setRollingFriction(.1); + body->setSpinningFriction(0.1); body->setAnisotropicFriction(colShape->getAnisotropicRollingFrictionDirection(),btCollisionObject::CF_ANISOTROPIC_ROLLING_FRICTION); diff --git a/examples/SharedMemory/IKTrajectoryHelper.cpp b/examples/SharedMemory/IKTrajectoryHelper.cpp index 13bd8a2ad..a9af38164 100644 --- a/examples/SharedMemory/IKTrajectoryHelper.cpp +++ b/examples/SharedMemory/IKTrajectoryHelper.cpp @@ -18,7 +18,6 @@ struct IKTrajectoryHelperInternalData VectorRn m_nullSpaceVelocity; b3AlignedObjectArray m_ikNodes; - Jacobian* m_ikJacobian; IKTrajectoryHelperInternalData() { @@ -48,23 +47,21 @@ bool IKTrajectoryHelper::computeIK(const double endEffectorTargetPosition[3], { bool useAngularPart = (ikMethod==IK2_VEL_DLS_WITH_ORIENTATION || ikMethod==IK2_VEL_DLS_WITH_ORIENTATION_NULLSPACE) ? true : false; - m_data->m_ikJacobian = new Jacobian(useAngularPart,numQ); - -// Reset(m_ikTree,m_ikJacobian); + Jacobian ikJacobian(useAngularPart,numQ); - m_data->m_ikJacobian->Reset(); + ikJacobian.Reset(); bool UseJacobianTargets1 = false; if ( UseJacobianTargets1 ) { - m_data->m_ikJacobian->SetJtargetActive(); + ikJacobian.SetJtargetActive(); } else { - m_data->m_ikJacobian->SetJendActive(); + ikJacobian.SetJendActive(); } VectorR3 targets; targets.Set(endEffectorTargetPosition[0],endEffectorTargetPosition[1],endEffectorTargetPosition[2]); - m_data->m_ikJacobian->ComputeJacobian(&targets); // Set up Jacobian and deltaS vectors + ikJacobian.ComputeJacobian(&targets); // Set up Jacobian and deltaS vectors // Set one end effector world position from Bullet VectorRn deltaS(3); @@ -112,8 +109,8 @@ bool IKTrajectoryHelper::computeIK(const double endEffectorTargetPosition[3], completeJacobian.Set(i+3,j,angular_jacobian[i*numQ+j]); } } - m_data->m_ikJacobian->SetDeltaS(deltaC); - m_data->m_ikJacobian->SetJendTrans(completeJacobian); + ikJacobian.SetDeltaS(deltaC); + ikJacobian.SetJendTrans(completeJacobian); } else { VectorRn deltaC(3); @@ -126,53 +123,53 @@ bool IKTrajectoryHelper::computeIK(const double endEffectorTargetPosition[3], completeJacobian.Set(i,j,linear_jacobian[i*numQ+j]); } } - m_data->m_ikJacobian->SetDeltaS(deltaC); - m_data->m_ikJacobian->SetJendTrans(completeJacobian); + ikJacobian.SetDeltaS(deltaC); + ikJacobian.SetJendTrans(completeJacobian); } } // Calculate the change in theta values switch (ikMethod) { case IK2_JACOB_TRANS: - m_data->m_ikJacobian->CalcDeltaThetasTranspose(); // Jacobian transpose method + ikJacobian.CalcDeltaThetasTranspose(); // Jacobian transpose method break; case IK2_DLS: case IK2_VEL_DLS: case IK2_VEL_DLS_WITH_ORIENTATION: - m_data->m_ikJacobian->CalcDeltaThetasDLS(); // Damped least squares method + ikJacobian.CalcDeltaThetasDLS(); // Damped least squares method break; case IK2_VEL_DLS_WITH_NULLSPACE: case IK2_VEL_DLS_WITH_ORIENTATION_NULLSPACE: assert(m_data->m_nullSpaceVelocity.GetLength()==numQ); - m_data->m_ikJacobian->CalcDeltaThetasDLSwithNullspace(m_data->m_nullSpaceVelocity); + ikJacobian.CalcDeltaThetasDLSwithNullspace(m_data->m_nullSpaceVelocity); break; case IK2_DLS_SVD: - m_data->m_ikJacobian->CalcDeltaThetasDLSwithSVD(); + ikJacobian.CalcDeltaThetasDLSwithSVD(); break; case IK2_PURE_PSEUDO: - m_data->m_ikJacobian->CalcDeltaThetasPseudoinverse(); // Pure pseudoinverse method + ikJacobian.CalcDeltaThetasPseudoinverse(); // Pure pseudoinverse method break; case IK2_SDLS: - m_data->m_ikJacobian->CalcDeltaThetasSDLS(); // Selectively damped least squares method + ikJacobian.CalcDeltaThetasSDLS(); // Selectively damped least squares method break; default: - m_data->m_ikJacobian->ZeroDeltaThetas(); + ikJacobian.ZeroDeltaThetas(); break; } // Use for velocity IK, update theta dot - //m_data->m_ikJacobian->UpdateThetaDot(); + //ikJacobian.UpdateThetaDot(); // Use for position IK, incrementally update theta - //m_data->m_ikJacobian->UpdateThetas(); + //ikJacobian.UpdateThetas(); // Apply the change in the theta values - //m_data->m_ikJacobian->UpdatedSClampValue(&targets); + //ikJacobian.UpdatedSClampValue(&targets); for (int i=0;im_ikJacobian->dTheta[i] + q_current[i]; + q_new[i] = ikJacobian.dTheta[i] + q_current[i]; // Use for position IK //q_new[i] = m_data->m_ikNodes[i]->GetTheta(); @@ -203,4 +200,4 @@ bool IKTrajectoryHelper::computeNullspaceVel(int numQ, const double* q_current, } } return true; -} \ No newline at end of file +} diff --git a/examples/SharedMemory/PhysicsClient.h b/examples/SharedMemory/PhysicsClient.h index f028f537f..e1c20cadb 100644 --- a/examples/SharedMemory/PhysicsClient.h +++ b/examples/SharedMemory/PhysicsClient.h @@ -48,6 +48,8 @@ public: virtual void getCachedContactPointInformation(struct b3ContactInformation* contactPointData)=0; + virtual void getCachedOverlappingObjects(struct b3AABBOverlapData* overlappingObjects) = 0; + virtual void getCachedVisualShapeInformation(struct b3VisualShapeInformation* visualShapesInfo) = 0; }; diff --git a/examples/SharedMemory/PhysicsClientC_API.cpp b/examples/SharedMemory/PhysicsClientC_API.cpp index 71ac91832..a9d217c3e 100644 --- a/examples/SharedMemory/PhysicsClientC_API.cpp +++ b/examples/SharedMemory/PhysicsClientC_API.cpp @@ -58,23 +58,108 @@ b3SharedMemoryCommandHandle b3LoadUrdfCommandInit(b3PhysicsClientHandle physClie b3Assert(cl); b3Assert(cl->canSubmitCommand()); - - struct SharedMemoryCommand* command = cl->getAvailableSharedMemoryCommand(); - b3Assert(command); - command->m_type = CMD_LOAD_URDF; - int len = strlen(urdfFileName); - if (lencanSubmitCommand()) { - strcpy(command->m_urdfArguments.m_urdfFileName,urdfFileName); - } else - { - command->m_urdfArguments.m_urdfFileName[0] = 0; + struct SharedMemoryCommand* command = cl->getAvailableSharedMemoryCommand(); + b3Assert(command); + command->m_type = CMD_LOAD_URDF; + int len = strlen(urdfFileName); + if (len < MAX_URDF_FILENAME_LENGTH) + { + strcpy(command->m_urdfArguments.m_urdfFileName, urdfFileName); + } + else + { + command->m_urdfArguments.m_urdfFileName[0] = 0; + } + command->m_updateFlags = URDF_ARGS_FILE_NAME; + + return (b3SharedMemoryCommandHandle)command; } - command->m_updateFlags = URDF_ARGS_FILE_NAME; - - return (b3SharedMemoryCommandHandle) command; + return 0; } +b3SharedMemoryCommandHandle b3LoadBulletCommandInit(b3PhysicsClientHandle physClient, const char* fileName) +{ + PhysicsClient* cl = (PhysicsClient*)physClient; + b3Assert(cl); + b3Assert(cl->canSubmitCommand()); + + if (cl->canSubmitCommand()) + { + struct SharedMemoryCommand* command = cl->getAvailableSharedMemoryCommand(); + b3Assert(command); + command->m_type = CMD_LOAD_BULLET; + int len = strlen(fileName); + if (len < MAX_URDF_FILENAME_LENGTH) + { + strcpy(command->m_fileArguments.m_fileName, fileName); + } + else + { + command->m_fileArguments.m_fileName[0] = 0; + } + command->m_updateFlags = 0; + + return (b3SharedMemoryCommandHandle)command; + } + return 0; +} + +b3SharedMemoryCommandHandle b3SaveBulletCommandInit(b3PhysicsClientHandle physClient, const char* fileName) +{ + PhysicsClient* cl = (PhysicsClient*)physClient; + b3Assert(cl); + b3Assert(cl->canSubmitCommand()); + + if (cl->canSubmitCommand()) + { + struct SharedMemoryCommand* command = cl->getAvailableSharedMemoryCommand(); + b3Assert(command); + command->m_type = CMD_SAVE_BULLET; + int len = strlen(fileName); + if (len < MAX_URDF_FILENAME_LENGTH) + { + strcpy(command->m_fileArguments.m_fileName, fileName); + } + else + { + command->m_fileArguments.m_fileName[0] = 0; + } + command->m_updateFlags = 0; + + return (b3SharedMemoryCommandHandle)command; + } + return 0; +} +b3SharedMemoryCommandHandle b3LoadMJCFCommandInit(b3PhysicsClientHandle physClient, const char* fileName) +{ + PhysicsClient* cl = (PhysicsClient*)physClient; + b3Assert(cl); + b3Assert(cl->canSubmitCommand()); + + if (cl->canSubmitCommand()) + { + struct SharedMemoryCommand* command = cl->getAvailableSharedMemoryCommand(); + b3Assert(command); + command->m_type = CMD_LOAD_MJCF; + int len = strlen(fileName); + if (len < MAX_URDF_FILENAME_LENGTH) + { + strcpy(command->m_fileArguments.m_fileName, fileName); + } + else + { + command->m_fileArguments.m_fileName[0] = 0; + } + command->m_updateFlags = 0; + + return (b3SharedMemoryCommandHandle)command; + } + return 0; +} + + b3SharedMemoryCommandHandle b3LoadBunnyCommandInit(b3PhysicsClientHandle physClient) { PhysicsClient* cl = (PhysicsClient* ) physClient; @@ -89,6 +174,33 @@ b3SharedMemoryCommandHandle b3LoadBunnyCommandInit(b3PhysicsClientHandle physCli return (b3SharedMemoryCommandHandle) command; } +int b3LoadBunnySetScale(b3SharedMemoryCommandHandle commandHandle, double scale) +{ + struct SharedMemoryCommand* command = (struct SharedMemoryCommand*) commandHandle; + b3Assert(command->m_type == CMD_LOAD_BUNNY); + command->m_loadBunnyArguments.m_scale = scale; + command->m_updateFlags |= LOAD_BUNNY_UPDATE_SCALE; + return 0; +} + +int b3LoadBunnySetMass(b3SharedMemoryCommandHandle commandHandle, double mass) +{ + struct SharedMemoryCommand* command = (struct SharedMemoryCommand*) commandHandle; + b3Assert(command->m_type == CMD_LOAD_BUNNY); + command->m_loadBunnyArguments.m_mass = mass; + command->m_updateFlags |= LOAD_BUNNY_UPDATE_MASS; + return 0; +} + +int b3LoadBunnySetCollisionMargin(b3SharedMemoryCommandHandle commandHandle, double collisionMargin) +{ + struct SharedMemoryCommand* command = (struct SharedMemoryCommand*) commandHandle; + b3Assert(command->m_type == CMD_LOAD_BUNNY); + command->m_loadBunnyArguments.m_collisionMargin = collisionMargin; + command->m_updateFlags |= LOAD_BUNNY_UPDATE_COLLISION_MARGIN; + return 0; +} + int b3LoadUrdfCommandSetUseMultiBody(b3SharedMemoryCommandHandle commandHandle, int useMultiBody) { struct SharedMemoryCommand* command = (struct SharedMemoryCommand*) commandHandle; @@ -116,35 +228,52 @@ int b3LoadUrdfCommandSetUseFixedBase(b3SharedMemoryCommandHandle commandHandle, struct SharedMemoryCommand* command = (struct SharedMemoryCommand*) commandHandle; b3Assert(command); b3Assert(command->m_type == CMD_LOAD_URDF); - command->m_updateFlags |=URDF_ARGS_USE_FIXED_BASE; - command->m_urdfArguments.m_useFixedBase = useFixedBase; - - return 0; + if (command && (command->m_type == CMD_LOAD_URDF)) + { + command->m_updateFlags |= URDF_ARGS_USE_FIXED_BASE; + command->m_urdfArguments.m_useFixedBase = useFixedBase; + return 0; + } + return -1; } int b3LoadUrdfCommandSetStartPosition(b3SharedMemoryCommandHandle commandHandle, double startPosX,double startPosY,double startPosZ) { struct SharedMemoryCommand* command = (struct SharedMemoryCommand*) commandHandle; b3Assert(command); - b3Assert(command->m_type == CMD_LOAD_URDF); - command->m_urdfArguments.m_initialPosition[0] = startPosX; - command->m_urdfArguments.m_initialPosition[1] = startPosY; - command->m_urdfArguments.m_initialPosition[2] = startPosZ; - command->m_updateFlags|=URDF_ARGS_INITIAL_POSITION; - return 0; + if (command) + { + b3Assert(command->m_type == CMD_LOAD_URDF); + if (command->m_type == CMD_LOAD_URDF) + { + command->m_urdfArguments.m_initialPosition[0] = startPosX; + command->m_urdfArguments.m_initialPosition[1] = startPosY; + command->m_urdfArguments.m_initialPosition[2] = startPosZ; + command->m_updateFlags |= URDF_ARGS_INITIAL_POSITION; + } + return 0; + } + return -1; } int b3LoadUrdfCommandSetStartOrientation(b3SharedMemoryCommandHandle commandHandle, double startOrnX,double startOrnY,double startOrnZ, double startOrnW) { struct SharedMemoryCommand* command = (struct SharedMemoryCommand*) commandHandle; b3Assert(command); - b3Assert(command->m_type == CMD_LOAD_URDF); - command->m_urdfArguments.m_initialOrientation[0] = startOrnX; - command->m_urdfArguments.m_initialOrientation[1] = startOrnY; - command->m_urdfArguments.m_initialOrientation[2] = startOrnZ; - command->m_urdfArguments.m_initialOrientation[3] = startOrnW; - command->m_updateFlags|=URDF_ARGS_INITIAL_ORIENTATION; - return 0; + if (command) + { + b3Assert(command->m_type == CMD_LOAD_URDF); + if (command->m_type == CMD_LOAD_URDF) + { + command->m_urdfArguments.m_initialOrientation[0] = startOrnX; + command->m_urdfArguments.m_initialOrientation[1] = startOrnY; + command->m_urdfArguments.m_initialOrientation[2] = startOrnZ; + command->m_urdfArguments.m_initialOrientation[3] = startOrnW; + command->m_updateFlags |= URDF_ARGS_INITIAL_ORIENTATION; + } + return 0; + } + return -1; } b3SharedMemoryCommandHandle b3InitPhysicsParamCommand(b3PhysicsClientHandle physClient) @@ -174,7 +303,7 @@ int b3PhysicsParamSetRealTimeSimulation(b3SharedMemoryCommandHandle commandH { struct SharedMemoryCommand* command = (struct SharedMemoryCommand*) commandHandle; b3Assert(command->m_type == CMD_SEND_PHYSICS_SIMULATION_PARAMETERS); - command->m_physSimParamArgs.m_allowRealTimeSimulation = enableRealTimeSimulation; + command->m_physSimParamArgs.m_allowRealTimeSimulation = (enableRealTimeSimulation!=0); command->m_updateFlags |= SIM_PARAM_UPDATE_REAL_TIME_SIMULATION; return 0; } @@ -188,6 +317,26 @@ int b3PhysicsParamSetInternalSimFlags(b3SharedMemoryCommandHandle commandHan return 0; } +int b3PhysicsParamSetUseSplitImpulse(b3SharedMemoryCommandHandle commandHandle, int useSplitImpulse) +{ + struct SharedMemoryCommand* command = (struct SharedMemoryCommand*) commandHandle; + b3Assert(command->m_type == CMD_SEND_PHYSICS_SIMULATION_PARAMETERS); + + command->m_physSimParamArgs.m_useSplitImpulse = useSplitImpulse; + command->m_updateFlags |= SIM_PARAM_UPDATE_USE_SPLIT_IMPULSE; + return 0; +} + +int b3PhysicsParamSetSplitImpulsePenetrationThreshold(b3SharedMemoryCommandHandle commandHandle, double splitImpulsePenetrationThreshold) +{ + struct SharedMemoryCommand* command = (struct SharedMemoryCommand*) commandHandle; + b3Assert(command->m_type == CMD_SEND_PHYSICS_SIMULATION_PARAMETERS); + + command->m_physSimParamArgs.m_splitImpulsePenetrationThreshold = splitImpulsePenetrationThreshold; + command->m_updateFlags |= SIM_PARAM_UPDATE_SPLIT_IMPULSE_PENETRATION_THRESHOLD; + return 0; +} + int b3PhysicsParamSetNumSolverIterations(b3SharedMemoryCommandHandle commandHandle, int numSolverIterations) { struct SharedMemoryCommand* command = (struct SharedMemoryCommand*) commandHandle; @@ -543,6 +692,40 @@ int b3CreatePoseCommandSetBaseOrientation(b3SharedMemoryCommandHandle commandHan return 0; } +int b3CreatePoseCommandSetBaseLinearVelocity(b3SharedMemoryCommandHandle commandHandle, double linVel[3]) +{ + struct SharedMemoryCommand* command = (struct SharedMemoryCommand*) commandHandle; + b3Assert(command); + b3Assert(command->m_type == CMD_INIT_POSE); + command->m_updateFlags |= INIT_POSE_HAS_BASE_LINEAR_VELOCITY; + command->m_initPoseArgs.m_hasInitialStateQdot[0] = 1; + command->m_initPoseArgs.m_hasInitialStateQdot[1] = 1; + command->m_initPoseArgs.m_hasInitialStateQdot[2] = 1; + + command->m_initPoseArgs.m_initialStateQdot[0] = linVel[0]; + command->m_initPoseArgs.m_initialStateQdot[1] = linVel[1]; + command->m_initPoseArgs.m_initialStateQdot[2] = linVel[2]; + + return 0; +} + +int b3CreatePoseCommandSetBaseAngularVelocity(b3SharedMemoryCommandHandle commandHandle, double angVel[3]) +{ + struct SharedMemoryCommand* command = (struct SharedMemoryCommand*) commandHandle; + b3Assert(command); + b3Assert(command->m_type == CMD_INIT_POSE); + command->m_updateFlags |= INIT_POSE_HAS_BASE_ANGULAR_VELOCITY; + command->m_initPoseArgs.m_hasInitialStateQdot[3] = 1; + command->m_initPoseArgs.m_hasInitialStateQdot[4] = 1; + command->m_initPoseArgs.m_hasInitialStateQdot[5] = 1; + + command->m_initPoseArgs.m_initialStateQdot[3] = angVel[0]; + command->m_initPoseArgs.m_initialStateQdot[4] = angVel[1]; + command->m_initPoseArgs.m_initialStateQdot[5] = angVel[2]; + + return 0; +} + int b3CreatePoseCommandSetJointPositions(b3SharedMemoryCommandHandle commandHandle, int numJointPositions, const double* jointPositions) { struct SharedMemoryCommand* command = (struct SharedMemoryCommand*) commandHandle; @@ -557,6 +740,8 @@ int b3CreatePoseCommandSetJointPositions(b3SharedMemoryCommandHandle commandHand return 0; } + + int b3CreatePoseCommandSetJointPosition(b3PhysicsClientHandle physClient, b3SharedMemoryCommandHandle commandHandle, int jointIndex, double jointPosition) { struct SharedMemoryCommand* command = (struct SharedMemoryCommand*) commandHandle; @@ -621,20 +806,11 @@ int b3CreateSensorEnableIMUForLink(b3SharedMemoryCommandHandle commandHandle, in } -b3PhysicsClientHandle b3ConnectSharedMemory(int key) -{ - - PhysicsClientSharedMemory* cl = new PhysicsClientSharedMemory(); - ///client should never create shared memory, only the server does - cl->setSharedMemoryKey(key); - cl->connect(); - return (b3PhysicsClientHandle ) cl; -} - void b3DisconnectSharedMemory(b3PhysicsClientHandle physClient) { PhysicsClient* cl = (PhysicsClient* ) physClient; + cl->disconnectSharedMemory(); delete cl; } @@ -673,6 +849,7 @@ int b3GetStatusBodyIndices(b3SharedMemoryStatusHandle statusHandle, int* bodyInd { switch (status->m_type) { + case CMD_BULLET_LOADING_COMPLETED: case CMD_SDF_LOADING_COMPLETED: { int i,maxBodies; @@ -772,22 +949,34 @@ int b3SubmitClientCommand(b3PhysicsClientHandle physClient, const b3SharedMemory { struct SharedMemoryCommand* command = (struct SharedMemoryCommand*) commandHandle; PhysicsClient* cl = (PhysicsClient* ) physClient; - return (int)cl->submitClientCommand(*command); + b3Assert(command); + b3Assert(cl); + if (command && cl) + { + return (int)cl->submitClientCommand(*command); + } + return -1; + } b3SharedMemoryStatusHandle b3SubmitClientCommandAndWaitStatus(b3PhysicsClientHandle physClient, const b3SharedMemoryCommandHandle commandHandle) { - int timeout = 1024*1024*1024; - b3SharedMemoryStatusHandle statusHandle=0; - - b3SubmitClientCommand(physClient,commandHandle); - - while ((statusHandle==0) && (timeout-- > 0)) - { - statusHandle =b3ProcessServerStatus(physClient); - } - return (b3SharedMemoryStatusHandle) statusHandle; - + int timeout = 1024 * 1024 * 1024; + b3SharedMemoryStatusHandle statusHandle = 0; + b3Assert(commandHandle); + b3Assert(physClient); + if (physClient && commandHandle) + { + b3SubmitClientCommand(physClient, commandHandle); + + while ((statusHandle == 0) && (timeout-- > 0)) + { + statusHandle = b3ProcessServerStatus(physClient); + } + return (b3SharedMemoryStatusHandle)statusHandle; + } + + return 0; } @@ -827,7 +1016,9 @@ int b3GetJointInfo(b3PhysicsClientHandle physClient, int bodyIndex, int jointInd return cl->getJointInfo(bodyIndex, jointIndex, *info); } -b3SharedMemoryCommandHandle b3CreateJoint(b3PhysicsClientHandle physClient, int parentBodyIndex, int parentJointIndex, int childBodyIndex, int childJointIndex, struct b3JointInfo* info) + + +b3SharedMemoryCommandHandle b3InitCreateUserConstraintCommand(b3PhysicsClientHandle physClient, int parentBodyIndex, int parentJointIndex, int childBodyIndex, int childJointIndex, struct b3JointInfo* info) { PhysicsClient* cl = (PhysicsClient* ) physClient; b3Assert(cl); @@ -835,22 +1026,52 @@ b3SharedMemoryCommandHandle b3CreateJoint(b3PhysicsClientHandle physClient, int struct SharedMemoryCommand* command = cl->getAvailableSharedMemoryCommand(); b3Assert(command); - command->m_type = CMD_CREATE_JOINT; - command->m_createJointArguments.m_parentBodyIndex = parentBodyIndex; - command->m_createJointArguments.m_parentJointIndex = parentJointIndex; - command->m_createJointArguments.m_childBodyIndex = childBodyIndex; - command->m_createJointArguments.m_childJointIndex = childJointIndex; + command->m_type = CMD_USER_CONSTRAINT; + command->m_updateFlags = USER_CONSTRAINT_ADD_CONSTRAINT; + + command->m_userConstraintArguments.m_parentBodyIndex = parentBodyIndex; + command->m_userConstraintArguments.m_parentJointIndex = parentJointIndex; + command->m_userConstraintArguments.m_childBodyIndex = childBodyIndex; + command->m_userConstraintArguments.m_childJointIndex = childJointIndex; for (int i = 0; i < 7; ++i) { - command->m_createJointArguments.m_parentFrame[i] = info->m_parentFrame[i]; - command->m_createJointArguments.m_childFrame[i] = info->m_childFrame[i]; + command->m_userConstraintArguments.m_parentFrame[i] = info->m_parentFrame[i]; + command->m_userConstraintArguments.m_childFrame[i] = info->m_childFrame[i]; } for (int i = 0; i < 3; ++i) { - command->m_createJointArguments.m_jointAxis[i] = info->m_jointAxis[i]; + command->m_userConstraintArguments.m_jointAxis[i] = info->m_jointAxis[i]; } - command->m_createJointArguments.m_jointType = info->m_jointType; + command->m_userConstraintArguments.m_jointType = info->m_jointType; return (b3SharedMemoryCommandHandle)command; } +b3SharedMemoryCommandHandle b3InitRemoveUserConstraintCommand(b3PhysicsClientHandle physClient, int userConstraintUniqueId) +{ + PhysicsClient* cl = (PhysicsClient* ) physClient; + b3Assert(cl); + b3Assert(cl->canSubmitCommand()); + struct SharedMemoryCommand* command = cl->getAvailableSharedMemoryCommand(); + b3Assert(command); + + command->m_type = CMD_USER_CONSTRAINT; + command->m_updateFlags = USER_CONSTRAINT_REMOVE_CONSTRAINT; + command->m_userConstraintArguments.m_userConstraintUniqueId = userConstraintUniqueId; + return (b3SharedMemoryCommandHandle)command; +} +int b3GetStatusUserConstraintUniqueId(b3SharedMemoryStatusHandle statusHandle) +{ + const SharedMemoryStatus* status = (const SharedMemoryStatus* ) statusHandle; + b3Assert(status); + b3Assert(status->m_type == CMD_USER_CONSTRAINT_COMPLETED); + if (status && status->m_type == CMD_USER_CONSTRAINT_COMPLETED) + { + return status->m_userConstraintResultArgs.m_userConstraintUniqueId; + } + + return -1; + +} + + b3SharedMemoryCommandHandle b3PickBody(b3PhysicsClientHandle physClient, double rayFromWorldX, double rayFromWorldY, double rayFromWorldZ, double rayToWorldX, double rayToWorldY, double rayToWorldZ) @@ -930,6 +1151,147 @@ void b3GetDebugLines(b3PhysicsClientHandle physClient, struct b3DebugLines* l } + +/// Add/remove user-specific debug lines and debug text messages +b3SharedMemoryCommandHandle b3InitUserDebugDrawAddLine3D(b3PhysicsClientHandle physClient, double fromXYZ[3], double toXYZ[3], double colorRGB[3], double lineWidth, double lifeTime) +{ + PhysicsClient* cl = (PhysicsClient* ) physClient; + b3Assert(cl); + b3Assert(cl->canSubmitCommand()); + struct SharedMemoryCommand* command = cl->getAvailableSharedMemoryCommand(); + b3Assert(command); + command->m_type =CMD_USER_DEBUG_DRAW; + command->m_updateFlags = USER_DEBUG_HAS_LINE; //USER_DEBUG_HAS_TEXT + + command->m_userDebugDrawArgs.m_debugLineFromXYZ[0] = fromXYZ[0]; + command->m_userDebugDrawArgs.m_debugLineFromXYZ[1] = fromXYZ[1]; + command->m_userDebugDrawArgs.m_debugLineFromXYZ[2] = fromXYZ[2]; + + command->m_userDebugDrawArgs.m_debugLineToXYZ[0] = toXYZ[0]; + command->m_userDebugDrawArgs.m_debugLineToXYZ[1] = toXYZ[1]; + command->m_userDebugDrawArgs.m_debugLineToXYZ[2] = toXYZ[2]; + + command->m_userDebugDrawArgs.m_debugLineColorRGB[0] = colorRGB[0]; + command->m_userDebugDrawArgs.m_debugLineColorRGB[1] = colorRGB[1]; + command->m_userDebugDrawArgs.m_debugLineColorRGB[2] = colorRGB[2]; + + command->m_userDebugDrawArgs.m_lineWidth = lineWidth; + command->m_userDebugDrawArgs.m_lifeTime = lifeTime; + + return (b3SharedMemoryCommandHandle) command; +} + +b3SharedMemoryCommandHandle b3InitUserDebugDrawAddText3D(b3PhysicsClientHandle physClient, const char* txt, double positionXYZ[3], double colorRGB[3], double textSize, double lifeTime) +{ + + PhysicsClient* cl = (PhysicsClient* ) physClient; + b3Assert(cl); + b3Assert(cl->canSubmitCommand()); + struct SharedMemoryCommand* command = cl->getAvailableSharedMemoryCommand(); + b3Assert(command); + command->m_type =CMD_USER_DEBUG_DRAW; + command->m_updateFlags = USER_DEBUG_HAS_TEXT; + + int len = strlen(txt); + if (lenm_userDebugDrawArgs.m_text,txt); + } else + { + command->m_userDebugDrawArgs.m_text[0] = 0; + } + command->m_userDebugDrawArgs.m_textPositionXYZ[0] = positionXYZ[0]; + command->m_userDebugDrawArgs.m_textPositionXYZ[1] = positionXYZ[1]; + command->m_userDebugDrawArgs.m_textPositionXYZ[2] = positionXYZ[2]; + + command->m_userDebugDrawArgs.m_textColorRGB[0] = colorRGB[0]; + command->m_userDebugDrawArgs.m_textColorRGB[1] = colorRGB[1]; + command->m_userDebugDrawArgs.m_textColorRGB[2] = colorRGB[2]; + + command->m_userDebugDrawArgs.m_textSize = textSize; + + command->m_userDebugDrawArgs.m_lifeTime = lifeTime; + + return (b3SharedMemoryCommandHandle) command; +} + +b3SharedMemoryCommandHandle b3InitUserDebugDrawRemove(b3PhysicsClientHandle physClient, int debugItemUniqueId) +{ + PhysicsClient* cl = (PhysicsClient* ) physClient; + b3Assert(cl); + b3Assert(cl->canSubmitCommand()); + struct SharedMemoryCommand* command = cl->getAvailableSharedMemoryCommand(); + b3Assert(command); + command->m_type =CMD_USER_DEBUG_DRAW; + command->m_updateFlags = USER_DEBUG_REMOVE_ONE_ITEM; + command->m_userDebugDrawArgs.m_removeItemUniqueId = debugItemUniqueId; + return (b3SharedMemoryCommandHandle) command; + +} + +b3SharedMemoryCommandHandle b3InitUserDebugDrawRemoveAll(b3PhysicsClientHandle physClient) +{ + PhysicsClient* cl = (PhysicsClient* ) physClient; + b3Assert(cl); + b3Assert(cl->canSubmitCommand()); + struct SharedMemoryCommand* command = cl->getAvailableSharedMemoryCommand(); + b3Assert(command); + command->m_type =CMD_USER_DEBUG_DRAW; + command->m_updateFlags = USER_DEBUG_REMOVE_ALL; + return (b3SharedMemoryCommandHandle) command; +} + +int b3GetDebugItemUniqueId(b3SharedMemoryStatusHandle statusHandle) +{ + const SharedMemoryStatus* status = (const SharedMemoryStatus*)statusHandle; + btAssert(status->m_type == CMD_USER_DEBUG_DRAW_COMPLETED); + if (status->m_type != CMD_USER_DEBUG_DRAW_COMPLETED) + return -1; + + return status->m_userDebugDrawArgs.m_debugItemUniqueId; +} + +b3SharedMemoryCommandHandle b3InitDebugDrawingCommand(b3PhysicsClientHandle physClient) +{ + PhysicsClient* cl = (PhysicsClient*)physClient; + b3Assert(cl); + b3Assert(cl->canSubmitCommand()); + struct SharedMemoryCommand* command = cl->getAvailableSharedMemoryCommand(); + b3Assert(command); + command->m_type = CMD_USER_DEBUG_DRAW; + command->m_updateFlags = 0; + return (b3SharedMemoryCommandHandle)command; +} + + + +void b3SetDebugObjectColor(b3SharedMemoryCommandHandle commandHandle, int objectUniqueId, int linkIndex, double objectColorRGB[3]) +{ + struct SharedMemoryCommand* command = (struct SharedMemoryCommand*) commandHandle; + b3Assert(command); + b3Assert(command->m_type == CMD_USER_DEBUG_DRAW); + command->m_updateFlags |= USER_DEBUG_SET_CUSTOM_OBJECT_COLOR; + command->m_userDebugDrawArgs.m_objectUniqueId = objectUniqueId; + command->m_userDebugDrawArgs.m_linkIndex = linkIndex; + command->m_userDebugDrawArgs.m_objectDebugColorRGB[0] = objectColorRGB[0]; + command->m_userDebugDrawArgs.m_objectDebugColorRGB[1] = objectColorRGB[1]; + command->m_userDebugDrawArgs.m_objectDebugColorRGB[2] = objectColorRGB[2]; +} + +void b3RemoveDebugObjectColor(b3SharedMemoryCommandHandle commandHandle, int objectUniqueId, int linkIndex) +{ + struct SharedMemoryCommand* command = (struct SharedMemoryCommand*) commandHandle; + b3Assert(command); + b3Assert(command->m_type == CMD_USER_DEBUG_DRAW); + command->m_updateFlags |= USER_DEBUG_REMOVE_CUSTOM_OBJECT_COLOR; + command->m_userDebugDrawArgs.m_objectUniqueId = objectUniqueId; + command->m_userDebugDrawArgs.m_linkIndex = linkIndex; + +} + + + + ///request an image from a simulated camera, using a software renderer. b3SharedMemoryCommandHandle b3InitRequestCameraImage(b3PhysicsClientHandle physClient) { @@ -966,209 +1328,300 @@ void b3RequestCameraImageSetCameraMatrices(b3SharedMemoryCommandHandle commandHa command->m_updateFlags |= REQUEST_PIXEL_ARGS_HAS_CAMERA_MATRICES; } +void b3RequestCameraImageSetLightDirection(b3SharedMemoryCommandHandle commandHandle, const float lightDirection[3]) +{ + struct SharedMemoryCommand* command = (struct SharedMemoryCommand*) commandHandle; + b3Assert(command); + b3Assert(command->m_type == CMD_REQUEST_CAMERA_IMAGE_DATA); + for (int i = 0; i<3; i++) + { + command->m_requestPixelDataArguments.m_lightDirection[i] = lightDirection[i]; + } + command->m_updateFlags |= REQUEST_PIXEL_ARGS_SET_LIGHT_DIRECTION; +} + +void b3RequestCameraImageSetLightColor(b3SharedMemoryCommandHandle commandHandle, const float lightColor[3]) +{ + struct SharedMemoryCommand* command = (struct SharedMemoryCommand*) commandHandle; + b3Assert(command); + b3Assert(command->m_type == CMD_REQUEST_CAMERA_IMAGE_DATA); + for (int i = 0; i<3; i++) + { + command->m_requestPixelDataArguments.m_lightColor[i] = lightColor[i]; + } + command->m_updateFlags |= REQUEST_PIXEL_ARGS_SET_LIGHT_COLOR; +} + +void b3RequestCameraImageSetLightDistance(b3SharedMemoryCommandHandle commandHandle, float lightDistance) +{ + struct SharedMemoryCommand* command = (struct SharedMemoryCommand*) commandHandle; + b3Assert(command); + b3Assert(command->m_type == CMD_REQUEST_CAMERA_IMAGE_DATA); + command->m_requestPixelDataArguments.m_lightDistance = lightDistance; + command->m_updateFlags |= REQUEST_PIXEL_ARGS_SET_LIGHT_DISTANCE; +} + +void b3RequestCameraImageSetLightAmbientCoeff(b3SharedMemoryCommandHandle commandHandle, float lightAmbientCoeff) +{ + struct SharedMemoryCommand* command = (struct SharedMemoryCommand*) commandHandle; + b3Assert(command); + b3Assert(command->m_type == CMD_REQUEST_CAMERA_IMAGE_DATA); + command->m_requestPixelDataArguments.m_lightAmbientCoeff = lightAmbientCoeff; + command->m_updateFlags |= REQUEST_PIXEL_ARGS_SET_AMBIENT_COEFF; +} + +void b3RequestCameraImageSetLightDiffuseCoeff(b3SharedMemoryCommandHandle commandHandle, float lightDiffuseCoeff) +{ + struct SharedMemoryCommand* command = (struct SharedMemoryCommand*) commandHandle; + b3Assert(command); + b3Assert(command->m_type == CMD_REQUEST_CAMERA_IMAGE_DATA); + command->m_requestPixelDataArguments.m_lightDiffuseCoeff = lightDiffuseCoeff; + command->m_updateFlags |= REQUEST_PIXEL_ARGS_SET_DIFFUSE_COEFF; +} + +void b3RequestCameraImageSetLightSpecularCoeff(b3SharedMemoryCommandHandle commandHandle, float lightSpecularCoeff) +{ + struct SharedMemoryCommand* command = (struct SharedMemoryCommand*) commandHandle; + b3Assert(command); + b3Assert(command->m_type == CMD_REQUEST_CAMERA_IMAGE_DATA); + command->m_requestPixelDataArguments.m_lightSpecularCoeff = lightSpecularCoeff; + command->m_updateFlags |= REQUEST_PIXEL_ARGS_SET_SPECULAR_COEFF; +} + +void b3RequestCameraImageSetShadow(b3SharedMemoryCommandHandle commandHandle, int hasShadow) +{ + struct SharedMemoryCommand* command = (struct SharedMemoryCommand*) commandHandle; + b3Assert(command); + b3Assert(command->m_type == CMD_REQUEST_CAMERA_IMAGE_DATA); + command->m_requestPixelDataArguments.m_hasShadow = hasShadow; + command->m_updateFlags |= REQUEST_PIXEL_ARGS_SET_SHADOW; +} + +void b3ComputeViewMatrixFromPositions(const float cameraPosition[3], const float cameraTargetPosition[3], const float cameraUp[3], float viewMatrix[16]) +{ + b3Vector3 eye = b3MakeVector3(cameraPosition[0], cameraPosition[1], cameraPosition[2]); + b3Vector3 center = b3MakeVector3(cameraTargetPosition[0], cameraTargetPosition[1], cameraTargetPosition[2]); + b3Vector3 up = b3MakeVector3(cameraUp[0], cameraUp[1], cameraUp[2]); + b3Vector3 f = (center - eye).normalized(); + b3Vector3 u = up.normalized(); + b3Vector3 s = (f.cross(u)).normalized(); + u = s.cross(f); + + viewMatrix[0 * 4 + 0] = s.x; + viewMatrix[1 * 4 + 0] = s.y; + viewMatrix[2 * 4 + 0] = s.z; + + viewMatrix[0 * 4 + 1] = u.x; + viewMatrix[1 * 4 + 1] = u.y; + viewMatrix[2 * 4 + 1] = u.z; + + viewMatrix[0 * 4 + 2] = -f.x; + viewMatrix[1 * 4 + 2] = -f.y; + viewMatrix[2 * 4 + 2] = -f.z; + + viewMatrix[0 * 4 + 3] = 0.f; + viewMatrix[1 * 4 + 3] = 0.f; + viewMatrix[2 * 4 + 3] = 0.f; + + viewMatrix[3 * 4 + 0] = -s.dot(eye); + viewMatrix[3 * 4 + 1] = -u.dot(eye); + viewMatrix[3 * 4 + 2] = f.dot(eye); + viewMatrix[3 * 4 + 3] = 1.f; +} + + +void b3ComputeViewMatrixFromYawPitchRoll(const float cameraTargetPosition[3], float distance, float yaw, float pitch, float roll, int upAxis, float viewMatrix[16]) +{ + b3Vector3 camUpVector; + b3Vector3 camForward; + b3Vector3 camPos; + b3Vector3 camTargetPos = b3MakeVector3(cameraTargetPosition[0], cameraTargetPosition[1], cameraTargetPosition[2]); + b3Vector3 eyePos = b3MakeVector3(0, 0, 0); + + int forwardAxis(-1); + + { + + switch (upAxis) + { + + case 1: + { + + + forwardAxis = 0; + eyePos[forwardAxis] = -distance; + camForward = b3MakeVector3(eyePos[0], eyePos[1], eyePos[2]); + if (camForward.length2() < B3_EPSILON) + { + camForward.setValue(1.f, 0.f, 0.f); + } + else + { + camForward.normalize(); + } + b3Scalar rollRad = roll * b3Scalar(0.01745329251994329547); + b3Quaternion rollRot(camForward, rollRad); + + camUpVector = b3QuatRotate(rollRot, b3MakeVector3(0, 1, 0)); + //gLightPos = b3MakeVector3(-50.f,100,30); + break; + } + case 2: + { + + + forwardAxis = 1; + eyePos[forwardAxis] = -distance; + camForward = b3MakeVector3(eyePos[0], eyePos[1], eyePos[2]); + if (camForward.length2() < B3_EPSILON) + { + camForward.setValue(1.f, 0.f, 0.f); + } + else + { + camForward.normalize(); + } + + b3Scalar rollRad = roll * b3Scalar(0.01745329251994329547); + b3Quaternion rollRot(camForward, rollRad); + + camUpVector = b3QuatRotate(rollRot, b3MakeVector3(0, 0, 1)); + //gLightPos = b3MakeVector3(-50.f,30,100); + break; + } + default: + { + //b3Assert(0); + return; + } + }; + } + + + b3Scalar yawRad = yaw * b3Scalar(0.01745329251994329547);// rads per deg + b3Scalar pitchRad = pitch * b3Scalar(0.01745329251994329547);// rads per deg + + b3Quaternion pitchRot(camUpVector, pitchRad); + + b3Vector3 right = camUpVector.cross(camForward); + b3Quaternion yawRot(right, -yawRad); + + eyePos = b3Matrix3x3(pitchRot) * b3Matrix3x3(yawRot) * eyePos; + camPos = eyePos; + camPos += camTargetPos; + + float camPosf[4] = { camPos[0],camPos[1],camPos[2],0 }; + float camPosTargetf[4] = { camTargetPos[0],camTargetPos[1],camTargetPos[2],0 }; + float camUpf[4] = { camUpVector[0],camUpVector[1],camUpVector[2],0 }; + + b3ComputeViewMatrixFromPositions(camPosf, camPosTargetf, camUpf,viewMatrix); + +} + + +void b3ComputeProjectionMatrix(float left, float right, float bottom, float top, float nearVal, float farVal, float projectionMatrix[16]) +{ + projectionMatrix[0 * 4 + 0] = (float(2) * nearVal) / (right - left); + projectionMatrix[0 * 4 + 1] = float(0); + projectionMatrix[0 * 4 + 2] = float(0); + projectionMatrix[0 * 4 + 3] = float(0); + + projectionMatrix[1 * 4 + 0] = float(0); + projectionMatrix[1 * 4 + 1] = (float(2) * nearVal) / (top - bottom); + projectionMatrix[1 * 4 + 2] = float(0); + projectionMatrix[1 * 4 + 3] = float(0); + + projectionMatrix[2 * 4 + 0] = (right + left) / (right - left); + projectionMatrix[2 * 4 + 1] = (top + bottom) / (top - bottom); + projectionMatrix[2 * 4 + 2] = -(farVal + nearVal) / (farVal - nearVal); + projectionMatrix[2 * 4 + 3] = float(-1); + + projectionMatrix[3 * 4 + 0] = float(0); + projectionMatrix[3 * 4 + 1] = float(0); + projectionMatrix[3 * 4 + 2] = -(float(2) * farVal * nearVal) / (farVal - nearVal); + projectionMatrix[3 * 4 + 3] = float(0); +} + + +void b3ComputeProjectionMatrixFOV(float fov, float aspect, float nearVal, float farVal, float projectionMatrix[16]) +{ + float yScale = 1.0 / tan((3.141592538 / 180.0) * fov / 2); + float xScale = yScale / aspect; + + projectionMatrix[0 * 4 + 0] = xScale; + projectionMatrix[0 * 4 + 1] = float(0); + projectionMatrix[0 * 4 + 2] = float(0); + projectionMatrix[0 * 4 + 3] = float(0); + + projectionMatrix[1 * 4 + 0] = float(0); + projectionMatrix[1 * 4 + 1] = yScale; + projectionMatrix[1 * 4 + 2] = float(0); + projectionMatrix[1 * 4 + 3] = float(0); + + projectionMatrix[2 * 4 + 0] = 0; + projectionMatrix[2 * 4 + 1] = 0; + projectionMatrix[2 * 4 + 2] = (nearVal + farVal) / (nearVal - farVal); + projectionMatrix[2 * 4 + 3] = float(-1); + + projectionMatrix[3 * 4 + 0] = float(0); + projectionMatrix[3 * 4 + 1] = float(0); + projectionMatrix[3 * 4 + 2] = (float(2) * farVal * nearVal) / (nearVal - farVal); + projectionMatrix[3 * 4 + 3] = float(0); +} + + void b3RequestCameraImageSetViewMatrix2(b3SharedMemoryCommandHandle commandHandle, const float cameraTargetPosition[3], float distance, float yaw, float pitch, float roll, int upAxis) { struct SharedMemoryCommand* command = (struct SharedMemoryCommand*) commandHandle; b3Assert(command); b3Assert(command->m_type == CMD_REQUEST_CAMERA_IMAGE_DATA); - b3Vector3 camUpVector; - b3Vector3 camForward; - b3Vector3 camPos; - b3Vector3 camTargetPos = b3MakeVector3(cameraTargetPosition[0],cameraTargetPosition[1],cameraTargetPosition[2]); - b3Vector3 eyePos = b3MakeVector3(0,0,0); - - int forwardAxis(-1); - - { - - switch (upAxis) - { - - case 1: - { - - - forwardAxis = 0; - eyePos[forwardAxis] = -distance; - camForward = b3MakeVector3(eyePos[0],eyePos[1],eyePos[2]); - if (camForward.length2() < B3_EPSILON) - { - camForward.setValue(1.f,0.f,0.f); - } else - { - camForward.normalize(); - } - b3Scalar rollRad = roll * b3Scalar(0.01745329251994329547); - b3Quaternion rollRot(camForward,rollRad); - - camUpVector = b3QuatRotate(rollRot,b3MakeVector3(0,1,0)); - //gLightPos = b3MakeVector3(-50.f,100,30); - break; - } - case 2: - { - - - forwardAxis = 1; - eyePos[forwardAxis] = -distance; - camForward = b3MakeVector3(eyePos[0],eyePos[1],eyePos[2]); - if (camForward.length2() < B3_EPSILON) - { - camForward.setValue(1.f,0.f,0.f); - } else - { - camForward.normalize(); - } - - b3Scalar rollRad = roll * b3Scalar(0.01745329251994329547); - b3Quaternion rollRot(camForward,rollRad); - - camUpVector = b3QuatRotate(rollRot,b3MakeVector3(0,0,1)); - //gLightPos = b3MakeVector3(-50.f,30,100); - break; - } - default: - { - //b3Assert(0); - return; - } - }; - } - - - b3Scalar yawRad = yaw * b3Scalar(0.01745329251994329547);// rads per deg - b3Scalar pitchRad = pitch * b3Scalar(0.01745329251994329547);// rads per deg - - b3Quaternion pitchRot(camUpVector,pitchRad); - - b3Vector3 right = camUpVector.cross(camForward); - b3Quaternion yawRot(right,-yawRad); - - - - eyePos = b3Matrix3x3(pitchRot) * b3Matrix3x3(yawRot) * eyePos; - camPos = eyePos; - camPos += camTargetPos; - - float camPosf[4] = {camPos[0],camPos[1],camPos[2],0}; - float camPosTargetf[4] = {camTargetPos[0],camTargetPos[1],camTargetPos[2],0}; - float camUpf[4] = {camUpVector[0],camUpVector[1],camUpVector[2],0}; - - b3RequestCameraImageSetViewMatrix(commandHandle,camPosf,camPosTargetf,camUpf); + + b3ComputeViewMatrixFromYawPitchRoll(cameraTargetPosition, distance, yaw, pitch, roll, upAxis, command->m_requestPixelDataArguments.m_viewMatrix); + command->m_updateFlags |= REQUEST_PIXEL_ARGS_HAS_CAMERA_MATRICES; } + + + + void b3RequestCameraImageSetViewMatrix(b3SharedMemoryCommandHandle commandHandle, const float cameraPosition[3], const float cameraTargetPosition[3], const float cameraUp[3]) { - b3Vector3 eye = b3MakeVector3(cameraPosition[0], cameraPosition[1], cameraPosition[2]); - b3Vector3 center = b3MakeVector3(cameraTargetPosition[0], cameraTargetPosition[1], cameraTargetPosition[2]); - b3Vector3 up = b3MakeVector3(cameraUp[0], cameraUp[1], cameraUp[2]); - b3Vector3 f = (center - eye).normalized(); - b3Vector3 u = up.normalized(); - b3Vector3 s = (f.cross(u)).normalized(); - u = s.cross(f); - - float viewMatrix[16]; - - viewMatrix[0*4+0] = s.x; - viewMatrix[1*4+0] = s.y; - viewMatrix[2*4+0] = s.z; - - viewMatrix[0*4+1] = u.x; - viewMatrix[1*4+1] = u.y; - viewMatrix[2*4+1] = u.z; - - viewMatrix[0*4+2] =-f.x; - viewMatrix[1*4+2] =-f.y; - viewMatrix[2*4+2] =-f.z; - - viewMatrix[0*4+3] = 0.f; - viewMatrix[1*4+3] = 0.f; - viewMatrix[2*4+3] = 0.f; - - viewMatrix[3*4+0] = -s.dot(eye); - viewMatrix[3*4+1] = -u.dot(eye); - viewMatrix[3*4+2] = f.dot(eye); - viewMatrix[3*4+3] = 1.f; + float viewMatrix[16]; + b3ComputeViewMatrixFromPositions(cameraPosition, cameraTargetPosition, cameraUp, viewMatrix); struct SharedMemoryCommand* command = (struct SharedMemoryCommand*) commandHandle; b3Assert(command); b3Assert(command->m_type == CMD_REQUEST_CAMERA_IMAGE_DATA); - for (int i=0;i<16;i++) - { - command->m_requestPixelDataArguments.m_viewMatrix[i] = viewMatrix[i]; - } + + b3ComputeViewMatrixFromPositions(cameraPosition, cameraTargetPosition, cameraUp, command->m_requestPixelDataArguments.m_viewMatrix); + command->m_updateFlags |= REQUEST_PIXEL_ARGS_HAS_CAMERA_MATRICES; } void b3RequestCameraImageSetProjectionMatrix(b3SharedMemoryCommandHandle commandHandle, float left, float right, float bottom, float top, float nearVal, float farVal) { - float frustum[16]; - - frustum[0*4+0] = (float(2) * nearVal) / (right - left); - frustum[0*4+1] = float(0); - frustum[0*4+2] = float(0); - frustum[0*4+3] = float(0); - - frustum[1*4+0] = float(0); - frustum[1*4+1] = (float(2) * nearVal) / (top - bottom); - frustum[1*4+2] = float(0); - frustum[1*4+3] = float(0); - - frustum[2*4+0] = (right + left) / (right - left); - frustum[2*4+1] = (top + bottom) / (top - bottom); - frustum[2*4+2] = -(farVal + nearVal) / (farVal - nearVal); - frustum[2*4+3] = float(-1); - - frustum[3*4+0] = float(0); - frustum[3*4+1] = float(0); - frustum[3*4+2] = -(float(2) * farVal * nearVal) / (farVal - nearVal); - frustum[3*4+3] = float(0); struct SharedMemoryCommand* command = (struct SharedMemoryCommand*) commandHandle; b3Assert(command); b3Assert(command->m_type == CMD_REQUEST_CAMERA_IMAGE_DATA); - for (int i=0;i<16;i++) - { - command->m_requestPixelDataArguments.m_projectionMatrix[i] = frustum[i]; - } + + b3ComputeProjectionMatrix(left, right, bottom, top, nearVal, farVal, command->m_requestPixelDataArguments.m_projectionMatrix); + command->m_updateFlags |= REQUEST_PIXEL_ARGS_HAS_CAMERA_MATRICES; } void b3RequestCameraImageSetFOVProjectionMatrix(b3SharedMemoryCommandHandle commandHandle, float fov, float aspect, float nearVal, float farVal) { - float yScale = 1.0 / tan((3.141592538 / 180.0) * fov / 2); - float xScale = yScale / aspect; - - float frustum[16]; - - frustum[0*4+0] = xScale; - frustum[0*4+1] = float(0); - frustum[0*4+2] = float(0); - frustum[0*4+3] = float(0); - - frustum[1*4+0] = float(0); - frustum[1*4+1] = yScale; - frustum[1*4+2] = float(0); - frustum[1*4+3] = float(0); - - frustum[2*4+0] = 0; - frustum[2*4+1] = 0; - frustum[2*4+2] = (nearVal + farVal) / (nearVal - farVal); - frustum[2*4+3] = float(-1); - - frustum[3*4+0] = float(0); - frustum[3*4+1] = float(0); - frustum[3*4+2] = (float(2) * farVal * nearVal) / (nearVal - farVal); - frustum[3*4+3] = float(0); + struct SharedMemoryCommand* command = (struct SharedMemoryCommand*) commandHandle; b3Assert(command); b3Assert(command->m_type == CMD_REQUEST_CAMERA_IMAGE_DATA); - for (int i=0;i<16;i++) - { - command->m_requestPixelDataArguments.m_projectionMatrix[i] = frustum[i]; - } + + b3ComputeProjectionMatrixFOV(fov, aspect, nearVal, farVal, command->m_requestPixelDataArguments.m_projectionMatrix); + command->m_updateFlags |= REQUEST_PIXEL_ARGS_HAS_CAMERA_MATRICES; } @@ -1203,6 +1656,8 @@ b3SharedMemoryCommandHandle b3InitRequestContactPointInformation(b3PhysicsClient command->m_requestContactPointArguments.m_startingContactPointIndex = 0; command->m_requestContactPointArguments.m_objectAIndexFilter = -1; command->m_requestContactPointArguments.m_objectBIndexFilter = -1; + command->m_requestContactPointArguments.m_linkIndexAIndexFilter = -2; + command->m_requestContactPointArguments.m_linkIndexBIndexFilter = -2; command->m_updateFlags = 0; return (b3SharedMemoryCommandHandle) command; } @@ -1215,6 +1670,37 @@ void b3SetContactFilterBodyA(b3SharedMemoryCommandHandle commandHandle, int body command->m_requestContactPointArguments.m_objectAIndexFilter = bodyUniqueIdA; } +void b3SetContactFilterLinkA(b3SharedMemoryCommandHandle commandHandle, int linkIndexA) +{ + struct SharedMemoryCommand* command = (struct SharedMemoryCommand*) commandHandle; + b3Assert(command); + b3Assert(command->m_type == CMD_REQUEST_CONTACT_POINT_INFORMATION); + command->m_updateFlags |= CMD_REQUEST_CONTACT_POINT_HAS_LINK_INDEX_A_FILTER; + command->m_requestContactPointArguments.m_linkIndexAIndexFilter= linkIndexA; +} + +void b3SetContactFilterLinkB(b3SharedMemoryCommandHandle commandHandle, int linkIndexB) +{ + struct SharedMemoryCommand* command = (struct SharedMemoryCommand*) commandHandle; + b3Assert(command); + b3Assert(command->m_type == CMD_REQUEST_CONTACT_POINT_INFORMATION); + command->m_updateFlags |= CMD_REQUEST_CONTACT_POINT_HAS_LINK_INDEX_B_FILTER; + command->m_requestContactPointArguments.m_linkIndexBIndexFilter = linkIndexB; +} + +void b3SetClosestDistanceFilterLinkA(b3SharedMemoryCommandHandle commandHandle, int linkIndexA) +{ + b3SetContactFilterLinkA(commandHandle, linkIndexA); +} + +void b3SetClosestDistanceFilterLinkB(b3SharedMemoryCommandHandle commandHandle, int linkIndexB) +{ + b3SetContactFilterLinkB(commandHandle, linkIndexB); +} + + + + void b3SetContactFilterBodyB(b3SharedMemoryCommandHandle commandHandle, int bodyUniqueIdB) { struct SharedMemoryCommand* command = (struct SharedMemoryCommand*) commandHandle; @@ -1223,7 +1709,69 @@ void b3SetContactFilterBodyB(b3SharedMemoryCommandHandle commandHandle, int body command->m_requestContactPointArguments.m_objectBIndexFilter = bodyUniqueIdB; } -void b3SetContactFilterBodyB(b3SharedMemoryCommandHandle commandHandle, int bodyUniqueIdB); + +///compute the closest points between two bodies +b3SharedMemoryCommandHandle b3InitClosestDistanceQuery(b3PhysicsClientHandle physClient) +{ + b3SharedMemoryCommandHandle commandHandle =b3InitRequestContactPointInformation(physClient); + struct SharedMemoryCommand* command = (struct SharedMemoryCommand*) commandHandle; + b3Assert(command); + b3Assert(command->m_type == CMD_REQUEST_CONTACT_POINT_INFORMATION); + command->m_updateFlags = CMD_REQUEST_CONTACT_POINT_HAS_QUERY_MODE; + command->m_requestContactPointArguments.m_mode = CONTACT_QUERY_MODE_COMPUTE_CLOSEST_POINTS; + return commandHandle; +} + +void b3SetClosestDistanceFilterBodyA(b3SharedMemoryCommandHandle commandHandle, int bodyUniqueIdA) +{ + b3SetContactFilterBodyA(commandHandle,bodyUniqueIdA); +} + +void b3SetClosestDistanceFilterBodyB(b3SharedMemoryCommandHandle commandHandle, int bodyUniqueIdB) +{ + b3SetContactFilterBodyB(commandHandle,bodyUniqueIdB); +} + +void b3SetClosestDistanceThreshold(b3SharedMemoryCommandHandle commandHandle, double distance) +{ + struct SharedMemoryCommand* command = (struct SharedMemoryCommand*) commandHandle; + b3Assert(command); + b3Assert(command->m_type == CMD_REQUEST_CONTACT_POINT_INFORMATION); + command->m_updateFlags += CMD_REQUEST_CONTACT_POINT_HAS_CLOSEST_DISTANCE_THRESHOLD; + command->m_requestContactPointArguments.m_closestDistanceThreshold = distance; +} + + +///get all the bodies that touch a given axis aligned bounding box specified in world space (min and max coordinates) +b3SharedMemoryCommandHandle b3InitAABBOverlapQuery(b3PhysicsClientHandle physClient, const double aabbMin[3], const double aabbMax[3]) +{ + PhysicsClient* cl = (PhysicsClient*)physClient; + b3Assert(cl); + b3Assert(cl->canSubmitCommand()); + struct SharedMemoryCommand* command = cl->getAvailableSharedMemoryCommand(); + b3Assert(command); + command->m_type = CMD_REQUEST_AABB_OVERLAP; + command->m_updateFlags = 0; + command->m_requestOverlappingObjectsArgs.m_startingOverlappingObjectIndex = 0; + command->m_requestOverlappingObjectsArgs.m_aabbQueryMin[0] = aabbMin[0]; + command->m_requestOverlappingObjectsArgs.m_aabbQueryMin[1] = aabbMin[1]; + command->m_requestOverlappingObjectsArgs.m_aabbQueryMin[2] = aabbMin[2]; + + command->m_requestOverlappingObjectsArgs.m_aabbQueryMax[0] = aabbMax[0]; + command->m_requestOverlappingObjectsArgs.m_aabbQueryMax[1] = aabbMax[1]; + command->m_requestOverlappingObjectsArgs.m_aabbQueryMax[2] = aabbMax[2]; + return (b3SharedMemoryCommandHandle)command; +} + +void b3GetAABBOverlapResults(b3PhysicsClientHandle physClient, struct b3AABBOverlapData* data) +{ + PhysicsClient* cl = (PhysicsClient*)physClient; + if (cl) + { + cl->getCachedOverlappingObjects(data); + } +} + void b3GetContactPointInformation(b3PhysicsClientHandle physClient, struct b3ContactInformation* contactPointData) @@ -1235,6 +1783,11 @@ void b3GetContactPointInformation(b3PhysicsClientHandle physClient, struct b3Con } } +void b3GetClosestPointInformation(b3PhysicsClientHandle physClient, struct b3ContactInformation* contactPointInfo) +{ + b3GetContactPointInformation(physClient,contactPointInfo); +} + //request visual shape information @@ -1428,6 +1981,7 @@ b3SharedMemoryCommandHandle b3CalculateJacobianCommandInit(b3PhysicsClientHandle return (b3SharedMemoryCommandHandle)command; } + int b3GetStatusJacobian(b3SharedMemoryStatusHandle statusHandle, double* linearJacobian, double* angularJacobian) { const SharedMemoryStatus* status = (const SharedMemoryStatus*)statusHandle; @@ -1580,4 +2134,4 @@ int b3GetStatusInverseKinematicsJointPositions(b3SharedMemoryStatusHandle status } return true; -} \ No newline at end of file +} diff --git a/examples/SharedMemory/PhysicsClientC_API.h b/examples/SharedMemory/PhysicsClientC_API.h index 9fa0cbbfb..97b6a14a6 100644 --- a/examples/SharedMemory/PhysicsClientC_API.h +++ b/examples/SharedMemory/PhysicsClientC_API.h @@ -11,14 +11,18 @@ B3_DECLARE_HANDLE(b3SharedMemoryCommandHandle); B3_DECLARE_HANDLE(b3SharedMemoryStatusHandle); +///There are several connection methods, see following header files: +#include "PhysicsClientSharedMemory_C_API.h" +#include "PhysicsClientSharedMemory2_C_API.h" +#include "PhysicsDirectC_API.h" +#include "PhysicsClientUDP_C_API.h" +#include "SharedMemoryInProcessPhysicsC_API.h" + #ifdef __cplusplus extern "C" { #endif -///b3ConnectSharedMemory will connect to a physics server over shared memory, so -///make sure to start the server first. -///and a way to spawn an OpenGL 3D GUI physics server and connect (b3CreateInProcessPhysicsServerAndConnect) -b3PhysicsClientHandle b3ConnectSharedMemory(int key); + ///b3DisconnectSharedMemory will disconnect the client from the server and cleanup memory. void b3DisconnectSharedMemory(b3PhysicsClientHandle physClient); @@ -68,33 +72,86 @@ int b3GetNumJoints(b3PhysicsClientHandle physClient, int bodyIndex); ///given a body and joint index, return the joint information. See b3JointInfo in SharedMemoryPublic.h int b3GetJointInfo(b3PhysicsClientHandle physClient, int bodyIndex, int jointIndex, struct b3JointInfo* info); -b3SharedMemoryCommandHandle b3CreateJoint(b3PhysicsClientHandle physClient, int parentBodyIndex, int parentJointIndex, int childBodyIndex, int childJointIndex, struct b3JointInfo* info); +b3SharedMemoryCommandHandle b3InitCreateUserConstraintCommand(b3PhysicsClientHandle physClient, int parentBodyIndex, int parentJointIndex, int childBodyIndex, int childJointIndex, struct b3JointInfo* info); +int b3GetStatusUserConstraintUniqueId(b3SharedMemoryStatusHandle statusHandle); +b3SharedMemoryCommandHandle b3InitRemoveUserConstraintCommand(b3PhysicsClientHandle physClient, int userConstraintUniqueId); -///Request debug lines for debug visualization. The flags in debugMode are the same as used in Bullet +///Request physics debug lines for debug visualization. The flags in debugMode are the same as used in Bullet ///See btIDebugDraw::DebugDrawModes in Bullet/src/LinearMath/btIDebugDraw.h b3SharedMemoryCommandHandle b3InitRequestDebugLinesCommand(b3PhysicsClientHandle physClient, int debugMode); -///Get the pointers to the debug line information, after b3InitRequestDebugLinesCommand returns +///Get the pointers to the physics debug line information, after b3InitRequestDebugLinesCommand returns ///status CMD_DEBUG_LINES_COMPLETED void b3GetDebugLines(b3PhysicsClientHandle physClient, struct b3DebugLines* lines); +/// Add/remove user-specific debug lines and debug text messages +b3SharedMemoryCommandHandle b3InitUserDebugDrawAddLine3D(b3PhysicsClientHandle physClient, double fromXYZ[3], double toXYZ[3], double colorRGB[3], double lineWidth, double lifeTime); +b3SharedMemoryCommandHandle b3InitUserDebugDrawAddText3D(b3PhysicsClientHandle physClient, const char* txt, double positionXYZ[3], double colorRGB[3], double textSize, double lifeTime); +b3SharedMemoryCommandHandle b3InitUserDebugDrawRemove(b3PhysicsClientHandle physClient, int debugItemUniqueId); +b3SharedMemoryCommandHandle b3InitUserDebugDrawRemoveAll(b3PhysicsClientHandle physClient); + +b3SharedMemoryCommandHandle b3InitDebugDrawingCommand(b3PhysicsClientHandle physClient); +void b3SetDebugObjectColor(b3SharedMemoryCommandHandle commandHandle, int objectUniqueId, int linkIndex, double objectColorRGB[3]); +void b3RemoveDebugObjectColor(b3SharedMemoryCommandHandle commandHandle, int objectUniqueId, int linkIndex); + +///All debug items unique Ids are positive: a negative unique Id means failure. +int b3GetDebugItemUniqueId(b3SharedMemoryStatusHandle statusHandle); + + ///request an image from a simulated camera, using a software renderer. b3SharedMemoryCommandHandle b3InitRequestCameraImage(b3PhysicsClientHandle physClient); void b3RequestCameraImageSetCameraMatrices(b3SharedMemoryCommandHandle command, float viewMatrix[16], float projectionMatrix[16]); -void b3RequestCameraImageSetViewMatrix(b3SharedMemoryCommandHandle command, const float cameraPosition[3], const float cameraTargetPosition[3], const float cameraUp[3]); -void b3RequestCameraImageSetViewMatrix2(b3SharedMemoryCommandHandle commandHandle, const float cameraTargetPosition[3], float distance, float yaw, float pitch, float roll, int upAxis); -void b3RequestCameraImageSetProjectionMatrix(b3SharedMemoryCommandHandle command, float left, float right, float bottom, float top, float nearVal, float farVal); -void b3RequestCameraImageSetFOVProjectionMatrix(b3SharedMemoryCommandHandle command, float fov, float aspect, float nearVal, float farVal); void b3RequestCameraImageSetPixelResolution(b3SharedMemoryCommandHandle command, int width, int height ); +void b3RequestCameraImageSetLightDirection(b3SharedMemoryCommandHandle commandHandle, const float lightDirection[3]); +void b3RequestCameraImageSetLightColor(b3SharedMemoryCommandHandle commandHandle, const float lightColor[3]); +void b3RequestCameraImageSetLightDistance(b3SharedMemoryCommandHandle commandHandle, float lightDistance); +void b3RequestCameraImageSetLightAmbientCoeff(b3SharedMemoryCommandHandle commandHandle, float lightAmbientCoeff); +void b3RequestCameraImageSetLightDiffuseCoeff(b3SharedMemoryCommandHandle commandHandle, float lightDiffuseCoeff); +void b3RequestCameraImageSetLightSpecularCoeff(b3SharedMemoryCommandHandle commandHandle, float lightSpecularCoeff); +void b3RequestCameraImageSetShadow(b3SharedMemoryCommandHandle commandHandle, int hasShadow); void b3RequestCameraImageSelectRenderer(b3SharedMemoryCommandHandle commandHandle, int renderer); void b3GetCameraImageData(b3PhysicsClientHandle physClient, struct b3CameraImageData* imageData); +///compute a view matrix, helper function for b3RequestCameraImageSetCameraMatrices +void b3ComputeViewMatrixFromPositions(const float cameraPosition[3], const float cameraTargetPosition[3], const float cameraUp[3], float viewMatrix[16]); +void b3ComputeViewMatrixFromYawPitchRoll(const float cameraTargetPosition[3], float distance, float yaw, float pitch, float roll, int upAxis, float viewMatrix[16]); + +///compute a projection matrix, helper function for b3RequestCameraImageSetCameraMatrices +void b3ComputeProjectionMatrix(float left, float right, float bottom, float top, float nearVal, float farVal, float projectionMatrix[16]); +void b3ComputeProjectionMatrixFOV(float fov, float aspect, float nearVal, float farVal, float projectionMatrix[16]); + + +/* obsolete, please use b3ComputeViewProjectionMatrices */ +void b3RequestCameraImageSetViewMatrix(b3SharedMemoryCommandHandle command, const float cameraPosition[3], const float cameraTargetPosition[3], const float cameraUp[3]); +/* obsolete, please use b3ComputeViewProjectionMatrices */ +void b3RequestCameraImageSetViewMatrix2(b3SharedMemoryCommandHandle commandHandle, const float cameraTargetPosition[3], float distance, float yaw, float pitch, float roll, int upAxis); +/* obsolete, please use b3ComputeViewProjectionMatrices */ +void b3RequestCameraImageSetProjectionMatrix(b3SharedMemoryCommandHandle command, float left, float right, float bottom, float top, float nearVal, float farVal); +/* obsolete, please use b3ComputeViewProjectionMatrices */ +void b3RequestCameraImageSetFOVProjectionMatrix(b3SharedMemoryCommandHandle command, float fov, float aspect, float nearVal, float farVal); + + ///request an contact point information b3SharedMemoryCommandHandle b3InitRequestContactPointInformation(b3PhysicsClientHandle physClient); void b3SetContactFilterBodyA(b3SharedMemoryCommandHandle commandHandle, int bodyUniqueIdA); void b3SetContactFilterBodyB(b3SharedMemoryCommandHandle commandHandle, int bodyUniqueIdB); +void b3SetContactFilterLinkA(b3SharedMemoryCommandHandle commandHandle, int linkIndexA); +void b3SetContactFilterLinkB(b3SharedMemoryCommandHandle commandHandle, int linkIndexB); void b3GetContactPointInformation(b3PhysicsClientHandle physClient, struct b3ContactInformation* contactPointInfo); +///compute the closest points between two bodies +b3SharedMemoryCommandHandle b3InitClosestDistanceQuery(b3PhysicsClientHandle physClient); +void b3SetClosestDistanceFilterBodyA(b3SharedMemoryCommandHandle commandHandle, int bodyUniqueIdA); +void b3SetClosestDistanceFilterLinkA(b3SharedMemoryCommandHandle commandHandle, int linkIndexA); +void b3SetClosestDistanceFilterBodyB(b3SharedMemoryCommandHandle commandHandle, int bodyUniqueIdB); +void b3SetClosestDistanceFilterLinkB(b3SharedMemoryCommandHandle commandHandle, int linkIndexB); +void b3SetClosestDistanceThreshold(b3SharedMemoryCommandHandle commandHandle, double distance); +void b3GetClosestPointInformation(b3PhysicsClientHandle physClient, struct b3ContactInformation* contactPointInfo); + +///get all the bodies that touch a given axis aligned bounding box specified in world space (min and max coordinates) +b3SharedMemoryCommandHandle b3InitAABBOverlapQuery(b3PhysicsClientHandle physClient, const double aabbMin[3],const double aabbMax[3]); +void b3GetAABBOverlapResults(b3PhysicsClientHandle physClient, struct b3AABBOverlapData* data); + //request visual shape information b3SharedMemoryCommandHandle b3InitRequestVisualShapeInformation(b3PhysicsClientHandle physClient, int bodyUniqueIdA); void b3GetVisualShapeInformation(b3PhysicsClientHandle physClient, struct b3VisualShapeInformation* visualShapeInfo); @@ -109,6 +166,9 @@ int b3PhysicsParamSetDefaultContactERP(b3SharedMemoryCommandHandle commandHandle int b3PhysicsParamSetNumSubSteps(b3SharedMemoryCommandHandle commandHandle, int numSubSteps); int b3PhysicsParamSetRealTimeSimulation(b3SharedMemoryCommandHandle commandHandle, int enableRealTimeSimulation); int b3PhysicsParamSetNumSolverIterations(b3SharedMemoryCommandHandle commandHandle, int numSolverIterations); +int b3PhysicsParamSetUseSplitImpulse(b3SharedMemoryCommandHandle commandHandle, int useSplitImpulse); +int b3PhysicsParamSetSplitImpulsePenetrationThreshold(b3SharedMemoryCommandHandle commandHandle, double splitImpulsePenetrationThreshold); + //b3PhysicsParamSetInternalSimFlags is for internal/temporary/easter-egg/experimental demo purposes //Use at own risk: magic things may or my not happen when calling this API @@ -128,6 +188,11 @@ int b3LoadUrdfCommandSetStartOrientation(b3SharedMemoryCommandHandle commandHand int b3LoadUrdfCommandSetUseMultiBody(b3SharedMemoryCommandHandle commandHandle, int useMultiBody); int b3LoadUrdfCommandSetUseFixedBase(b3SharedMemoryCommandHandle commandHandle, int useFixedBase); +b3SharedMemoryCommandHandle b3LoadBulletCommandInit(b3PhysicsClientHandle physClient, const char* fileName); +b3SharedMemoryCommandHandle b3SaveBulletCommandInit(b3PhysicsClientHandle physClient, const char* fileName); +b3SharedMemoryCommandHandle b3LoadMJCFCommandInit(b3PhysicsClientHandle physClient, const char* fileName); + + ///compute the forces to achieve an acceleration, given a state q and qdot using inverse dynamics b3SharedMemoryCommandHandle b3CalculateInverseDynamicsCommandInit(b3PhysicsClientHandle physClient, int bodyIndex, @@ -199,6 +264,9 @@ int b3CreateBoxCommandSetColorRGBA(b3SharedMemoryCommandHandle commandHandle, do b3SharedMemoryCommandHandle b3CreatePoseCommandInit(b3PhysicsClientHandle physClient, int bodyIndex); int b3CreatePoseCommandSetBasePosition(b3SharedMemoryCommandHandle commandHandle, double startPosX,double startPosY,double startPosZ); int b3CreatePoseCommandSetBaseOrientation(b3SharedMemoryCommandHandle commandHandle, double startOrnX,double startOrnY,double startOrnZ, double startOrnW); +int b3CreatePoseCommandSetBaseLinearVelocity(b3SharedMemoryCommandHandle commandHandle, double linVel[3]); +int b3CreatePoseCommandSetBaseAngularVelocity(b3SharedMemoryCommandHandle commandHandle, double angVel[3]); + int b3CreatePoseCommandSetJointPositions(b3SharedMemoryCommandHandle commandHandle, int numJointPositions, const double* jointPositions); int b3CreatePoseCommandSetJointPosition(b3PhysicsClientHandle physClient, b3SharedMemoryCommandHandle commandHandle, int jointIndex, double jointPosition); @@ -228,7 +296,11 @@ b3SharedMemoryCommandHandle b3ApplyExternalForceCommandInit(b3PhysicsClientHandl void b3ApplyExternalForce(b3SharedMemoryCommandHandle commandHandle, int bodyUniqueId, int linkId, const double force[3], const double position[3], int flags); void b3ApplyExternalTorque(b3SharedMemoryCommandHandle commandHandle, int bodyUniqueId, int linkId, const double torque[3], int flags); +///experiments of robots interacting with non-rigid objects (such as btSoftBody) b3SharedMemoryCommandHandle b3LoadBunnyCommandInit(b3PhysicsClientHandle physClient); +int b3LoadBunnySetScale(b3SharedMemoryCommandHandle commandHandle, double scale); +int b3LoadBunnySetMass(b3SharedMemoryCommandHandle commandHandle, double mass); +int b3LoadBunnySetCollisionMargin(b3SharedMemoryCommandHandle commandHandle, double collisionMargin); #ifdef __cplusplus } diff --git a/examples/SharedMemory/PhysicsClientExample.cpp b/examples/SharedMemory/PhysicsClientExample.cpp index b0fe2be97..98c59b2d5 100644 --- a/examples/SharedMemory/PhysicsClientExample.cpp +++ b/examples/SharedMemory/PhysicsClientExample.cpp @@ -89,10 +89,10 @@ protected: virtual void resetCamera() { - float dist = 4; - float pitch = 193; - float yaw = 25; - float targetPos[3]={0,0,0.5};//-3,2.8,-2.5}; + float dist = 4; + float pitch = 193; + float yaw = 25; + float targetPos[3]={0,0,0.5};//-3,2.8,-2.5}; m_guiHelper->resetCamera(dist,pitch,yaw,targetPos[0],targetPos[1],targetPos[2]); } @@ -481,6 +481,22 @@ void PhysicsClientExample::prepareAndSubmitCommand(int commandId) } break; } + case CMD_SET_SHADOW: + { + b3SharedMemoryCommandHandle commandHandle = b3InitRequestCameraImage(m_physicsClientHandle); + float viewMatrix[16]; + float projectionMatrix[16]; + m_guiHelper->getRenderInterface()->getActiveCamera()->getCameraProjectionMatrix(projectionMatrix); + m_guiHelper->getRenderInterface()->getActiveCamera()->getCameraViewMatrix(viewMatrix); + + b3RequestCameraImageSetCameraMatrices(commandHandle, viewMatrix,projectionMatrix); + b3RequestCameraImageSetPixelResolution(commandHandle, camVisualizerWidth,camVisualizerHeight); + bool hasShadow = true; + b3RequestCameraImageSetShadow(commandHandle, hasShadow); + b3SubmitClientCommand(m_physicsClientHandle, commandHandle); + break; + } + default: { b3Error("Unknown buttonId"); @@ -556,6 +572,7 @@ void PhysicsClientExample::createButtons() createButton("Load URDF",CMD_LOAD_URDF, isTrigger); createButton("Load SDF",CMD_LOAD_SDF, isTrigger); createButton("Save World",CMD_SAVE_WORLD, isTrigger); + createButton("Set Shadow",CMD_SET_SHADOW, isTrigger); createButton("Get Camera Image",CMD_REQUEST_CAMERA_IMAGE_DATA,isTrigger); createButton("Step Sim",CMD_STEP_FORWARD_SIMULATION, isTrigger); createButton("Realtime Sim",CMD_CUSTOM_SET_REALTIME_SIMULATION, isTrigger); diff --git a/examples/SharedMemory/PhysicsClientSharedMemory.cpp b/examples/SharedMemory/PhysicsClientSharedMemory.cpp index 334806ff5..e02d11e2d 100644 --- a/examples/SharedMemory/PhysicsClientSharedMemory.cpp +++ b/examples/SharedMemory/PhysicsClientSharedMemory.cpp @@ -40,7 +40,7 @@ struct PhysicsClientSharedMemoryInternalData { btAlignedObjectArray m_cachedSegmentationMaskBuffer; btAlignedObjectArray m_cachedContactPoints; - + btAlignedObjectArray m_cachedOverlappingObjects; btAlignedObjectArray m_cachedVisualShapes; btAlignedObjectArray m_bodyIdsRequestInfo; @@ -100,6 +100,10 @@ bool PhysicsClientSharedMemory::getBodyInfo(int bodyUniqueId, struct b3BodyInfo& info.m_baseName = bodyJoints->m_baseName.c_str(); return true; } + + + + return false; } @@ -124,8 +128,11 @@ bool PhysicsClientSharedMemory::getJointInfo(int bodyUniqueId, int jointIndex, b if (bodyJointsPtr && *bodyJointsPtr) { BodyJointInfoCache* bodyJoints = *bodyJointsPtr; - info = bodyJoints->m_jointInfo[jointIndex]; - return true; + if ((jointIndex >= 0) && (jointIndex < bodyJoints->m_jointInfo.size())) + { + info = bodyJoints->m_jointInfo[jointIndex]; + return true; + } } return false; } @@ -201,6 +208,32 @@ bool PhysicsClientSharedMemory::connect() { b3Error("Cannot connect to shared memory"); return false; } +#if 0 + if (m_data->m_isConnected) + { + //get all existing bodies and body info... + + SharedMemoryCommand& command = m_data->m_testBlock1->m_clientCommands[0]; + //now transfer the information of the individual objects etc. + command.m_type = CMD_REQUEST_BODY_INFO; + command.m_sdfRequestInfoArgs.m_bodyUniqueId = 37; + submitClientCommand(command); + int timeout = 1024 * 1024 * 1024; + + const SharedMemoryStatus* status = 0; + + while ((status == 0) && (timeout-- > 0)) + { + status = processServerStatus(); + + } + + + //submitClientCommand(command); + + + } +#endif return true; } @@ -210,7 +243,7 @@ void PhysicsClientSharedMemory::processBodyJointInfo(int bodyUniqueId, const Sha { bParse::btBulletFile bf( &this->m_data->m_testBlock1->m_bulletStreamDataServerToClientRefactor[0], - serverCmd.m_dataStreamArguments.m_streamChunkLength); + serverCmd.m_numDataStreamBytes); bf.setFileDNAisMemoryDNA(); bf.parse(false); @@ -291,16 +324,17 @@ const SharedMemoryStatus* PhysicsClientSharedMemory::processServerStatus() { break; } + case CMD_URDF_LOADING_COMPLETED: { if (m_data->m_verboseOutput) { b3Printf("Server loading the URDF OK\n"); } - if (serverCmd.m_dataStreamArguments.m_streamChunkLength > 0) { + if (serverCmd.m_numDataStreamBytes > 0) { bParse::btBulletFile bf( this->m_data->m_testBlock1->m_bulletStreamDataServerToClientRefactor, - serverCmd.m_dataStreamArguments.m_streamChunkLength); + serverCmd.m_numDataStreamBytes); bf.setFileDNAisMemoryDNA(); bf.parse(false); int bodyUniqueId = serverCmd.m_dataStreamArguments.m_bodyUniqueId; @@ -592,6 +626,30 @@ const SharedMemoryStatus* PhysicsClientSharedMemory::processServerStatus() { b3Warning("Inverse Dynamics computations failed"); break; } + case CMD_REQUEST_AABB_OVERLAP_FAILED: + { + b3Warning("Overlapping object query failed"); + break; + } + case CMD_REQUEST_AABB_OVERLAP_COMPLETED: + { + if (m_data->m_verboseOutput) + { + b3Printf("Overlapping object request completed"); + } + + int startOverlapIndex = serverCmd.m_sendOverlappingObjectsArgs.m_startingOverlappingObjectIndex; + int numOverlapCopied = serverCmd.m_sendOverlappingObjectsArgs.m_numOverlappingObjectsCopied; + m_data->m_cachedOverlappingObjects.resize(startOverlapIndex + numOverlapCopied); + b3OverlappingObject* objects = (b3OverlappingObject*)m_data->m_testBlock1->m_bulletStreamDataServerToClientRefactor; + + for (int i = 0; i < numOverlapCopied; i++) + { + m_data->m_cachedOverlappingObjects[startOverlapIndex + i] = objects[i]; + } + + break; + } case CMD_CONTACT_POINT_INFORMATION_COMPLETED: { if (m_data->m_verboseOutput) @@ -675,6 +733,43 @@ const SharedMemoryStatus* PhysicsClientSharedMemory::processServerStatus() { b3Warning("Load texture failed"); break; } + case CMD_BULLET_LOADING_COMPLETED: + { + break; + } + case CMD_BULLET_LOADING_FAILED: + { + b3Warning("Load .bullet failed"); + break; + } + case CMD_BULLET_SAVING_FAILED: + { + b3Warning("Save .bullet failed"); + break; + } + case CMD_MJCF_LOADING_FAILED: + { + b3Warning("Load .mjcf failed"); + break; + } + case CMD_USER_DEBUG_DRAW_COMPLETED: + { + break; + } + case CMD_USER_DEBUG_DRAW_FAILED: + { + b3Warning("User debug draw failed"); + break; + } + case CMD_USER_CONSTRAINT_COMPLETED: + { + break; + } + case CMD_USER_CONSTRAINT_FAILED: + { + b3Warning("createConstraint failed"); + break; + } default: { b3Error("Unknown server status %d\n", serverCmd.m_type); btAssert(0); @@ -736,6 +831,18 @@ const SharedMemoryStatus* PhysicsClientSharedMemory::processServerStatus() { m_data->m_lastServerStatus = m_data->m_tempBackupServerStatus; } } + + if (serverCmd.m_type == CMD_REQUEST_AABB_OVERLAP_COMPLETED) + { + SharedMemoryCommand& command = m_data->m_testBlock1->m_clientCommands[0]; + if (serverCmd.m_sendOverlappingObjectsArgs.m_numRemainingOverlappingObjects > 0 && serverCmd.m_sendOverlappingObjectsArgs.m_numOverlappingObjectsCopied) + { + command.m_type = CMD_REQUEST_AABB_OVERLAP; + command.m_requestOverlappingObjectsArgs.m_startingOverlappingObjectIndex = serverCmd.m_sendOverlappingObjectsArgs.m_startingOverlappingObjectIndex + serverCmd.m_sendOverlappingObjectsArgs.m_numOverlappingObjectsCopied; + submitClientCommand(command); + return 0; + } + } if (serverCmd.m_type == CMD_CONTACT_POINT_INFORMATION_COMPLETED) { @@ -869,6 +976,14 @@ void PhysicsClientSharedMemory::getCachedContactPointInformation(struct b3Contac } +void PhysicsClientSharedMemory::getCachedOverlappingObjects(struct b3AABBOverlapData* overlappingObjects) +{ + overlappingObjects->m_numOverlappingObjects = m_data->m_cachedOverlappingObjects.size(); + overlappingObjects->m_overlappingObjects = m_data->m_cachedOverlappingObjects.size() ? + &m_data->m_cachedOverlappingObjects[0] : 0; +} + + void PhysicsClientSharedMemory::getCachedVisualShapeInformation(struct b3VisualShapeInformation* visualShapesInfo) { visualShapesInfo->m_numVisualShapes = m_data->m_cachedVisualShapes.size(); diff --git a/examples/SharedMemory/PhysicsClientSharedMemory.h b/examples/SharedMemory/PhysicsClientSharedMemory.h index 2dc659646..d5f6b3cff 100644 --- a/examples/SharedMemory/PhysicsClientSharedMemory.h +++ b/examples/SharedMemory/PhysicsClientSharedMemory.h @@ -12,7 +12,7 @@ class PhysicsClientSharedMemory : public PhysicsClient { protected: virtual void setSharedMemoryInterface(class SharedMemoryInterface* sharedMem); void processBodyJointInfo(int bodyUniqueId, const struct SharedMemoryStatus& serverCmd); - + public: PhysicsClientSharedMemory(); @@ -57,6 +57,8 @@ public: virtual void getCachedContactPointInformation(struct b3ContactInformation* contactPointData); + virtual void getCachedOverlappingObjects(struct b3AABBOverlapData* overlappingObjects); + virtual void getCachedVisualShapeInformation(struct b3VisualShapeInformation* visualShapesInfo); }; diff --git a/examples/SharedMemory/PhysicsClientSharedMemory2.cpp b/examples/SharedMemory/PhysicsClientSharedMemory2.cpp new file mode 100644 index 000000000..7eea2298d --- /dev/null +++ b/examples/SharedMemory/PhysicsClientSharedMemory2.cpp @@ -0,0 +1,27 @@ + +#include "PhysicsClientSharedMemory2.h" +#include "PosixSharedMemory.h" +#include "Win32SharedMemory.h" +#include "Bullet3Common/b3Logging.h" +#include "Bullet3Common/b3Scalar.h" + +#include "SharedMemoryCommandProcessor.h" + + +PhysicsClientSharedMemory2::PhysicsClientSharedMemory2(SharedMemoryCommandProcessor* proc) + :PhysicsDirect(proc) +{ + m_proc = proc; +} +PhysicsClientSharedMemory2::~PhysicsClientSharedMemory2() +{ +} + +void PhysicsClientSharedMemory2::setSharedMemoryInterface(class SharedMemoryInterface* sharedMem) +{ + if (m_proc) + { + m_proc->setSharedMemoryInterface(sharedMem); + } +} + diff --git a/examples/SharedMemory/PhysicsClientSharedMemory2.h b/examples/SharedMemory/PhysicsClientSharedMemory2.h new file mode 100644 index 000000000..e3b109370 --- /dev/null +++ b/examples/SharedMemory/PhysicsClientSharedMemory2.h @@ -0,0 +1,18 @@ +#ifndef PHYSICS_CLIENT_SHARED_MEMORY2_H +#define PHYSICS_CLIENT_SHARED_MEMORY2_H + +#include "PhysicsDirect.h" + +class PhysicsClientSharedMemory2 : public PhysicsDirect +{ + class SharedMemoryCommandProcessor* m_proc; + +public: + PhysicsClientSharedMemory2(SharedMemoryCommandProcessor* proc); + virtual ~PhysicsClientSharedMemory2(); + + void setSharedMemoryInterface(class SharedMemoryInterface* sharedMem); + +}; + +#endif //PHYSICS_CLIENT_SHARED_MEMORY2_H \ No newline at end of file diff --git a/examples/SharedMemory/PhysicsClientSharedMemory2_C_API.cpp b/examples/SharedMemory/PhysicsClientSharedMemory2_C_API.cpp new file mode 100644 index 000000000..7323205d0 --- /dev/null +++ b/examples/SharedMemory/PhysicsClientSharedMemory2_C_API.cpp @@ -0,0 +1,19 @@ +#include "PhysicsClientSharedMemory2_C_API.h" + +#include "PhysicsDirect.h" +#include "SharedMemoryCommandProcessor.h" + +b3PhysicsClientHandle b3ConnectSharedMemory2(int key) +{ + + SharedMemoryCommandProcessor* cmdProc = new SharedMemoryCommandProcessor(); + cmdProc->setSharedMemoryKey(key); + PhysicsDirect* cl = new PhysicsDirect(cmdProc); + + cl->setSharedMemoryKey(key); + + cl->connect(); + + return (b3PhysicsClientHandle)cl; +} + diff --git a/examples/SharedMemory/PhysicsClientSharedMemory2_C_API.h b/examples/SharedMemory/PhysicsClientSharedMemory2_C_API.h new file mode 100644 index 000000000..95d4bf690 --- /dev/null +++ b/examples/SharedMemory/PhysicsClientSharedMemory2_C_API.h @@ -0,0 +1,18 @@ +#ifndef PHYSICS_CLIENT_SHARED_MEMORY2_H +#define PHYSICS_CLIENT_SHARED_MEMORY2_H + +#include "PhysicsClientC_API.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +b3PhysicsClientHandle b3ConnectSharedMemory2(int key); + + +#ifdef __cplusplus +} +#endif + +#endif //PHYSICS_CLIENT_SHARED_MEMORY2_H diff --git a/examples/SharedMemory/PhysicsClientSharedMemory_C_API.cpp b/examples/SharedMemory/PhysicsClientSharedMemory_C_API.cpp new file mode 100644 index 000000000..36c794f80 --- /dev/null +++ b/examples/SharedMemory/PhysicsClientSharedMemory_C_API.cpp @@ -0,0 +1,11 @@ +#include "PhysicsClientSharedMemory_C_API.h" + +#include "PhysicsClientSharedMemory.h" + +b3PhysicsClientHandle b3ConnectSharedMemory(int key) +{ + PhysicsClientSharedMemory* cl = new PhysicsClientSharedMemory(); + cl->setSharedMemoryKey(key); + cl->connect(); + return (b3PhysicsClientHandle)cl; +} diff --git a/examples/SharedMemory/PhysicsClientSharedMemory_C_API.h b/examples/SharedMemory/PhysicsClientSharedMemory_C_API.h new file mode 100644 index 000000000..2a4e4e665 --- /dev/null +++ b/examples/SharedMemory/PhysicsClientSharedMemory_C_API.h @@ -0,0 +1,16 @@ +#ifndef PHYSICS_CLIENT_SHARED_MEMORY_H +#define PHYSICS_CLIENT_SHARED_MEMORY_H + +#include "PhysicsClientC_API.h" + +#ifdef __cplusplus +extern "C" { +#endif + + b3PhysicsClientHandle b3ConnectSharedMemory(int key); + +#ifdef __cplusplus +} +#endif + +#endif //PHYSICS_CLIENT_SHARED_MEMORY_H diff --git a/examples/SharedMemory/PhysicsClientUDP.cpp b/examples/SharedMemory/PhysicsClientUDP.cpp new file mode 100644 index 000000000..0d76f8310 --- /dev/null +++ b/examples/SharedMemory/PhysicsClientUDP.cpp @@ -0,0 +1,592 @@ +#include "PhysicsClientUDP.h" +#include +#include +#include +#include "../Utils/b3Clock.h" +#include "PhysicsClient.h" +//#include "LinearMath/btVector3.h" +#include "SharedMemoryCommands.h" +#include +#include "Bullet3Common/b3Logging.h" +#include "../MultiThreading/b3ThreadSupportInterface.h" +void UDPThreadFunc(void* userPtr, void* lsMemory); +void* UDPlsMemoryFunc(); +bool gVerboseNetworkMessagesClient = false; + +#ifndef _WIN32 +#include "../MultiThreading/b3PosixThreadSupport.h" + +b3ThreadSupportInterface* createUDPThreadSupport(int numThreads) +{ + b3PosixThreadSupport::ThreadConstructionInfo constructionInfo("UDPThread", + UDPThreadFunc, + UDPlsMemoryFunc, + numThreads); + b3ThreadSupportInterface* threadSupport = new b3PosixThreadSupport(constructionInfo); + + return threadSupport; + +} + + +#elif defined( _WIN32) +#include "../MultiThreading/b3Win32ThreadSupport.h" + +b3ThreadSupportInterface* createUDPThreadSupport(int numThreads) +{ + b3Win32ThreadSupport::Win32ThreadConstructionInfo threadConstructionInfo("UDPThread", UDPThreadFunc, UDPlsMemoryFunc, numThreads); + b3Win32ThreadSupport* threadSupport = new b3Win32ThreadSupport(threadConstructionInfo); + return threadSupport; + +} +#endif + + + +struct UDPThreadLocalStorage +{ + int threadId; +}; + + + +unsigned int b3DeserializeInt(const unsigned char* input) +{ + unsigned int tmp = (input[3] << 24) + (input[2] << 16) + (input[1] << 8) + input[0]; + return tmp; +} + +struct UdpNetworkedInternalData +{ + ENetHost* m_client; + ENetAddress m_address; + ENetPeer* m_peer; + ENetEvent m_event; + bool m_isConnected; + + b3ThreadSupportInterface* m_threadSupport; + + b3CriticalSection* m_cs; + + UdpNetworkedInternalData* m_udpInternalData; + + + SharedMemoryCommand m_clientCmd; + bool m_hasCommand; + + bool m_hasStatus; + SharedMemoryStatus m_lastStatus; + b3AlignedObjectArray m_stream; + + std::string m_hostName; + int m_port; + + UdpNetworkedInternalData() + :m_client(0), + m_peer(0), + m_isConnected(false), + m_threadSupport(0), + m_hasCommand(false), + m_hasStatus(false) + { + + } + + bool connectUDP() + { + if (m_isConnected) + return true; + + + + if (enet_initialize() != 0) + { + fprintf(stderr, "Error initialising enet"); + + exit(EXIT_FAILURE); + + } + + m_client = enet_host_create(NULL, /* create a client host */ + 1, /* number of clients */ + 2, /* number of channels */ + 57600 / 8, /* incoming bandwith */ + 14400 / 8); /* outgoing bandwith */ + + if (m_client == NULL) { + fprintf(stderr, "Could not create client host"); + return false; + } + + enet_address_set_host(&m_address, m_hostName.c_str()); + m_address.port = m_port; + + m_peer = enet_host_connect(m_client, + &m_address, /* address to connect to */ + 2, /* number of channels */ + 0); /* user data supplied to + the receiving host */ + + if (m_peer == NULL) { + fprintf(stderr, "No available peers for initiating an ENet " + "connection.\n"); + return false; + + } + + + /* Try to connect to server within 5 seconds */ + if (enet_host_service(m_client, &m_event, 5000) > 0 && + m_event.type == ENET_EVENT_TYPE_CONNECT) + { + puts("Connection to server succeeded."); + } + else + { + /* Either the 5 seconds are up or a disconnect event was */ + /* received. Reset the peer in the event the 5 seconds */ + /* had run out without any significant event. */ + enet_peer_reset(m_peer); + + fprintf(stderr, "Connection to server failed."); + return false; + } + + + int serviceResult = enet_host_service(m_client, &m_event, 0); + + if (serviceResult > 0) + { + switch (m_event.type) + { + case ENET_EVENT_TYPE_CONNECT: + printf("A new client connected from %x:%u.\n", + m_event.peer->address.host, + m_event.peer->address.port); + m_event.peer->data = (void*)"New User"; + break; + + case ENET_EVENT_TYPE_RECEIVE: + + if (gVerboseNetworkMessagesClient) + { + printf("A packet of length %u containing '%s' was " + "received from %s on channel %u.\n", + m_event.packet->dataLength, + m_event.packet->data, + m_event.peer->data, + m_event.channelID); + } + /* Clean up the packet now that we're done using it. + > */ + enet_packet_destroy(m_event.packet); + + break; + + case ENET_EVENT_TYPE_DISCONNECT: + printf("%s disconected.\n", m_event.peer->data); + + break; + default: + { + printf("unknown event type: %d.\n", m_event.type); + } + } + } + else if (serviceResult > 0) + { + puts("Error with servicing the client"); + return false; + } + + m_isConnected = true; + return m_isConnected; + } + + bool checkData() + { + bool hasStatus = false; + + int serviceResult = enet_host_service(m_client, &m_event, 0); + + if (serviceResult > 0) + { + switch (m_event.type) + { + case ENET_EVENT_TYPE_CONNECT: + printf("A new client connected from %x:%u.\n", + m_event.peer->address.host, + m_event.peer->address.port); + + m_event.peer->data = (void*)"New User"; + break; + + case ENET_EVENT_TYPE_RECEIVE: + { + if (gVerboseNetworkMessagesClient) + { + printf("A packet of length %u containing '%s' was " + "received from %s on channel %u.\n", + m_event.packet->dataLength, + m_event.packet->data, + m_event.peer->data, + m_event.channelID); + } + + int packetSizeInBytes = b3DeserializeInt(m_event.packet->data); + + if (packetSizeInBytes == m_event.packet->dataLength) + { + + SharedMemoryStatus* statPtr = (SharedMemoryStatus*)&m_event.packet->data[4]; + m_lastStatus = *statPtr; + int streamOffsetInBytes = 4 + sizeof(SharedMemoryStatus); + int numStreamBytes = packetSizeInBytes - streamOffsetInBytes; + m_stream.resize(numStreamBytes); + for (int i = 0; i < numStreamBytes; i++) + { + m_stream[i] = m_event.packet->data[i + streamOffsetInBytes]; + } + } + else + { + printf("unknown status message received\n"); + } + enet_packet_destroy(m_event.packet); + hasStatus = true; + break; + } + case ENET_EVENT_TYPE_DISCONNECT: + { + printf("%s disconected.\n", m_event.peer->data); + + break; + } + default: + { + printf("unknown event type: %d.\n", m_event.type); + } + } + } + else if (serviceResult > 0) + { + puts("Error with servicing the client"); + } + + return hasStatus; + } + +}; + +enum UDPThreadEnums +{ + eUDPRequestTerminate = 13, + eUDPIsUnInitialized, + eUDPIsInitialized, + eUDPInitializationFailed, + eUDPHasTerminated +}; + + + +enum UDPCommandEnums +{ + eUDPIdle = 13, + eUDP_ConnectRequest, + eUDP_Connected, + eUDP_ConnectionFailed, + eUDP_DisconnectRequest, + eUDP_Disconnected, + +}; + +void UDPThreadFunc(void* userPtr, void* lsMemory) +{ + printf("UDPThreadFunc thread started\n"); + UDPThreadLocalStorage* localStorage = (UDPThreadLocalStorage*)lsMemory; + + UdpNetworkedInternalData* args = (UdpNetworkedInternalData*)userPtr; + int workLeft = true; + b3Clock clock; + clock.reset(); + bool init = true; + if (init) + { + + args->m_cs->lock(); + args->m_cs->setSharedParam(0, eUDPIsInitialized); + args->m_cs->unlock(); + + + double deltaTimeInSeconds = 0; + + do + { + deltaTimeInSeconds += double(clock.getTimeMicroseconds()) / 1000000.; + + if (deltaTimeInSeconds<(1. / 5000.)) + { +// b3Clock::usleep(250); + } + else + { + + clock.reset(); + deltaTimeInSeconds = 0.f; + switch (args->m_cs->getSharedParam(1)) + { + case eUDP_ConnectRequest: + { + bool connected = args->connectUDP(); + if (connected) + { + args->m_cs->setSharedParam(1, eUDP_Connected); + } + else + { + args->m_cs->setSharedParam(1, eUDP_ConnectionFailed); + } + break; + } + default: + { + } + }; + + if (args->m_isConnected) + { + + args->m_cs->lock(); + bool hasCommand = args->m_hasCommand; + args->m_cs->unlock(); + + + if (hasCommand) + { + + int sz = sizeof(SharedMemoryCommand); + ENetPacket *packet = enet_packet_create(&args->m_clientCmd, sz, ENET_PACKET_FLAG_RELIABLE); + int res = enet_peer_send(args->m_peer, 0, packet); + args->m_cs->lock(); + args->m_hasCommand = false; + args->m_cs->unlock(); + } + + + bool hasNewStatus = args->checkData(); + if (hasNewStatus) + { + if (args->m_hasStatus) + { + //overflow: last status hasn't been processed yet + b3Assert(0); + printf("Error: received new status but previous status not processed yet"); + } + else + { + args->m_cs->lock(); + args->m_hasStatus = hasNewStatus; + args->m_cs->unlock(); + } + } + } + + } + + } while (args->m_cs->getSharedParam(0) != eUDPRequestTerminate); + } + else + { + args->m_cs->lock(); + args->m_cs->setSharedParam(0, eUDPInitializationFailed); + args->m_cs->unlock(); + } + + + printf("finished\n"); + +} + + + +void* UDPlsMemoryFunc() +{ + //don't create local store memory, just return 0 + return new UDPThreadLocalStorage; +} + + + + + + + +UdpNetworkedPhysicsProcessor::UdpNetworkedPhysicsProcessor(const char* hostName, int port) +{ + m_data = new UdpNetworkedInternalData; + if (hostName) + { + m_data->m_hostName = hostName; + } + m_data->m_port = port; + +} + +UdpNetworkedPhysicsProcessor::~UdpNetworkedPhysicsProcessor() +{ + disconnect(); + delete m_data; +} + +bool UdpNetworkedPhysicsProcessor::processCommand(const struct SharedMemoryCommand& clientCmd, struct SharedMemoryStatus& serverStatusOut, char* bufferServerToClient, int bufferSizeInBytes) +{ + int sz = sizeof(SharedMemoryCommand); + int timeout = 1024 * 1024 * 1024; + + m_data->m_cs->lock(); + m_data->m_clientCmd = clientCmd; + m_data->m_hasCommand = true; + m_data->m_cs->unlock(); + + while (m_data->m_hasCommand && (timeout-- > 0)) + { +// b3Clock::usleep(100); + } + +#if 0 + + timeout = 1024 * 1024 * 1024; + + bool hasStatus = false; + + const SharedMemoryStatus* stat = 0; + while ((!hasStatus) && (timeout-- > 0)) + { + hasStatus = receiveStatus(serverStatusOut, bufferServerToClient, bufferSizeInBytes); + b3Clock::usleep(100); + } + return hasStatus; + +#endif + + return false; +} + +bool UdpNetworkedPhysicsProcessor::receiveStatus(struct SharedMemoryStatus& serverStatusOut, char* bufferServerToClient, int bufferSizeInBytes) +{ + bool hasStatus = false; + if (m_data->m_hasStatus) + { + hasStatus = true; + serverStatusOut = m_data->m_lastStatus; + int numStreamBytes = m_data->m_stream.size(); + + if (numStreamBytes < bufferSizeInBytes) + { + for (int i = 0; i < numStreamBytes; i++) + { + bufferServerToClient[i] = m_data->m_stream[i]; + } + } + else + { + printf("Error: steam buffer overflow\n"); + } + + m_data->m_cs->lock(); + m_data->m_hasStatus = false; + m_data->m_cs->unlock(); + } + + + return hasStatus; + +} + + +void UdpNetworkedPhysicsProcessor::renderScene() +{ +} + +void UdpNetworkedPhysicsProcessor::physicsDebugDraw(int debugDrawFlags) +{ +} + +void UdpNetworkedPhysicsProcessor::setGuiHelper(struct GUIHelperInterface* guiHelper) +{ +} + +bool UdpNetworkedPhysicsProcessor::isConnected() const +{ + return m_data->m_isConnected; +} + + +bool UdpNetworkedPhysicsProcessor::connect() +{ + if (m_data->m_threadSupport==0) + { + m_data->m_threadSupport = createUDPThreadSupport(1); + + m_data->m_cs = m_data->m_threadSupport->createCriticalSection(); + m_data->m_cs->setSharedParam(0, eUDPIsUnInitialized); + m_data->m_threadSupport->runTask(B3_THREAD_SCHEDULE_TASK, (void*) m_data, 0); + + while (m_data->m_cs->getSharedParam(0) == eUDPIsUnInitialized) + { + b3Clock::usleep(1000); + } + + m_data->m_cs->lock(); + m_data->m_cs->setSharedParam(1, eUDP_ConnectRequest); + m_data->m_cs->unlock(); + + while (m_data->m_cs->getSharedParam(1) == eUDP_ConnectRequest) + { + b3Clock::usleep(1000); + } + + } + + + return true; +} + +void UdpNetworkedPhysicsProcessor::disconnect() +{ + if (m_data->m_threadSupport) + { + m_data->m_cs->lock(); + m_data->m_cs->setSharedParam(0, eUDPRequestTerminate); + m_data->m_cs->unlock(); + + int numActiveThreads = 1; + + while (numActiveThreads) + { + int arg0, arg1; + if (m_data->m_threadSupport->isTaskCompleted(&arg0, &arg1, 0)) + { + numActiveThreads--; + printf("numActiveThreads = %d\n", numActiveThreads); + } + else + { + b3Clock::usleep(1000); + } + }; + + printf("stopping threads\n"); + + delete m_data->m_threadSupport; + m_data->m_threadSupport = 0; + } + + + +} + + + + + diff --git a/examples/SharedMemory/PhysicsClientUDP.h b/examples/SharedMemory/PhysicsClientUDP.h new file mode 100644 index 000000000..27b94fd48 --- /dev/null +++ b/examples/SharedMemory/PhysicsClientUDP.h @@ -0,0 +1,37 @@ +#ifndef PHYSICS_CLIENT_UDP_H +#define PHYSICS_CLIENT_UDP_H + +#include "PhysicsDirect.h" +#include "PhysicsServerCommandProcessor.h" + +class UdpNetworkedPhysicsProcessor : public PhysicsCommandProcessorInterface +{ + + struct UdpNetworkedInternalData* m_data; + +public: + UdpNetworkedPhysicsProcessor(const char* hostName, int port); + + virtual ~UdpNetworkedPhysicsProcessor(); + + virtual bool connect(); + + virtual void disconnect(); + + virtual bool isConnected() const; + + virtual bool processCommand(const struct SharedMemoryCommand& clientCmd, struct SharedMemoryStatus& serverStatusOut, char* bufferServerToClient, int bufferSizeInBytes); + + virtual bool receiveStatus(struct SharedMemoryStatus& serverStatusOut, char* bufferServerToClient, int bufferSizeInBytes); + + virtual void renderScene(); + + virtual void physicsDebugDraw(int debugDrawFlags); + + virtual void setGuiHelper(struct GUIHelperInterface* guiHelper); + +}; + + +#endif //PHYSICS_CLIENT_UDP_H + diff --git a/examples/SharedMemory/PhysicsClientUDP_C_API.cpp b/examples/SharedMemory/PhysicsClientUDP_C_API.cpp new file mode 100644 index 000000000..f48fdedb8 --- /dev/null +++ b/examples/SharedMemory/PhysicsClientUDP_C_API.cpp @@ -0,0 +1,21 @@ + +#include "PhysicsClientUDP_C_API.h" +#include "PhysicsClientUDP.h" +#include "PhysicsDirect.h" +#include + +//think more about naming. The b3ConnectPhysicsLoopback +b3PhysicsClientHandle b3ConnectPhysicsUDP(const char* hostName, int port) +{ + + UdpNetworkedPhysicsProcessor* udp = new UdpNetworkedPhysicsProcessor(hostName, port); + + PhysicsDirect* direct = new PhysicsDirect(udp); + + bool connected = direct->connect(); + printf("direct!\n"); + return (b3PhysicsClientHandle)direct; +} + + + diff --git a/examples/SharedMemory/PhysicsClientUDP_C_API.h b/examples/SharedMemory/PhysicsClientUDP_C_API.h new file mode 100644 index 000000000..fdb97bcab --- /dev/null +++ b/examples/SharedMemory/PhysicsClientUDP_C_API.h @@ -0,0 +1,19 @@ +#ifndef PHYSICS_CLIENT_UDP_C_API_H +#define PHYSICS_CLIENT_UDP_C_API_H + +#include "PhysicsClientC_API.h" + +#ifdef __cplusplus +extern "C" { +#endif + + + ///send physics commands using UDP networking + b3PhysicsClientHandle b3ConnectPhysicsUDP(const char* hostName, int port); + + +#ifdef __cplusplus +} +#endif + +#endif //PHYSICS_CLIENT_UDP_C_API_H diff --git a/examples/SharedMemory/PhysicsCommandProcessorInterface.h b/examples/SharedMemory/PhysicsCommandProcessorInterface.h new file mode 100644 index 000000000..39b5f36d5 --- /dev/null +++ b/examples/SharedMemory/PhysicsCommandProcessorInterface.h @@ -0,0 +1,27 @@ +#ifndef PHYSICS_COMMAND_PROCESSOR_INTERFACE_H +#define PHYSICS_COMMAND_PROCESSOR_INTERFACE_H + +class PhysicsCommandProcessorInterface +{ + +public: + virtual ~PhysicsCommandProcessorInterface() {} + + virtual bool connect()=0; + + virtual void disconnect() = 0; + + virtual bool isConnected() const = 0; + + virtual bool processCommand(const struct SharedMemoryCommand& clientCmd, struct SharedMemoryStatus& serverStatusOut, char* bufferServerToClient, int bufferSizeInBytes) = 0; + + virtual bool receiveStatus(struct SharedMemoryStatus& serverStatusOut, char* bufferServerToClient, int bufferSizeInBytes) = 0; + + virtual void renderScene() = 0; + virtual void physicsDebugDraw(int debugDrawFlags) = 0; + virtual void setGuiHelper(struct GUIHelperInterface* guiHelper) = 0; + + +}; + +#endif //PHYSICS_COMMAND_PROCESSOR_INTERFACE_H diff --git a/examples/SharedMemory/PhysicsDirect.cpp b/examples/SharedMemory/PhysicsDirect.cpp index 65c1beb13..cb7a16abd 100644 --- a/examples/SharedMemory/PhysicsDirect.cpp +++ b/examples/SharedMemory/PhysicsDirect.cpp @@ -3,7 +3,9 @@ #include "PhysicsClientSharedMemory.h" #include "../CommonInterfaces/CommonGUIHelperInterface.h" #include "SharedMemoryCommands.h" -#include "PhysicsServerCommandProcessor.h" +#include "PhysicsCommandProcessorInterface.h" + + #include "LinearMath/btHashMap.h" #include "LinearMath/btAlignedObjectArray.h" #include "../../Extras/Serialize/BulletFileLoader/btBulletFile.h" @@ -21,6 +23,7 @@ struct PhysicsDirectInternalData { DummyGUIHelper m_noGfx; + btAlignedObjectArray m_serverDNA; SharedMemoryCommand m_command; SharedMemoryStatus m_serverStatus; bool m_hasStatus; @@ -41,29 +44,38 @@ struct PhysicsDirectInternalData btAlignedObjectArray m_cachedSegmentationMask; btAlignedObjectArray m_cachedContactPoints; - + btAlignedObjectArray m_cachedOverlappingObjects; + btAlignedObjectArray m_cachedVisualShapes; - PhysicsServerCommandProcessor* m_commandProcessor; + PhysicsCommandProcessorInterface* m_commandProcessor; + bool m_ownsCommandProcessor; PhysicsDirectInternalData() :m_hasStatus(false), - m_verboseOutput(false) + m_verboseOutput(false), + m_ownsCommandProcessor(false) { } }; -PhysicsDirect::PhysicsDirect() +PhysicsDirect::PhysicsDirect(PhysicsCommandProcessorInterface* physSdk) { m_data = new PhysicsDirectInternalData; - m_data->m_commandProcessor = new PhysicsServerCommandProcessor; - - + m_data->m_commandProcessor = physSdk; + m_data->m_ownsCommandProcessor = false; } PhysicsDirect::~PhysicsDirect() { - delete m_data->m_commandProcessor; + if (m_data->m_commandProcessor->isConnected()) + { + m_data->m_commandProcessor->disconnect(); + } + if (m_data->m_ownsCommandProcessor) + { + delete m_data->m_commandProcessor; + } delete m_data; } @@ -71,23 +83,51 @@ PhysicsDirect::~PhysicsDirect() // return true if connection succesfull, can also check 'isConnected' bool PhysicsDirect::connect() { + bool connected = m_data->m_commandProcessor->connect(); m_data->m_commandProcessor->setGuiHelper(&m_data->m_noGfx); - return true; + + //also request serialization data + { + SharedMemoryCommand command; + command.m_type = CMD_REQUEST_INTERNAL_DATA; + bool hasStatus = m_data->m_commandProcessor->processCommand(command, m_data->m_serverStatus, &m_data->m_bulletStreamDataServerToClient[0], SHARED_MEMORY_MAX_STREAM_CHUNK_SIZE); + if (hasStatus) + { + postProcessStatus(m_data->m_serverStatus); + } + else + { + int timeout = 1024 * 1024 * 1024; + while ((!hasStatus) && (timeout-- > 0)) + { + const SharedMemoryStatus* stat = processServerStatus(); + if (stat) + { + hasStatus = true; + } + } + } + } + + return connected; } // return true if connection succesfull, can also check 'isConnected' bool PhysicsDirect::connect(struct GUIHelperInterface* guiHelper) { + bool connected = m_data->m_commandProcessor->connect(); + m_data->m_commandProcessor->setGuiHelper(guiHelper); - return true; + return connected; } void PhysicsDirect::renderScene() { m_data->m_commandProcessor->renderScene(); } + void PhysicsDirect::debugDraw(int debugDrawMode) { m_data->m_commandProcessor->physicsDebugDraw(debugDrawMode); @@ -96,21 +136,31 @@ void PhysicsDirect::debugDraw(int debugDrawMode) ////todo: rename to 'disconnect' void PhysicsDirect::disconnectSharedMemory() { + m_data->m_commandProcessor->disconnect(); m_data->m_commandProcessor->setGuiHelper(0); } bool PhysicsDirect::isConnected() const { - return true; + return m_data->m_commandProcessor->isConnected(); } // return non-null if there is a status, nullptr otherwise const SharedMemoryStatus* PhysicsDirect::processServerStatus() { + + if (!m_data->m_hasStatus) + { + m_data->m_hasStatus = m_data->m_commandProcessor->receiveStatus(m_data->m_serverStatus, &m_data->m_bulletStreamDataServerToClient[0], SHARED_MEMORY_MAX_STREAM_CHUNK_SIZE); + } + SharedMemoryStatus* stat = 0; if (m_data->m_hasStatus) { stat = &m_data->m_serverStatus; + + postProcessStatus(m_data->m_serverStatus); + m_data->m_hasStatus = false; } return stat; @@ -136,7 +186,19 @@ bool PhysicsDirect::processDebugLines(const struct SharedMemoryCommand& orgComma { bool hasStatus = m_data->m_commandProcessor->processCommand(command,m_data->m_serverStatus,&m_data->m_bulletStreamDataServerToClient[0],SHARED_MEMORY_MAX_STREAM_CHUNK_SIZE); + + int timeout = 1024 * 1024 * 1024; + while ((!hasStatus) && (timeout-- > 0)) + { + const SharedMemoryStatus* stat = processServerStatus(); + if (stat) + { + hasStatus = true; + } + } + m_data->m_hasStatus = hasStatus; + if (hasStatus) { btAssert(m_data->m_serverStatus.m_type == CMD_DEBUG_LINES_COMPLETED); @@ -184,6 +246,8 @@ bool PhysicsDirect::processDebugLines(const struct SharedMemoryCommand& orgComma if (serverCmd.m_sendDebugLinesArgs.m_numRemainingDebugLines > 0) { + m_data->m_hasStatus = false; + command.m_type = CMD_REQUEST_DEBUG_LINES; command.m_requestDebugLinesArguments.m_startingLineIndex = serverCmd.m_sendDebugLinesArgs.m_numDebugLines + @@ -204,6 +268,17 @@ bool PhysicsDirect::processVisualShapeData(const struct SharedMemoryCommand& org do { bool hasStatus = m_data->m_commandProcessor->processCommand(command, m_data->m_serverStatus, &m_data->m_bulletStreamDataServerToClient[0], SHARED_MEMORY_MAX_STREAM_CHUNK_SIZE); + + int timeout = 1024 * 1024 * 1024; + while ((!hasStatus) && (timeout-- > 0)) + { + const SharedMemoryStatus* stat = processServerStatus(); + if (stat) + { + hasStatus = true; + } + } + m_data->m_hasStatus = hasStatus; if (hasStatus) { @@ -223,6 +298,8 @@ bool PhysicsDirect::processVisualShapeData(const struct SharedMemoryCommand& org if (serverCmd.m_sendVisualShapeArgs.m_numRemainingVisualShapes >0 && serverCmd.m_sendVisualShapeArgs.m_numVisualShapesCopied) { + m_data->m_hasStatus = false; + command.m_type = CMD_REQUEST_VISUAL_SHAPE_INFO; command.m_requestVisualShapeDataArguments.m_startingVisualShapeIndex = serverCmd.m_sendVisualShapeArgs.m_startingVisualShapeIndex + serverCmd.m_sendVisualShapeArgs.m_numVisualShapesCopied; command.m_requestVisualShapeDataArguments.m_bodyUniqueId = serverCmd.m_sendVisualShapeArgs.m_bodyUniqueId; @@ -233,6 +310,60 @@ bool PhysicsDirect::processVisualShapeData(const struct SharedMemoryCommand& org return m_data->m_hasStatus; } +bool PhysicsDirect::processOverlappingObjects(const struct SharedMemoryCommand& orgCommand) +{ + SharedMemoryCommand command = orgCommand; + + const SharedMemoryStatus& serverCmd = m_data->m_serverStatus; + + do + { + bool hasStatus = m_data->m_commandProcessor->processCommand(command, m_data->m_serverStatus, &m_data->m_bulletStreamDataServerToClient[0], SHARED_MEMORY_MAX_STREAM_CHUNK_SIZE); + + int timeout = 1024 * 1024 * 1024; + while ((!hasStatus) && (timeout-- > 0)) + { + const SharedMemoryStatus* stat = processServerStatus(); + if (stat) + { + hasStatus = true; + } + } + + + m_data->m_hasStatus = hasStatus; + if (hasStatus) + { + if (m_data->m_verboseOutput) + { + b3Printf("Overlapping Objects Request OK\n"); + } + + int startOverlapIndex = serverCmd.m_sendOverlappingObjectsArgs.m_startingOverlappingObjectIndex; + int numOverlapCopied = serverCmd.m_sendOverlappingObjectsArgs.m_numOverlappingObjectsCopied; + m_data->m_cachedOverlappingObjects.resize(startOverlapIndex + numOverlapCopied); + b3OverlappingObject* objects = (b3OverlappingObject*)&m_data->m_bulletStreamDataServerToClient[0]; + + for (int i = 0; i < numOverlapCopied; i++) + { + m_data->m_cachedOverlappingObjects[startOverlapIndex + i] = objects[i]; + } + + if (serverCmd.m_sendOverlappingObjectsArgs.m_numRemainingOverlappingObjects > 0 && serverCmd.m_sendOverlappingObjectsArgs.m_numOverlappingObjectsCopied) + { + m_data->m_hasStatus = false; + command.m_type = CMD_REQUEST_AABB_OVERLAP; + command.m_requestOverlappingObjectsArgs.m_startingOverlappingObjectIndex = serverCmd.m_sendOverlappingObjectsArgs.m_startingOverlappingObjectIndex + serverCmd.m_sendOverlappingObjectsArgs.m_numOverlappingObjectsCopied; + } + + } + } while (serverCmd.m_sendOverlappingObjectsArgs.m_numRemainingOverlappingObjects > 0 && serverCmd.m_sendOverlappingObjectsArgs.m_numOverlappingObjectsCopied); + + return m_data->m_hasStatus; + +} + + bool PhysicsDirect::processContactPointData(const struct SharedMemoryCommand& orgCommand) { @@ -243,7 +374,19 @@ bool PhysicsDirect::processContactPointData(const struct SharedMemoryCommand& or do { bool hasStatus = m_data->m_commandProcessor->processCommand(command,m_data->m_serverStatus,&m_data->m_bulletStreamDataServerToClient[0],SHARED_MEMORY_MAX_STREAM_CHUNK_SIZE); - m_data->m_hasStatus = hasStatus; + + int timeout = 1024 * 1024 * 1024; + while ((!hasStatus) && (timeout-- > 0)) + { + const SharedMemoryStatus* stat = processServerStatus(); + if (stat) + { + hasStatus = true; + } + } + + + m_data->m_hasStatus = hasStatus; if (hasStatus) { if (m_data->m_verboseOutput) @@ -264,7 +407,10 @@ bool PhysicsDirect::processContactPointData(const struct SharedMemoryCommand& or if (serverCmd.m_sendContactPointArgs.m_numRemainingContactPoints>0 && serverCmd.m_sendContactPointArgs.m_numContactPointsCopied) { - command.m_type = CMD_REQUEST_CONTACT_POINT_INFORMATION; + + m_data->m_hasStatus = false; + + command.m_type = CMD_REQUEST_CONTACT_POINT_INFORMATION; command.m_requestContactPointArguments.m_startingContactPointIndex = serverCmd.m_sendContactPointArgs.m_startingContactPointIndex+serverCmd.m_sendContactPointArgs.m_numContactPointsCopied; command.m_requestContactPointArguments.m_objectAIndexFilter = -1; command.m_requestContactPointArguments.m_objectBIndexFilter = -1; @@ -289,6 +435,18 @@ bool PhysicsDirect::processCamera(const struct SharedMemoryCommand& orgCommand) { bool hasStatus = m_data->m_commandProcessor->processCommand(command,m_data->m_serverStatus,&m_data->m_bulletStreamDataServerToClient[0],SHARED_MEMORY_MAX_STREAM_CHUNK_SIZE); + + int timeout = 1024 * 1024 * 1024; + while ((!hasStatus) && (timeout-- > 0)) + { + const SharedMemoryStatus* stat = processServerStatus(); + if (stat) + { + hasStatus = true; + } + } + + m_data->m_hasStatus = hasStatus; if (hasStatus) { @@ -340,6 +498,7 @@ bool PhysicsDirect::processCamera(const struct SharedMemoryCommand& orgCommand) if (serverCmd.m_sendPixelDataArguments.m_numRemainingPixels > 0 && serverCmd.m_sendPixelDataArguments.m_numPixelsCopied) { + m_data->m_hasStatus = false; // continue requesting remaining pixels command.m_type = CMD_REQUEST_CAMERA_IMAGE_DATA; @@ -365,8 +524,15 @@ void PhysicsDirect::processBodyJointInfo(int bodyUniqueId, const SharedMemorySta { bParse::btBulletFile bf( &m_data->m_bulletStreamDataServerToClient[0], - serverCmd.m_dataStreamArguments.m_streamChunkLength); - bf.setFileDNAisMemoryDNA(); + serverCmd.m_numDataStreamBytes); + if (m_data->m_serverDNA.size()) + { + bf.setFileDNA(false, &m_data->m_serverDNA[0], m_data->m_serverDNA.size()); + } + else + { + bf.setFileDNAisMemoryDNA(); + } bf.parse(false); BodyJointInfoCache2* bodyJoints = new BodyJointInfoCache2; @@ -379,19 +545,27 @@ void PhysicsDirect::processBodyJointInfo(int bodyUniqueId, const SharedMemorySta { Bullet::btMultiBodyDoubleData* mb = (Bullet::btMultiBodyDoubleData*)bf.m_multiBodies[i]; - bodyJoints->m_baseName = mb->m_baseName; - + + if (mb->m_baseName) + { + bodyJoints->m_baseName = mb->m_baseName; + } addJointInfoFromMultiBodyData(mb,bodyJoints, m_data->m_verboseOutput); } else { Bullet::btMultiBodyFloatData* mb = (Bullet::btMultiBodyFloatData*)bf.m_multiBodies[i]; - bodyJoints->m_baseName = mb->m_baseName; + + if (mb->m_baseName) + { + bodyJoints->m_baseName = mb->m_baseName; + } addJointInfoFromMultiBodyData(mb,bodyJoints, m_data->m_verboseOutput); } } - if (bf.ok()) { + if (bf.ok()) + { if (m_data->m_verboseOutput) { b3Printf("Received robot description ok!\n"); @@ -402,6 +576,118 @@ void PhysicsDirect::processBodyJointInfo(int bodyUniqueId, const SharedMemorySta } } +void PhysicsDirect::postProcessStatus(const struct SharedMemoryStatus& serverCmd) +{ + switch (serverCmd.m_type) + { + + case CMD_REQUEST_INTERNAL_DATA_COMPLETED: + { + if (serverCmd.m_numDataStreamBytes) + { + int numStreamBytes = serverCmd.m_numDataStreamBytes; + m_data->m_serverDNA.resize(numStreamBytes); + for (int i = 0; i < numStreamBytes; i++) + { + m_data->m_serverDNA[i] = m_data->m_bulletStreamDataServerToClient[i]; + } + } + break; + } + case CMD_RESET_SIMULATION_COMPLETED: + { + m_data->m_debugLinesFrom.clear(); + m_data->m_debugLinesTo.clear(); + m_data->m_debugLinesColor.clear(); + for (int i = 0; im_bodyJointMap.size(); i++) + { + BodyJointInfoCache2** bodyJointsPtr = m_data->m_bodyJointMap.getAtIndex(i); + if (bodyJointsPtr && *bodyJointsPtr) + { + BodyJointInfoCache2* bodyJoints = *bodyJointsPtr; + for (int j = 0; jm_jointInfo.size(); j++) { + if (bodyJoints->m_jointInfo[j].m_jointName) + { + free(bodyJoints->m_jointInfo[j].m_jointName); + } + if (bodyJoints->m_jointInfo[j].m_linkName) + { + free(bodyJoints->m_jointInfo[j].m_linkName); + } + } + delete (*bodyJointsPtr); + } + } + m_data->m_bodyJointMap.clear(); + + break; + } + case CMD_SDF_LOADING_COMPLETED: + { + //we'll stream further info from the physics server + //so serverCmd will be invalid, make a copy + + + int numBodies = serverCmd.m_sdfLoadedArgs.m_numBodies; + for (int i = 0; im_commandProcessor->processCommand(infoRequestCommand, infoStatus, &m_data->m_bulletStreamDataServerToClient[0], SHARED_MEMORY_MAX_STREAM_CHUNK_SIZE); + + + int timeout = 1024 * 1024 * 1024; + while ((!hasStatus) && (timeout-- > 0)) + { + hasStatus = m_data->m_commandProcessor->receiveStatus(infoStatus, &m_data->m_bulletStreamDataServerToClient[0], SHARED_MEMORY_MAX_STREAM_CHUNK_SIZE); + } + + if (hasStatus) + { + processBodyJointInfo(bodyUniqueId, infoStatus); + } + } + break; + } + case CMD_URDF_LOADING_COMPLETED: + { + + if (serverCmd.m_numDataStreamBytes > 0) + { + int bodyIndex = serverCmd.m_dataStreamArguments.m_bodyUniqueId; + processBodyJointInfo(bodyIndex, serverCmd); + } + break; + } + case CMD_BULLET_LOADING_FAILED: + { + b3Warning("Couldn't load .bullet file"); + break; + } + case CMD_BULLET_LOADING_COMPLETED: + { + break; + } + case CMD_USER_CONSTRAINT_COMPLETED: + { + break; + } + case CMD_USER_CONSTRAINT_FAILED: + { + b3Warning("createConstraint failed"); + break; + } + default: + { + //b3Warning("Unknown server status type"); + } + }; + + +} bool PhysicsDirect::submitClientCommand(const struct SharedMemoryCommand& command) { if (command.m_type==CMD_REQUEST_DEBUG_LINES) @@ -422,83 +708,16 @@ bool PhysicsDirect::submitClientCommand(const struct SharedMemoryCommand& comman { return processVisualShapeData(command); } + if (command.m_type == CMD_REQUEST_AABB_OVERLAP) + { + return processOverlappingObjects(command); + } bool hasStatus = m_data->m_commandProcessor->processCommand(command,m_data->m_serverStatus,&m_data->m_bulletStreamDataServerToClient[0],SHARED_MEMORY_MAX_STREAM_CHUNK_SIZE); m_data->m_hasStatus = hasStatus; if (hasStatus) { - const SharedMemoryStatus& serverCmd = m_data->m_serverStatus; - - switch (m_data->m_serverStatus.m_type) - { - case CMD_RESET_SIMULATION_COMPLETED: - { - m_data->m_debugLinesFrom.clear(); - m_data->m_debugLinesTo.clear(); - m_data->m_debugLinesColor.clear(); - for (int i=0;im_bodyJointMap.size();i++) - { - BodyJointInfoCache2** bodyJointsPtr = m_data->m_bodyJointMap.getAtIndex(i); - if (bodyJointsPtr && *bodyJointsPtr) - { - BodyJointInfoCache2* bodyJoints = *bodyJointsPtr; - for (int j=0;jm_jointInfo.size();j++) { - if (bodyJoints->m_jointInfo[j].m_jointName) - { - free(bodyJoints->m_jointInfo[j].m_jointName); - } - if (bodyJoints->m_jointInfo[j].m_linkName) - { - free(bodyJoints->m_jointInfo[j].m_linkName); - } - } - delete (*bodyJointsPtr); - } - } - m_data->m_bodyJointMap.clear(); - - break; - } - case CMD_SDF_LOADING_COMPLETED: - { - //we'll stream further info from the physics server - //so serverCmd will be invalid, make a copy - - - int numBodies = serverCmd.m_sdfLoadedArgs.m_numBodies; - for (int i=0;im_commandProcessor->processCommand(infoRequestCommand,infoStatus,&m_data->m_bulletStreamDataServerToClient[0],SHARED_MEMORY_MAX_STREAM_CHUNK_SIZE); - if (hasStatus) - { - processBodyJointInfo(bodyUniqueId, infoStatus); - } - } - break; - } - case CMD_URDF_LOADING_COMPLETED: - { - - if (serverCmd.m_dataStreamArguments.m_streamChunkLength > 0) - { - int bodyIndex = serverCmd.m_dataStreamArguments.m_bodyUniqueId; - processBodyJointInfo(bodyIndex,serverCmd); - } - break; - } - - default: - { - // b3Error("Unknown server status type"); - } - }; - - + postProcessStatus(m_data->m_serverStatus); } return hasStatus; } @@ -549,7 +768,7 @@ bool PhysicsDirect::getJointInfo(int bodyIndex, int jointIndex, struct b3JointIn if (bodyJointsPtr && *bodyJointsPtr) { BodyJointInfoCache2* bodyJoints = *bodyJointsPtr; - if (jointIndex < bodyJoints->m_jointInfo.size()) + if ((jointIndex >=0) && (jointIndex < bodyJoints->m_jointInfo.size())) { info = bodyJoints->m_jointInfo[jointIndex]; return true; @@ -619,6 +838,14 @@ void PhysicsDirect::getCachedContactPointInformation(struct b3ContactInformation } +void PhysicsDirect::getCachedOverlappingObjects(struct b3AABBOverlapData* overlappingObjects) +{ + overlappingObjects->m_numOverlappingObjects = m_data->m_cachedOverlappingObjects.size(); + overlappingObjects->m_overlappingObjects = m_data->m_cachedOverlappingObjects.size() ? + &m_data->m_cachedOverlappingObjects[0] : 0; +} + + void PhysicsDirect::getCachedVisualShapeInformation(struct b3VisualShapeInformation* visualShapesInfo) { visualShapesInfo->m_numVisualShapes = m_data->m_cachedVisualShapes.size(); diff --git a/examples/SharedMemory/PhysicsDirect.h b/examples/SharedMemory/PhysicsDirect.h index 2252da3c3..963281f7e 100644 --- a/examples/SharedMemory/PhysicsDirect.h +++ b/examples/SharedMemory/PhysicsDirect.h @@ -7,9 +7,6 @@ #include "PhysicsClient.h" #include "LinearMath/btVector3.h" -///todo: the PhysicsClient API was designed with shared memory in mind, -///now it become more general we need to move out the shared memory specifics away -///for example naming [disconnectSharedMemory -> disconnect] [ move setSharedMemoryKey to shared memory specific subclass ] ///PhysicsDirect executes the commands directly, without transporting them or having a separate server executing commands class PhysicsDirect : public PhysicsClient { @@ -23,13 +20,17 @@ protected: bool processContactPointData(const struct SharedMemoryCommand& orgCommand); + bool processOverlappingObjects(const struct SharedMemoryCommand& orgCommand); + bool processVisualShapeData(const struct SharedMemoryCommand& orgCommand); void processBodyJointInfo(int bodyUniqueId, const struct SharedMemoryStatus& serverCmd); + void postProcessStatus(const struct SharedMemoryStatus& serverCmd); + public: - PhysicsDirect(); + PhysicsDirect(class PhysicsCommandProcessorInterface* physSdk); virtual ~PhysicsDirect(); @@ -76,8 +77,11 @@ public: virtual void getCachedContactPointInformation(struct b3ContactInformation* contactPointData); + virtual void getCachedOverlappingObjects(struct b3AABBOverlapData* overlappingObjects); + virtual void getCachedVisualShapeInformation(struct b3VisualShapeInformation* visualShapesInfo); + //those 2 APIs are for internal use for visualization virtual bool connect(struct GUIHelperInterface* guiHelper); virtual void renderScene(); diff --git a/examples/SharedMemory/PhysicsDirectC_API.cpp b/examples/SharedMemory/PhysicsDirectC_API.cpp index e5e73b203..61ceef26f 100644 --- a/examples/SharedMemory/PhysicsDirectC_API.cpp +++ b/examples/SharedMemory/PhysicsDirectC_API.cpp @@ -2,13 +2,21 @@ #include "PhysicsDirect.h" +#include "PhysicsServerCommandProcessor.h" + //think more about naming. The b3ConnectPhysicsLoopback b3PhysicsClientHandle b3ConnectPhysicsDirect() { - PhysicsDirect* direct = new PhysicsDirect(); + PhysicsServerCommandProcessor* sdk = new PhysicsServerCommandProcessor; + + PhysicsDirect* direct = new PhysicsDirect(sdk); bool connected = direct->connect(); return (b3PhysicsClientHandle )direct; } + + +// + diff --git a/examples/SharedMemory/PhysicsLoopBack.cpp b/examples/SharedMemory/PhysicsLoopBack.cpp index f669dde30..3e9c3d77d 100644 --- a/examples/SharedMemory/PhysicsLoopBack.cpp +++ b/examples/SharedMemory/PhysicsLoopBack.cpp @@ -144,4 +144,10 @@ void PhysicsLoopBack::getCachedContactPointInformation(struct b3ContactInformati void PhysicsLoopBack::getCachedVisualShapeInformation(struct b3VisualShapeInformation* visualShapesInfo) { return m_data->m_physicsClient->getCachedVisualShapeInformation(visualShapesInfo); -} \ No newline at end of file +} + +void PhysicsLoopBack::getCachedOverlappingObjects(struct b3AABBOverlapData* overlappingObjects) +{ + return m_data->m_physicsClient->getCachedOverlappingObjects(overlappingObjects); +} + diff --git a/examples/SharedMemory/PhysicsLoopBack.h b/examples/SharedMemory/PhysicsLoopBack.h index 42acca718..c9187c4b8 100644 --- a/examples/SharedMemory/PhysicsLoopBack.h +++ b/examples/SharedMemory/PhysicsLoopBack.h @@ -62,6 +62,8 @@ public: virtual void getCachedContactPointInformation(struct b3ContactInformation* contactPointData); + virtual void getCachedOverlappingObjects(struct b3AABBOverlapData* overlappingObjects); + virtual void getCachedVisualShapeInformation(struct b3VisualShapeInformation* visualShapesInfo); }; diff --git a/examples/SharedMemory/PhysicsServerCommandProcessor.cpp b/examples/SharedMemory/PhysicsServerCommandProcessor.cpp index 86d3e2ac5..5425100ef 100644 --- a/examples/SharedMemory/PhysicsServerCommandProcessor.cpp +++ b/examples/SharedMemory/PhysicsServerCommandProcessor.cpp @@ -43,8 +43,13 @@ bool gCloseToKuka=false; bool gEnableRealTimeSimVR=false; bool gCreateDefaultRobotAssets = false; int gInternalSimFlags = 0; +bool gResetSimulation = 0; +int gHuskyId = -1; +btTransform huskyTr = btTransform::getIdentity(); int gCreateObjectSimVR = -1; +int gEnableKukaControl = 0; + btScalar simTimeScalingFactor = 1; btScalar gRhsClamp = 1.f; @@ -123,6 +128,17 @@ struct InteralBodyData } }; +struct InteralUserConstraintData +{ + btTypedConstraint* m_rbConstraint; + btMultiBodyConstraint* m_mbConstraint; + InteralUserConstraintData() + :m_rbConstraint(0), + m_mbConstraint(0) + { + } +}; + ///todo: templatize this struct InternalBodyHandle : public InteralBodyData { @@ -318,6 +334,45 @@ struct SaveWorldObjectData std::string m_fileName; }; +struct MyBroadphaseCallback : public btBroadphaseAabbCallback +{ + b3AlignedObjectArray m_bodyUniqueIds; + b3AlignedObjectArray m_links; + + + MyBroadphaseCallback() + { + } + virtual ~MyBroadphaseCallback() + { + } + void clear() + { + m_bodyUniqueIds.clear(); + m_links.clear(); + } + virtual bool process(const btBroadphaseProxy* proxy) + { + btCollisionObject* colObj = (btCollisionObject*)proxy->m_clientObject; + btMultiBodyLinkCollider* mbl = btMultiBodyLinkCollider::upcast(colObj); + if (mbl) + { + int bodyUniqueId = mbl->m_multiBody->getUserIndex2(); + m_bodyUniqueIds.push_back(bodyUniqueId); + m_links.push_back(mbl->m_link); + return true; + } + int bodyUniqueId = colObj->getUserIndex2(); + if (bodyUniqueId >= 0) + { + m_bodyUniqueIds.push_back(bodyUniqueId); + m_links.push_back(mbl->m_link); + } + return true; + } +}; + + struct PhysicsServerCommandProcessorInternalData { ///handle management @@ -429,6 +484,10 @@ struct PhysicsServerCommandProcessorInternalData btAlignedObjectArray m_multiBodyJointFeedbacks; btHashMap m_inverseDynamicsBodies; btHashMap m_inverseKinematicsHelpers; + + int m_userConstraintUIDGenerator; + btHashMap m_userConstraints; + b3AlignedObjectArray m_saveWorldBodyData; @@ -453,6 +512,8 @@ struct PhysicsServerCommandProcessorInternalData SharedMemoryDebugDrawer* m_remoteDebugDrawer; btAlignedObjectArray m_cachedContactPoints; + MyBroadphaseCallback m_cachedOverlappingObjects; + btAlignedObjectArray m_sdfRecentLoadedBodies; @@ -491,6 +552,7 @@ struct PhysicsServerCommandProcessorInternalData m_logPlayback(0), m_physicsDeltaTime(1./240.), m_numSimulationSubSteps(0), + m_userConstraintUIDGenerator(1), m_dynamicsWorld(0), m_remoteDebugDrawer(0), m_guiHelper(0), @@ -605,8 +667,6 @@ PhysicsServerCommandProcessor::PhysicsServerCommandProcessor() m_data = new PhysicsServerCommandProcessorInternalData(); createEmptyDynamicsWorld(); - m_data->m_dynamicsWorld->getSolverInfo().m_linearSlop = 0.00001; - m_data->m_dynamicsWorld->getSolverInfo().m_numIterations = 100; } @@ -647,7 +707,7 @@ void PhysicsServerCommandProcessor::createEmptyDynamicsWorld() #endif //Workaround: in a VR application, where we avoid synchronizaing between GFX/Physics threads, we don't want to resize this array, so pre-allocate it - m_data->m_dynamicsWorld->getCollisionObjectArray().reserve(8192); + m_data->m_dynamicsWorld->getCollisionObjectArray().reserve(32768); m_data->m_remoteDebugDrawer = new SharedMemoryDebugDrawer(); @@ -655,8 +715,25 @@ void PhysicsServerCommandProcessor::createEmptyDynamicsWorld() m_data->m_dynamicsWorld->setGravity(btVector3(0, 0, 0)); m_data->m_dynamicsWorld->getSolverInfo().m_erp2 = 0.08; + m_data->m_dynamicsWorld->getSolverInfo().m_linearSlop = 0.00001; + m_data->m_dynamicsWorld->getSolverInfo().m_numIterations = 50; + m_data->m_dynamicsWorld->getSolverInfo().m_leastSquaresResidualThreshold = 1e-7; + } +void PhysicsServerCommandProcessor::deleteCachedInverseKinematicsBodies() +{ + for (int i = 0; i < m_data->m_inverseKinematicsHelpers.size(); i++) + { + IKTrajectoryHelper** ikHelperPtr = m_data->m_inverseKinematicsHelpers.getAtIndex(i); + if (ikHelperPtr) + { + IKTrajectoryHelper* ikHelper = *ikHelperPtr; + delete ikHelper; + } + } + m_data->m_inverseKinematicsHelpers.clear(); +} void PhysicsServerCommandProcessor::deleteCachedInverseDynamicsBodies() { for (int i = 0; i < m_data->m_inverseDynamicsBodies.size(); i++) @@ -675,7 +752,7 @@ void PhysicsServerCommandProcessor::deleteCachedInverseDynamicsBodies() void PhysicsServerCommandProcessor::deleteDynamicsWorld() { deleteCachedInverseDynamicsBodies(); - + deleteCachedInverseKinematicsBodies(); for (int i=0;im_multiBodyJointFeedbacks.size();i++) { @@ -1036,10 +1113,17 @@ bool PhysicsServerCommandProcessor::loadUrdf(const char* fileName, const btVecto UrdfLinkNameMapUtil* util = new UrdfLinkNameMapUtil; m_data->m_urdfLinkNameMapper.push_back(util); util->m_mb = mb; + for (int i = 0; i < bufferSizeInBytes; i++) + { + bufferServerToClient[i] = 0xcc; + } util->m_memSerializer = new btDefaultSerializer(bufferSizeInBytes ,(unsigned char*)bufferServerToClient); //disable serialization of the collision objects (they are too big, and the client likely doesn't need them); util->m_memSerializer->m_skipPointers.insert(mb->getBaseCollider(),0); + util->m_memSerializer->startSerialization(); + + bodyHandle->m_linkLocalInertialFrames.reserve(mb->getNumLinks()); for (int i=0;igetNumLinks();i++) { @@ -1066,18 +1150,19 @@ bool PhysicsServerCommandProcessor::loadUrdf(const char* fileName, const btVecto std::string* baseName = new std::string(u2b.getLinkName(u2b.getRootLinkIndex())); m_data->m_strings.push_back(baseName); - - util->m_memSerializer->registerNameForPointer(baseName->c_str(),baseName->c_str()); mb->setBaseName(baseName->c_str()); + util->m_memSerializer->registerNameForPointer(baseName->c_str(),baseName->c_str()); - util->m_memSerializer->insertHeader(); + int len = mb->calculateSerializeBufferSize(); btChunk* chunk = util->m_memSerializer->allocate(len,1); const char* structType = mb->serialize(chunk->m_oldPtr, util->m_memSerializer); util->m_memSerializer->finalizeChunk(chunk,structType,BT_MULTIBODY_CODE,mb); + + return true; } else { @@ -1129,6 +1214,8 @@ int PhysicsServerCommandProcessor::createBodyInfoStream(int bodyUniqueId, char* m_data->m_urdfLinkNameMapper.push_back(util); util->m_mb = mb; util->m_memSerializer = new btDefaultSerializer(bufferSizeInBytes ,(unsigned char*)bufferServerToClient); + util->m_memSerializer->startSerialization(); + //disable serialization of the collision objects (they are too big, and the client likely doesn't need them); util->m_memSerializer->m_skipPointers.insert(mb->getBaseCollider(),0); if (mb->getBaseName()) @@ -1147,7 +1234,6 @@ int PhysicsServerCommandProcessor::createBodyInfoStream(int bodyUniqueId, char* util->m_memSerializer->registerNameForPointer(mb->getBaseName(),mb->getBaseName()); - util->m_memSerializer->insertHeader(); int len = mb->calculateSerializeBufferSize(); btChunk* chunk = util->m_memSerializer->allocate(len,1); @@ -1187,6 +1273,8 @@ bool PhysicsServerCommandProcessor::processCommand(const struct SharedMemoryComm //catch uninitialized cases serverStatusOut.m_type = CMD_INVALID_STATUS; + serverStatusOut.m_numDataStreamBytes = 0; + serverStatusOut.m_dataStream = 0; //consume the command switch (clientCmd.m_type) @@ -1244,7 +1332,8 @@ bool PhysicsServerCommandProcessor::processCommand(const struct SharedMemoryComm } //9 floats per line: 3 floats for 'from', 3 floats for 'to' and 3 floats for 'color' - int maxNumLines = bufferSizeInBytes/(sizeof(float)*9)-1; + int bytesPerLine = (sizeof(float) * 9); + int maxNumLines = bufferSizeInBytes/bytesPerLine-1; if (startingLineIndex >m_data->m_remoteDebugDrawer->m_lines2.size()) { b3Warning("m_startingLineIndex exceeds total number of debug lines"); @@ -1277,7 +1366,7 @@ bool PhysicsServerCommandProcessor::processCommand(const struct SharedMemoryComm } serverStatusOut.m_type = CMD_DEBUG_LINES_COMPLETED; - + serverStatusOut.m_numDataStreamBytes = numLines * bytesPerLine; serverStatusOut.m_sendDebugLinesArgs.m_numDebugLines = numLines; serverStatusOut.m_sendDebugLinesArgs.m_startingLineIndex = startingLineIndex; serverStatusOut.m_sendDebugLinesArgs.m_numRemainingDebugLines = m_data->m_remoteDebugDrawer->m_lines2.size()-(startingLineIndex+numLines); @@ -1327,6 +1416,8 @@ bool PhysicsServerCommandProcessor::processCommand(const struct SharedMemoryComm float* depthBuffer = (float*)(bufferServerToClient+numRequestedPixels*4); int* segmentationMaskBuffer = (int*)(bufferServerToClient+numRequestedPixels*8); + serverStatusOut.m_numDataStreamBytes = numRequestedPixels * totalBytesPerPixel; + if ((clientCmd.m_updateFlags & ER_BULLET_HARDWARE_OPENGL)!=0) { m_data->m_guiHelper->copyCameraImageData(clientCmd.m_requestPixelDataArguments.m_viewMatrix, @@ -1341,6 +1432,40 @@ bool PhysicsServerCommandProcessor::processCommand(const struct SharedMemoryComm { // printf("-------------------------------\nRendering\n"); + if ((clientCmd.m_updateFlags & REQUEST_PIXEL_ARGS_SET_LIGHT_DIRECTION) != 0) + { + m_data->m_visualConverter.setLightDirection(clientCmd.m_requestPixelDataArguments.m_lightDirection[0], clientCmd.m_requestPixelDataArguments.m_lightDirection[1], clientCmd.m_requestPixelDataArguments.m_lightDirection[2]); + } + + if ((clientCmd.m_updateFlags & REQUEST_PIXEL_ARGS_SET_LIGHT_COLOR) != 0) + { + m_data->m_visualConverter.setLightColor(clientCmd.m_requestPixelDataArguments.m_lightColor[0], clientCmd.m_requestPixelDataArguments.m_lightColor[1], clientCmd.m_requestPixelDataArguments.m_lightColor[2]); + } + + if ((clientCmd.m_updateFlags & REQUEST_PIXEL_ARGS_SET_LIGHT_DISTANCE) != 0) + { + m_data->m_visualConverter.setLightDistance(clientCmd.m_requestPixelDataArguments.m_lightDistance); + } + + if ((clientCmd.m_updateFlags & REQUEST_PIXEL_ARGS_SET_SHADOW) != 0) + { + m_data->m_visualConverter.setShadow(clientCmd.m_requestPixelDataArguments.m_hasShadow); + } + + if ((clientCmd.m_updateFlags & REQUEST_PIXEL_ARGS_SET_AMBIENT_COEFF) != 0) + { + m_data->m_visualConverter.setLightAmbientCoeff(clientCmd.m_requestPixelDataArguments.m_lightAmbientCoeff); + } + + if ((clientCmd.m_updateFlags & REQUEST_PIXEL_ARGS_SET_DIFFUSE_COEFF) != 0) + { + m_data->m_visualConverter.setLightDiffuseCoeff(clientCmd.m_requestPixelDataArguments.m_lightDiffuseCoeff); + } + + if ((clientCmd.m_updateFlags & REQUEST_PIXEL_ARGS_SET_SPECULAR_COEFF) != 0) + { + m_data->m_visualConverter.setLightSpecularCoeff(clientCmd.m_requestPixelDataArguments.m_lightSpecularCoeff); + } if ((clientCmd.m_updateFlags & REQUEST_PIXEL_ARGS_HAS_CAMERA_MATRICES)!=0) { @@ -1368,6 +1493,7 @@ bool PhysicsServerCommandProcessor::processCommand(const struct SharedMemoryComm } serverStatusOut.m_type = CMD_CAMERA_IMAGE_COMPLETED; + serverStatusOut.m_sendPixelDataArguments.m_numPixelsCopied = numPixelsCopied; serverStatusOut.m_sendPixelDataArguments.m_numRemainingPixels = numRemainingPixels - numPixelsCopied; serverStatusOut.m_sendPixelDataArguments.m_startingPixelIndex = startPixelIndex; @@ -1386,7 +1512,8 @@ bool PhysicsServerCommandProcessor::processCommand(const struct SharedMemoryComm serverStatusOut.m_type = CMD_BODY_INFO_COMPLETED; serverStatusOut.m_dataStreamArguments.m_bodyUniqueId = sdfInfoArgs.m_bodyUniqueId; - serverStatusOut.m_dataStreamArguments.m_streamChunkLength = streamSizeInBytes; + serverStatusOut.m_numDataStreamBytes = streamSizeInBytes; + hasStatus = true; break; } @@ -1606,11 +1733,11 @@ bool PhysicsServerCommandProcessor::processCommand(const struct SharedMemoryComm m_data->m_guiHelper->autogenerateGraphicsObjects(this->m_data->m_dynamicsWorld); serverStatusOut.m_type = CMD_URDF_LOADING_COMPLETED; - serverStatusOut.m_dataStreamArguments.m_streamChunkLength = 0; + if (m_data->m_urdfLinkNameMapper.size()) { - serverStatusOut.m_dataStreamArguments.m_streamChunkLength = m_data->m_urdfLinkNameMapper.at(m_data->m_urdfLinkNameMapper.size()-1)->m_memSerializer->getCurrentBufferSize(); + serverStatusOut.m_numDataStreamBytes = m_data->m_urdfLinkNameMapper.at(m_data->m_urdfLinkNameMapper.size()-1)->m_memSerializer->getCurrentBufferSize(); } serverStatusOut.m_dataStreamArguments.m_bodyUniqueId = bodyUniqueId; hasStatus = true; @@ -1629,6 +1756,21 @@ bool PhysicsServerCommandProcessor::processCommand(const struct SharedMemoryComm case CMD_LOAD_BUNNY: { #ifdef USE_SOFT_BODY_MULTI_BODY_DYNAMICS_WORLD + double scale = 0.1; + double mass = 0.1; + double collisionMargin = 0.02; + if (clientCmd.m_updateFlags & LOAD_BUNNY_UPDATE_SCALE) + { + scale = clientCmd.m_loadBunnyArguments.m_scale; + } + if (clientCmd.m_updateFlags & LOAD_BUNNY_UPDATE_MASS) + { + mass = clientCmd.m_loadBunnyArguments.m_mass; + } + if (clientCmd.m_updateFlags & LOAD_BUNNY_UPDATE_COLLISION_MARGIN) + { + collisionMargin = clientCmd.m_loadBunnyArguments.m_collisionMargin; + } m_data->m_softBodyWorldInfo.air_density = (btScalar)1.2; m_data->m_softBodyWorldInfo.water_density = 0; m_data->m_softBodyWorldInfo.water_offset = 0; @@ -1643,14 +1785,14 @@ bool PhysicsServerCommandProcessor::processCommand(const struct SharedMemoryComm pm->m_kLST = 1.0; pm->m_flags -= btSoftBody::fMaterial::DebugDraw; psb->generateBendingConstraints(2,pm); - psb->m_cfg.piterations = 2; + psb->m_cfg.piterations = 50; psb->m_cfg.kDF = 0.5; psb->randomizeConstraints(); psb->rotate(btQuaternion(0.70711,0,0,0.70711)); - psb->translate(btVector3(0,0,3.0)); - psb->scale(btVector3(0.1,0.1,0.1)); - psb->setTotalMass(1,true); - psb->getCollisionShape()->setMargin(0.01); + psb->translate(btVector3(0,0,1.0)); + psb->scale(btVector3(scale,scale,scale)); + psb->setTotalMass(mass,true); + psb->getCollisionShape()->setMargin(collisionMargin); m_data->m_dynamicsWorld->addSoftBody(psb); #endif @@ -2156,6 +2298,28 @@ bool PhysicsServerCommandProcessor::processCommand(const struct SharedMemoryComm break; } + case CMD_REQUEST_INTERNAL_DATA: + { + //todo: also check version etc? + + SharedMemoryStatus& serverCmd = serverStatusOut; + serverCmd.m_type = CMD_REQUEST_INTERNAL_DATA_FAILED; + hasStatus = true; + + int sz = btDefaultSerializer::getMemoryDnaSizeInBytes(); + const char* memDna = btDefaultSerializer::getMemoryDna(); + if (sz < bufferSizeInBytes) + { + for (int i = 0; i < sz; i++) + { + bufferServerToClient[i] = memDna[i]; + } + serverCmd.m_type = CMD_REQUEST_INTERNAL_DATA_COMPLETED; + serverCmd.m_numDataStreamBytes = sz; + } + + break; + }; case CMD_SEND_PHYSICS_SIMULATION_PARAMETERS: { if (clientCmd.m_updateFlags&SIM_PARAM_UPDATE_DELTA_TIME) @@ -2191,6 +2355,17 @@ bool PhysicsServerCommandProcessor::processCommand(const struct SharedMemoryComm { m_data->m_dynamicsWorld->getSolverInfo().m_numIterations = clientCmd.m_physSimParamArgs.m_numSolverIterations; } + + if (clientCmd.m_updateFlags & SIM_PARAM_UPDATE_USE_SPLIT_IMPULSE) + { + m_data->m_dynamicsWorld->getSolverInfo().m_splitImpulse = clientCmd.m_physSimParamArgs.m_useSplitImpulse; + } + if (clientCmd.m_updateFlags &SIM_PARAM_UPDATE_SPLIT_IMPULSE_PENETRATION_THRESHOLD) + { + m_data->m_dynamicsWorld->getSolverInfo().m_splitImpulsePenetrationThreshold = clientCmd.m_physSimParamArgs.m_splitImpulsePenetrationThreshold; + } + + if (clientCmd.m_updateFlags&SIM_PARAM_UPDATE_NUM_SIMULATION_SUB_STEPS) { m_data->m_numSimulationSubSteps = clientCmd.m_physSimParamArgs.m_numSimulationSubSteps; @@ -2216,9 +2391,54 @@ bool PhysicsServerCommandProcessor::processCommand(const struct SharedMemoryComm int bodyUniqueId = clientCmd.m_initPoseArgs.m_bodyUniqueId; InteralBodyData* body = m_data->getHandle(bodyUniqueId); + btVector3 baseLinVel(0, 0, 0); + btVector3 baseAngVel(0, 0, 0); + + if (clientCmd.m_updateFlags & INIT_POSE_HAS_BASE_LINEAR_VELOCITY) + { + baseLinVel.setValue(clientCmd.m_initPoseArgs.m_initialStateQdot[0], + clientCmd.m_initPoseArgs.m_initialStateQdot[1], + clientCmd.m_initPoseArgs.m_initialStateQdot[2]); + } + if (clientCmd.m_updateFlags & INIT_POSE_HAS_BASE_ANGULAR_VELOCITY) + { + baseAngVel.setValue(clientCmd.m_initPoseArgs.m_initialStateQdot[3], + clientCmd.m_initPoseArgs.m_initialStateQdot[4], + clientCmd.m_initPoseArgs.m_initialStateQdot[5]); + } + btVector3 basePos(0, 0, 0); + if (clientCmd.m_updateFlags & INIT_POSE_HAS_INITIAL_POSITION) + { + basePos = btVector3( + clientCmd.m_initPoseArgs.m_initialStateQ[0], + clientCmd.m_initPoseArgs.m_initialStateQ[1], + clientCmd.m_initPoseArgs.m_initialStateQ[2]); + } + btQuaternion baseOrn(0, 0, 0, 1); + if (clientCmd.m_updateFlags & INIT_POSE_HAS_INITIAL_ORIENTATION) + { + baseOrn.setValue(clientCmd.m_initPoseArgs.m_initialStateQ[3], + clientCmd.m_initPoseArgs.m_initialStateQ[4], + clientCmd.m_initPoseArgs.m_initialStateQ[5], + clientCmd.m_initPoseArgs.m_initialStateQ[6]); + } if (body && body->m_multiBody) { btMultiBody* mb = body->m_multiBody; + + + + if (clientCmd.m_updateFlags & INIT_POSE_HAS_BASE_LINEAR_VELOCITY) + { + mb->setBaseVel(baseLinVel); + } + + if (clientCmd.m_updateFlags & INIT_POSE_HAS_BASE_ANGULAR_VELOCITY) + { + mb->setBaseOmega(baseAngVel); + } + + if (clientCmd.m_updateFlags & INIT_POSE_HAS_INITIAL_POSITION) { btVector3 zero(0,0,0); @@ -2226,11 +2446,8 @@ bool PhysicsServerCommandProcessor::processCommand(const struct SharedMemoryComm clientCmd.m_initPoseArgs.m_hasInitialStateQ[1] && clientCmd.m_initPoseArgs.m_hasInitialStateQ[2]); - mb->setBaseVel(zero); - mb->setBasePos(btVector3( - clientCmd.m_initPoseArgs.m_initialStateQ[0], - clientCmd.m_initPoseArgs.m_initialStateQ[1], - clientCmd.m_initPoseArgs.m_initialStateQ[2])); + mb->setBaseVel(baseLinVel); + mb->setBasePos(basePos); } if (clientCmd.m_updateFlags & INIT_POSE_HAS_INITIAL_ORIENTATION) { @@ -2239,11 +2456,8 @@ bool PhysicsServerCommandProcessor::processCommand(const struct SharedMemoryComm clientCmd.m_initPoseArgs.m_hasInitialStateQ[5] && clientCmd.m_initPoseArgs.m_hasInitialStateQ[6]); - mb->setBaseOmega(btVector3(0,0,0)); - btQuaternion invOrn(clientCmd.m_initPoseArgs.m_initialStateQ[3], - clientCmd.m_initPoseArgs.m_initialStateQ[4], - clientCmd.m_initPoseArgs.m_initialStateQ[5], - clientCmd.m_initPoseArgs.m_initialStateQ[6]); + mb->setBaseOmega(baseAngVel); + btQuaternion invOrn(baseOrn); mb->setWorldToBaseRot(invOrn.inverse()); } @@ -2260,6 +2474,43 @@ bool PhysicsServerCommandProcessor::processCommand(const struct SharedMemoryComm dofIndex += mb->getLink(i).m_dofCount; } } + + btAlignedObjectArray scratch_q; + btAlignedObjectArray scratch_m; + + mb->forwardKinematics(scratch_q,scratch_m); + int nLinks = mb->getNumLinks(); + scratch_q.resize(nLinks+1); + scratch_m.resize(nLinks+1); + + mb->updateCollisionObjectWorldTransforms(scratch_q,scratch_m); + + + } + + if (body && body->m_rigidBody) + { + if (clientCmd.m_updateFlags & INIT_POSE_HAS_BASE_LINEAR_VELOCITY) + { + body->m_rigidBody->setLinearVelocity(baseLinVel); + } + if (clientCmd.m_updateFlags & INIT_POSE_HAS_BASE_ANGULAR_VELOCITY) + { + body->m_rigidBody->setAngularVelocity(baseAngVel); + } + + if (clientCmd.m_updateFlags & INIT_POSE_HAS_INITIAL_POSITION) + { + body->m_rigidBody->getWorldTransform().setOrigin(basePos); + body->m_rigidBody->setLinearVelocity(baseLinVel); + } + + if (clientCmd.m_updateFlags & INIT_POSE_HAS_INITIAL_ORIENTATION) + { + body->m_rigidBody->getWorldTransform().setRotation(baseOrn); + body->m_rigidBody->setAngularVelocity(baseAngVel); + } + } SharedMemoryStatus& serverCmd =serverStatusOut; @@ -2272,29 +2523,12 @@ bool PhysicsServerCommandProcessor::processCommand(const struct SharedMemoryComm case CMD_RESET_SIMULATION: { - //clean up all data - deleteCachedInverseDynamicsBodies(); - - if (m_data && m_data->m_guiHelper) - { - m_data->m_guiHelper->removeAllGraphicsInstances(); - } - if (m_data) - { - m_data->m_visualConverter.resetAll(); - } - - deleteDynamicsWorld(); - createEmptyDynamicsWorld(); - - m_data->exitHandles(); - m_data->initHandles(); + + resetSimulation(); SharedMemoryStatus& serverCmd =serverStatusOut; serverCmd.m_type = CMD_RESET_SIMULATION_COMPLETED; hasStatus = true; - m_data->m_hasGround = false; - m_data->m_gripperRigidbodyFixed = 0; break; } case CMD_CREATE_RIGID_BODY: @@ -2470,92 +2704,339 @@ bool PhysicsServerCommandProcessor::processCommand(const struct SharedMemoryComm hasStatus = true; break; } + case CMD_REQUEST_AABB_OVERLAP: + { + SharedMemoryStatus& serverCmd = serverStatusOut; + int curObjectIndex = clientCmd.m_requestOverlappingObjectsArgs.m_startingOverlappingObjectIndex; + + if (0== curObjectIndex) + { + //clientCmd.m_requestContactPointArguments.m_aabbQueryMin + btVector3 aabbMin, aabbMax; + aabbMin.setValue(clientCmd.m_requestOverlappingObjectsArgs.m_aabbQueryMin[0], + clientCmd.m_requestOverlappingObjectsArgs.m_aabbQueryMin[1], + clientCmd.m_requestOverlappingObjectsArgs.m_aabbQueryMin[2]); + aabbMax.setValue(clientCmd.m_requestOverlappingObjectsArgs.m_aabbQueryMax[0], + clientCmd.m_requestOverlappingObjectsArgs.m_aabbQueryMax[1], + clientCmd.m_requestOverlappingObjectsArgs.m_aabbQueryMax[2]); + + m_data->m_cachedOverlappingObjects.clear(); + + m_data->m_dynamicsWorld->getBroadphase()->aabbTest(aabbMin, aabbMax, m_data->m_cachedOverlappingObjects); + } + + + int totalBytesPerObject = sizeof(b3OverlappingObject); + int overlapCapacity = bufferSizeInBytes / totalBytesPerObject - 1; + int numOverlap = m_data->m_cachedOverlappingObjects.m_bodyUniqueIds.size(); + int remainingObjects = numOverlap - curObjectIndex; + + int curNumObjects = btMin(overlapCapacity, remainingObjects); + + if (numOverlap < overlapCapacity) + { + + b3OverlappingObject* overlapStorage = (b3OverlappingObject*)bufferServerToClient; + for (int i = 0; i < m_data->m_cachedOverlappingObjects.m_bodyUniqueIds.size(); i++) + { + overlapStorage[i].m_objectUniqueId = m_data->m_cachedOverlappingObjects.m_bodyUniqueIds[i]; + overlapStorage[i].m_linkIndex = m_data->m_cachedOverlappingObjects.m_links[i]; + } + + serverCmd.m_type = CMD_REQUEST_AABB_OVERLAP_COMPLETED; + + int m_startingOverlappingObjectIndex; + int m_numOverlappingObjectsCopied; + int m_numRemainingOverlappingObjects; + serverCmd.m_sendOverlappingObjectsArgs.m_startingOverlappingObjectIndex = clientCmd.m_requestOverlappingObjectsArgs.m_startingOverlappingObjectIndex; + serverCmd.m_sendOverlappingObjectsArgs.m_numOverlappingObjectsCopied = m_data->m_cachedOverlappingObjects.m_bodyUniqueIds.size(); + serverCmd.m_sendOverlappingObjectsArgs.m_numRemainingOverlappingObjects = remainingObjects - curNumObjects; + } + else + { + serverCmd.m_type = CMD_REQUEST_AABB_OVERLAP_FAILED; + } + + hasStatus = true; + break; + } case CMD_REQUEST_CONTACT_POINT_INFORMATION: { SharedMemoryStatus& serverCmd =serverStatusOut; serverCmd.m_sendContactPointArgs.m_numContactPointsCopied = 0; //make a snapshot of the contact manifolds into individual contact points - if (clientCmd.m_requestContactPointArguments.m_startingContactPointIndex==0) - { - int numContactManifolds = m_data->m_dynamicsWorld->getDispatcher()->getNumManifolds(); + if (clientCmd.m_requestContactPointArguments.m_startingContactPointIndex == 0) + { m_data->m_cachedContactPoints.resize(0); - m_data->m_cachedContactPoints.reserve(numContactManifolds*4); - for (int i=0;im_dynamicsWorld->getDispatcher()->getInternalManifoldPointer()[i]; - int linkIndexA = -1; - int linkIndexB = -1; - - int objectIndexB = -1; - const btRigidBody* bodyB = btRigidBody::upcast(manifold->getBody1()); - if (bodyB) + int mode = CONTACT_QUERY_MODE_REPORT_EXISTING_CONTACT_POINTS; + + if (clientCmd.m_updateFlags & CMD_REQUEST_CONTACT_POINT_HAS_QUERY_MODE) + { + mode = clientCmd.m_requestContactPointArguments.m_mode; + } + + switch (mode) + { + case CONTACT_QUERY_MODE_REPORT_EXISTING_CONTACT_POINTS: + { + int numContactManifolds = m_data->m_dynamicsWorld->getDispatcher()->getNumManifolds(); + m_data->m_cachedContactPoints.reserve(numContactManifolds * 4); + for (int i = 0; i < numContactManifolds; i++) { - objectIndexB = bodyB->getUserIndex2(); - } - const btMultiBodyLinkCollider* mblB = btMultiBodyLinkCollider::upcast(manifold->getBody1()); - if (mblB && mblB->m_multiBody) - { - linkIndexB = mblB->m_link; - objectIndexB = mblB->m_multiBody->getUserIndex2(); - } + const btPersistentManifold* manifold = m_data->m_dynamicsWorld->getDispatcher()->getInternalManifoldPointer()[i]; + int linkIndexA = -1; + int linkIndexB = -1; - int objectIndexA = -1; - const btRigidBody* bodyA = btRigidBody::upcast(manifold->getBody0()); - if (bodyA) - { - objectIndexA = bodyA->getUserIndex2(); - } - const btMultiBodyLinkCollider* mblA = btMultiBodyLinkCollider::upcast(manifold->getBody0()); - if (mblA && mblA->m_multiBody) - { - linkIndexA = mblA->m_link; + int objectIndexB = -1; - objectIndexA = mblA->m_multiBody->getUserIndex2(); - } - - btAssert(bodyA || mblA); - - //apply the filter, if the user provides it - if (clientCmd.m_requestContactPointArguments.m_objectAIndexFilter>=0) - { - if ((clientCmd.m_requestContactPointArguments.m_objectAIndexFilter != objectIndexA) && - (clientCmd.m_requestContactPointArguments.m_objectAIndexFilter != objectIndexB)) - continue; - } - - //apply the second object filter, if the user provides it - if (clientCmd.m_requestContactPointArguments.m_objectBIndexFilter>=0) - { - if ((clientCmd.m_requestContactPointArguments.m_objectBIndexFilter != objectIndexA) && - (clientCmd.m_requestContactPointArguments.m_objectBIndexFilter != objectIndexB)) - continue; - } - - for (int p=0;pgetNumContacts();p++) - { - - b3ContactPointData pt; - pt.m_bodyUniqueIdA = objectIndexA; - pt.m_bodyUniqueIdB = objectIndexB; - const btManifoldPoint& srcPt = manifold->getContactPoint(p); - pt.m_contactDistance = srcPt.getDistance(); - pt.m_contactFlags = 0; - pt.m_linkIndexA = linkIndexA; - pt.m_linkIndexB = linkIndexB; - for (int j=0;j<3;j++) + const btRigidBody* bodyB = btRigidBody::upcast(manifold->getBody1()); + if (bodyB) { - pt.m_contactNormalOnBInWS[j] = srcPt.m_normalWorldOnB[j]; - pt.m_positionOnAInWS[j] = srcPt.getPositionWorldOnA()[j]; - pt.m_positionOnBInWS[j] = srcPt.getPositionWorldOnB()[j]; + objectIndexB = bodyB->getUserIndex2(); + } + const btMultiBodyLinkCollider* mblB = btMultiBodyLinkCollider::upcast(manifold->getBody1()); + if (mblB && mblB->m_multiBody) + { + linkIndexB = mblB->m_link; + objectIndexB = mblB->m_multiBody->getUserIndex2(); + } + + int objectIndexA = -1; + const btRigidBody* bodyA = btRigidBody::upcast(manifold->getBody0()); + if (bodyA) + { + objectIndexA = bodyA->getUserIndex2(); + } + const btMultiBodyLinkCollider* mblA = btMultiBodyLinkCollider::upcast(manifold->getBody0()); + if (mblA && mblA->m_multiBody) + { + linkIndexA = mblA->m_link; + + objectIndexA = mblA->m_multiBody->getUserIndex2(); + } + + btAssert(bodyA || mblA); + + //apply the filter, if the user provides it + if (clientCmd.m_requestContactPointArguments.m_objectAIndexFilter >= 0) + { + if ((clientCmd.m_requestContactPointArguments.m_objectAIndexFilter != objectIndexA) && + (clientCmd.m_requestContactPointArguments.m_objectAIndexFilter != objectIndexB)) + continue; + } + + //apply the second object filter, if the user provides it + if (clientCmd.m_requestContactPointArguments.m_objectBIndexFilter >= 0) + { + if ((clientCmd.m_requestContactPointArguments.m_objectBIndexFilter != objectIndexA) && + (clientCmd.m_requestContactPointArguments.m_objectBIndexFilter != objectIndexB)) + continue; + } + + for (int p = 0; p < manifold->getNumContacts(); p++) + { + + b3ContactPointData pt; + pt.m_bodyUniqueIdA = objectIndexA; + pt.m_bodyUniqueIdB = objectIndexB; + const btManifoldPoint& srcPt = manifold->getContactPoint(p); + pt.m_contactDistance = srcPt.getDistance(); + pt.m_contactFlags = 0; + pt.m_linkIndexA = linkIndexA; + pt.m_linkIndexB = linkIndexB; + for (int j = 0; j < 3; j++) + { + pt.m_contactNormalOnBInWS[j] = srcPt.m_normalWorldOnB[j]; + pt.m_positionOnAInWS[j] = srcPt.getPositionWorldOnA()[j]; + pt.m_positionOnBInWS[j] = srcPt.getPositionWorldOnB()[j]; + } + pt.m_normalForce = srcPt.getAppliedImpulse() / m_data->m_physicsDeltaTime; + // pt.m_linearFrictionForce = srcPt.m_appliedImpulseLateral1; + m_data->m_cachedContactPoints.push_back(pt); } - pt.m_normalForce = srcPt.getAppliedImpulse()/m_data->m_physicsDeltaTime; -// pt.m_linearFrictionForce = srcPt.m_appliedImpulseLateral1; - m_data->m_cachedContactPoints.push_back (pt); } - } - } + break; + } + + case CONTACT_QUERY_MODE_COMPUTE_CLOSEST_POINTS: + { + //todo(erwincoumans) compute closest points between all, and vs all, pair + btScalar closestDistanceThreshold = 0.f; + + if (clientCmd.m_updateFlags & CMD_REQUEST_CONTACT_POINT_HAS_CLOSEST_DISTANCE_THRESHOLD) + { + closestDistanceThreshold = clientCmd.m_requestContactPointArguments.m_closestDistanceThreshold; + } + + int bodyUniqueIdA = clientCmd.m_requestContactPointArguments.m_objectAIndexFilter; + int bodyUniqueIdB = clientCmd.m_requestContactPointArguments.m_objectBIndexFilter; + + bool hasLinkIndexAFilter = (0!=(clientCmd.m_updateFlags & CMD_REQUEST_CONTACT_POINT_HAS_LINK_INDEX_A_FILTER)); + bool hasLinkIndexBFilter = (0!=(clientCmd.m_updateFlags & CMD_REQUEST_CONTACT_POINT_HAS_LINK_INDEX_B_FILTER)); + + int linkIndexA = clientCmd.m_requestContactPointArguments.m_linkIndexAIndexFilter; + int linkIndexB = clientCmd.m_requestContactPointArguments.m_linkIndexBIndexFilter; + + btAlignedObjectArray setA; + btAlignedObjectArray setB; + btAlignedObjectArray setALinkIndex; + btAlignedObjectArray setBLinkIndex; + + if (bodyUniqueIdA >= 0) + { + InteralBodyData* bodyA = m_data->getHandle(bodyUniqueIdA); + if (bodyA) + { + if (bodyA->m_multiBody) + { + if (bodyA->m_multiBody->getBaseCollider()) + { + if (!hasLinkIndexAFilter || (linkIndexA == -1)) + { + setA.push_back(bodyA->m_multiBody->getBaseCollider()); + setALinkIndex.push_back(-1); + } + } + for (int i = 0; i < bodyA->m_multiBody->getNumLinks(); i++) + { + if (bodyA->m_multiBody->getLink(i).m_collider) + { + if (!hasLinkIndexAFilter || (linkIndexA == i)) + { + setA.push_back(bodyA->m_multiBody->getLink(i).m_collider); + setALinkIndex.push_back(i); + } + } + } + } + if (bodyA->m_rigidBody) + { + setA.push_back(bodyA->m_rigidBody); + setALinkIndex.push_back(-1); + } + } + } + if (bodyUniqueIdB>=0) + { + InteralBodyData* bodyB = m_data->getHandle(bodyUniqueIdB); + if (bodyB) + { + if (bodyB->m_multiBody) + { + if (bodyB->m_multiBody->getBaseCollider()) + { + if (!hasLinkIndexBFilter || (linkIndexB == -1)) + { + setB.push_back(bodyB->m_multiBody->getBaseCollider()); + setBLinkIndex.push_back(-1); + } + } + for (int i = 0; i < bodyB->m_multiBody->getNumLinks(); i++) + { + if (bodyB->m_multiBody->getLink(i).m_collider) + { + if (!hasLinkIndexBFilter || (linkIndexB ==i)) + { + setB.push_back(bodyB->m_multiBody->getLink(i).m_collider); + setBLinkIndex.push_back(i); + } + } + } + } + if (bodyB->m_rigidBody) + { + setB.push_back(bodyB->m_rigidBody); + setBLinkIndex.push_back(-1); + + } + } + } + + { + ///ContactResultCallback is used to report contact points + struct MyContactResultCallback : public btCollisionWorld::ContactResultCallback + { + //short int m_collisionFilterGroup; + //short int m_collisionFilterMask; + int m_bodyUniqueIdA; + int m_bodyUniqueIdB; + int m_linkIndexA; + int m_linkIndexB; + btScalar m_deltaTime; + + btAlignedObjectArray& m_cachedContactPoints; + + MyContactResultCallback(btAlignedObjectArray& pointCache) + :m_cachedContactPoints(pointCache) + { + } + + virtual ~MyContactResultCallback() + { + } + + virtual bool needsCollision(btBroadphaseProxy* proxy0) const + { + //bool collides = (proxy0->m_collisionFilterGroup & m_collisionFilterMask) != 0; + //collides = collides && (m_collisionFilterGroup & proxy0->m_collisionFilterMask); + //return collides; + return true; + } + + virtual btScalar addSingleResult(btManifoldPoint& cp, const btCollisionObjectWrapper* colObj0Wrap, int partId0, int index0, const btCollisionObjectWrapper* colObj1Wrap, int partId1, int index1) + { + b3ContactPointData pt; + pt.m_bodyUniqueIdA = m_bodyUniqueIdA; + pt.m_bodyUniqueIdB = m_bodyUniqueIdB; + const btManifoldPoint& srcPt = cp; + pt.m_contactDistance = srcPt.getDistance(); + pt.m_contactFlags = 0; + pt.m_linkIndexA = m_linkIndexA; + pt.m_linkIndexB = m_linkIndexB; + for (int j = 0; j < 3; j++) + { + pt.m_contactNormalOnBInWS[j] = srcPt.m_normalWorldOnB[j]; + pt.m_positionOnAInWS[j] = srcPt.getPositionWorldOnA()[j]; + pt.m_positionOnBInWS[j] = srcPt.getPositionWorldOnB()[j]; + } + pt.m_normalForce = srcPt.getAppliedImpulse() / m_deltaTime; + // pt.m_linearFrictionForce = srcPt.m_appliedImpulseLateral1; + m_cachedContactPoints.push_back(pt); + + return 1; + } + }; + + + MyContactResultCallback cb(m_data->m_cachedContactPoints); + + cb.m_bodyUniqueIdA = bodyUniqueIdA; + cb.m_bodyUniqueIdB = bodyUniqueIdB; + cb.m_deltaTime = m_data->m_physicsDeltaTime; + + for (int i = 0; i < setA.size(); i++) + { + cb.m_linkIndexA = setALinkIndex[i]; + for (int j = 0; j < setB.size(); j++) + { + cb.m_linkIndexB = setBLinkIndex[j]; + cb.m_closestDistanceThreshold = closestDistanceThreshold; + this->m_data->m_dynamicsWorld->contactPairTest(setA[i], setB[j], cb); + } + } + } + + break; + } + default: + { + b3Warning("Unknown contact query mode: %d", mode); + } + + } + } int numContactPoints = m_data->m_cachedContactPoints.size(); @@ -2583,7 +3064,7 @@ bool PhysicsServerCommandProcessor::processCommand(const struct SharedMemoryComm serverCmd.m_sendContactPointArgs.m_startingContactPointIndex = clientCmd.m_requestContactPointArguments.m_startingContactPointIndex; serverCmd.m_sendContactPointArgs.m_numRemainingContactPoints = numContactPoints - clientCmd.m_requestContactPointArguments.m_startingContactPointIndex - serverCmd.m_sendContactPointArgs.m_numContactPointsCopied; - + serverCmd.m_numDataStreamBytes = totalBytesPerContact * serverCmd.m_sendContactPointArgs.m_numContactPointsCopied; serverCmd.m_type = CMD_CONTACT_POINT_INFORMATION_COMPLETED; //CMD_CONTACT_POINT_INFORMATION_FAILED, hasStatus = true; break; @@ -2703,11 +3184,12 @@ bool PhysicsServerCommandProcessor::processCommand(const struct SharedMemoryComm for (int i = 0; i < clientCmd.m_externalForceArguments.m_numForcesAndTorques; ++i) { InteralBodyData* body = m_data->getHandle(clientCmd.m_externalForceArguments.m_bodyUniqueIds[i]); + bool isLinkFrame = ((clientCmd.m_externalForceArguments.m_forceFlags[i] & EF_LINK_FRAME) != 0); + if (body && body->m_multiBody) { btMultiBody* mb = body->m_multiBody; - bool isLinkFrame = ((clientCmd.m_externalForceArguments.m_forceFlags[i] & EF_LINK_FRAME)!=0); - + if ((clientCmd.m_externalForceArguments.m_forceFlags[i] & EF_FORCE)!=0) { btVector3 forceLocal(clientCmd.m_externalForceArguments.m_forcesAndTorques[i*3+0], @@ -2755,6 +3237,36 @@ bool PhysicsServerCommandProcessor::processCommand(const struct SharedMemoryComm } } } + + if (body && body->m_rigidBody) + { + btRigidBody* rb = body->m_rigidBody; + if ((clientCmd.m_externalForceArguments.m_forceFlags[i] & EF_FORCE) != 0) + { + btVector3 forceLocal(clientCmd.m_externalForceArguments.m_forcesAndTorques[i * 3 + 0], + clientCmd.m_externalForceArguments.m_forcesAndTorques[i * 3 + 1], + clientCmd.m_externalForceArguments.m_forcesAndTorques[i * 3 + 2]); + btVector3 positionLocal( + clientCmd.m_externalForceArguments.m_positions[i * 3 + 0], + clientCmd.m_externalForceArguments.m_positions[i * 3 + 1], + clientCmd.m_externalForceArguments.m_positions[i * 3 + 2]); + + btVector3 forceWorld = isLinkFrame ? forceLocal : rb->getWorldTransform().getBasis()*forceLocal; + btVector3 relPosWorld = isLinkFrame ? positionLocal : rb->getWorldTransform().getBasis()*positionLocal; + rb->applyForce(forceWorld, relPosWorld); + + } + + if ((clientCmd.m_externalForceArguments.m_forceFlags[i] & EF_TORQUE) != 0) + { + btVector3 torqueLocal(clientCmd.m_externalForceArguments.m_forcesAndTorques[i * 3 + 0], + clientCmd.m_externalForceArguments.m_forcesAndTorques[i * 3 + 1], + clientCmd.m_externalForceArguments.m_forcesAndTorques[i * 3 + 2]); + + btVector3 torqueWorld = isLinkFrame ? torqueLocal : rb->getWorldTransform().getBasis()*torqueLocal; + rb->applyTorque(torqueWorld); + } + } } SharedMemoryStatus& serverCmd =serverStatusOut; @@ -2762,72 +3274,144 @@ bool PhysicsServerCommandProcessor::processCommand(const struct SharedMemoryComm hasStatus = true; break; } - case CMD_CREATE_JOINT: + case CMD_USER_CONSTRAINT: { - InteralBodyData* parentBody = m_data->getHandle(clientCmd.m_createJointArguments.m_parentBodyIndex); - if (parentBody && parentBody->m_multiBody) - { - InteralBodyData* childBody = m_data->getHandle(clientCmd.m_createJointArguments.m_childBodyIndex); - if (childBody) - { - btVector3 pivotInParent(clientCmd.m_createJointArguments.m_parentFrame[0], clientCmd.m_createJointArguments.m_parentFrame[1], clientCmd.m_createJointArguments.m_parentFrame[2]); - btVector3 pivotInChild(clientCmd.m_createJointArguments.m_childFrame[0], clientCmd.m_createJointArguments.m_childFrame[1], clientCmd.m_createJointArguments.m_childFrame[2]); - btMatrix3x3 frameInParent(btQuaternion(clientCmd.m_createJointArguments.m_parentFrame[3], clientCmd.m_createJointArguments.m_parentFrame[4], clientCmd.m_createJointArguments.m_parentFrame[5], clientCmd.m_createJointArguments.m_parentFrame[6])); - btMatrix3x3 frameInChild(btQuaternion(clientCmd.m_createJointArguments.m_childFrame[3], clientCmd.m_createJointArguments.m_childFrame[4], clientCmd.m_createJointArguments.m_childFrame[5], clientCmd.m_createJointArguments.m_childFrame[6])); - btVector3 jointAxis(clientCmd.m_createJointArguments.m_jointAxis[0], clientCmd.m_createJointArguments.m_jointAxis[1], clientCmd.m_createJointArguments.m_jointAxis[2]); - if (clientCmd.m_createJointArguments.m_jointType == eFixedType) - { - if (childBody->m_multiBody) - { - btMultiBodyFixedConstraint* multibodyFixed = new btMultiBodyFixedConstraint(parentBody->m_multiBody,clientCmd.m_createJointArguments.m_parentJointIndex,childBody->m_multiBody,clientCmd.m_createJointArguments.m_childJointIndex,pivotInParent,pivotInChild,frameInParent,frameInChild); - multibodyFixed->setMaxAppliedImpulse(500.0); - m_data->m_dynamicsWorld->addMultiBodyConstraint(multibodyFixed); - } - else - { - btMultiBodyFixedConstraint* rigidbodyFixed = new btMultiBodyFixedConstraint(parentBody->m_multiBody,clientCmd.m_createJointArguments.m_parentJointIndex,childBody->m_rigidBody,pivotInParent,pivotInChild,frameInParent,frameInChild); - rigidbodyFixed->setMaxAppliedImpulse(500.0); - btMultiBodyDynamicsWorld* world = (btMultiBodyDynamicsWorld*) m_data->m_dynamicsWorld; - world->addMultiBodyConstraint(rigidbodyFixed); - } - } - else if (clientCmd.m_createJointArguments.m_jointType == ePrismaticType) - { - if (childBody->m_multiBody) - { - btMultiBodySliderConstraint* multibodySlider = new btMultiBodySliderConstraint(parentBody->m_multiBody,clientCmd.m_createJointArguments.m_parentJointIndex,childBody->m_multiBody,clientCmd.m_createJointArguments.m_childJointIndex,pivotInParent,pivotInChild,frameInParent,frameInChild,jointAxis); - multibodySlider->setMaxAppliedImpulse(500.0); - m_data->m_dynamicsWorld->addMultiBodyConstraint(multibodySlider); - } - else - { - btMultiBodySliderConstraint* rigidbodySlider = new btMultiBodySliderConstraint(parentBody->m_multiBody,clientCmd.m_createJointArguments.m_parentJointIndex,childBody->m_rigidBody,pivotInParent,pivotInChild,frameInParent,frameInChild,jointAxis); - rigidbodySlider->setMaxAppliedImpulse(500.0); - btMultiBodyDynamicsWorld* world = (btMultiBodyDynamicsWorld*) m_data->m_dynamicsWorld; - world->addMultiBodyConstraint(rigidbodySlider); - } - } else if (clientCmd.m_createJointArguments.m_jointType == ePoint2PointType) - { - if (childBody->m_multiBody) - { - btMultiBodyPoint2Point* p2p = new btMultiBodyPoint2Point(parentBody->m_multiBody,clientCmd.m_createJointArguments.m_parentJointIndex,childBody->m_multiBody,clientCmd.m_createJointArguments.m_childJointIndex,pivotInParent,pivotInChild); - p2p->setMaxAppliedImpulse(500); - m_data->m_dynamicsWorld->addMultiBodyConstraint(p2p); - } - else - { - btMultiBodyPoint2Point* p2p = new btMultiBodyPoint2Point(parentBody->m_multiBody,clientCmd.m_createJointArguments.m_parentJointIndex,childBody->m_rigidBody,pivotInParent,pivotInChild); - p2p->setMaxAppliedImpulse(500); - btMultiBodyDynamicsWorld* world = (btMultiBodyDynamicsWorld*) m_data->m_dynamicsWorld; - world->addMultiBodyConstraint(p2p); - } - } - - } - } SharedMemoryStatus& serverCmd =serverStatusOut; - serverCmd.m_type = CMD_CLIENT_COMMAND_COMPLETED; + serverCmd.m_type = CMD_USER_CONSTRAINT_FAILED; hasStatus = true; + + if (clientCmd.m_updateFlags & USER_CONSTRAINT_ADD_CONSTRAINT) + { + InteralBodyData* parentBody = m_data->getHandle(clientCmd.m_userConstraintArguments.m_parentBodyIndex); + if (parentBody && parentBody->m_multiBody) + { + InteralBodyData* childBody = m_data->getHandle(clientCmd.m_userConstraintArguments.m_childBodyIndex); + if (childBody) + { + btVector3 pivotInParent(clientCmd.m_userConstraintArguments.m_parentFrame[0], clientCmd.m_userConstraintArguments.m_parentFrame[1], clientCmd.m_userConstraintArguments.m_parentFrame[2]); + btVector3 pivotInChild(clientCmd.m_userConstraintArguments.m_childFrame[0], clientCmd.m_userConstraintArguments.m_childFrame[1], clientCmd.m_userConstraintArguments.m_childFrame[2]); + btMatrix3x3 frameInParent(btQuaternion(clientCmd.m_userConstraintArguments.m_parentFrame[3], clientCmd.m_userConstraintArguments.m_parentFrame[4], clientCmd.m_userConstraintArguments.m_parentFrame[5], clientCmd.m_userConstraintArguments.m_parentFrame[6])); + btMatrix3x3 frameInChild(btQuaternion(clientCmd.m_userConstraintArguments.m_childFrame[3], clientCmd.m_userConstraintArguments.m_childFrame[4], clientCmd.m_userConstraintArguments.m_childFrame[5], clientCmd.m_userConstraintArguments.m_childFrame[6])); + btVector3 jointAxis(clientCmd.m_userConstraintArguments.m_jointAxis[0], clientCmd.m_userConstraintArguments.m_jointAxis[1], clientCmd.m_userConstraintArguments.m_jointAxis[2]); + if (clientCmd.m_userConstraintArguments.m_jointType == eFixedType) + { + if (childBody->m_multiBody) + { + btMultiBodyFixedConstraint* multibodyFixed = new btMultiBodyFixedConstraint(parentBody->m_multiBody,clientCmd.m_userConstraintArguments.m_parentJointIndex,childBody->m_multiBody,clientCmd.m_userConstraintArguments.m_childJointIndex,pivotInParent,pivotInChild,frameInParent,frameInChild); + multibodyFixed->setMaxAppliedImpulse(500.0); + m_data->m_dynamicsWorld->addMultiBodyConstraint(multibodyFixed); + InteralUserConstraintData userConstraintData; + userConstraintData.m_mbConstraint = multibodyFixed; + int uid = m_data->m_userConstraintUIDGenerator++; + m_data->m_userConstraints.insert(uid,userConstraintData); + serverCmd.m_userConstraintResultArgs.m_userConstraintUniqueId = uid; + serverCmd.m_type = CMD_USER_CONSTRAINT_COMPLETED; + + } + else + { + btMultiBodyFixedConstraint* rigidbodyFixed = new btMultiBodyFixedConstraint(parentBody->m_multiBody,clientCmd.m_userConstraintArguments.m_parentJointIndex,childBody->m_rigidBody,pivotInParent,pivotInChild,frameInParent,frameInChild); + rigidbodyFixed->setMaxAppliedImpulse(500.0); + btMultiBodyDynamicsWorld* world = (btMultiBodyDynamicsWorld*) m_data->m_dynamicsWorld; + world->addMultiBodyConstraint(rigidbodyFixed); + InteralUserConstraintData userConstraintData; + userConstraintData.m_mbConstraint = rigidbodyFixed; + int uid = m_data->m_userConstraintUIDGenerator++; + m_data->m_userConstraints.insert(uid,userConstraintData); + serverCmd.m_userConstraintResultArgs.m_userConstraintUniqueId = uid; + serverCmd.m_type = CMD_USER_CONSTRAINT_COMPLETED; + } + + } + else if (clientCmd.m_userConstraintArguments.m_jointType == ePrismaticType) + { + if (childBody->m_multiBody) + { + btMultiBodySliderConstraint* multibodySlider = new btMultiBodySliderConstraint(parentBody->m_multiBody,clientCmd.m_userConstraintArguments.m_parentJointIndex,childBody->m_multiBody,clientCmd.m_userConstraintArguments.m_childJointIndex,pivotInParent,pivotInChild,frameInParent,frameInChild,jointAxis); + multibodySlider->setMaxAppliedImpulse(500.0); + m_data->m_dynamicsWorld->addMultiBodyConstraint(multibodySlider); + InteralUserConstraintData userConstraintData; + userConstraintData.m_mbConstraint = multibodySlider; + int uid = m_data->m_userConstraintUIDGenerator++; + m_data->m_userConstraints.insert(uid,userConstraintData); + serverCmd.m_userConstraintResultArgs.m_userConstraintUniqueId = uid; + serverCmd.m_type = CMD_USER_CONSTRAINT_COMPLETED; + } + else + { + btMultiBodySliderConstraint* rigidbodySlider = new btMultiBodySliderConstraint(parentBody->m_multiBody,clientCmd.m_userConstraintArguments.m_parentJointIndex,childBody->m_rigidBody,pivotInParent,pivotInChild,frameInParent,frameInChild,jointAxis); + rigidbodySlider->setMaxAppliedImpulse(500.0); + btMultiBodyDynamicsWorld* world = (btMultiBodyDynamicsWorld*) m_data->m_dynamicsWorld; + world->addMultiBodyConstraint(rigidbodySlider); + InteralUserConstraintData userConstraintData; + userConstraintData.m_mbConstraint = rigidbodySlider; + int uid = m_data->m_userConstraintUIDGenerator++; + m_data->m_userConstraints.insert(uid,userConstraintData); + serverCmd.m_userConstraintResultArgs.m_userConstraintUniqueId = uid; + serverCmd.m_type = CMD_USER_CONSTRAINT_COMPLETED; + } + + } else if (clientCmd.m_userConstraintArguments.m_jointType == ePoint2PointType) + { + if (childBody->m_multiBody) + { + btMultiBodyPoint2Point* p2p = new btMultiBodyPoint2Point(parentBody->m_multiBody,clientCmd.m_userConstraintArguments.m_parentJointIndex,childBody->m_multiBody,clientCmd.m_userConstraintArguments.m_childJointIndex,pivotInParent,pivotInChild); + p2p->setMaxAppliedImpulse(500); + m_data->m_dynamicsWorld->addMultiBodyConstraint(p2p); + InteralUserConstraintData userConstraintData; + userConstraintData.m_mbConstraint = p2p; + int uid = m_data->m_userConstraintUIDGenerator++; + m_data->m_userConstraints.insert(uid,userConstraintData); + serverCmd.m_userConstraintResultArgs.m_userConstraintUniqueId = uid; + serverCmd.m_type = CMD_USER_CONSTRAINT_COMPLETED; + } + else + { + btMultiBodyPoint2Point* p2p = new btMultiBodyPoint2Point(parentBody->m_multiBody,clientCmd.m_userConstraintArguments.m_parentJointIndex,childBody->m_rigidBody,pivotInParent,pivotInChild); + p2p->setMaxAppliedImpulse(500); + btMultiBodyDynamicsWorld* world = (btMultiBodyDynamicsWorld*) m_data->m_dynamicsWorld; + world->addMultiBodyConstraint(p2p); + InteralUserConstraintData userConstraintData; + userConstraintData.m_mbConstraint = p2p; + int uid = m_data->m_userConstraintUIDGenerator++; + m_data->m_userConstraints.insert(uid,userConstraintData); + serverCmd.m_userConstraintResultArgs.m_userConstraintUniqueId = uid; + serverCmd.m_type = CMD_USER_CONSTRAINT_COMPLETED; + } + + } else + { + b3Warning("unknown constraint type"); + } + + + } + } + } + + if (clientCmd.m_updateFlags & USER_CONSTRAINT_REMOVE_CONSTRAINT) + { + int userConstraintUidRemove = clientCmd.m_userConstraintArguments.m_userConstraintUniqueId; + InteralUserConstraintData* userConstraintPtr = m_data->m_userConstraints.find(userConstraintUidRemove); + if (userConstraintPtr) + { + if (userConstraintPtr->m_mbConstraint) + { + m_data->m_dynamicsWorld->removeMultiBodyConstraint(userConstraintPtr->m_mbConstraint); + delete userConstraintPtr->m_mbConstraint; + m_data->m_userConstraints.remove(userConstraintUidRemove); + } + if (userConstraintPtr->m_rbConstraint) + { + + } + serverCmd.m_userConstraintResultArgs.m_userConstraintUniqueId = -1; + serverCmd.m_type = CMD_USER_CONSTRAINT_COMPLETED; + } + + + } + break; } case CMD_CALCULATE_INVERSE_KINEMATICS: @@ -3006,7 +3590,7 @@ bool PhysicsServerCommandProcessor::processCommand(const struct SharedMemoryComm serverCmd.m_sendVisualShapeArgs.m_numVisualShapesCopied = 1; serverCmd.m_sendVisualShapeArgs.m_startingVisualShapeIndex = clientCmd.m_requestVisualShapeDataArguments.m_startingVisualShapeIndex; serverCmd.m_sendVisualShapeArgs.m_bodyUniqueId = clientCmd.m_requestVisualShapeDataArguments.m_bodyUniqueId; - + serverCmd.m_numDataStreamBytes = sizeof(b3VisualShapeData)*serverCmd.m_sendVisualShapeArgs.m_numVisualShapesCopied; serverCmd.m_type =CMD_VISUAL_SHAPE_INFO_COMPLETED; hasStatus = true; break; @@ -3028,14 +3612,220 @@ bool PhysicsServerCommandProcessor::processCommand(const struct SharedMemoryComm SharedMemoryStatus& serverCmd = serverStatusOut; serverCmd.m_type = CMD_LOAD_TEXTURE_FAILED; - m_data->m_visualConverter.loadTextureFile(clientCmd.m_loadTextureArguments.m_textureFileName); + int uid = m_data->m_visualConverter.loadTextureFile(clientCmd.m_loadTextureArguments.m_textureFileName); - serverCmd.m_type = CMD_LOAD_TEXTURE_COMPLETED; + if (uid>=0) + { + serverCmd.m_type = CMD_LOAD_TEXTURE_COMPLETED; + } else + { + serverCmd.m_type = CMD_LOAD_TEXTURE_FAILED; + } hasStatus = true; break; } + case CMD_LOAD_BULLET: + { + + SharedMemoryStatus& serverCmd = serverStatusOut; + btBulletWorldImporter* importer = new btBulletWorldImporter(m_data->m_dynamicsWorld); + + const char* prefix[] = { "", "./", "./data/", "../data/", "../../data/", "../../../data/", "../../../../data/" }; + int numPrefixes = sizeof(prefix) / sizeof(const char*); + char relativeFileName[1024]; + FILE* f = 0; + bool found = false; + + for (int i = 0; !f && iloadFile(relativeFileName); + if (ok) + { + + + int numRb = importer->getNumRigidBodies(); + serverStatusOut.m_sdfLoadedArgs.m_numBodies = 0; + + for( int i=0;igetRigidBodyByIndex(i); + if (colObj) + { + btRigidBody* rb = btRigidBody::upcast(colObj); + if (rb) + { + int bodyUniqueId = m_data->allocHandle(); + InternalBodyHandle* bodyHandle = m_data->getHandle(bodyUniqueId); + colObj->setUserIndex2(bodyUniqueId); + bodyHandle->m_rigidBody = rb; + + if (serverStatusOut.m_sdfLoadedArgs.m_numBodiesm_guiHelper->autogenerateGraphicsObjects(m_data->m_dynamicsWorld); + hasStatus = true; + break; + } + } + serverCmd.m_type = CMD_BULLET_LOADING_FAILED; + hasStatus = true; + break; + } + + case CMD_SAVE_BULLET: + { + SharedMemoryStatus& serverCmd = serverStatusOut; + + FILE* f = fopen(clientCmd.m_fileArguments.m_fileName, "wb"); + if (f) + { + btDefaultSerializer* ser = new btDefaultSerializer(); + m_data->m_dynamicsWorld->serialize(ser); + fwrite(ser->getBufferPointer(), ser->getCurrentBufferSize(), 1, f); + fclose(f); + serverCmd.m_type = CMD_BULLET_SAVING_COMPLETED; + delete ser; + } + serverCmd.m_type = CMD_BULLET_SAVING_FAILED; + hasStatus = true; + break; + } + + case CMD_LOAD_MJCF: + { + SharedMemoryStatus& serverCmd = serverStatusOut; + serverCmd.m_type = CMD_MJCF_LOADING_FAILED; + hasStatus = true; + break; + } + + case CMD_USER_DEBUG_DRAW: + { + SharedMemoryStatus& serverCmd = serverStatusOut; + serverCmd.m_type = CMD_USER_DEBUG_DRAW_FAILED; + hasStatus = true; + + if ((clientCmd.m_updateFlags & USER_DEBUG_SET_CUSTOM_OBJECT_COLOR) || (clientCmd.m_updateFlags & USER_DEBUG_REMOVE_CUSTOM_OBJECT_COLOR)) + { + int bodyUniqueId = clientCmd.m_userDebugDrawArgs.m_objectUniqueId; + InteralBodyData* body = m_data->getHandle(bodyUniqueId); + if (body) + { + btCollisionObject* destColObj = 0; + + if (body->m_multiBody) + { + if (clientCmd.m_userDebugDrawArgs.m_linkIndex == -1) + { + destColObj = body->m_multiBody->getBaseCollider(); + } + else + { + if (clientCmd.m_userDebugDrawArgs.m_linkIndex >= 0 && clientCmd.m_userDebugDrawArgs.m_linkIndex < body->m_multiBody->getNumLinks()) + { + destColObj = body->m_multiBody->getLink(clientCmd.m_userDebugDrawArgs.m_linkIndex).m_collider; + } + } + + } + if (body->m_rigidBody) + { + destColObj = body->m_rigidBody; + } + + if (destColObj) + { + if (clientCmd.m_updateFlags & USER_DEBUG_REMOVE_CUSTOM_OBJECT_COLOR) + { + destColObj->removeCustomDebugColor(); + serverCmd.m_type = CMD_USER_DEBUG_DRAW_COMPLETED; + } + if (clientCmd.m_updateFlags & USER_DEBUG_SET_CUSTOM_OBJECT_COLOR) + { + btVector3 objectColorRGB; + objectColorRGB.setValue(clientCmd.m_userDebugDrawArgs.m_objectDebugColorRGB[0], + clientCmd.m_userDebugDrawArgs.m_objectDebugColorRGB[1], + clientCmd.m_userDebugDrawArgs.m_objectDebugColorRGB[2]); + destColObj->setCustomDebugColor(objectColorRGB); + serverCmd.m_type = CMD_USER_DEBUG_DRAW_COMPLETED; + } + } + } + } + + if (clientCmd.m_updateFlags & USER_DEBUG_HAS_TEXT) + { + int uid = m_data->m_guiHelper->addUserDebugText3D(clientCmd.m_userDebugDrawArgs.m_text, + clientCmd.m_userDebugDrawArgs.m_textPositionXYZ, + clientCmd.m_userDebugDrawArgs.m_textColorRGB, + clientCmd.m_userDebugDrawArgs.m_textSize, + clientCmd.m_userDebugDrawArgs.m_lifeTime); + + if (uid>=0) + { + serverCmd.m_userDebugDrawArgs.m_debugItemUniqueId = uid; + serverCmd.m_type = CMD_USER_DEBUG_DRAW_COMPLETED; + } + } + + if (clientCmd.m_updateFlags & USER_DEBUG_HAS_LINE) + { + int uid = m_data->m_guiHelper->addUserDebugLine( + clientCmd.m_userDebugDrawArgs.m_debugLineFromXYZ, + clientCmd.m_userDebugDrawArgs.m_debugLineToXYZ, + clientCmd.m_userDebugDrawArgs.m_debugLineColorRGB, + clientCmd.m_userDebugDrawArgs.m_lineWidth, + clientCmd.m_userDebugDrawArgs.m_lifeTime); + + if (uid>=0) + { + serverCmd.m_userDebugDrawArgs.m_debugItemUniqueId = uid; + serverCmd.m_type = CMD_USER_DEBUG_DRAW_COMPLETED; + } + } + + + if (clientCmd.m_updateFlags & USER_DEBUG_REMOVE_ALL) + { + m_data->m_guiHelper->removeAllUserDebugItems(); + serverCmd.m_type = CMD_USER_DEBUG_DRAW_COMPLETED; + + } + if (clientCmd.m_updateFlags & USER_DEBUG_REMOVE_ONE_ITEM) + { + m_data->m_guiHelper->removeUserDebugItem(clientCmd.m_userDebugDrawArgs.m_removeItemUniqueId); + serverCmd.m_type = CMD_USER_DEBUG_DRAW_COMPLETED; + + } + + break; + } + + default: { b3Error("Unknown command encountered"); @@ -3091,6 +3881,7 @@ void PhysicsServerCommandProcessor::physicsDebugDraw(int debugDrawFlags) bool PhysicsServerCommandProcessor::pickBody(const btVector3& rayFromWorld, const btVector3& rayToWorld) { + if (m_data->m_dynamicsWorld==0) return false; @@ -3124,7 +3915,7 @@ bool PhysicsServerCommandProcessor::pickBody(const btVector3& rayFromWorld, cons } else { btMultiBodyLinkCollider* multiCol = (btMultiBodyLinkCollider*)btMultiBodyLinkCollider::upcast(rayCallback.m_collisionObject); - if (multiCol && multiCol->m_multiBody) + if (multiCol && multiCol->m_multiBody && multiCol->m_multiBody->getBaseMass()>0.) { m_data->m_prevCanSleep = multiCol->m_multiBody->getCanSleep(); @@ -3241,7 +4032,7 @@ void PhysicsServerCommandProcessor::replayFromLogFile(const char* fileName) } -btVector3 gVRGripperPos(0,0,0.2); +btVector3 gVRGripperPos(0.6, 0.4, 0.7); btQuaternion gVRGripperOrn(0,0,0,1); btVector3 gVRController2Pos(0,0,0.2); btQuaternion gVRController2Orn(0,0,0,1); @@ -3255,9 +4046,21 @@ int gDroppedSimulationSteps = 0; int gNumSteps = 0; double gDtInSec = 0.f; double gSubStep = 0.f; + +void PhysicsServerCommandProcessor::enableRealTimeSimulation(bool enableRealTimeSim) +{ + m_data->m_allowRealTimeSimulation = enableRealTimeSim; +} + void PhysicsServerCommandProcessor::stepSimulationRealTime(double dtInSec) { - if ((gEnableRealTimeSimVR || m_data->m_allowRealTimeSimulation) && m_data->m_guiHelper) + if (gResetSimulation) + { + resetSimulation(); + gResetSimulation = false; + } + + if ((m_data->m_allowRealTimeSimulation) && m_data->m_guiHelper) { ///this hardcoded C++ scene creation is temporary for demo purposes. It will be done in Python later... @@ -3276,6 +4079,16 @@ void PhysicsServerCommandProcessor::stepSimulationRealTime(double dtInSec) gSubStep = m_data->m_physicsDeltaTime; } + if (gHuskyId >= 0) + { + InternalBodyHandle* bodyHandle = m_data->getHandle(gHuskyId); + if (bodyHandle && bodyHandle->m_multiBody) + { + huskyTr = bodyHandle->m_multiBody->getBaseWorldTransform(); + } + } + + int numSteps = m_data->m_dynamicsWorld->stepSimulation(dtInSec*simTimeScalingFactor,maxSteps, gSubStep); gDroppedSimulationSteps += numSteps > maxSteps ? numSteps - maxSteps : 0; @@ -3304,7 +4117,30 @@ void PhysicsServerCommandProcessor::applyJointDamping(int bodyUniqueId) } } +void PhysicsServerCommandProcessor::resetSimulation() +{ + //clean up all data + deleteCachedInverseDynamicsBodies(); + if (m_data && m_data->m_guiHelper) + { + m_data->m_guiHelper->removeAllGraphicsInstances(); + } + if (m_data) + { + m_data->m_visualConverter.resetAll(); + } + + deleteDynamicsWorld(); + createEmptyDynamicsWorld(); + + m_data->exitHandles(); + m_data->initHandles(); + + m_data->m_hasGround = false; + m_data->m_gripperRigidbodyFixed = 0; + +} //todo: move this to Python/scripting void PhysicsServerCommandProcessor::createDefaultRobotAssets() { @@ -3336,12 +4172,13 @@ void PhysicsServerCommandProcessor::createDefaultRobotAssets() loadUrdf("plane.urdf", btVector3(0, 0, 0), btQuaternion(0, 0, 0, 1), true, true, &bodyId, &gBufferServerToClient[0], gBufferServerToClient.size()); loadUrdf("samurai.urdf", btVector3(0, 0, 0), btQuaternion(0, 0, 0, 1), true, false, &bodyId, &gBufferServerToClient[0], gBufferServerToClient.size()); +// loadUrdf("quadruped/quadruped.urdf", btVector3(2, 2, 1), btQuaternion(0, 0, 0, 1), true, false, &bodyId, &gBufferServerToClient[0], gBufferServerToClient.size()); if (m_data->m_gripperRigidbodyFixed == 0) { int bodyId = 0; - if (loadUrdf("pr2_gripper.urdf", btVector3(0, 0, 0.1), btQuaternion(0, 0, 0, 1), true, false, &bodyId, &gBufferServerToClient[0], gBufferServerToClient.size())) + if (loadUrdf("pr2_gripper.urdf", btVector3(-0.2, 0.15, 0.9), btQuaternion(0, 0, 0, 1), true, false, &bodyId, &gBufferServerToClient[0], gBufferServerToClient.size())) { InteralBodyData* parentBody = m_data->getHandle(bodyId); if (parentBody->m_multiBody) @@ -3371,6 +4208,30 @@ void PhysicsServerCommandProcessor::createDefaultRobotAssets() loadUrdf("kuka_iiwa/model_vr_limits.urdf", btVector3(1.4, -0.2, 0.6), btQuaternion(0, 0, 0, 1), true, false, &bodyId, &gBufferServerToClient[0], gBufferServerToClient.size()); m_data->m_KukaId = bodyId; + InteralBodyData* kukaBody = m_data->getHandle(m_data->m_KukaId); + if (kukaBody->m_multiBody && kukaBody->m_multiBody->getNumDofs() == 7) + { + btScalar q[7]; + q[0] = 0;// -SIMD_HALF_PI; + q[1] = 0; + q[2] = 0; + q[3] = SIMD_HALF_PI; + q[4] = 0; + q[5] = -SIMD_HALF_PI*0.66; + q[6] = 0; + + for (int i = 0; i < 7; i++) + { + kukaBody->m_multiBody->setJointPos(i, q[i]); + } + btAlignedObjectArray scratch_q; + btAlignedObjectArray scratch_m; + kukaBody->m_multiBody->forwardKinematics(scratch_q, scratch_m); + int nLinks = kukaBody->m_multiBody->getNumLinks(); + scratch_q.resize(nLinks + 1); + scratch_m.resize(nLinks + 1); + kukaBody->m_multiBody->updateCollisionObjectWorldTransforms(scratch_q, scratch_m); + } loadUrdf("lego/lego.urdf", btVector3(1.0, -0.2, .7), btQuaternion(0, 0, 0, 1), true, false, &bodyId, &gBufferServerToClient[0], gBufferServerToClient.size()); loadUrdf("lego/lego.urdf", btVector3(1.0, -0.2, .8), btQuaternion(0, 0, 0, 1), true, false, &bodyId, &gBufferServerToClient[0], gBufferServerToClient.size()); loadUrdf("lego/lego.urdf", btVector3(1.0, -0.2, .9), btQuaternion(0, 0, 0, 1), true, false, &bodyId, &gBufferServerToClient[0], gBufferServerToClient.size()); @@ -3379,7 +4240,7 @@ void PhysicsServerCommandProcessor::createDefaultRobotAssets() // Load one motor gripper for kuka loadSdf("gripper/wsg50_one_motor_gripper_new_free_base.sdf", &gBufferServerToClient[0], gBufferServerToClient.size(), true); m_data->m_gripperId = bodyId + 1; - InteralBodyData* kukaBody = m_data->getHandle(m_data->m_KukaId); + InteralBodyData* gripperBody = m_data->getHandle(m_data->m_gripperId); // Reset the default gripper motor maximum torque for damping to 0 @@ -3421,6 +4282,7 @@ void PhysicsServerCommandProcessor::createDefaultRobotAssets() m_data->m_dynamicsWorld->addMultiBodyConstraint(m_data->m_kukaGripperRevolute1); m_data->m_dynamicsWorld->addMultiBodyConstraint(m_data->m_kukaGripperRevolute2); + kukaBody = m_data->getHandle(m_data->m_KukaId); if (kukaBody->m_multiBody && kukaBody->m_multiBody->getNumDofs()==7) { gripperBody->m_multiBody->setHasSelfCollision(0); @@ -3447,7 +4309,7 @@ void PhysicsServerCommandProcessor::createDefaultRobotAssets() btTransform objectLocalTr[] = { btTransform(btQuaternion(0, 0, 0, 1), btVector3(0.0, 0.0, 0.0)), - btTransform(btQuaternion(0, 0, 0, 1), btVector3(0.0, 0.15, 0.64)), + btTransform(btQuaternion(btVector3(0,0,1),-SIMD_HALF_PI), btVector3(0.0, 0.15, 0.64)), btTransform(btQuaternion(0, 0, 0, 1), btVector3(0.1, 0.15, 0.85)), btTransform(btQuaternion(0, 0, 0, 1), btVector3(-0.4, 0.05, 0.85)), btTransform(btQuaternion(0, 0, 0, 1), btVector3(-0.3, -0.05, 0.7)), @@ -3474,7 +4336,7 @@ void PhysicsServerCommandProcessor::createDefaultRobotAssets() // Table area loadUrdf("table/table.urdf", objectWorldTr[0].getOrigin(), objectWorldTr[0].getRotation(), true, false, &bodyId, &gBufferServerToClient[0], gBufferServerToClient.size()); - loadUrdf("tray.urdf", objectWorldTr[1].getOrigin(), objectWorldTr[1].getRotation(), true, false, &bodyId, &gBufferServerToClient[0], gBufferServerToClient.size()); + //loadUrdf("tray/tray_textured.urdf", objectWorldTr[1].getOrigin(), objectWorldTr[1].getRotation(), true, false, &bodyId, &gBufferServerToClient[0], gBufferServerToClient.size()); //loadUrdf("cup_small.urdf", objectWorldTr[2].getOrigin(), objectWorldTr[2].getRotation(), true, false, &bodyId, &gBufferServerToClient[0], gBufferServerToClient.size()); //loadUrdf("pitcher_small.urdf", objectWorldTr[3].getOrigin(), objectWorldTr[3].getRotation(), true, false, &bodyId, &gBufferServerToClient[0], gBufferServerToClient.size()); loadUrdf("teddy_vhacd.urdf", objectWorldTr[4].getOrigin(), objectWorldTr[4].getRotation(), true, false, &bodyId, &gBufferServerToClient[0], gBufferServerToClient.size()); @@ -3498,7 +4360,9 @@ void PhysicsServerCommandProcessor::createDefaultRobotAssets() //loadUrdf("rook.urdf", btVector3(-1.2, 0, 0.7), btQuaternion(btVector3(1, 0, 0), SIMD_HALF_PI), true, false, &bodyId, &gBufferServerToClient[0], gBufferServerToClient.size()); //loadUrdf("knight.urdf", btVector3(-1.2, 0.2, 0.7), btQuaternion(btVector3(1, 0, 0), SIMD_HALF_PI), true, false, &bodyId, &gBufferServerToClient[0], gBufferServerToClient.size()); - //loadUrdf("husky/husky.urdf", btVector3(2, -5, 1), btQuaternion(0, 0, 0, 1), true, false, &bodyId, &gBufferServerToClient[0], gBufferServerToClient.size()); + loadUrdf("husky/husky.urdf", btVector3(2, -5, 1), btQuaternion(0, 0, 0, 1), true, false, &bodyId, &gBufferServerToClient[0], gBufferServerToClient.size()); + gHuskyId = bodyId; + b3Printf("huskyId = %d", gHuskyId); m_data->m_huskyId = bodyId; m_data->m_dynamicsWorld->setGravity(btVector3(0, 0, -10)); @@ -3513,9 +4377,10 @@ void PhysicsServerCommandProcessor::createDefaultRobotAssets() if (motor) { btScalar posTarget = (-0.048)*btMin(btScalar(0.75), gVRGripper2Analog) / 0.75; - motor->setPositionTarget(posTarget, .2); + motor->setPositionTarget(posTarget, .8); motor->setVelocityTarget(0.0, .5); - motor->setMaxAppliedImpulse(5.0); + motor->setMaxAppliedImpulse(1.0); + } } @@ -3523,6 +4388,8 @@ void PhysicsServerCommandProcessor::createDefaultRobotAssets() { m_data->m_gripperRigidbodyFixed->setFrameInB(btMatrix3x3(gVRGripperOrn)); m_data->m_gripperRigidbodyFixed->setPivotInB(gVRGripperPos); + btScalar avg = 0.f; + for (int i = 0; i < m_data->m_gripperMultiBody->getNumLinks(); i++) { if (supportsJointMotor(m_data->m_gripperMultiBody, i)) @@ -3533,7 +4400,14 @@ void PhysicsServerCommandProcessor::createDefaultRobotAssets() motor->setErp(0.2); btScalar posTarget = 0.1 + (1 - btMin(btScalar(0.75),gVRGripperAnalog)*btScalar(1.5))*SIMD_HALF_PI*0.29; btScalar maxPosTarget = 0.55; - + + btScalar correction = 0.f; + + if (avg) + { + correction = m_data->m_gripperMultiBody->getJointPos(i) - avg; + } + if (m_data->m_gripperMultiBody->getJointPos(i) < 0) { m_data->m_gripperMultiBody->setJointPos(i,0); @@ -3543,10 +4417,19 @@ void PhysicsServerCommandProcessor::createDefaultRobotAssets() m_data->m_gripperMultiBody->setJointPos(i, maxPosTarget); } - motor->setPositionTarget(posTarget, 1); + if (avg) + { + motor->setPositionTarget(avg, 1); + } + else + { + motor->setPositionTarget(posTarget, 1); + } motor->setVelocityTarget(0, 0.5); - btScalar maxImp = 1*m_data->m_physicsDeltaTime; + btScalar maxImp = (1+0.1*i)*m_data->m_physicsDeltaTime; motor->setMaxAppliedImpulse(maxImp); + avg = m_data->m_gripperMultiBody->getJointPos(i); + //motor->setRhsClamp(gRhsClamp); } } @@ -3554,7 +4437,7 @@ void PhysicsServerCommandProcessor::createDefaultRobotAssets() } // Inverse kinematics for KUKA - //if (0) + if (m_data->m_KukaId>=0) { InternalBodyHandle* bodyHandle = m_data->getHandle(m_data->m_KukaId); if (bodyHandle && bodyHandle->m_multiBody && bodyHandle->m_multiBody->getNumDofs()==7) @@ -3583,7 +4466,7 @@ void PhysicsServerCommandProcessor::createDefaultRobotAssets() q_new[5] = -SIMD_HALF_PI*0.66; q_new[6] = 0; - if (gCloseToKuka) + if (gCloseToKuka && gEnableKukaControl) { double dampIk[6] = {1.0, 1.0, 1.0, 1.0, 1.0, 0.0}; @@ -3730,6 +4613,7 @@ void PhysicsServerCommandProcessor::createDefaultRobotAssets() } //directly set the position of the links, only for debugging IK, don't use this method! +#if 0 if (0) { for (int i=0;igetNumLinks();i++) @@ -3738,6 +4622,7 @@ void PhysicsServerCommandProcessor::createDefaultRobotAssets() mb->setJointPosMultiDof(i,&desiredPosition); } } else +#endif { int numMotors = 0; //find the joint motors and apply the desired velocity and maximum force/torque @@ -3772,4 +4657,4 @@ void PhysicsServerCommandProcessor::createDefaultRobotAssets() } } -} \ No newline at end of file +} diff --git a/examples/SharedMemory/PhysicsServerCommandProcessor.h b/examples/SharedMemory/PhysicsServerCommandProcessor.h index 2814d11dd..c8a060069 100644 --- a/examples/SharedMemory/PhysicsServerCommandProcessor.h +++ b/examples/SharedMemory/PhysicsServerCommandProcessor.h @@ -3,6 +3,8 @@ #include "LinearMath/btVector3.h" +#include "PhysicsCommandProcessorInterface.h" + struct SharedMemLines { btVector3 m_from; @@ -10,8 +12,10 @@ struct SharedMemLines btVector3 m_color; }; + + ///todo: naming. Perhaps PhysicsSdkCommandprocessor? -class PhysicsServerCommandProcessor +class PhysicsServerCommandProcessor : public PhysicsCommandProcessorInterface { struct PhysicsServerCommandProcessorInternalData* m_data; @@ -19,32 +23,53 @@ class PhysicsServerCommandProcessor //todo: move this to physics client side / Python void createDefaultRobotAssets(); + void resetSimulation(); + protected: - - bool loadSdf(const char* fileName, char* bufferServerToClient, int bufferSizeInBytes, bool useMultiBody); + + bool loadSdf(const char* fileName, char* bufferServerToClient, int bufferSizeInBytes, bool useMultiBody); bool loadUrdf(const char* fileName, const class btVector3& pos, const class btQuaternion& orn, - bool useMultiBody, bool useFixedBase, int* bodyUniqueIdPtr, char* bufferServerToClient, int bufferSizeInBytes); + bool useMultiBody, bool useFixedBase, int* bodyUniqueIdPtr, char* bufferServerToClient, int bufferSizeInBytes); bool supportsJointMotor(class btMultiBody* body, int linkIndex); - + int createBodyInfoStream(int bodyUniqueId, char* bufferServerToClient, int bufferSizeInBytes); void deleteCachedInverseDynamicsBodies(); + void deleteCachedInverseKinematicsBodies(); public: PhysicsServerCommandProcessor(); virtual ~PhysicsServerCommandProcessor(); void createJointMotors(class btMultiBody* body); - + virtual void createEmptyDynamicsWorld(); virtual void deleteDynamicsWorld(); - - virtual bool processCommand(const struct SharedMemoryCommand& clientCmd, struct SharedMemoryStatus& serverStatusOut, char* bufferServerToClient, int bufferSizeInBytes ); + virtual bool connect() + { + return true; + }; + + virtual void disconnect() {} + + virtual bool isConnected() const + { + return true; + } + + + + virtual bool processCommand(const struct SharedMemoryCommand& clientCmd, struct SharedMemoryStatus& serverStatusOut, char* bufferServerToClient, int bufferSizeInBytes); + + virtual bool receiveStatus(struct SharedMemoryStatus& serverStatusOut, char* bufferServerToClient, int bufferSizeInBytes) + { + return false; + }; virtual void renderScene(); virtual void physicsDebugDraw(int debugDrawFlags); @@ -60,6 +85,7 @@ public: void replayFromLogFile(const char* fileName); void replayLogCommand(char* bufferServerToClient, int bufferSizeInBytes ); void stepSimulationRealTime(double dtInSec); + void enableRealTimeSimulation(bool enableRealTimeSim); void applyJointDamping(int bodyUniqueId); }; diff --git a/examples/SharedMemory/PhysicsServerExample.cpp b/examples/SharedMemory/PhysicsServerExample.cpp index 77eaa6cd9..2bc823d3b 100644 --- a/examples/SharedMemory/PhysicsServerExample.cpp +++ b/examples/SharedMemory/PhysicsServerExample.cpp @@ -4,7 +4,9 @@ #include "PhysicsServerExample.h" - +#ifdef B3_USE_MIDI +#include "RtMidi.h" +#endif//B3_USE_MIDI #include "PhysicsServerSharedMemory.h" #include "Bullet3Common/b3CommandLineArgs.h" @@ -24,7 +26,8 @@ //@todo(erwincoumans) those globals are hacks for a VR demo, move this to Python/pybullet! extern btVector3 gLastPickPos; -btVector3 gVRTeleportPos(0,0,0); +btVector3 gVRTeleportPos1(0,0,0); +btScalar gVRTeleportRotZ = 0; btQuaternion gVRTeleportOrn(0, 0, 0,1); extern btVector3 gVRGripperPos; extern btQuaternion gVRGripperOrn; @@ -37,11 +40,100 @@ extern bool gEnableRealTimeSimVR; extern bool gCreateDefaultRobotAssets; extern int gInternalSimFlags; extern int gCreateObjectSimVR; -static int gGraspingController = -1; +extern bool gResetSimulation; +extern int gEnableKukaControl; +int gGraspingController = -1; extern btScalar simTimeScalingFactor; extern bool gVRGripperClosed; +const char* startFileNameVR = "0_VRDemoSettings.txt"; + +#include + +//remember the settings (you don't want to re-tune again and again...) +static void saveCurrentSettingsVR() +{ + FILE* f = fopen(startFileNameVR, "w"); + if (f) + { + fprintf(f, "--camPosX= %f\n", gVRTeleportPos1[0]); + fprintf(f, "--camPosY= %f\n", gVRTeleportPos1[1]); + fprintf(f, "--camPosZ= %f\n", gVRTeleportPos1[2]); + fprintf(f, "--camRotZ= %f\n", gVRTeleportRotZ); + fclose(f); + } +}; + +static void loadCurrentSettingsVR(b3CommandLineArgs& args) +{ + int currentEntry = 0; + FILE* f = fopen(startFileNameVR, "r"); + if (f) + { + char oneline[1024]; + char* argv[] = { 0,&oneline[0] }; + + while (fgets(oneline, 1024, f) != NULL) + { + char *pos; + if ((pos = strchr(oneline, '\n')) != NULL) + *pos = '\0'; + args.addArgs(2, argv); + } + fclose(f); + } + +}; +#if B3_USE_MIDI + + +static float getParamf(float rangeMin, float rangeMax, int midiVal) +{ + float v = rangeMin + (rangeMax - rangeMin)* (float(midiVal / 127.)); + return v; +} +void midiCallback(double deltatime, std::vector< unsigned char > *message, void *userData) +{ + unsigned int nBytes = message->size(); + for (unsigned int i = 0; i 0) + std::cout << "stamp = " << deltatime << std::endl; + + if (nBytes > 2) + { + + if (message->at(0) == 176) + { + if (message->at(1) == 16) + { + gVRTeleportRotZ= getParamf(-3.1415, 3.1415, message->at(2)); + gVRTeleportOrn = btQuaternion(btVector3(0, 0, 1), gVRTeleportRotZ); + saveCurrentSettingsVR(); + b3Printf("gVRTeleportOrn rotZ = %f\n", gVRTeleportRotZ); + } + + if (message->at(1) == 32) + { + gCreateDefaultRobotAssets = 1; + } + + for (int i = 0; i < 3; i++) + { + if (message->at(1) == i) + { + gVRTeleportPos1[i] = getParamf(-2, 2, message->at(2)); + saveCurrentSettingsVR(); + b3Printf("gVRTeleportPos[%d] = %f\n", i,gVRTeleportPos1[i]); + + } + } + } + } +} + +#endif //B3_USE_MIDI bool gDebugRenderToggle = false; void MotionThreadFunc(void* userPtr,void* lsMemory); @@ -74,6 +166,11 @@ enum MultiThreadedGUIHelperCommunicationEnums eGUIHelperCreateRigidBodyGraphicsObject, eGUIHelperRemoveAllGraphicsInstances, eGUIHelperCopyCameraImageData, + eGUIHelperAutogenerateGraphicsObjects, + eGUIUserDebugAddText, + eGUIUserDebugAddLine, + eGUIUserDebugRemoveItem, + eGUIUserDebugRemoveAllItems, }; #include @@ -107,7 +204,19 @@ b3ThreadSupportInterface* createMotionThreadSupport(int numThreads) } #endif +enum MyMouseCommandType +{ + MyMouseMove = 1, + MyMouseButtonDown, + MyMouseButtonUp +}; +struct MyMouseCommand +{ + btVector3 m_rayFrom; + btVector3 m_rayTo; + int m_type; +}; struct MotionArgs { @@ -123,6 +232,8 @@ struct MotionArgs } } b3CriticalSection* m_cs; + + btAlignedObjectArray m_mouseCommands; PhysicsServerSharedMemory* m_physicsServerPtr; b3AlignedObjectArray m_positions; @@ -192,31 +303,31 @@ void MotionThreadFunc(void* userPtr,void* lsMemory) btMatrix3x3 mat(args->m_vrControllerOrn[c]); btScalar pickDistance = 1000.; - btVector3 toX = from+mat.getColumn(0); - btVector3 toY = from+mat.getColumn(1); - btVector3 toZ = from+mat.getColumn(2)*pickDistance; + btVector3 to = from+mat.getColumn(0)*pickDistance; +// btVector3 toY = from+mat.getColumn(1)*pickDistance; +// btVector3 toZ = from+mat.getColumn(2)*pickDistance; if (args->m_isVrControllerTeleporting[c]) { args->m_isVrControllerTeleporting[c] = false; - args->m_physicsServerPtr->pickBody(from,-toZ); + args->m_physicsServerPtr->pickBody(from, to); args->m_physicsServerPtr->removePickingConstraint(); } - if (!gCloseToKuka) +// if (!gEnableKukaControl) { if (args->m_isVrControllerPicking[c]) { args->m_isVrControllerPicking[c] = false; args->m_isVrControllerDragging[c] = true; - args->m_physicsServerPtr->pickBody(from,-toZ); + args->m_physicsServerPtr->pickBody(from, to); //printf("PICK!\n"); } } if (args->m_isVrControllerDragging[c]) { - args->m_physicsServerPtr->movePickedBody(from,-toZ); + args->m_physicsServerPtr->movePickedBody(from, to); // printf("."); } @@ -242,6 +353,37 @@ void MotionThreadFunc(void* userPtr,void* lsMemory) } + args->m_cs->lock(); + for (int i = 0; i < args->m_mouseCommands.size(); i++) + { + switch (args->m_mouseCommands[i].m_type) + { + case MyMouseMove: + { + args->m_physicsServerPtr->movePickedBody(args->m_mouseCommands[i].m_rayFrom, args->m_mouseCommands[i].m_rayTo); + break; + }; + case MyMouseButtonDown: + { + args->m_physicsServerPtr->pickBody(args->m_mouseCommands[i].m_rayFrom, args->m_mouseCommands[i].m_rayTo); + break; + } + case MyMouseButtonUp: + { + args->m_physicsServerPtr->removePickingConstraint(); + break; + } + + default: + { + } + + } + } + args->m_mouseCommands.clear(); + args->m_cs->unlock(); + + args->m_physicsServerPtr->processClientCommands(); } while (args->m_cs->getSharedParam(0)!=eRequestTerminateMotion); @@ -270,17 +412,44 @@ void* MotionlsMemoryFunc() +struct UserDebugDrawLine +{ + double m_debugLineFromXYZ[3]; + double m_debugLineToXYZ[3]; + double m_debugLineColorRGB[3]; + double m_lineWidth; + + double m_lifeTime; + int m_itemUniqueId; +}; + +struct UserDebugText +{ + char m_text[1024]; + double m_textPositionXYZ[3]; + double m_textColorRGB[3]; + double textSize; + + double m_lifeTime; + int m_itemUniqueId; +}; + + + class MultiThreadedOpenGLGuiHelper : public GUIHelperInterface { CommonGraphicsApp* m_app; b3CriticalSection* m_cs; + + public: GUIHelperInterface* m_childGuiHelper; + int m_uidGenerator; const unsigned char* m_texels; int m_textureWidth; int m_textureHeight; @@ -300,10 +469,12 @@ public: int m_textureId; int m_instanceId; + MultiThreadedOpenGLGuiHelper(CommonGraphicsApp* app, GUIHelperInterface* guiHelper) :m_app(app) ,m_cs(0), + m_uidGenerator(0), m_texels(0), m_textureId(-1) { @@ -466,7 +637,7 @@ public: virtual CommonRenderInterface* getRenderInterface() { - return 0; + return m_childGuiHelper->getRenderInterface(); } virtual CommonGraphicsApp* getAppInterface() @@ -530,13 +701,113 @@ public: } + btDiscreteDynamicsWorld* m_dynamicsWorld; + virtual void autogenerateGraphicsObjects(btDiscreteDynamicsWorld* rbWorld) { + m_dynamicsWorld = rbWorld; + m_cs->lock(); + m_cs->setSharedParam(1, eGUIHelperAutogenerateGraphicsObjects); + m_cs->unlock(); + while (m_cs->getSharedParam(1) != eGUIHelperIdle) + { + b3Clock::usleep(1000); + } } virtual void drawText3D( const char* txt, float posX, float posZY, float posZ, float size) { } + + + + + btAlignedObjectArray m_userDebugText; + + UserDebugText m_tmpText; + + virtual int addUserDebugText3D( const char* txt, const double positionXYZ[3], const double textColorRGB[3], double size, double lifeTime) + { + + m_tmpText.m_itemUniqueId = m_uidGenerator++; + m_tmpText.m_lifeTime = lifeTime; + m_tmpText.textSize = size; + int len = strlen(txt); + strcpy(m_tmpText.m_text,txt); + m_tmpText.m_textPositionXYZ[0] = positionXYZ[0]; + m_tmpText.m_textPositionXYZ[1] = positionXYZ[1]; + m_tmpText.m_textPositionXYZ[2] = positionXYZ[2]; + m_tmpText.m_textColorRGB[0] = textColorRGB[0]; + m_tmpText.m_textColorRGB[1] = textColorRGB[1]; + m_tmpText.m_textColorRGB[2] = textColorRGB[2]; + + m_cs->lock(); + m_cs->setSharedParam(1, eGUIUserDebugAddText); + m_cs->unlock(); + while (m_cs->getSharedParam(1) != eGUIHelperIdle) + { + b3Clock::usleep(150); + } + + return m_userDebugText[m_userDebugText.size()-1].m_itemUniqueId; + } + + btAlignedObjectArray m_userDebugLines; + UserDebugDrawLine m_tmpLine; + + virtual int addUserDebugLine(const double debugLineFromXYZ[3], const double debugLineToXYZ[3], const double debugLineColorRGB[3], double lineWidth, double lifeTime ) + { + m_tmpLine.m_lifeTime = lifeTime; + m_tmpLine.m_lineWidth = lineWidth; + m_tmpLine.m_itemUniqueId = m_uidGenerator++; + m_tmpLine.m_debugLineFromXYZ[0] = debugLineFromXYZ[0]; + m_tmpLine.m_debugLineFromXYZ[1] = debugLineFromXYZ[1]; + m_tmpLine.m_debugLineFromXYZ[2] = debugLineFromXYZ[2]; + + m_tmpLine.m_debugLineToXYZ[0] = debugLineToXYZ[0]; + m_tmpLine.m_debugLineToXYZ[1] = debugLineToXYZ[1]; + m_tmpLine.m_debugLineToXYZ[2] = debugLineToXYZ[2]; + + m_tmpLine.m_debugLineColorRGB[0] = debugLineColorRGB[0]; + m_tmpLine.m_debugLineColorRGB[1] = debugLineColorRGB[1]; + m_tmpLine.m_debugLineColorRGB[2] = debugLineColorRGB[2]; + + m_cs->lock(); + m_cs->setSharedParam(1, eGUIUserDebugAddLine); + m_cs->unlock(); + while (m_cs->getSharedParam(1) != eGUIHelperIdle) + { + b3Clock::usleep(150); + } + return m_userDebugLines[m_userDebugLines.size()-1].m_itemUniqueId; + } + + int m_removeDebugItemUid; + + virtual void removeUserDebugItem( int debugItemUniqueId) + { + m_removeDebugItemUid = debugItemUniqueId; + m_cs->lock(); + m_cs->setSharedParam(1, eGUIUserDebugRemoveItem); + m_cs->unlock(); + while (m_cs->getSharedParam(1) != eGUIHelperIdle) + { + b3Clock::usleep(150); + } + + } + virtual void removeAllUserDebugItems( ) + { + m_cs->lock(); + m_cs->setSharedParam(1, eGUIUserDebugRemoveAllItems); + m_cs->unlock(); + while (m_cs->getSharedParam(1) != eGUIHelperIdle) + { + b3Clock::usleep(150); + } + + } + }; @@ -548,7 +819,9 @@ class PhysicsServerExample : public SharedMemoryCommon MotionArgs m_args[MAX_MOTION_NUM_THREADS]; MultiThreadedOpenGLGuiHelper* m_multiThreadedHelper; bool m_wantsShutdown; - +#ifdef B3_USE_MIDI + RtMidiIn* m_midi; +#endif bool m_isConnected; btClock m_clock; bool m_replay; @@ -593,6 +866,7 @@ public: virtual bool wantsTermination(); virtual bool isConnected(); virtual void renderScene(); + void drawUserDebugLines(); virtual void exitPhysics(); virtual void physicsDebugDraw(int debugFlags); @@ -608,8 +882,8 @@ public: if (m_replay) return false; - CommonRenderInterface* renderer = m_guiHelper->getRenderInterface(); - + CommonRenderInterface* renderer = m_multiThreadedHelper->m_childGuiHelper->getRenderInterface();// m_guiHelper->getRenderInterface(); + if (!renderer) { return false; @@ -618,7 +892,14 @@ public: btVector3 rayTo = getRayTo(int(x), int(y)); btVector3 rayFrom; renderer->getActiveCamera()->getCameraPosition(rayFrom); - m_physicsServer.movePickedBody(rayFrom,rayTo); + + MyMouseCommand cmd; + cmd.m_rayFrom = rayFrom; + cmd.m_rayTo = rayTo; + cmd.m_type = MyMouseMove; + m_args[0].m_cs->lock(); + m_args[0].m_mouseCommands.push_back(cmd); + m_args[0].m_cs->unlock(); return false; }; @@ -647,7 +928,13 @@ public: btVector3 rayFrom = camPos; btVector3 rayTo = getRayTo(int(x),int(y)); - m_physicsServer.pickBody(rayFrom, rayTo); + MyMouseCommand cmd; + cmd.m_rayFrom = rayFrom; + cmd.m_rayTo = rayTo; + cmd.m_type = MyMouseButtonDown; + m_args[0].m_cs->lock(); + m_args[0].m_mouseCommands.push_back(cmd); + m_args[0].m_cs->unlock(); } @@ -655,7 +942,14 @@ public: { if (button==0) { - m_physicsServer.removePickingConstraint(); + //m_physicsServer.removePickingConstraint(); + MyMouseCommand cmd; + cmd.m_rayFrom.setValue(0,0,0); + cmd.m_rayTo.setValue(0, 0, 0); + cmd.m_type = MyMouseButtonUp; + m_args[0].m_cs->lock(); + m_args[0].m_mouseCommands.push_back(cmd); + m_args[0].m_cs->unlock(); //remove p2p } } @@ -673,6 +967,30 @@ public: virtual void processCommandLineArgs(int argc, char* argv[]) { b3CommandLineArgs args(argc,argv); + loadCurrentSettingsVR(args); + if (args.GetCmdLineArgument("camPosX", gVRTeleportPos1[0])) + { + printf("camPosX=%f\n", gVRTeleportPos1[0]); + } + + if (args.GetCmdLineArgument("camPosY", gVRTeleportPos1[1])) + { + printf("camPosY=%f\n", gVRTeleportPos1[1]); + } + + if (args.GetCmdLineArgument("camPosZ", gVRTeleportPos1[2])) + { + printf("camPosZ=%f\n", gVRTeleportPos1[2]); + } + + float camRotZ = 0.f; + if (args.GetCmdLineArgument("camRotZ", camRotZ)) + { + printf("camRotZ = %f\n", camRotZ); + btQuaternion ornZ(btVector3(0, 0, 1), camRotZ); + gVRTeleportOrn = ornZ; + } + if (args.CheckCmdLineFlag("robotassets")) { gCreateDefaultRobotAssets = true; @@ -688,6 +1006,40 @@ public: }; +#ifdef B3_USE_MIDI +static bool chooseMidiPort(RtMidiIn *rtmidi) +{ + /* + + std::cout << "\nWould you like to open a virtual input port? [y/N] "; + + std::string keyHit; + std::getline( std::cin, keyHit ); + if ( keyHit == "y" ) { + rtmidi->openVirtualPort(); + return true; + } + */ + + std::string portName; + unsigned int i = 0, nPorts = rtmidi->getPortCount(); + if (nPorts == 0) { + std::cout << "No midi input ports available!" << std::endl; + return false; + } + + if (nPorts > 0) { + std::cout << "\nOpening midi input port " << rtmidi->getPortName() << std::endl; + } + + // std::getline( std::cin, keyHit ); // used to clear out stdin + rtmidi->openPort(i); + + return true; +} +#endif //B3_USE_MIDI + + PhysicsServerExample::PhysicsServerExample(MultiThreadedOpenGLGuiHelper* helper, SharedMemoryInterface* sharedMem, int options) :SharedMemoryCommon(helper), m_physicsServer(sharedMem), @@ -699,6 +1051,14 @@ m_options(options) ,m_tinyVrGui(0) #endif { +#ifdef B3_USE_MIDI + m_midi = new RtMidiIn(); + chooseMidiPort(m_midi); + m_midi->setCallback(&midiCallback); + // Don't ignore sysex, timing, or active sensing messages. + m_midi->ignoreTypes(false, false, false); + +#endif m_multiThreadedHelper = helper; b3Printf("Started PhysicsServer\n"); } @@ -707,6 +1067,10 @@ m_options(options) PhysicsServerExample::~PhysicsServerExample() { +#ifdef B3_USE_MIDI + delete m_midi; + m_midi = 0; +#endif #ifdef BT_ENABLE_VR delete m_tinyVrGui; #endif @@ -916,10 +1280,76 @@ void PhysicsServerExample::stepSimulation(float deltaTime) m_multiThreadedHelper->getCriticalSection()->unlock(); break; } + case eGUIHelperAutogenerateGraphicsObjects: + { + m_multiThreadedHelper->m_childGuiHelper->autogenerateGraphicsObjects(m_multiThreadedHelper->m_dynamicsWorld); + m_multiThreadedHelper->getCriticalSection()->lock(); + m_multiThreadedHelper->getCriticalSection()->setSharedParam(1, eGUIHelperIdle); + m_multiThreadedHelper->getCriticalSection()->unlock(); + break; + } + + case eGUIUserDebugAddText: + { + m_multiThreadedHelper->m_userDebugText.push_back(m_multiThreadedHelper->m_tmpText); + m_multiThreadedHelper->getCriticalSection()->lock(); + m_multiThreadedHelper->getCriticalSection()->setSharedParam(1, eGUIHelperIdle); + m_multiThreadedHelper->getCriticalSection()->unlock(); + break; + } + case eGUIUserDebugAddLine: + { + m_multiThreadedHelper->m_userDebugLines.push_back(m_multiThreadedHelper->m_tmpLine); + m_multiThreadedHelper->getCriticalSection()->lock(); + m_multiThreadedHelper->getCriticalSection()->setSharedParam(1, eGUIHelperIdle); + m_multiThreadedHelper->getCriticalSection()->unlock(); + break; + } + case eGUIUserDebugRemoveItem: + { + for (int i=0;im_userDebugLines.size();i++) + { + if (m_multiThreadedHelper->m_userDebugLines[i].m_itemUniqueId == m_multiThreadedHelper->m_removeDebugItemUid) + { + m_multiThreadedHelper->m_userDebugLines.swap(i,m_multiThreadedHelper->m_userDebugLines.size()-1); + m_multiThreadedHelper->m_userDebugLines.pop_back(); + break; + } + } + + + for (int i=0;im_userDebugText.size();i++) + { + if (m_multiThreadedHelper->m_userDebugText[i].m_itemUniqueId == m_multiThreadedHelper->m_removeDebugItemUid) + { + m_multiThreadedHelper->m_userDebugText.swap(i,m_multiThreadedHelper->m_userDebugText.size()-1); + m_multiThreadedHelper->m_userDebugText.pop_back(); + break; + } + } + + m_multiThreadedHelper->getCriticalSection()->lock(); + m_multiThreadedHelper->getCriticalSection()->setSharedParam(1, eGUIHelperIdle); + m_multiThreadedHelper->getCriticalSection()->unlock(); + break; + } + case eGUIUserDebugRemoveAllItems: + { + m_multiThreadedHelper->m_userDebugLines.clear(); + m_multiThreadedHelper->m_userDebugText.clear(); + m_multiThreadedHelper->m_uidGenerator = 0; + m_multiThreadedHelper->getCriticalSection()->lock(); + m_multiThreadedHelper->getCriticalSection()->setSharedParam(1, eGUIHelperIdle); + m_multiThreadedHelper->getCriticalSection()->unlock(); + break; + } case eGUIHelperIdle: + { + break; + } default: { - + btAssert(0); } } @@ -961,13 +1391,72 @@ extern int gDroppedSimulationSteps; extern int gNumSteps; extern double gDtInSec; extern double gSubStep; +extern int gHuskyId; +extern btTransform huskyTr; +void PhysicsServerExample::drawUserDebugLines() +{ + static char line0[1024]; + static char line1[1024]; + + //draw all user-debug-lines + + //add array of lines + + //draw all user- 'text3d' messages + if (m_multiThreadedHelper) + { + + for (int i = 0; im_userDebugLines.size(); i++) + { + btVector3 from; + from.setValue(m_multiThreadedHelper->m_userDebugLines[i].m_debugLineFromXYZ[0], + m_multiThreadedHelper->m_userDebugLines[i].m_debugLineFromXYZ[1], + m_multiThreadedHelper->m_userDebugLines[i].m_debugLineFromXYZ[2]); + btVector3 toX; + toX.setValue(m_multiThreadedHelper->m_userDebugLines[i].m_debugLineToXYZ[0], + m_multiThreadedHelper->m_userDebugLines[i].m_debugLineToXYZ[1], + m_multiThreadedHelper->m_userDebugLines[i].m_debugLineToXYZ[2]); + + btVector3 color; + color.setValue(m_multiThreadedHelper->m_userDebugLines[i].m_debugLineColorRGB[0], + m_multiThreadedHelper->m_userDebugLines[i].m_debugLineColorRGB[1], + m_multiThreadedHelper->m_userDebugLines[i].m_debugLineColorRGB[2]); + + + m_guiHelper->getAppInterface()->m_renderer->drawLine(from, toX, color, m_multiThreadedHelper->m_userDebugLines[i].m_lineWidth); + } + + for (int i = 0; im_userDebugText.size(); i++) + { + m_guiHelper->getAppInterface()->drawText3D(m_multiThreadedHelper->m_userDebugText[i].m_text, + m_multiThreadedHelper->m_userDebugText[i].m_textPositionXYZ[0], + m_multiThreadedHelper->m_userDebugText[i].m_textPositionXYZ[1], + m_multiThreadedHelper->m_userDebugText[i].m_textPositionXYZ[2], + m_multiThreadedHelper->m_userDebugText[i].textSize); + + } + } + +} + void PhysicsServerExample::renderScene() { + +#if 0 + ///little VR test to follow/drive Husky vehicle + if (gHuskyId >= 0) + { + gVRTeleportPos1 = huskyTr.getOrigin(); + gVRTeleportOrn = huskyTr.getRotation(); + } +#endif + + B3_PROFILE("PhysicsServerExample::RenderScene"); - static char line0[1024]; - static char line1[1024]; + + drawUserDebugLines(); if (gEnableRealTimeSimVR) { @@ -981,6 +1470,7 @@ void PhysicsServerExample::renderScene() static int count = 0; count++; +#if 0 if (0 == (count & 1)) { btScalar curTime = m_clock.getTimeSeconds(); @@ -1001,6 +1491,7 @@ void PhysicsServerExample::renderScene() worseFps = 1000000; } } +#endif #ifdef BT_ENABLE_VR if ((gInternalSimFlags&2 ) && m_tinyVrGui==0) @@ -1025,7 +1516,9 @@ void PhysicsServerExample::renderScene() tr = tr*b3Transform(b3Quaternion(0,0,-SIMD_HALF_PI),b3MakeVector3(0,0,0)); b3Scalar dt = 0.01; m_tinyVrGui->clearTextArea(); - + static char line0[1024]; + static char line1[1024]; + m_tinyVrGui->grapicalPrintf(line0,0,0,0,0,0,255); m_tinyVrGui->grapicalPrintf(line1,0,16,255,255,255,255); @@ -1037,9 +1530,27 @@ void PhysicsServerExample::renderScene() //m_args[0].m_cs->lock(); //gVRTeleportPos[0] += 0.01; - vrOffset[12]=-gVRTeleportPos[0]; - vrOffset[13]=-gVRTeleportPos[1]; - vrOffset[14]=-gVRTeleportPos[2]; + btTransform tr2a, tr2; + tr2a.setIdentity(); + tr2.setIdentity(); + tr2.setOrigin(gVRTeleportPos1); + tr2a.setRotation(gVRTeleportOrn); + btTransform trTotal = tr2*tr2a; + btTransform trInv = trTotal.inverse(); + + btMatrix3x3 vrOffsetRot; + vrOffsetRot.setRotation(trInv.getRotation()); + for (int i = 0; i < 3; i++) + { + for (int j = 0; j < 3; j++) + { + vrOffset[i + 4 * j] = vrOffsetRot[i][j]; + } + } + + vrOffset[12]= trInv.getOrigin()[0]; + vrOffset[13]= trInv.getOrigin()[1]; + vrOffset[14]= trInv.getOrigin()[2]; this->m_multiThreadedHelper->m_childGuiHelper->getRenderInterface()-> getActiveCamera()->setVRCameraOffsetTransform(vrOffset); @@ -1073,62 +1584,22 @@ void PhysicsServerExample::renderScene() if (m_guiHelper->getAppInterface()->m_renderer->getActiveCamera()->isVRCamera()) { - gEnableRealTimeSimVR = true; - } - - if (gDebugRenderToggle) - if (m_guiHelper->getAppInterface()->m_renderer->getActiveCamera()->isVRCamera()) - { - - B3_PROFILE("Draw Debug HUD"); - //some little experiment to add text/HUD to a VR camera (HTC Vive/Oculus Rift) - - - float pos[4]; - m_guiHelper->getAppInterface()->m_renderer->getActiveCamera()->getCameraTargetPosition(pos); - pos[0]+=gVRTeleportPos[0]; - pos[1]+=gVRTeleportPos[1]; - pos[2]+=gVRTeleportPos[2]; - - btTransform viewTr; - btScalar m[16]; - float mf[16]; - m_guiHelper->getAppInterface()->m_renderer->getActiveCamera()->getCameraViewMatrix(mf); - for (int i=0;i<16;i++) + if (!gEnableRealTimeSimVR) { - m[i] = mf[i]; + gEnableRealTimeSimVR = true; + m_physicsServer.enableRealTimeSimulation(1); } - m[12]=+gVRTeleportPos[0]; - m[13]=+gVRTeleportPos[1]; - m[14]=+gVRTeleportPos[2]; - viewTr.setFromOpenGLMatrix(m); - btTransform viewTrInv = viewTr.inverse(); - - btVector3 side = viewTrInv.getBasis().getColumn(0); - btVector3 up = viewTrInv.getBasis().getColumn(1); - btVector3 fwd = viewTrInv.getBasis().getColumn(2); - - - float upMag = 0; - float sideMag = 2.2; - float fwdMag = -4; - - m_guiHelper->getAppInterface()->drawText3D(line0,pos[0]+upMag*up[0]-sideMag*side[0]+fwdMag*fwd[0],pos[1]+upMag*up[1]-sideMag*side[1]+fwdMag*fwd[1],pos[2]+upMag*up[2]-sideMag*side[2]+fwdMag*fwd[2],1); - //btVector3 fwd = viewTrInv.getBasis().getColumn(2); - - up = viewTrInv.getBasis().getColumn(1); - upMag = -0.3; - - - - m_guiHelper->getAppInterface()->drawText3D(line1,pos[0]+upMag*up[0]-sideMag*side[0]+fwdMag*fwd[0],pos[1]+upMag*up[1]-sideMag*side[1]+fwdMag*fwd[1],pos[2]+upMag*up[2]-sideMag*side[2]+fwdMag*fwd[2],1); } + + //m_args[0].m_cs->unlock(); } void PhysicsServerExample::physicsDebugDraw(int debugDrawFlags) { + drawUserDebugLines(); + ///debug rendering m_physicsServer.physicsDebugDraw(debugDrawFlags); @@ -1238,13 +1709,16 @@ void PhysicsServerExample::vrControllerButtonCallback(int controllerId, int butt return; if (gGraspingController < 0) + { gGraspingController = controllerId; - + gEnableKukaControl = true; + } if (controllerId != gGraspingController) { if (button == 1 && state == 0) { - gVRTeleportPos = gLastPickPos; + gResetSimulation = true; + //gVRTeleportPos1 = gLastPickPos; } } else { @@ -1256,7 +1730,7 @@ void PhysicsServerExample::vrControllerButtonCallback(int controllerId, int butt } else { gDebugRenderToggle = 0; - +#if 0//it confuses people, make it into a debug option in a VR GUI? if (simTimeScalingFactor==0) { simTimeScalingFactor = 1; @@ -1271,15 +1745,26 @@ void PhysicsServerExample::vrControllerButtonCallback(int controllerId, int butt simTimeScalingFactor = 0; } } +#endif } } else { } } + + if (button==32 && state==0) { - gCreateObjectSimVR = 1; + + if (controllerId == gGraspingController) + { + gCreateObjectSimVR = 1; + } + else + { +// gEnableKukaControl = !gEnableKukaControl; + } } @@ -1300,42 +1785,87 @@ void PhysicsServerExample::vrControllerButtonCallback(int controllerId, int butt m_args[0].m_isVrControllerPicking[controllerId] = (state != 0); m_args[0].m_isVrControllerReleasing[controllerId] = (state == 0); } + + btTransform trLocal; + trLocal.setIdentity(); + trLocal.setRotation(btQuaternion(btVector3(0, 0, 1), SIMD_HALF_PI)*btQuaternion(btVector3(0, 1, 0), SIMD_HALF_PI)); + + btTransform trOrg; + trOrg.setIdentity(); + trOrg.setOrigin(btVector3(pos[0], pos[1], pos[2])); + trOrg.setRotation(btQuaternion(orn[0], orn[1], orn[2], orn[3])); + + btTransform tr2a; + tr2a.setIdentity(); + btTransform tr2; + tr2.setIdentity(); + + + + tr2.setOrigin(gVRTeleportPos1); + tr2a.setRotation(gVRTeleportOrn); + + + btTransform trTotal = tr2*tr2a*trOrg*trLocal; + if ((button == 33) || (button == 1)) { - m_args[0].m_vrControllerPos[controllerId].setValue(pos[0] + gVRTeleportPos[0], pos[1] + gVRTeleportPos[1], pos[2] + gVRTeleportPos[2]); - m_args[0].m_vrControllerOrn[controllerId].setValue(orn[0], orn[1], orn[2], orn[3]); +// m_args[0].m_vrControllerPos[controllerId].setValue(pos[0] + gVRTeleportPos[0], pos[1] + gVRTeleportPos[1], pos[2] + gVRTeleportPos[2]); + // m_args[0].m_vrControllerOrn[controllerId].setValue(orn[0], orn[1], orn[2], orn[3]); + m_args[0].m_vrControllerPos[controllerId] = trTotal.getOrigin(); + m_args[0].m_vrControllerOrn[controllerId] = trTotal.getRotation(); } + } } - void PhysicsServerExample::vrControllerMoveCallback(int controllerId, float pos[4], float orn[4], float analogAxis) { - gEnableRealTimeSimVR = true; - if (controllerId <= 0 || controllerId >= MAX_VR_CONTROLLERS) { printf("Controller Id exceeds max: %d > %d", controllerId, MAX_VR_CONTROLLERS); return; } + + btTransform trLocal; + trLocal.setIdentity(); + trLocal.setRotation(btQuaternion(btVector3(0, 0, 1), SIMD_HALF_PI)*btQuaternion(btVector3(0, 1, 0), SIMD_HALF_PI)); + + btTransform trOrg; + trOrg.setIdentity(); + trOrg.setOrigin(btVector3(pos[0], pos[1], pos[2])); + trOrg.setRotation(btQuaternion(orn[0], orn[1], orn[2], orn[3])); + + btTransform tr2a; + tr2a.setIdentity(); + btTransform tr2; + tr2.setIdentity(); + + + + tr2.setOrigin(gVRTeleportPos1); + tr2a.setRotation(gVRTeleportOrn); + + + btTransform trTotal = tr2*tr2a*trOrg*trLocal; + if (controllerId == gGraspingController) { gVRGripperAnalog = analogAxis; - gVRGripperPos.setValue(pos[0] + gVRTeleportPos[0], pos[1] + gVRTeleportPos[1], pos[2] + gVRTeleportPos[2]); - btQuaternion orgOrn(orn[0], orn[1], orn[2], orn[3]); - gVRGripperOrn = orgOrn*btQuaternion(btVector3(0, 0, 1), SIMD_HALF_PI)*btQuaternion(btVector3(0, 1, 0), SIMD_HALF_PI); + + gVRGripperPos = trTotal.getOrigin(); + gVRGripperOrn = trTotal.getRotation(); } else { gVRGripper2Analog = analogAxis; - gVRController2Pos.setValue(pos[0] + gVRTeleportPos[0], pos[1] + gVRTeleportPos[1], pos[2] + gVRTeleportPos[2]); - btQuaternion orgOrn(orn[0], orn[1], orn[2], orn[3]); - gVRController2Orn = orgOrn*btQuaternion(btVector3(0, 0, 1), SIMD_HALF_PI)*btQuaternion(btVector3(0, 1, 0), SIMD_HALF_PI); + gVRController2Pos = trTotal.getOrigin(); + gVRController2Orn = trTotal.getRotation(); - m_args[0].m_vrControllerPos[controllerId].setValue(pos[0] + gVRTeleportPos[0], pos[1] + gVRTeleportPos[1], pos[2] + gVRTeleportPos[2]); - m_args[0].m_vrControllerOrn[controllerId].setValue(orn[0], orn[1], orn[2], orn[3]); + m_args[0].m_vrControllerPos[controllerId] = trTotal.getOrigin(); + m_args[0].m_vrControllerOrn[controllerId] = trTotal.getRotation(); } } diff --git a/examples/SharedMemory/PhysicsServerSharedMemory.cpp b/examples/SharedMemory/PhysicsServerSharedMemory.cpp index 111ac07f5..158bdac6b 100644 --- a/examples/SharedMemory/PhysicsServerSharedMemory.cpp +++ b/examples/SharedMemory/PhysicsServerSharedMemory.cpp @@ -241,6 +241,12 @@ void PhysicsServerSharedMemory::stepSimulationRealTime(double dtInSec) m_data->m_commandProcessor->stepSimulationRealTime(dtInSec); } +void PhysicsServerSharedMemory::enableRealTimeSimulation(bool enableRealTimeSim) +{ + m_data->m_commandProcessor->enableRealTimeSimulation(enableRealTimeSim); +} + + void PhysicsServerSharedMemory::processClientCommands() { diff --git a/examples/SharedMemory/PhysicsServerSharedMemory.h b/examples/SharedMemory/PhysicsServerSharedMemory.h index f96e7ca4b..f29e844f2 100644 --- a/examples/SharedMemory/PhysicsServerSharedMemory.h +++ b/examples/SharedMemory/PhysicsServerSharedMemory.h @@ -28,9 +28,11 @@ public: virtual void stepSimulationRealTime(double dtInSec); + virtual void enableRealTimeSimulation(bool enableRealTimeSim); + //bool supportsJointMotor(class btMultiBody* body, int linkIndex); - //@todo(erwincoumans) Should we have shared memory commands for picking objects? + ///The pickBody method will try to pick the first body along a ray, return true if succeeds, false otherwise virtual bool pickBody(const btVector3& rayFromWorld, const btVector3& rayToWorld); virtual bool movePickedBody(const btVector3& rayFromWorld, const btVector3& rayToWorld); diff --git a/examples/SharedMemory/SharedMemoryCommandProcessor.cpp b/examples/SharedMemory/SharedMemoryCommandProcessor.cpp new file mode 100644 index 000000000..406b9ae4f --- /dev/null +++ b/examples/SharedMemory/SharedMemoryCommandProcessor.cpp @@ -0,0 +1,216 @@ +#include "SharedMemoryCommandProcessor.h" + +#include "PosixSharedMemory.h" +#include "Win32SharedMemory.h" +#include "Bullet3Common/b3Logging.h" +#include "Bullet3Common/b3Scalar.h" + +#include "SharedMemoryBlock.h" + + +struct SharedMemoryCommandProcessorInternalData +{ + int m_sharedMemoryKey; + bool m_isConnected; + SharedMemoryInterface* m_sharedMemory; + bool m_ownsSharedMemory; + bool m_verboseOutput; + bool m_waitingForServer; + SharedMemoryStatus m_lastServerStatus; + SharedMemoryBlock* m_testBlock1; + + + SharedMemoryCommandProcessorInternalData() + :m_sharedMemoryKey(SHARED_MEMORY_KEY), + m_isConnected(false), + m_sharedMemory(0), + m_ownsSharedMemory(false), + m_verboseOutput(false), + m_waitingForServer(false), + m_testBlock1(0) + { + + } +}; + +SharedMemoryCommandProcessor::SharedMemoryCommandProcessor() +{ + m_data = new SharedMemoryCommandProcessorInternalData; + m_data->m_sharedMemoryKey = SHARED_MEMORY_KEY; +#ifdef _WIN32 + m_data->m_sharedMemory = new Win32SharedMemoryClient(); +#else + m_data->m_sharedMemory = new PosixSharedMemory(); +#endif + m_data->m_ownsSharedMemory = true; + + +} + +SharedMemoryCommandProcessor::~SharedMemoryCommandProcessor() +{ + if (m_data->m_isConnected) + { + disconnect(); + } + if (m_data->m_ownsSharedMemory) + { + delete m_data->m_sharedMemory; + } + delete m_data; + +} + +bool SharedMemoryCommandProcessor::connect() +{ + + if (m_data->m_isConnected) + return true; + + bool allowCreation = false; + m_data->m_testBlock1 = (SharedMemoryBlock*)m_data->m_sharedMemory->allocateSharedMemory( + m_data->m_sharedMemoryKey, SHARED_MEMORY_SIZE, allowCreation); + + if (m_data->m_testBlock1) { + if (m_data->m_testBlock1->m_magicId != SHARED_MEMORY_MAGIC_NUMBER) { + b3Error("Error: please start server before client\n"); + m_data->m_sharedMemory->releaseSharedMemory(m_data->m_sharedMemoryKey, + SHARED_MEMORY_SIZE); + m_data->m_testBlock1 = 0; + return false; + } + else { + if (m_data->m_verboseOutput) { + b3Printf("Connected to existing shared memory, status OK.\n"); + } + m_data->m_isConnected = true; + } + } + else { + b3Error("Cannot connect to shared memory"); + return false; + } + return true; + +} + +void SharedMemoryCommandProcessor::disconnect() +{ + if (m_data->m_isConnected && m_data->m_sharedMemory) + { + m_data->m_sharedMemory->releaseSharedMemory(m_data->m_sharedMemoryKey, SHARED_MEMORY_SIZE); + } + m_data->m_isConnected = false; + +} + +bool SharedMemoryCommandProcessor::isConnected() const +{ + return m_data->m_isConnected; +} + + +bool SharedMemoryCommandProcessor::processCommand(const struct SharedMemoryCommand& clientCmd, struct SharedMemoryStatus& serverStatusOut, char* bufferServerToClient, int bufferSizeInBytes) +{ + if (!m_data->m_waitingForServer) { + if (&m_data->m_testBlock1->m_clientCommands[0] != &clientCmd) { + m_data->m_testBlock1->m_clientCommands[0] = clientCmd; + } + m_data->m_testBlock1->m_numClientCommands++; + m_data->m_waitingForServer = true; + } + + return false; +} + +bool SharedMemoryCommandProcessor::receiveStatus(struct SharedMemoryStatus& serverStatusOut, char* bufferServerToClient, int bufferSizeInBytes) +{ + SharedMemoryStatus* stat = 0; + + m_data->m_lastServerStatus.m_dataStream = 0; + m_data->m_lastServerStatus.m_numDataStreamBytes = 0; + + if (!m_data->m_testBlock1) + { + //m_data->m_lastServerStatus.m_type = CMD_SHARED_MEMORY_NOT_INITIALIZED; + //return &m_data->m_lastServerStatus; + //serverStatusOut = m_data->m_lastServerStatus; + return false; + } + + if (!m_data->m_waitingForServer) { + return false; + } + + if (m_data->m_testBlock1->m_magicId != SHARED_MEMORY_MAGIC_NUMBER) + { + //m_data->m_lastServerStatus.m_type = CMD_SHARED_MEMORY_NOT_INITIALIZED; + //return &m_data->m_lastServerStatus; + return false; + } + + if (m_data->m_testBlock1->m_numServerCommands > + m_data->m_testBlock1->m_numProcessedServerCommands) + { + b3Assert(m_data->m_testBlock1->m_numServerCommands == + m_data->m_testBlock1->m_numProcessedServerCommands + 1); + + const SharedMemoryStatus& serverCmd = m_data->m_testBlock1->m_serverCommands[0]; + m_data->m_lastServerStatus = serverCmd; + m_data->m_lastServerStatus.m_dataStream = m_data->m_testBlock1->m_bulletStreamDataServerToClientRefactor; + + for (int i = 0; i < m_data->m_lastServerStatus.m_numDataStreamBytes; i++) + { + bufferServerToClient[i] = m_data->m_testBlock1->m_bulletStreamDataServerToClientRefactor[i]; + } + + m_data->m_testBlock1->m_numProcessedServerCommands++; + // we don't have more than 1 command outstanding (in total, either server or client) + b3Assert(m_data->m_testBlock1->m_numProcessedServerCommands == + m_data->m_testBlock1->m_numServerCommands); + + if (m_data->m_testBlock1->m_numServerCommands == + m_data->m_testBlock1->m_numProcessedServerCommands) { + m_data->m_waitingForServer = false; + } + else { + m_data->m_waitingForServer = true; + } + + serverStatusOut = m_data->m_lastServerStatus; + + return true; + } + return false; +} + +void SharedMemoryCommandProcessor::renderScene() +{ +} + +void SharedMemoryCommandProcessor::physicsDebugDraw(int debugDrawFlags) +{ +} + +void SharedMemoryCommandProcessor::setGuiHelper(struct GUIHelperInterface* guiHelper) +{ +} + +void SharedMemoryCommandProcessor::setSharedMemoryInterface(class SharedMemoryInterface* sharedMem) +{ + if (m_data->m_sharedMemory && m_data->m_ownsSharedMemory) + { + delete m_data->m_sharedMemory; + } + m_data->m_ownsSharedMemory = false; + m_data->m_sharedMemory = sharedMem; + +} + + +void SharedMemoryCommandProcessor::setSharedMemoryKey(int key) +{ + m_data->m_sharedMemoryKey = key; +} + + diff --git a/examples/SharedMemory/SharedMemoryCommandProcessor.h b/examples/SharedMemory/SharedMemoryCommandProcessor.h new file mode 100644 index 000000000..bec9e614f --- /dev/null +++ b/examples/SharedMemory/SharedMemoryCommandProcessor.h @@ -0,0 +1,37 @@ +#ifndef SHARED_MEMORY_COMMAND_PROCESSOR_H +#define SHARED_MEMORY_COMMAND_PROCESSOR_H + +#include "PhysicsCommandProcessorInterface.h" + +class SharedMemoryCommandProcessor : public PhysicsCommandProcessorInterface +{ + + struct SharedMemoryCommandProcessorInternalData* m_data; + +public: + SharedMemoryCommandProcessor(); + + virtual ~SharedMemoryCommandProcessor(); + + virtual bool connect(); + + virtual void disconnect(); + + virtual bool isConnected() const; + + virtual bool processCommand(const struct SharedMemoryCommand& clientCmd, struct SharedMemoryStatus& serverStatusOut, char* bufferServerToClient, int bufferSizeInBytes); + + virtual bool receiveStatus(struct SharedMemoryStatus& serverStatusOut, char* bufferServerToClient, int bufferSizeInBytes); + + virtual void renderScene(); + virtual void physicsDebugDraw(int debugDrawFlags); + virtual void setGuiHelper(struct GUIHelperInterface* guiHelper); + + void setSharedMemoryInterface(class SharedMemoryInterface* sharedMem); + void setSharedMemoryKey(int key); + + +}; + +#endif //SHARED_MEMORY_COMMAND_PROCESSOR_H + diff --git a/examples/SharedMemory/SharedMemoryCommands.h b/examples/SharedMemory/SharedMemoryCommands.h index 8a34189be..d905ca980 100644 --- a/examples/SharedMemory/SharedMemoryCommands.h +++ b/examples/SharedMemory/SharedMemoryCommands.h @@ -24,7 +24,7 @@ typedef unsigned long long int smUint64_t; #endif -#define SHARED_MEMORY_MAX_STREAM_CHUNK_SIZE (256*1024) +#define SHARED_MEMORY_MAX_STREAM_CHUNK_SIZE (512*1024) #define SHARED_MEMORY_SERVER_TEST_C #define MAX_DEGREE_OF_FREEDOM 128 @@ -67,6 +67,11 @@ struct SdfArgs int m_useMultiBody; }; +struct FileArgs +{ + char m_fileName[MAX_URDF_FILENAME_LENGTH]; +}; + enum EnumUrdfArgsUpdateFlags { URDF_ARGS_FILE_NAME=1, @@ -90,7 +95,6 @@ struct UrdfArgs struct BulletDataStreamArgs { char m_bulletFileName[MAX_FILENAME_LENGTH]; - int m_streamChunkLength; int m_bodyUniqueId; }; @@ -105,7 +109,9 @@ enum EnumInitPoseFlags { INIT_POSE_HAS_INITIAL_POSITION=1, INIT_POSE_HAS_INITIAL_ORIENTATION=2, - INIT_POSE_HAS_JOINT_STATE=4 + INIT_POSE_HAS_JOINT_STATE=4, + INIT_POSE_HAS_BASE_LINEAR_VELOCITY = 8, + INIT_POSE_HAS_BASE_ANGULAR_VELOCITY = 16, }; @@ -118,6 +124,8 @@ struct InitPoseArgs int m_bodyUniqueId; int m_hasInitialStateQ[MAX_DEGREE_OF_FREEDOM]; double m_initialStateQ[MAX_DEGREE_OF_FREEDOM]; + int m_hasInitialStateQdot[MAX_DEGREE_OF_FREEDOM]; + double m_initialStateQdot[MAX_DEGREE_OF_FREEDOM]; }; @@ -134,21 +142,54 @@ struct RequestPixelDataArgs int m_startPixelIndex; int m_pixelWidth; int m_pixelHeight; + float m_lightDirection[3]; + float m_lightColor[3]; + float m_lightDistance; + float m_lightAmbientCoeff; + float m_lightDiffuseCoeff; + float m_lightSpecularCoeff; + int m_hasShadow; }; enum EnumRequestPixelDataUpdateFlags { REQUEST_PIXEL_ARGS_HAS_CAMERA_MATRICES=1, - REQUEST_PIXEL_ARGS_SET_PIXEL_WIDTH_HEIGHT=4, + REQUEST_PIXEL_ARGS_SET_PIXEL_WIDTH_HEIGHT=2, + REQUEST_PIXEL_ARGS_SET_LIGHT_DIRECTION=4, + REQUEST_PIXEL_ARGS_SET_LIGHT_COLOR=8, + REQUEST_PIXEL_ARGS_SET_LIGHT_DISTANCE=16, + REQUEST_PIXEL_ARGS_SET_SHADOW=32, + REQUEST_PIXEL_ARGS_SET_AMBIENT_COEFF=64, + REQUEST_PIXEL_ARGS_SET_DIFFUSE_COEFF=128, + REQUEST_PIXEL_ARGS_SET_SPECULAR_COEFF=256, //don't exceed (1<<15), because this enum is shared with EnumRenderer in SharedMemoryPublic.h }; +enum EnumRequestContactDataUpdateFlags +{ + CMD_REQUEST_CONTACT_POINT_HAS_QUERY_MODE=1, + CMD_REQUEST_CONTACT_POINT_HAS_CLOSEST_DISTANCE_THRESHOLD=2, + CMD_REQUEST_CONTACT_POINT_HAS_LINK_INDEX_A_FILTER = 4, + CMD_REQUEST_CONTACT_POINT_HAS_LINK_INDEX_B_FILTER = 8, +}; + struct RequestContactDataArgs { int m_startingContactPointIndex; int m_objectAIndexFilter; int m_objectBIndexFilter; + int m_linkIndexAIndexFilter; + int m_linkIndexBIndexFilter; + double m_closestDistanceThreshold; + int m_mode; +}; + +struct RequestOverlappingObjectsArgs +{ + int m_startingOverlappingObjectIndex; + double m_aabbQueryMin[3]; + double m_aabbQueryMax[3]; }; struct RequestVisualShapeDataArgs @@ -252,7 +293,16 @@ enum EnumSimParamUpdateFlags SIM_PARAM_UPDATE_NUM_SIMULATION_SUB_STEPS=8, SIM_PARAM_UPDATE_REAL_TIME_SIMULATION = 16, SIM_PARAM_UPDATE_DEFAULT_CONTACT_ERP=32, - SIM_PARAM_UPDATE_INTERNAL_SIMULATION_FLAGS=64 + SIM_PARAM_UPDATE_INTERNAL_SIMULATION_FLAGS=64, + SIM_PARAM_UPDATE_USE_SPLIT_IMPULSE=128, + SIM_PARAM_UPDATE_SPLIT_IMPULSE_PENETRATION_THRESHOLD = 256, +}; + +enum EnumLoadBunnyUpdateFlags +{ + LOAD_BUNNY_UPDATE_SCALE=1, + LOAD_BUNNY_UPDATE_MASS=2, + LOAD_BUNNY_UPDATE_COLLISION_MARGIN=4 }; enum EnumSimParamInternalSimFlags @@ -270,10 +320,19 @@ struct SendPhysicsSimulationParameters int m_numSimulationSubSteps; int m_numSolverIterations; bool m_allowRealTimeSimulation; + int m_useSplitImpulse; + double m_splitImpulsePenetrationThreshold; int m_internalSimFlags; double m_defaultContactERP; }; +struct LoadBunnyArgs +{ + double m_scale; + double m_mass; + double m_collisionMargin; +}; + struct RequestActualStateArgs { int m_bodyUniqueId; @@ -455,7 +514,14 @@ struct CalculateInverseKinematicsResultArgs double m_jointPositions[MAX_DEGREE_OF_FREEDOM]; }; -struct CreateJointArgs +enum EnumUserConstraintFlags +{ + USER_CONSTRAINT_ADD_CONSTRAINT=1, + USER_CONSTRAINT_REMOVE_CONSTRAINT=2, + USER_CONSTRAINT_CHANGE_CONSTRAINT=4 +}; + +struct UserConstraintArgs { int m_parentBodyIndex; int m_parentJointIndex; @@ -465,8 +531,53 @@ struct CreateJointArgs double m_childFrame[7]; double m_jointAxis[3]; int m_jointType; + int m_userConstraintUniqueId; }; +struct UserConstraintResultArgs +{ + int m_userConstraintUniqueId; +}; + +enum EnumUserDebugDrawFlags +{ + USER_DEBUG_HAS_LINE=1, + USER_DEBUG_HAS_TEXT=2, + USER_DEBUG_REMOVE_ONE_ITEM=4, + USER_DEBUG_REMOVE_ALL=8, + USER_DEBUG_SET_CUSTOM_OBJECT_COLOR = 16, + USER_DEBUG_REMOVE_CUSTOM_OBJECT_COLOR = 32, + +}; + +struct UserDebugDrawArgs +{ + double m_debugLineFromXYZ[3]; + double m_debugLineToXYZ[3]; + double m_debugLineColorRGB[3]; + double m_lineWidth; + + double m_lifeTime; + int m_removeItemUniqueId; + + char m_text[MAX_FILENAME_LENGTH]; + double m_textPositionXYZ[3]; + double m_textColorRGB[3]; + double m_textSize; + + double m_objectDebugColorRGB[3]; + int m_objectUniqueId; + int m_linkIndex; +}; + + + +struct UserDebugDrawResultArgs +{ + int m_debugItemUniqueId; +}; + + struct SharedMemoryCommand { int m_type; @@ -481,6 +592,7 @@ struct SharedMemoryCommand { struct UrdfArgs m_urdfArguments; struct SdfArgs m_sdfArguments; + struct FileArgs m_fileArguments; struct SdfRequestInfoArgs m_sdfRequestInfoArgs; struct InitPoseArgs m_initPoseArgs; struct SendPhysicsSimulationParameters m_physSimParamArgs; @@ -495,12 +607,15 @@ struct SharedMemoryCommand struct ExternalForceArgs m_externalForceArguments; struct CalculateInverseDynamicsArgs m_calculateInverseDynamicsArguments; struct CalculateJacobianArgs m_calculateJacobianArguments; - struct CreateJointArgs m_createJointArguments; + struct UserConstraintArgs m_userConstraintArguments; struct RequestContactDataArgs m_requestContactPointArguments; + struct RequestOverlappingObjectsArgs m_requestOverlappingObjectsArgs; struct RequestVisualShapeDataArgs m_requestVisualShapeDataArguments; struct UpdateVisualShapeDataArgs m_updateVisualShapeDataArguments; struct LoadTextureArgs m_loadTextureArguments; struct CalculateInverseKinematicsArgs m_calculateInverseKinematicsArguments; + struct UserDebugDrawArgs m_userDebugDrawArgs; + struct LoadBunnyArgs m_loadBunnyArguments; }; }; @@ -516,6 +631,13 @@ struct SendContactDataArgs int m_numRemainingContactPoints; }; +struct SendOverlappingObjectsArgs +{ + int m_startingOverlappingObjectIndex; + int m_numOverlappingObjectsCopied; + int m_numRemainingOverlappingObjects; +}; + struct SharedMemoryStatus { int m_type; @@ -523,6 +645,10 @@ struct SharedMemoryStatus smUint64_t m_timeStamp; int m_sequenceNumber; + //m_streamBytes is only for internal purposes + int m_numDataStreamBytes; + char* m_dataStream; + union { struct BulletDataStreamArgs m_dataStreamArguments; @@ -534,8 +660,11 @@ struct SharedMemoryStatus struct CalculateInverseDynamicsResultArgs m_inverseDynamicsResultArgs; struct CalculateJacobianResultArgs m_jacobianResultArgs; struct SendContactDataArgs m_sendContactPointArgs; + struct SendOverlappingObjectsArgs m_sendOverlappingObjectsArgs; struct CalculateInverseKinematicsResultArgs m_inverseKinematicsResultArgs; struct SendVisualShapeDataArgs m_sendVisualShapeArgs; + struct UserDebugDrawResultArgs m_userDebugDrawArgs; + struct UserConstraintResultArgs m_userConstraintResultArgs; }; }; diff --git a/examples/SharedMemory/SharedMemoryPublic.h b/examples/SharedMemory/SharedMemoryPublic.h index b435a38a5..fe79d9dcb 100644 --- a/examples/SharedMemory/SharedMemoryPublic.h +++ b/examples/SharedMemory/SharedMemoryPublic.h @@ -7,20 +7,22 @@ enum EnumSharedMemoryClientCommand { CMD_LOAD_SDF, CMD_LOAD_URDF, + CMD_LOAD_BULLET, + CMD_SAVE_BULLET, + CMD_LOAD_MJCF, CMD_LOAD_BUNNY, - CMD_SEND_BULLET_DATA_STREAM, - CMD_CREATE_BOX_COLLISION_SHAPE, -// CMD_DELETE_BOX_COLLISION_SHAPE, - CMD_CREATE_RIGID_BODY, - CMD_DELETE_RIGID_BODY, - CMD_CREATE_SENSOR,///enable or disable joint feedback for force/torque sensors -// CMD_REQUEST_SENSOR_MEASUREMENTS,//see CMD_REQUEST_ACTUAL_STATE/CMD_ACTUAL_STATE_UPDATE_COMPLETED - CMD_INIT_POSE, - CMD_SEND_PHYSICS_SIMULATION_PARAMETERS, - CMD_SEND_DESIRED_STATE,//todo: reconsider naming, for example SET_JOINT_CONTROL_VARIABLE? - CMD_REQUEST_ACTUAL_STATE, - CMD_REQUEST_DEBUG_LINES, + CMD_SEND_BULLET_DATA_STREAM, + CMD_CREATE_BOX_COLLISION_SHAPE, + CMD_CREATE_RIGID_BODY, + CMD_DELETE_RIGID_BODY, + CMD_CREATE_SENSOR,///enable or disable joint feedback for force/torque sensors + CMD_INIT_POSE, + CMD_SEND_PHYSICS_SIMULATION_PARAMETERS, + CMD_SEND_DESIRED_STATE,//todo: reconsider naming, for example SET_JOINT_CONTROL_VARIABLE? + CMD_REQUEST_ACTUAL_STATE, + CMD_REQUEST_DEBUG_LINES, CMD_REQUEST_BODY_INFO, + CMD_REQUEST_INTERNAL_DATA, CMD_STEP_FORWARD_SIMULATION, CMD_RESET_SIMULATION, CMD_PICK_BODY, @@ -31,12 +33,16 @@ enum EnumSharedMemoryClientCommand CMD_CALCULATE_INVERSE_DYNAMICS, CMD_CALCULATE_INVERSE_KINEMATICS, CMD_CALCULATE_JACOBIAN, - CMD_CREATE_JOINT, + CMD_USER_CONSTRAINT, CMD_REQUEST_CONTACT_POINT_INFORMATION, + CMD_REQUEST_AABB_OVERLAP, CMD_SAVE_WORLD, CMD_REQUEST_VISUAL_SHAPE_INFO, CMD_UPDATE_VISUAL_SHAPE, CMD_LOAD_TEXTURE, + CMD_SET_SHADOW, + CMD_USER_DEBUG_DRAW, + //don't go beyond this command! CMD_MAX_CLIENT_COMMANDS, @@ -54,6 +60,14 @@ enum EnumSharedMemoryServerStatus CMD_SDF_LOADING_FAILED, CMD_URDF_LOADING_COMPLETED, CMD_URDF_LOADING_FAILED, + CMD_BULLET_LOADING_COMPLETED, + CMD_BULLET_LOADING_FAILED, + CMD_BULLET_SAVING_COMPLETED, + CMD_BULLET_SAVING_FAILED, + CMD_MJCF_LOADING_COMPLETED, + CMD_MJCF_LOADING_FAILED, + CMD_REQUEST_INTERNAL_DATA_COMPLETED, + CMD_REQUEST_INTERNAL_DATA_FAILED, CMD_BULLET_DATA_STREAM_RECEIVED_COMPLETED, CMD_BULLET_DATA_STREAM_RECEIVED_FAILED, CMD_BOX_COLLISION_SHAPE_CREATION_COMPLETED, @@ -77,6 +91,8 @@ enum EnumSharedMemoryServerStatus CMD_CALCULATED_JACOBIAN_FAILED, CMD_CONTACT_POINT_INFORMATION_COMPLETED, CMD_CONTACT_POINT_INFORMATION_FAILED, + CMD_REQUEST_AABB_OVERLAP_COMPLETED, + CMD_REQUEST_AABB_OVERLAP_FAILED, CMD_CALCULATE_INVERSE_KINEMATICS_COMPLETED, CMD_CALCULATE_INVERSE_KINEMATICS_FAILED, CMD_SAVE_WORLD_COMPLETED, @@ -87,6 +103,10 @@ enum EnumSharedMemoryServerStatus CMD_VISUAL_SHAPE_UPDATE_FAILED, CMD_LOAD_TEXTURE_COMPLETED, CMD_LOAD_TEXTURE_FAILED, + CMD_USER_DEBUG_DRAW_COMPLETED, + CMD_USER_DEBUG_DRAW_FAILED, + CMD_USER_CONSTRAINT_COMPLETED, + CMD_USER_CONSTRAINT_FAILED, //don't go beyond 'CMD_MAX_SERVER_COMMANDS! CMD_MAX_SERVER_COMMANDS }; @@ -110,10 +130,12 @@ enum // copied from btMultiBodyLink.h enum JointType { - eRevoluteType = 0, - ePrismaticType = 1, - eFixedType = 2, - ePoint2PointType = 3, + eRevoluteType = 0, + ePrismaticType = 1, + eSphericalType = 2, + ePlanarType = 3, + eFixedType = 4, + ePoint2PointType = 5, }; struct b3JointInfo @@ -155,6 +177,18 @@ struct b3DebugLines const float* m_linesColor;//float red,green,blue times 'm_numDebugLines'. }; +struct b3OverlappingObject +{ + int m_objectUniqueId; + int m_linkIndex; +}; + +struct b3AABBOverlapData +{ + int m_numOverlappingObjects; + struct b3OverlappingObject* m_overlappingObjects; +}; + struct b3CameraImageData { int m_pixelWidth; @@ -189,6 +223,13 @@ struct b3ContactPointData // double m_angularFrictionForce; }; +enum +{ + CONTACT_QUERY_MODE_REPORT_EXISTING_CONTACT_POINTS = 0, + CONTACT_QUERY_MODE_COMPUTE_CLOSEST_POINTS = 1, +}; + + struct b3ContactInformation { @@ -207,6 +248,7 @@ struct b3VisualShapeData char m_meshAssetFileName[VISUAL_SHAPE_MAX_PATH_LEN]; double m_localInertiaFrame[7];//pos[3], orn[4] //todo: add more data if necessary (material color etc, although material can be in asset file .obj file) + double m_rgbaColor[4]; }; struct b3VisualShapeInformation diff --git a/examples/SharedMemory/TinyRendererVisualShapeConverter.cpp b/examples/SharedMemory/TinyRendererVisualShapeConverter.cpp index 9bf123413..830e629e8 100644 --- a/examples/SharedMemory/TinyRendererVisualShapeConverter.cpp +++ b/examples/SharedMemory/TinyRendererVisualShapeConverter.cpp @@ -36,7 +36,6 @@ subject to the following restrictions: #include "../TinyRenderer/model.h" #include "../ThirdPartyLibs/stb_image/stb_image.h" - enum MyFileType { MY_FILE_STL=1, @@ -72,17 +71,35 @@ struct TinyRendererVisualShapeConverterInternalData TGAImage m_rgbColorBuffer; b3AlignedObjectArray m_textures; b3AlignedObjectArray m_depthBuffer; + b3AlignedObjectArray m_shadowBuffer; b3AlignedObjectArray m_segmentationMaskBuffer; - + btVector3 m_lightDirection; + bool m_hasLightDirection; + btVector3 m_lightColor; + bool m_hasLightColor; + float m_lightDistance; + bool m_hasLightDistance; + float m_lightAmbientCoeff; + bool m_hasLightAmbientCoeff; + float m_lightDiffuseCoeff; + bool m_hasLightDiffuseCoeff; + float m_lightSpecularCoeff; + bool m_hasLightSpecularCoeff; + bool m_hasShadow; SimpleCamera m_camera; + TinyRendererVisualShapeConverterInternalData() :m_upAxis(2), m_swWidth(START_WIDTH), m_swHeight(START_HEIGHT), - m_rgbColorBuffer(START_WIDTH,START_HEIGHT,TGAImage::RGB) + m_rgbColorBuffer(START_WIDTH,START_HEIGHT,TGAImage::RGB), + m_hasLightDirection(false), + m_hasLightColor(false), + m_hasShadow(false) { m_depthBuffer.resize(m_swWidth*m_swHeight); + m_shadowBuffer.resize(m_swWidth*m_swHeight); m_segmentationMaskBuffer.resize(m_swWidth*m_swHeight,-1); } @@ -108,8 +125,46 @@ TinyRendererVisualShapeConverter::~TinyRendererVisualShapeConverter() delete m_data; } +void TinyRendererVisualShapeConverter::setLightDirection(float x, float y, float z) +{ + m_data->m_lightDirection.setValue(x, y, z); + m_data->m_hasLightDirection = true; +} +void TinyRendererVisualShapeConverter::setLightColor(float x, float y, float z) +{ + m_data->m_lightColor.setValue(x, y, z); + m_data->m_hasLightColor = true; +} +void TinyRendererVisualShapeConverter::setLightDistance(float dist) +{ + m_data->m_lightDistance = dist; + m_data->m_hasLightDistance = true; +} + +void TinyRendererVisualShapeConverter::setShadow(bool hasShadow) +{ + m_data->m_hasShadow = hasShadow; +} + +void TinyRendererVisualShapeConverter::setLightAmbientCoeff(float ambientCoeff) +{ + m_data->m_lightAmbientCoeff = ambientCoeff; + m_data->m_hasLightAmbientCoeff = true; +} + +void TinyRendererVisualShapeConverter::setLightDiffuseCoeff(float diffuseCoeff) +{ + m_data->m_lightDiffuseCoeff = diffuseCoeff; + m_data->m_hasLightDiffuseCoeff = true; +} + +void TinyRendererVisualShapeConverter::setLightSpecularCoeff(float specularCoeff) +{ + m_data->m_lightSpecularCoeff = specularCoeff; + m_data->m_hasLightSpecularCoeff = true; +} void convertURDFToVisualShape(const UrdfVisual* visual, const char* urdfPathPrefix, const btTransform& visualTransform, btAlignedObjectArray& verticesOut, btAlignedObjectArray& indicesOut, btAlignedObjectArray& texturesOut, b3VisualShapeData& visualShapeOut) { @@ -527,13 +582,17 @@ void TinyRendererVisualShapeConverter::convertVisualShapes(int linkIndex, const visualShape.m_localInertiaFrame[4] = localInertiaFrame.getRotation()[1]; visualShape.m_localInertiaFrame[5] = localInertiaFrame.getRotation()[2]; visualShape.m_localInertiaFrame[6] = localInertiaFrame.getRotation()[3]; - + visualShape.m_rgbaColor[0] = rgbaColor[0]; + visualShape.m_rgbaColor[1] = rgbaColor[1]; + visualShape.m_rgbaColor[2] = rgbaColor[2]; + visualShape.m_rgbaColor[3] = rgbaColor[3]; + convertURDFToVisualShape(&vis, pathPrefix, localInertiaFrame.inverse()*childTrans, vertices, indices,textures, visualShape); m_data->m_visualShapes.push_back(visualShape); if (vertices.size() && indices.size()) { - TinyRenderObjectData* tinyObj = new TinyRenderObjectData(m_data->m_rgbColorBuffer,m_data->m_depthBuffer, &m_data->m_segmentationMaskBuffer, bodyUniqueId); + TinyRenderObjectData* tinyObj = new TinyRenderObjectData(m_data->m_rgbColorBuffer,m_data->m_depthBuffer, &m_data->m_shadowBuffer, &m_data->m_segmentationMaskBuffer, bodyUniqueId); unsigned char* textureImage=0; int textureWidth=0; int textureHeight=0; @@ -639,6 +698,7 @@ void TinyRendererVisualShapeConverter::clearBuffers(TGAColor& clearColor) { m_data->m_rgbColorBuffer.set(x,y,clearColor); m_data->m_depthBuffer[x+y*m_data->m_swWidth] = -1e30f; + m_data->m_shadowBuffer[x+y*m_data->m_swWidth] = -1e30f; m_data->m_segmentationMaskBuffer[x+y*m_data->m_swWidth] = -1; } } @@ -673,28 +733,110 @@ void TinyRendererVisualShapeConverter::render(const float viewMat[16], const flo btVector3 lightDirWorld(-5,200,-40); - switch (m_data->m_upAxis) - { - case 1: - lightDirWorld = btVector3(-50.f,100,30); - break; - case 2: - lightDirWorld = btVector3(-50.f,30,100); - break; - default:{} - }; + if (m_data->m_hasLightDirection) + { + lightDirWorld = m_data->m_lightDirection; + } + else + { + switch (m_data->m_upAxis) + { + case 1: + lightDirWorld = btVector3(-50.f, 100, 30); + break; + case 2: + lightDirWorld = btVector3(-50.f, 30, 100); + break; + default: {} + }; + } lightDirWorld.normalize(); - // printf("num m_swRenderInstances = %d\n", m_data->m_swRenderInstances.size()); - for (int i=0;im_swRenderInstances.size();i++) + btVector3 lightColor(1.0,1.0,1.0); + if (m_data->m_hasLightColor) { - TinyRendererObjectArray** visualArrayPtr = m_data->m_swRenderInstances.getAtIndex(i); + lightColor = m_data->m_lightColor; + } + + float lightDistance = 2.0; + if (m_data->m_hasLightDistance) + { + lightDistance = m_data->m_lightDistance; + } + + float lightAmbientCoeff = 0.6; + if (m_data->m_hasLightAmbientCoeff) + { + lightAmbientCoeff = m_data->m_lightAmbientCoeff; + } + + float lightDiffuseCoeff = 0.35; + if (m_data->m_hasLightDiffuseCoeff) + { + lightDiffuseCoeff = m_data->m_lightDiffuseCoeff; + } + + float lightSpecularCoeff = 0.05; + if (m_data->m_hasLightSpecularCoeff) + { + lightSpecularCoeff = m_data->m_lightSpecularCoeff; + } + + if (m_data->m_hasShadow) + { + for (int n=0;nm_swRenderInstances.size();n++) + { + TinyRendererObjectArray** visualArrayPtr = m_data->m_swRenderInstances.getAtIndex(n); + if (0==visualArrayPtr) + continue;//can this ever happen? + TinyRendererObjectArray* visualArray = *visualArrayPtr; + + btHashPtr colObjHash = m_data->m_swRenderInstances.getKeyAtIndex(n); + + + const btCollisionObject* colObj = (btCollisionObject*) colObjHash.getPointer(); + + for (int v=0;vm_renderObjects.size();v++) + { + + TinyRenderObjectData* renderObj = visualArray->m_renderObjects[v]; + + + //sync the object transform + const btTransform& tr = colObj->getWorldTransform(); + tr.getOpenGLMatrix(modelMat); + + for (int i=0;i<4;i++) + { + for (int j=0;j<4;j++) + { + + renderObj->m_projectionMatrix[i][j] = projMat[i+4*j]; + renderObj->m_modelMatrix[i][j] = modelMat[i+4*j]; + renderObj->m_viewMatrix[i][j] = viewMat[i+4*j]; + } + } + renderObj->m_localScaling = colObj->getCollisionShape()->getLocalScaling(); + renderObj->m_lightDirWorld = lightDirWorld; + renderObj->m_lightColor = lightColor; + renderObj->m_lightDistance = lightDistance; + renderObj->m_lightAmbientCoeff = lightAmbientCoeff; + renderObj->m_lightDiffuseCoeff = lightDiffuseCoeff; + renderObj->m_lightSpecularCoeff = lightSpecularCoeff; + TinyRenderer::renderObjectDepth(*renderObj); + } + } + } + + for (int n=0;nm_swRenderInstances.size();n++) + { + TinyRendererObjectArray** visualArrayPtr = m_data->m_swRenderInstances.getAtIndex(n); if (0==visualArrayPtr) continue;//can this ever happen? TinyRendererObjectArray* visualArray = *visualArrayPtr; - - btHashPtr colObjHash = m_data->m_swRenderInstances.getKeyAtIndex(i); + + btHashPtr colObjHash = m_data->m_swRenderInstances.getKeyAtIndex(n); const btCollisionObject* colObj = (btCollisionObject*) colObjHash.getPointer(); @@ -704,11 +846,11 @@ void TinyRendererVisualShapeConverter::render(const float viewMat[16], const flo TinyRenderObjectData* renderObj = visualArray->m_renderObjects[v]; - + //sync the object transform const btTransform& tr = colObj->getWorldTransform(); tr.getOpenGLMatrix(modelMat); - + for (int i=0;i<4;i++) { for (int j=0;j<4;j++) @@ -717,10 +859,15 @@ void TinyRendererVisualShapeConverter::render(const float viewMat[16], const flo renderObj->m_projectionMatrix[i][j] = projMat[i+4*j]; renderObj->m_modelMatrix[i][j] = modelMat[i+4*j]; renderObj->m_viewMatrix[i][j] = viewMat[i+4*j]; - renderObj->m_localScaling = colObj->getCollisionShape()->getLocalScaling(); - renderObj->m_lightDirWorld = lightDirWorld; } } + renderObj->m_localScaling = colObj->getCollisionShape()->getLocalScaling(); + renderObj->m_lightDirWorld = lightDirWorld; + renderObj->m_lightColor = lightColor; + renderObj->m_lightDistance = lightDistance; + renderObj->m_lightAmbientCoeff = lightAmbientCoeff; + renderObj->m_lightDiffuseCoeff = lightDiffuseCoeff; + renderObj->m_lightSpecularCoeff = lightSpecularCoeff; TinyRenderer::renderObject(*renderObj); } } @@ -739,6 +886,7 @@ void TinyRendererVisualShapeConverter::render(const float viewMat[16], const flo for (int i=0;im_swWidth;i++) { btSwap(m_data->m_depthBuffer[l1+i],m_data->m_depthBuffer[l2+i]); + btSwap(m_data->m_shadowBuffer[l1+i],m_data->m_shadowBuffer[l2+i]); btSwap(m_data->m_segmentationMaskBuffer[l1+i],m_data->m_segmentationMaskBuffer[l2+i]); } } @@ -758,6 +906,7 @@ void TinyRendererVisualShapeConverter::setWidthAndHeight(int width, int height) m_data->m_swHeight = height; m_data->m_depthBuffer.resize(m_data->m_swWidth*m_data->m_swHeight); + m_data->m_shadowBuffer.resize(m_data->m_swWidth*m_data->m_swHeight); m_data->m_segmentationMaskBuffer.resize(m_data->m_swWidth*m_data->m_swHeight); m_data->m_rgbColorBuffer = TGAImage(width, height, TGAImage::RGB); @@ -872,10 +1021,14 @@ int TinyRendererVisualShapeConverter::registerTexture(unsigned char* texels, int return m_data->m_textures.size()-1; } -void TinyRendererVisualShapeConverter::loadTextureFile(const char* filename) +int TinyRendererVisualShapeConverter::loadTextureFile(const char* filename) { int width,height,n; unsigned char* image=0; image = stbi_load(filename, &width, &height, &n, 3); - registerTexture(image, width, height); -} \ No newline at end of file + if (image && (width>=0) && (height>=0)) + { + return registerTexture(image, width, height); + } + return -1; +} diff --git a/examples/SharedMemory/TinyRendererVisualShapeConverter.h b/examples/SharedMemory/TinyRendererVisualShapeConverter.h index afd0a2ae6..78b4c62d6 100644 --- a/examples/SharedMemory/TinyRendererVisualShapeConverter.h +++ b/examples/SharedMemory/TinyRendererVisualShapeConverter.h @@ -32,13 +32,20 @@ struct TinyRendererVisualShapeConverter : public LinkVisualShapesConverter void getWidthAndHeight(int& width, int& height); void setWidthAndHeight(int width, int height); - + void setLightDirection(float x, float y, float z); + void setLightColor(float x, float y, float z); + void setLightDistance(float dist); + void setLightAmbientCoeff(float ambientCoeff); + void setLightDiffuseCoeff(float diffuseCoeff); + void setLightSpecularCoeff(float specularCoeff); + void setShadow(bool hasShadow); + void copyCameraImageData(unsigned char* pixelsRGBA, int rgbaBufferSizeInPixels, float* depthBuffer, int depthBufferSizeInPixels,int* segmentationMaskBuffer, int segmentationMaskSizeInPixels, int startPixelIndex, int* widthPtr, int* heightPtr, int* numPixelsCopied); void render(); void render(const float viewMat[16], const float projMat[16]); - void loadTextureFile(const char* filename); + int loadTextureFile(const char* filename); int registerTexture(unsigned char* texels, int width, int height); void activateShapeTexture(int shapeUniqueId, int textureUniqueId); void activateShapeTexture(int objectUniqueId, int jointIndex, int shapeIndex, int textureUniqueId); diff --git a/examples/SharedMemory/premake4.lua b/examples/SharedMemory/premake4.lua index 2215cfbe0..a17afb1f8 100644 --- a/examples/SharedMemory/premake4.lua +++ b/examples/SharedMemory/premake4.lua @@ -42,6 +42,14 @@ myfiles = "PhysicsLoopBack.h", "PhysicsLoopBackC_API.cpp", "PhysicsLoopBackC_API.h", + "PhysicsClientSharedMemory_C_API.cpp", + "PhysicsClientSharedMemory_C_API.h", + "PhysicsClientSharedMemory2_C_API.cpp", + "PhysicsClientSharedMemory2_C_API.h", + "PhysicsClientSharedMemory2.cpp", + "PhysicsClientSharedMemory2.h", + "SharedMemoryCommandProcessor.cpp", + "SharedMemoryCommandProcessor.h", "PhysicsServerCommandProcessor.cpp", "PhysicsServerCommandProcessor.h", "TinyRendererVisualShapeConverter.cpp", @@ -146,6 +154,37 @@ links { language "C++" + if _OPTIONS["midi"] then + + defines {"B3_USE_MIDI"} + + + + includedirs{"../ThirdPartyLibs/midi"} + + files { + "../ThirdPartyLibs/midi/RtMidi.cpp", + "../ThirdPartyLibs/midi/RtMidi.h", + "../ThirdPartyLibs/midi/RtError.h", + } + if os.is("Windows") then + links {"winmm"} + defines {"__WINDOWS_MM__", "WIN32"} + end + + if os.is("Linux") then + defines {"__LINUX_ALSA__"} + links {"asound","pthread"} + end + + if os.is("MacOSX") then + links{"CoreAudio.framework", "coreMIDI.framework", "Cocoa.framework"} + defines {"__MACOSX_CORE__"} + end + + end + + files { myfiles, "../StandaloneMain/main_opengl_single_example.cpp", @@ -205,7 +244,37 @@ if os.is("Windows") then else kind "ConsoleApp" end + + if _OPTIONS["midi"] then + defines {"B3_USE_MIDI"} + + + + includedirs{"../ThirdPartyLibs/midi"} + + files { + "../ThirdPartyLibs/midi/RtMidi.cpp", + "../ThirdPartyLibs/midi/RtMidi.h", + "../ThirdPartyLibs/midi/RtError.h", + } + if os.is("Windows") then + links {"winmm"} + defines {"__WINDOWS_MM__", "WIN32"} + end + + if os.is("Linux") then + defines {"__LINUX_ALSA__"} + links {"asound","pthread"} + end + + if os.is("MacOSX") then + links{"CoreAudio.framework", "coreMIDI.framework", "Cocoa.framework"} + defines {"__MACOSX_CORE__"} + end + + end + includedirs { ".","../../src", "../ThirdPartyLibs", "../ThirdPartyLibs/openvr/headers", @@ -288,4 +357,7 @@ if os.is("Windows") then end -end \ No newline at end of file +end + + +include "udp" diff --git a/examples/SharedMemory/udp/main.cpp b/examples/SharedMemory/udp/main.cpp new file mode 100644 index 000000000..bc8c6c57d --- /dev/null +++ b/examples/SharedMemory/udp/main.cpp @@ -0,0 +1,209 @@ +/* server.cpp */ +#include +#include +#include "../../CommonInterfaces/CommonGUIHelperInterface.h" +#ifdef NO_SHARED_MEMORY + #include "PhysicsServerCommandProcessor.h" + typedef PhysicsServerCommandProcessor MyCommandProcessor; +#else + #include "SharedMemoryCommandProcessor.h" + typedef SharedMemoryCommandProcessor MyCommandProcessor ; +#endif //NO_SHARED_MEMORY +#include "SharedMemoryCommands.h" +#include "Bullet3Common/b3AlignedObjectArray.h" +#include "PhysicsServerCommandProcessor.h" + + +bool gVerboseNetworkMessagesServer = false; + +void MySerializeInt(unsigned int sz, unsigned char* output) +{ + unsigned int tmp = sz; + output[0] = tmp & 255; + tmp = tmp >> 8; + output[1] = tmp & 255; + tmp = tmp >> 8; + output[2] = tmp & 255; + tmp = tmp >> 8; + output[3] = tmp & 255; +} + + + +int main(int argc, char *argv[]) +{ + + DummyGUIHelper guiHelper; + PhysicsCommandProcessorInterface* sm = new MyCommandProcessor; + sm->setGuiHelper(&guiHelper); + +// PhysicsDirect* sm = new PhysicsDirect(sdk); + + //PhysicsClientSharedMemory* sm = new PhysicsClientSharedMemory(); + + bool isPhysicsClientConnected = sm->connect(); + + if (isPhysicsClientConnected) + { + + ENetAddress address; + ENetHost *server; + ENetEvent event; + int serviceResult; + + puts("Starting server"); + + if (enet_initialize() != 0) + { + puts("Error initialising enet"); + exit(EXIT_FAILURE); + } + + + /* Bind the server to the default localhost. */ + /* A specific host address can be specified by */ + /* enet_address_set_host (& address, "x.x.x.x"); */ + address.host = ENET_HOST_ANY; + /* Bind the server to port 1234. */ + address.port = 1234; + + server = enet_host_create(&address, + 32, /* number of clients */ + 2, /* number of channels */ + 0, /* Any incoming bandwith */ + 0); /* Any outgoing bandwith */ + + if (server == NULL) + { + puts("Could not create server host"); + exit(EXIT_FAILURE); + } + + + while (true) + { + serviceResult = 1; + + /* Keep doing host_service until no events are left */ + while (serviceResult > 0) + { + /* Wait up to 1000 milliseconds for an event. */ + serviceResult = enet_host_service(server, &event, 0); + if (serviceResult > 0) + { + + switch (event.type) + { + case ENET_EVENT_TYPE_CONNECT: + { + printf("A new client connected from %x:%u.\n", + event.peer->address.host, + event.peer->address.port); + + /* Store any relevant client information here. */ + event.peer->data = (void*)"Client information"; + + break; + } + case ENET_EVENT_TYPE_RECEIVE: + { + if (gVerboseNetworkMessagesServer) + { + printf("A packet of length %u containing '%s' was " + "received from %s on channel %u.\n", + event.packet->dataLength, + event.packet->data, + event.peer->data, + event.channelID); + } + if (event.packet->dataLength == sizeof(SharedMemoryCommand)) + { + SharedMemoryCommand* cmdPtr = (SharedMemoryCommand*)event.packet->data; + SharedMemoryStatus serverStatus; + b3AlignedObjectArray buffer; + buffer.resize(SHARED_MEMORY_MAX_STREAM_CHUNK_SIZE); + + bool hasStatus = sm->processCommand(*cmdPtr,serverStatus, &buffer[0], buffer.size()); + + int timeout = 1024 * 1024 * 1024; + while ((!hasStatus) && (timeout-- > 0)) + { + hasStatus = sm->receiveStatus(serverStatus, &buffer[0], buffer.size()); + + } + if (gVerboseNetworkMessagesServer) + { + printf("buffer.size = %d\n", buffer.size()); + printf("serverStatus.m_numDataStreamBytes = %d\n", serverStatus.m_numDataStreamBytes); + } + if (hasStatus) + { + //create packetData with [int packetSizeInBytes, status, streamBytes) + unsigned char* statBytes = (unsigned char*)&serverStatus; + b3AlignedObjectArray packetData; + packetData.resize(4 + sizeof(SharedMemoryStatus) + serverStatus.m_numDataStreamBytes); + int sz = packetData.size(); + int curPos = 0; + + MySerializeInt(sz, &packetData[curPos]); + curPos += 4; + for (int i = 0; i < sizeof(SharedMemoryStatus); i++) + { + packetData[i + curPos] = statBytes[i]; + } + curPos += sizeof(SharedMemoryStatus); + + for (int i = 0; i < serverStatus.m_numDataStreamBytes; i++) + { + packetData[i + curPos] = buffer[i]; + } + + ENetPacket *packet = enet_packet_create(&packetData[0], packetData.size() , ENET_PACKET_FLAG_RELIABLE); + enet_peer_send(event.peer, 0, packet); + //enet_host_broadcast(server, 0, packet); + } + } + else + { + printf("received packet with unknown contents\n"); + } + + + /* Tell all clients about this message */ + //enet_host_broadcast(server, 0, event.packet); + + break; + } + case ENET_EVENT_TYPE_DISCONNECT: + { + printf("%s disconnected.\n", event.peer->data); + + /* Reset the peer's client information. */ + + event.peer->data = NULL; + + break; + } + default: + { + + } + } + } + else if (serviceResult > 0) + { + puts("Error with servicing the server"); + exit(EXIT_FAILURE); + } + } + + } + + enet_host_destroy(server); + enet_deinitialize(); + } + delete sm; + + return 0; + +} diff --git a/examples/SharedMemory/udp/premake4.lua b/examples/SharedMemory/udp/premake4.lua new file mode 100644 index 000000000..531b098bf --- /dev/null +++ b/examples/SharedMemory/udp/premake4.lua @@ -0,0 +1,126 @@ + +project ("App_PhysicsServerSharedMemoryBridgeUDP") + + language "C++" + + kind "ConsoleApp" + + includedirs {"../../ThirdPartyLibs/enet/include","../../../src",".."} + + if os.is("Windows") then + defines { "WIN32" } + + + links {"Ws2_32","Winmm"} + end + if os.is("Linux") then + end + if os.is("MacOSX") then + end + + + links { + "enet", + "BulletFileLoader", + "Bullet3Common", + "LinearMath" + } + + files { + "main.cpp", + "../PhysicsClient.cpp", + "../PhysicsClient.h", + "../PhysicsDirect.cpp", + "../PhysicsDirect.h", + "../PhysicsCommandProcessorInterface.h", + "../SharedMemoryCommandProcessor.cpp", + "../SharedMemoryCommandProcessor.h", + "../PhysicsClientC_API.cpp", + "../PhysicsClientC_API.h", + "../Win32SharedMemory.cpp", + "../Win32SharedMemory.h", + "../PosixSharedMemory.cpp", + "../PosixSharedMemory.h", + "../../Utils/b3ResourcePath.cpp", + "../../Utils/b3ResourcePath.h", + } + + +project "App_PhysicsServerUDP" + +if _OPTIONS["ios"] then + kind "WindowedApp" +else + kind "ConsoleApp" +end + +defines { "NO_SHARED_MEMORY" } + +includedirs {"..","../../../src", "../../ThirdPartyLibs","../../ThirdPartyLibs/enet/include"} + +links { + "enet","Bullet3Common","BulletInverseDynamicsUtils", "BulletInverseDynamics", "BulletDynamics","BulletCollision", "LinearMath", "BussIK" +} + +if os.is("Windows") then + defines { "WIN32" } + links {"Ws2_32","Winmm"} +end + +language "C++" + +myfiles = +{ + "../IKTrajectoryHelper.cpp", + "../IKTrajectoryHelper.h", + "../SharedMemoryCommands.h", + "../SharedMemoryPublic.h", + "../PhysicsServerCommandProcessor.cpp", + "../PhysicsServerCommandProcessor.h", + "../TinyRendererVisualShapeConverter.cpp", + "../TinyRendererVisualShapeConverter.h", + "../../TinyRenderer/geometry.cpp", + "../../TinyRenderer/model.cpp", + "../../TinyRenderer/tgaimage.cpp", + "../../TinyRenderer/our_gl.cpp", + "../../TinyRenderer/TinyRenderer.cpp", + "../../OpenGLWindow/SimpleCamera.cpp", + "../../OpenGLWindow/SimpleCamera.h", + "../../Importers/ImportURDFDemo/ConvertRigidBodies2MultiBody.h", + "../../Importers/ImportURDFDemo/MultiBodyCreationInterface.h", + "../../Importers/ImportURDFDemo/MyMultiBodyCreator.cpp", + "../../Importers/ImportURDFDemo/MyMultiBodyCreator.h", + "../../Importers/ImportURDFDemo/BulletUrdfImporter.cpp", + "../../Importers/ImportURDFDemo/BulletUrdfImporter.h", + "../../Importers/ImportURDFDemo/UrdfParser.cpp", + "../../Importers/ImportURDFDemo/urdfStringSplit.cpp", + "../../Importers/ImportURDFDemo/UrdfParser.cpp", + "../../Importers/ImportURDFDemo/UrdfParser.h", + "../../Importers/ImportURDFDemo/URDF2Bullet.cpp", + "../../Importers/ImportURDFDemo/URDF2Bullet.h", + "../../Utils/b3ResourcePath.cpp", + "../../Utils/b3Clock.cpp", + "../../../Extras/Serialize/BulletWorldImporter/*", + "../../../Extras/Serialize/BulletFileLoader/*", + "../../Importers/ImportURDFDemo/URDFImporterInterface.h", + "../../Importers/ImportURDFDemo/URDFJointTypes.h", + "../../Importers/ImportObjDemo/Wavefront2GLInstanceGraphicsShape.cpp", + "../../Importers/ImportObjDemo/LoadMeshFromObj.cpp", + "../../Importers/ImportSTLDemo/ImportSTLSetup.h", + "../../Importers/ImportSTLDemo/LoadMeshFromSTL.h", + "../../Importers/ImportColladaDemo/LoadMeshFromCollada.cpp", + "../../Importers/ImportColladaDemo/ColladaGraphicsInstance.h", + "../../ThirdPartyLibs/Wavefront/tiny_obj_loader.cpp", + "../../ThirdPartyLibs/tinyxml/tinystr.cpp", + "../../ThirdPartyLibs/tinyxml/tinyxml.cpp", + "../../ThirdPartyLibs/tinyxml/tinyxmlerror.cpp", + "../../ThirdPartyLibs/tinyxml/tinyxmlparser.cpp", + "../../Importers/ImportMeshUtility/b3ImportMeshUtility.cpp", + "../../ThirdPartyLibs/stb_image/stb_image.cpp", +} + +files { + myfiles, + "main.cpp", +} + diff --git a/examples/SoftDemo/SoftDemo.cpp b/examples/SoftDemo/SoftDemo.cpp index 7a046f9c4..49b59e444 100644 --- a/examples/SoftDemo/SoftDemo.cpp +++ b/examples/SoftDemo/SoftDemo.cpp @@ -2131,12 +2131,12 @@ void SoftDemo::initPhysics() for (int j=0;jGetControllerState( unDevice, &state ) ) + if( m_pHMD->GetControllerState( unDevice, &state ,sizeof(vr::VRControllerState_t)) ) { //we need to have the 'move' events, so no early out here //if (sPrevStates[unDevice].unPacketNum != state.unPacketNum) @@ -776,12 +779,14 @@ void CMainApplication::RunMainLoop() while ( !bQuit && !m_app->m_window->requestedExit()) { + { B3_PROFILE("main"); bQuit = HandleInput(); RenderFrame(); } + } } @@ -844,7 +849,7 @@ void CMainApplication::RenderFrame() // happen right before and after the vsync causing all kinds of jittering issues. This glFinish() // appears to clear that up. Temporary fix while I try to get nvidia to investigate this problem. // 1/29/2014 mikesart - glFinish(); + //glFinish(); } // SwapWindow @@ -1282,6 +1287,8 @@ void CMainApplication::AddCubeToScene( Matrix4 mat, std::vector &vertdata //----------------------------------------------------------------------------- // Purpose: Draw all of the controllers as X/Y/Z lines //----------------------------------------------------------------------------- +extern int gGraspingController; + void CMainApplication::DrawControllers() { // don't draw controllers if somebody else has input focus @@ -1295,6 +1302,8 @@ void CMainApplication::DrawControllers() for ( vr::TrackedDeviceIndex_t unTrackedDevice = vr::k_unTrackedDeviceIndex_Hmd + 1; unTrackedDevice < vr::k_unMaxTrackedDeviceCount; ++unTrackedDevice ) { + + if ( !m_pHMD->IsTrackedDeviceConnected( unTrackedDevice ) ) continue; @@ -1479,8 +1488,9 @@ void CMainApplication::SetupDistortion() u = x*w; v = 1-y*h; vert.position = Vector2( Xoffset+u, -1+2*y*h ); - vr::DistortionCoordinates_t dc0 = m_pHMD->ComputeDistortion(vr::Eye_Left, u, v); - + vr::DistortionCoordinates_t dc0; + bool result = m_pHMD->ComputeDistortion(vr::Eye_Left, u, v,&dc0); + btAssert(result); vert.texCoordRed = Vector2(dc0.rfRed[0], 1 - dc0.rfRed[1]); vert.texCoordGreen = Vector2(dc0.rfGreen[0], 1 - dc0.rfGreen[1]); vert.texCoordBlue = Vector2(dc0.rfBlue[0], 1 - dc0.rfBlue[1]); @@ -1498,8 +1508,9 @@ void CMainApplication::SetupDistortion() u = x*w; v = 1-y*h; vert.position = Vector2( Xoffset+u, -1+2*y*h ); - vr::DistortionCoordinates_t dc0 = m_pHMD->ComputeDistortion( vr::Eye_Right, u, v ); - + vr::DistortionCoordinates_t dc0; + bool result = m_pHMD->ComputeDistortion( vr::Eye_Right, u, v,&dc0 ); + btAssert(result); vert.texCoordRed = Vector2(dc0.rfRed[0], 1 - dc0.rfRed[1]); vert.texCoordGreen = Vector2(dc0.rfGreen[0], 1 - dc0.rfGreen[1]); vert.texCoordBlue = Vector2(dc0.rfBlue[0], 1 - dc0.rfBlue[1]); @@ -2183,9 +2194,11 @@ void CGLRenderModel::Draw() //----------------------------------------------------------------------------- int main(int argc, char *argv[]) { + + #ifdef BT_USE_CUSTOM_PROFILER - //b3SetCustomEnterProfileZoneFunc(...); - //b3SetCustomLeaveProfileZoneFunc(...); + b3SetCustomEnterProfileZoneFunc(dcEnter); + b3SetCustomLeaveProfileZoneFunc(dcLeave); #endif @@ -2223,7 +2236,6 @@ int main(int argc, char *argv[]) pMainApplication->Shutdown(); #ifdef BT_USE_CUSTOM_PROFILER -//... #endif return 0; diff --git a/examples/StandaloneMain/main_opengl_single_example.cpp b/examples/StandaloneMain/main_opengl_single_example.cpp index 8bf97619d..a040882c6 100644 --- a/examples/StandaloneMain/main_opengl_single_example.cpp +++ b/examples/StandaloneMain/main_opengl_single_example.cpp @@ -83,8 +83,11 @@ int main(int argc, char* argv[]) //DummyGUIHelper gui; CommonExampleOptions options(&gui); + example = StandaloneExampleCreateFunc(options); + example->processCommandLineArgs(argc, argv); + example->initPhysics(); example->resetCamera(); diff --git a/examples/StandaloneMain/main_sw_tinyrenderer_single_example.cpp b/examples/StandaloneMain/main_sw_tinyrenderer_single_example.cpp index 2ab5d3992..3dd8b2cce 100644 --- a/examples/StandaloneMain/main_sw_tinyrenderer_single_example.cpp +++ b/examples/StandaloneMain/main_sw_tinyrenderer_single_example.cpp @@ -209,10 +209,13 @@ public: renderObj->m_projectionMatrix[i][j] = projMat[i+4*j]; renderObj->m_modelMatrix[i][j] = modelMat[i+4*j]; renderObj->m_viewMatrix[i][j] = viewMat[i+4*j]; - renderObj->m_localScaling = colObj->getCollisionShape()->getLocalScaling(); - renderObj->m_lightDirWorld = lightDirWorld; } } + renderObj->m_localScaling = colObj->getCollisionShape()->getLocalScaling(); + renderObj->m_lightDirWorld = lightDirWorld; + renderObj->m_lightAmbientCoeff = 0.6; + renderObj->m_lightDiffuseCoeff = 0.35; + renderObj->m_lightSpecularCoeff = 0.05; TinyRenderer::renderObject(*renderObj); } } diff --git a/examples/StandaloneMain/main_tinyrenderer_single_example.cpp b/examples/StandaloneMain/main_tinyrenderer_single_example.cpp index 6ca0efa36..4ebda9d3b 100644 --- a/examples/StandaloneMain/main_tinyrenderer_single_example.cpp +++ b/examples/StandaloneMain/main_tinyrenderer_single_example.cpp @@ -230,10 +230,13 @@ struct TinyRendererGUIHelper : public GUIHelperInterface renderObj->m_projectionMatrix[i][j] = projMat[i+4*j]; renderObj->m_modelMatrix[i][j] = modelMat[i+4*j]; renderObj->m_viewMatrix[i][j] = viewMat[i+4*j]; - renderObj->m_localScaling = colObj->getCollisionShape()->getLocalScaling(); - renderObj->m_lightDirWorld = lightDirWorld; } } + renderObj->m_localScaling = colObj->getCollisionShape()->getLocalScaling(); + renderObj->m_lightDirWorld = lightDirWorld; + renderObj->m_lightAmbientCoeff = 0.6; + renderObj->m_lightDiffuseCoeff = 0.35; + renderObj->m_lightSpecularCoeff = 0.05; TinyRenderer::renderObject(*renderObj); } } @@ -379,6 +382,20 @@ struct TinyRendererGUIHelper : public GUIHelperInterface virtual void drawText3D( const char* txt, float posX, float posZY, float posZ, float size) { + } + virtual int addUserDebugText3D( const char* txt, const double positionXYZ[3], const double textColorRGB[3], double size, double lifeTime) + { + return -1; + } + virtual int addUserDebugLine(const double debugLineFromXYZ[3], const double debugLineToXYZ[3], const double debugLineColorRGB[3], double lineWidth, double lifeTime ) + { + return -1; + } + virtual void removeUserDebugItem( int debugItemUniqueId) + { + } + virtual void removeAllUserDebugItems( ) + { } }; diff --git a/examples/ThirdPartyLibs/BussIK/Tree.cpp b/examples/ThirdPartyLibs/BussIK/Tree.cpp index 6891f0601..0ce6486d8 100644 --- a/examples/ThirdPartyLibs/BussIK/Tree.cpp +++ b/examples/ThirdPartyLibs/BussIK/Tree.cpp @@ -98,10 +98,10 @@ Node* Tree::SearchJoint(Node* node, int index) if (node->seqNumJoint == index) { return node; } else { - if (ret = SearchJoint(node->left, index)) { + if ((ret = SearchJoint(node->left, index))) { return ret; } - if (ret = SearchJoint(node->right, index)) { + if ((ret = SearchJoint(node->right, index))) { return ret; } return NULL; @@ -127,10 +127,10 @@ Node* Tree::SearchEffector(Node* node, int index) if (node->seqNumEffector == index) { return node; } else { - if (ret = SearchEffector(node->left, index)) { + if ((ret = SearchEffector(node->left, index))) { return ret; } - if (ret = SearchEffector(node->right, index)) { + if ((ret = SearchEffector(node->right, index))) { return ret; } return NULL; @@ -214,4 +214,4 @@ void Tree::UnFreezeTree(Node* node) void Tree::UnFreeze(void) { UnFreezeTree(root); -} \ No newline at end of file +} diff --git a/examples/ThirdPartyLibs/enet/premake4.lua b/examples/ThirdPartyLibs/enet/premake4.lua index 522db3431..05390e766 100644 --- a/examples/ThirdPartyLibs/enet/premake4.lua +++ b/examples/ThirdPartyLibs/enet/premake4.lua @@ -14,8 +14,7 @@ files{"unix.c"} end - targetdir "../../../lib" - + includedirs { ".","include" } diff --git a/examples/ThirdPartyLibs/midi/LICENSE.txt b/examples/ThirdPartyLibs/midi/LICENSE.txt new file mode 100644 index 000000000..5b85f871c --- /dev/null +++ b/examples/ThirdPartyLibs/midi/LICENSE.txt @@ -0,0 +1,29 @@ + RtMidi WWW site: http://music.mcgill.ca/~gary/rtmidi/ + + RtMidi: realtime MIDI i/o C++ classes + Copyright (c) 2003-2012 Gary P. Scavone + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation files + (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of the Software, + and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + Any person wishing to distribute modifications to the Software is + asked to send the modifications to the original developer so that + they can be incorporated into the canonical version. This is, + however, not a binding provision of this license. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ \ No newline at end of file diff --git a/examples/ThirdPartyLibs/midi/RtError.h b/examples/ThirdPartyLibs/midi/RtError.h new file mode 100644 index 000000000..5cf7d510a --- /dev/null +++ b/examples/ThirdPartyLibs/midi/RtError.h @@ -0,0 +1,60 @@ +/************************************************************************/ +/*! \class RtError +\brief Exception handling class for RtAudio & RtMidi. + +The RtError class is quite simple but it does allow errors to be +"caught" by RtError::Type. See the RtAudio and RtMidi +documentation to know which methods can throw an RtError. + +*/ +/************************************************************************/ + +#ifndef RTERROR_H +#define RTERROR_H + +#include +#include +#include + +class RtError : public std::exception +{ +public: + //! Defined RtError types. + enum Type { + WARNING, /*!< A non-critical error. */ + DEBUG_WARNING, /*!< A non-critical error which might be useful for debugging. */ + UNSPECIFIED, /*!< The default, unspecified error type. */ + NO_DEVICES_FOUND, /*!< No devices found on system. */ + INVALID_DEVICE, /*!< An invalid device ID was specified. */ + MEMORY_ERROR, /*!< An error occured during memory allocation. */ + INVALID_PARAMETER, /*!< An invalid parameter was specified to a function. */ + INVALID_USE, /*!< The function was called incorrectly. */ + DRIVER_ERROR, /*!< A system driver error occured. */ + SYSTEM_ERROR, /*!< A system error occured. */ + THREAD_ERROR /*!< A thread error occured. */ + }; + + //! The constructor. + RtError(const std::string& message, Type type = RtError::UNSPECIFIED) throw() : message_(message), type_(type) {} + + //! The destructor. + virtual ~RtError(void) throw() {} + + //! Prints thrown error message to stderr. + virtual void printMessage(void) const throw() { std::cerr << '\n' << message_ << "\n\n"; } + + //! Returns the thrown error message type. + virtual const Type& getType(void) const throw() { return type_; } + + //! Returns the thrown error message string. + virtual const std::string& getMessage(void) const throw() { return message_; } + + //! Returns the thrown error message as a c-style string. + virtual const char* what(void) const throw() { return message_.c_str(); } + +protected: + std::string message_; + Type type_; +}; + +#endif \ No newline at end of file diff --git a/examples/ThirdPartyLibs/midi/RtMidi.cpp b/examples/ThirdPartyLibs/midi/RtMidi.cpp new file mode 100644 index 000000000..9cbd260f0 --- /dev/null +++ b/examples/ThirdPartyLibs/midi/RtMidi.cpp @@ -0,0 +1,3803 @@ +/**********************************************************************/ +/*! \class RtMidi + \brief An abstract base class for realtime MIDI input/output. + + This class implements some common functionality for the realtime + MIDI input/output subclasses RtMidiIn and RtMidiOut. + + RtMidi WWW site: http://music.mcgill.ca/~gary/rtmidi/ + + RtMidi: realtime MIDI i/o C++ classes + Copyright (c) 2003-2012 Gary P. Scavone + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation files + (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of the Software, + and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + Any person wishing to distribute modifications to the Software is + asked to send the modifications to the original developer so that + they can be incorporated into the canonical version. This is, + however, not a binding provision of this license. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ +/**********************************************************************/ + +// RtMidi: Version 2.0.1 + +#include "RtMidi.h" +#include +#include //exit + +//*********************************************************************// +// RtMidi Definitions +//*********************************************************************// + +void RtMidi :: getCompiledApi( std::vector &apis ) +{ + apis.clear(); + + // The order here will control the order of RtMidi's API search in + // the constructor. +#if defined(__MACOSX_CORE__) + apis.push_back( MACOSX_CORE ); +#endif +#if defined(__LINUX_ALSA__) + apis.push_back( LINUX_ALSA ); +#endif +#if defined(__UNIX_JACK__) + apis.push_back( UNIX_JACK ); +#endif +#if defined(__WINDOWS_MM__) + apis.push_back( WINDOWS_MM ); +#endif +#if defined(__WINDOWS_KS__) + apis.push_back( WINDOWS_KS ); +#endif +#if defined(__RTMIDI_DUMMY__) + apis.push_back( RTMIDI_DUMMY ); +#endif + +} + +void RtMidi :: error( RtError::Type type, std::string errorString ) +{ + if (type == RtError::WARNING) { + std::cerr << '\n' << errorString << "\n\n"; + } + else if (type == RtError::DEBUG_WARNING) { +#if defined(__RTMIDI_DEBUG__) + std::cerr << '\n' << errorString << "\n\n"; +#endif + } + else { + std::cerr << '\n' << errorString << "\n\n"; +// exit(0); + } +} + +//*********************************************************************// +// RtMidiIn Definitions +//*********************************************************************// + +void RtMidiIn :: openMidiApi( RtMidi::Api api, const std::string clientName, unsigned int queueSizeLimit ) +{ + if ( rtapi_ ) + delete rtapi_; + rtapi_ = 0; + +#if defined(__UNIX_JACK__) + if ( api == UNIX_JACK ) + rtapi_ = new MidiInJack( clientName, queueSizeLimit ); +#endif +#if defined(__LINUX_ALSA__) + if ( api == LINUX_ALSA ) + rtapi_ = new MidiInAlsa( clientName, queueSizeLimit ); +#endif +#if defined(__WINDOWS_MM__) + if ( api == WINDOWS_MM ) + rtapi_ = new MidiInWinMM( clientName, queueSizeLimit ); +#endif +#if defined(__WINDOWS_KS__) + if ( api == WINDOWS_KS ) + rtapi_ = new MidiInWinKS( clientName, queueSizeLimit ); +#endif +#if defined(__MACOSX_CORE__) + if ( api == MACOSX_CORE ) + rtapi_ = new MidiInCore( clientName, queueSizeLimit ); +#endif +#if defined(__RTMIDI_DUMMY__) + if ( api == RTMIDI_DUMMY ) + rtapi_ = new MidiInDummy( clientName, queueSizeLimit ); +#endif +} + +RtMidiIn :: RtMidiIn( RtMidi::Api api, const std::string clientName, unsigned int queueSizeLimit ) +{ + rtapi_ = 0; + + if ( api != UNSPECIFIED ) { + // Attempt to open the specified API. + openMidiApi( api, clientName, queueSizeLimit ); + if ( rtapi_ ) return; + + // No compiled support for specified API value. Issue a debug + // warning and continue as if no API was specified. + RtMidi::error( RtError::WARNING, "RtMidiIn: no compiled support for specified API argument!" ); + } + + // Iterate through the compiled APIs and return as soon as we find + // one with at least one port or we reach the end of the list. + std::vector< RtMidi::Api > apis; + getCompiledApi( apis ); + for ( unsigned int i=0; igetPortCount() ) break; + } + + if ( rtapi_ ) return; + + // It should not be possible to get here because the preprocessor + // definition __RTMIDI_DUMMY__ is automatically defined if no + // API-specific definitions are passed to the compiler. But just in + // case something weird happens, we'll print out an error message. + RtMidi::error( RtError::WARNING, "RtMidiIn: no compiled API support found ... critical error!!" ); +} + +RtMidiIn :: ~RtMidiIn() +{ + delete rtapi_; +} + + +//*********************************************************************// +// RtMidiOut Definitions +//*********************************************************************// + +void RtMidiOut :: openMidiApi( RtMidi::Api api, const std::string clientName ) +{ + if ( rtapi_ ) + delete rtapi_; + rtapi_ = 0; + +#if defined(__UNIX_JACK__) + if ( api == UNIX_JACK ) + rtapi_ = new MidiOutJack( clientName ); +#endif +#if defined(__LINUX_ALSA__) + if ( api == LINUX_ALSA ) + rtapi_ = new MidiOutAlsa( clientName ); +#endif +#if defined(__WINDOWS_MM__) + if ( api == WINDOWS_MM ) + rtapi_ = new MidiOutWinMM( clientName ); +#endif +#if defined(__WINDOWS_KS__) + if ( api == WINDOWS_KS ) + rtapi_ = new MidiOutWinKS( clientName ); +#endif +#if defined(__MACOSX_CORE__) + if ( api == MACOSX_CORE ) + rtapi_ = new MidiOutCore( clientName ); +#endif +#if defined(__RTMIDI_DUMMY__) + if ( api == RTMIDI_DUMMY ) + rtapi_ = new MidiOutDummy( clientName ); +#endif +} + +RtMidiOut :: RtMidiOut( RtMidi::Api api, const std::string clientName ) +{ + rtapi_ = 0; + + if ( api != UNSPECIFIED ) { + // Attempt to open the specified API. + openMidiApi( api, clientName ); + if ( rtapi_ ) return; + + // No compiled support for specified API value. Issue a debug + // warning and continue as if no API was specified. + RtMidi::error( RtError::WARNING, "RtMidiOut: no compiled support for specified API argument!" ); + } + + // Iterate through the compiled APIs and return as soon as we find + // one with at least one port or we reach the end of the list. + std::vector< RtMidi::Api > apis; + getCompiledApi( apis ); + for ( unsigned int i=0; igetPortCount() ) break; + } + + if ( rtapi_ ) return; + + // It should not be possible to get here because the preprocessor + // definition __RTMIDI_DUMMY__ is automatically defined if no + // API-specific definitions are passed to the compiler. But just in + // case something weird happens, we'll print out an error message. + RtMidi::error( RtError::WARNING, "RtMidiOut: no compiled API support found ... critical error!!" ); +} + +RtMidiOut :: ~RtMidiOut() +{ + delete rtapi_; +} + +//*********************************************************************// +// Common MidiInApi Definitions +//*********************************************************************// + +MidiInApi :: MidiInApi( unsigned int queueSizeLimit ) + : apiData_( 0 ), connected_( false ) +{ + // Allocate the MIDI queue. + inputData_.queue.ringSize = queueSizeLimit; + if ( inputData_.queue.ringSize > 0 ) + inputData_.queue.ring = new MidiMessage[ inputData_.queue.ringSize ]; +} + +MidiInApi :: ~MidiInApi( void ) +{ + // Delete the MIDI queue. + if ( inputData_.queue.ringSize > 0 ) delete [] inputData_.queue.ring; +} + +void MidiInApi :: setCallback( RtMidiIn::RtMidiCallback callback, void *userData ) +{ + if ( inputData_.usingCallback ) { + errorString_ = "MidiInApi::setCallback: a callback function is already set!"; + RtMidi::error( RtError::WARNING, errorString_ ); + return; + } + + if ( !callback ) { + errorString_ = "RtMidiIn::setCallback: callback function value is invalid!"; + RtMidi::error( RtError::WARNING, errorString_ ); + return; + } + + inputData_.userCallback = (void *) callback; + inputData_.userData = userData; + inputData_.usingCallback = true; +} + +void MidiInApi :: cancelCallback() +{ + if ( !inputData_.usingCallback ) { + errorString_ = "RtMidiIn::cancelCallback: no callback function was set!"; + RtMidi::error( RtError::WARNING, errorString_ ); + return; + } + + inputData_.userCallback = 0; + inputData_.userData = 0; + inputData_.usingCallback = false; +} + +void MidiInApi :: ignoreTypes( bool midiSysex, bool midiTime, bool midiSense ) +{ + inputData_.ignoreFlags = 0; + if ( midiSysex ) inputData_.ignoreFlags = 0x01; + if ( midiTime ) inputData_.ignoreFlags |= 0x02; + if ( midiSense ) inputData_.ignoreFlags |= 0x04; +} + +double MidiInApi :: getMessage( std::vector *message ) +{ + message->clear(); + + if ( inputData_.usingCallback ) { + errorString_ = "RtMidiIn::getNextMessage: a user callback is currently set for this port."; + RtMidi::error( RtError::WARNING, errorString_ ); + return 0.0; + } + + if ( inputData_.queue.size == 0 ) return 0.0; + + // Copy queued message to the vector pointer argument and then "pop" it. + std::vector *bytes = &(inputData_.queue.ring[inputData_.queue.front].bytes); + message->assign( bytes->begin(), bytes->end() ); + double deltaTime = inputData_.queue.ring[inputData_.queue.front].timeStamp; + inputData_.queue.size--; + inputData_.queue.front++; + if ( inputData_.queue.front == inputData_.queue.ringSize ) + inputData_.queue.front = 0; + + return deltaTime; +} + +//*********************************************************************// +// Common MidiOutApi Definitions +//*********************************************************************// + +MidiOutApi :: MidiOutApi( void ) + : apiData_( 0 ), connected_( false ) +{ +} + +MidiOutApi :: ~MidiOutApi( void ) +{ +} + +// *************************************************** // +// +// OS/API-specific methods. +// +// *************************************************** // + +#if defined(__MACOSX_CORE__) + +// The CoreMIDI API is based on the use of a callback function for +// MIDI input. We convert the system specific time stamps to delta +// time values. + +// OS-X CoreMIDI header files. +#include +#include +#include + +// A structure to hold variables related to the CoreMIDI API +// implementation. +struct CoreMidiData { + MIDIClientRef client; + MIDIPortRef port; + MIDIEndpointRef endpoint; + MIDIEndpointRef destinationId; + unsigned long long lastTime; + MIDISysexSendRequest sysexreq; +}; + +//*********************************************************************// +// API: OS-X +// Class Definitions: MidiInCore +//*********************************************************************// + +void midiInputCallback( const MIDIPacketList *list, void *procRef, void *srcRef ) +{ + MidiInApi::RtMidiInData *data = static_cast (procRef); + CoreMidiData *apiData = static_cast (data->apiData); + + unsigned char status; + unsigned short nBytes, iByte, size; + unsigned long long time; + + bool& continueSysex = data->continueSysex; + MidiInApi::MidiMessage& message = data->message; + + const MIDIPacket *packet = &list->packet[0]; + for ( unsigned int i=0; inumPackets; ++i ) { + + // My interpretation of the CoreMIDI documentation: all message + // types, except sysex, are complete within a packet and there may + // be several of them in a single packet. Sysex messages can be + // broken across multiple packets and PacketLists but are bundled + // alone within each packet (these packets do not contain other + // message types). If sysex messages are split across multiple + // MIDIPacketLists, they must be handled by multiple calls to this + // function. + + nBytes = packet->length; + if ( nBytes == 0 ) continue; + + // Calculate time stamp. + + if ( data->firstMessage ) { + message.timeStamp = 0.0; + data->firstMessage = false; + } + else { + time = packet->timeStamp; + if ( time == 0 ) { // this happens when receiving asynchronous sysex messages + time = AudioGetCurrentHostTime(); + } + time -= apiData->lastTime; + time = AudioConvertHostTimeToNanos( time ); + if ( !continueSysex ) + message.timeStamp = time * 0.000000001; + } + apiData->lastTime = packet->timeStamp; + if ( apiData->lastTime == 0 ) { // this happens when receiving asynchronous sysex messages + apiData->lastTime = AudioGetCurrentHostTime(); + } + //std::cout << "TimeStamp = " << packet->timeStamp << std::endl; + + iByte = 0; + if ( continueSysex ) { + // We have a continuing, segmented sysex message. + if ( !( data->ignoreFlags & 0x01 ) ) { + // If we're not ignoring sysex messages, copy the entire packet. + for ( unsigned int j=0; jdata[j] ); + } + continueSysex = packet->data[nBytes-1] != 0xF7; + + if ( !continueSysex ) { + // If not a continuing sysex message, invoke the user callback function or queue the message. + if ( data->usingCallback ) { + RtMidiIn::RtMidiCallback callback = (RtMidiIn::RtMidiCallback) data->userCallback; + callback( message.timeStamp, &message.bytes, data->userData ); + } + else { + // As long as we haven't reached our queue size limit, push the message. + if ( data->queue.size < data->queue.ringSize ) { + data->queue.ring[data->queue.back++] = message; + if ( data->queue.back == data->queue.ringSize ) + data->queue.back = 0; + data->queue.size++; + } + else + std::cerr << "\nMidiInCore: message queue limit reached!!\n\n"; + } + message.bytes.clear(); + } + } + else { + while ( iByte < nBytes ) { + size = 0; + // We are expecting that the next byte in the packet is a status byte. + status = packet->data[iByte]; + if ( !(status & 0x80) ) break; + // Determine the number of bytes in the MIDI message. + if ( status < 0xC0 ) size = 3; + else if ( status < 0xE0 ) size = 2; + else if ( status < 0xF0 ) size = 3; + else if ( status == 0xF0 ) { + // A MIDI sysex + if ( data->ignoreFlags & 0x01 ) { + size = 0; + iByte = nBytes; + } + else size = nBytes - iByte; + continueSysex = packet->data[nBytes-1] != 0xF7; + } + else if ( status == 0xF1 ) { + // A MIDI time code message + if ( data->ignoreFlags & 0x02 ) { + size = 0; + iByte += 2; + } + else size = 2; + } + else if ( status == 0xF2 ) size = 3; + else if ( status == 0xF3 ) size = 2; + else if ( status == 0xF8 && ( data->ignoreFlags & 0x02 ) ) { + // A MIDI timing tick message and we're ignoring it. + size = 0; + iByte += 1; + } + else if ( status == 0xFE && ( data->ignoreFlags & 0x04 ) ) { + // A MIDI active sensing message and we're ignoring it. + size = 0; + iByte += 1; + } + else size = 1; + + // Copy the MIDI data to our vector. + if ( size ) { + message.bytes.assign( &packet->data[iByte], &packet->data[iByte+size] ); + if ( !continueSysex ) { + // If not a continuing sysex message, invoke the user callback function or queue the message. + if ( data->usingCallback ) { + RtMidiIn::RtMidiCallback callback = (RtMidiIn::RtMidiCallback) data->userCallback; + callback( message.timeStamp, &message.bytes, data->userData ); + } + else { + // As long as we haven't reached our queue size limit, push the message. + if ( data->queue.size < data->queue.ringSize ) { + data->queue.ring[data->queue.back++] = message; + if ( data->queue.back == data->queue.ringSize ) + data->queue.back = 0; + data->queue.size++; + } + else + std::cerr << "\nMidiInCore: message queue limit reached!!\n\n"; + } + message.bytes.clear(); + } + iByte += size; + } + } + } + packet = MIDIPacketNext(packet); + } +} + +MidiInCore :: MidiInCore( const std::string clientName, unsigned int queueSizeLimit ) : MidiInApi( queueSizeLimit ) +{ + initialize( clientName ); +} + +MidiInCore :: ~MidiInCore( void ) +{ + // Close a connection if it exists. + closePort(); + + // Cleanup. + CoreMidiData *data = static_cast (apiData_); + MIDIClientDispose( data->client ); + if ( data->endpoint ) MIDIEndpointDispose( data->endpoint ); + delete data; +} + +void MidiInCore :: initialize( const std::string& clientName ) +{ + // Set up our client. + MIDIClientRef client; + OSStatus result = MIDIClientCreate( CFStringCreateWithCString( NULL, clientName.c_str(), kCFStringEncodingASCII ), NULL, NULL, &client ); + if ( result != noErr ) { + errorString_ = "MidiInCore::initialize: error creating OS-X MIDI client object."; + RtMidi::error( RtError::DRIVER_ERROR, errorString_ ); + } + + // Save our api-specific connection information. + CoreMidiData *data = (CoreMidiData *) new CoreMidiData; + data->client = client; + data->endpoint = 0; + apiData_ = (void *) data; + inputData_.apiData = (void *) data; +} + +void MidiInCore :: openPort( unsigned int portNumber, const std::string portName ) +{ + if ( connected_ ) { + errorString_ = "MidiInCore::openPort: a valid connection already exists!"; + RtMidi::error( RtError::WARNING, errorString_ ); + return; + } + + unsigned int nSrc = MIDIGetNumberOfSources(); + if (nSrc < 1) { + errorString_ = "MidiInCore::openPort: no MIDI input sources found!"; + RtMidi::error( RtError::NO_DEVICES_FOUND, errorString_ ); + } + + std::ostringstream ost; + if ( portNumber >= nSrc ) { + ost << "MidiInCore::openPort: the 'portNumber' argument (" << portNumber << ") is invalid."; + errorString_ = ost.str(); + RtMidi::error( RtError::INVALID_PARAMETER, errorString_ ); + } + + MIDIPortRef port; + CoreMidiData *data = static_cast (apiData_); + OSStatus result = MIDIInputPortCreate( data->client, + CFStringCreateWithCString( NULL, portName.c_str(), kCFStringEncodingASCII ), + midiInputCallback, (void *)&inputData_, &port ); + if ( result != noErr ) { + MIDIClientDispose( data->client ); + errorString_ = "MidiInCore::openPort: error creating OS-X MIDI input port."; + RtMidi::error( RtError::DRIVER_ERROR, errorString_ ); + } + + // Get the desired input source identifier. + MIDIEndpointRef endpoint = MIDIGetSource( portNumber ); + if ( endpoint == 0 ) { + MIDIPortDispose( port ); + MIDIClientDispose( data->client ); + errorString_ = "MidiInCore::openPort: error getting MIDI input source reference."; + RtMidi::error( RtError::DRIVER_ERROR, errorString_ ); + } + + // Make the connection. + result = MIDIPortConnectSource( port, endpoint, NULL ); + if ( result != noErr ) { + MIDIPortDispose( port ); + MIDIClientDispose( data->client ); + errorString_ = "MidiInCore::openPort: error connecting OS-X MIDI input port."; + RtMidi::error( RtError::DRIVER_ERROR, errorString_ ); + } + + // Save our api-specific port information. + data->port = port; + + connected_ = true; +} + +void MidiInCore :: openVirtualPort( const std::string portName ) +{ + CoreMidiData *data = static_cast (apiData_); + + // Create a virtual MIDI input destination. + MIDIEndpointRef endpoint; + OSStatus result = MIDIDestinationCreate( data->client, + CFStringCreateWithCString( NULL, portName.c_str(), kCFStringEncodingASCII ), + midiInputCallback, (void *)&inputData_, &endpoint ); + if ( result != noErr ) { + errorString_ = "MidiInCore::openVirtualPort: error creating virtual OS-X MIDI destination."; + RtMidi::error( RtError::DRIVER_ERROR, errorString_ ); + } + + // Save our api-specific connection information. + data->endpoint = endpoint; +} + +void MidiInCore :: closePort( void ) +{ + if ( connected_ ) { + CoreMidiData *data = static_cast (apiData_); + MIDIPortDispose( data->port ); + connected_ = false; + } +} + +unsigned int MidiInCore :: getPortCount() +{ + return MIDIGetNumberOfSources(); +} + +// This function was submitted by Douglas Casey Tucker and apparently +// derived largely from PortMidi. +CFStringRef EndpointName( MIDIEndpointRef endpoint, bool isExternal ) +{ + CFMutableStringRef result = CFStringCreateMutable( NULL, 0 ); + CFStringRef str; + + // Begin with the endpoint's name. + str = NULL; + MIDIObjectGetStringProperty( endpoint, kMIDIPropertyName, &str ); + if ( str != NULL ) { + CFStringAppend( result, str ); + CFRelease( str ); + } + + MIDIEntityRef entity = NULL; + MIDIEndpointGetEntity( endpoint, &entity ); + if ( entity == 0 ) + // probably virtual + return result; + + if ( CFStringGetLength( result ) == 0 ) { + // endpoint name has zero length -- try the entity + str = NULL; + MIDIObjectGetStringProperty( entity, kMIDIPropertyName, &str ); + if ( str != NULL ) { + CFStringAppend( result, str ); + CFRelease( str ); + } + } + // now consider the device's name + MIDIDeviceRef device = 0; + MIDIEntityGetDevice( entity, &device ); + if ( device == 0 ) + return result; + + str = NULL; + MIDIObjectGetStringProperty( device, kMIDIPropertyName, &str ); + if ( CFStringGetLength( result ) == 0 ) { + CFRelease( result ); + return str; + } + if ( str != NULL ) { + // if an external device has only one entity, throw away + // the endpoint name and just use the device name + if ( isExternal && MIDIDeviceGetNumberOfEntities( device ) < 2 ) { + CFRelease( result ); + return str; + } else { + if ( CFStringGetLength( str ) == 0 ) { + CFRelease( str ); + return result; + } + // does the entity name already start with the device name? + // (some drivers do this though they shouldn't) + // if so, do not prepend + if ( CFStringCompareWithOptions( result, /* endpoint name */ + str /* device name */, + CFRangeMake(0, CFStringGetLength( str ) ), 0 ) != kCFCompareEqualTo ) { + // prepend the device name to the entity name + if ( CFStringGetLength( result ) > 0 ) + CFStringInsert( result, 0, CFSTR(" ") ); + CFStringInsert( result, 0, str ); + } + CFRelease( str ); + } + } + return result; +} + +// This function was submitted by Douglas Casey Tucker and apparently +// derived largely from PortMidi. +static CFStringRef ConnectedEndpointName( MIDIEndpointRef endpoint ) +{ + CFMutableStringRef result = CFStringCreateMutable( NULL, 0 ); + CFStringRef str; + OSStatus err; + int i; + + // Does the endpoint have connections? + CFDataRef connections = NULL; + int nConnected = 0; + bool anyStrings = false; + err = MIDIObjectGetDataProperty( endpoint, kMIDIPropertyConnectionUniqueID, &connections ); + if ( connections != NULL ) { + // It has connections, follow them + // Concatenate the names of all connected devices + nConnected = CFDataGetLength( connections ) / sizeof(MIDIUniqueID); + if ( nConnected ) { + const SInt32 *pid = (const SInt32 *)(CFDataGetBytePtr(connections)); + for ( i=0; i= MIDIGetNumberOfSources() ) { + ost << "MidiInCore::getPortName: the 'portNumber' argument (" << portNumber << ") is invalid."; + errorString_ = ost.str(); + RtMidi::error( RtError::WARNING, errorString_ ); + //RtMidi::error( RtError::INVALID_PARAMETER, errorString_ ); + return stringName; + } + + portRef = MIDIGetSource( portNumber ); + nameRef = ConnectedEndpointName(portRef); + CFStringGetCString( nameRef, name, sizeof(name), 0); + CFRelease( nameRef ); + + return stringName = name; +} + +//*********************************************************************// +// API: OS-X +// Class Definitions: MidiOutCore +//*********************************************************************// + +MidiOutCore :: MidiOutCore( const std::string clientName ) : MidiOutApi() +{ + initialize( clientName ); +} + +MidiOutCore :: ~MidiOutCore( void ) +{ + // Close a connection if it exists. + closePort(); + + // Cleanup. + CoreMidiData *data = static_cast (apiData_); + MIDIClientDispose( data->client ); + if ( data->endpoint ) MIDIEndpointDispose( data->endpoint ); + delete data; +} + +void MidiOutCore :: initialize( const std::string& clientName ) +{ + // Set up our client. + MIDIClientRef client; + OSStatus result = MIDIClientCreate( CFStringCreateWithCString( NULL, clientName.c_str(), kCFStringEncodingASCII ), NULL, NULL, &client ); + if ( result != noErr ) { + errorString_ = "MidiOutCore::initialize: error creating OS-X MIDI client object."; + RtMidi::error( RtError::DRIVER_ERROR, errorString_ ); + } + + // Save our api-specific connection information. + CoreMidiData *data = (CoreMidiData *) new CoreMidiData; + data->client = client; + data->endpoint = 0; + apiData_ = (void *) data; +} + +unsigned int MidiOutCore :: getPortCount() +{ + return MIDIGetNumberOfDestinations(); +} + +std::string MidiOutCore :: getPortName( unsigned int portNumber ) +{ + CFStringRef nameRef; + MIDIEndpointRef portRef; + std::ostringstream ost; + char name[128]; + + std::string stringName; + if ( portNumber >= MIDIGetNumberOfDestinations() ) { + ost << "MidiOutCore::getPortName: the 'portNumber' argument (" << portNumber << ") is invalid."; + errorString_ = ost.str(); + RtMidi::error( RtError::WARNING, errorString_ ); + return stringName; + //RtMidi::error( RtError::INVALID_PARAMETER, errorString_ ); + } + + portRef = MIDIGetDestination( portNumber ); + nameRef = ConnectedEndpointName(portRef); + CFStringGetCString( nameRef, name, sizeof(name), 0); + CFRelease( nameRef ); + + return stringName = name; +} + +void MidiOutCore :: openPort( unsigned int portNumber, const std::string portName ) +{ + if ( connected_ ) { + errorString_ = "MidiOutCore::openPort: a valid connection already exists!"; + RtMidi::error( RtError::WARNING, errorString_ ); + return; + } + + unsigned int nDest = MIDIGetNumberOfDestinations(); + if (nDest < 1) { + errorString_ = "MidiOutCore::openPort: no MIDI output destinations found!"; + RtMidi::error( RtError::NO_DEVICES_FOUND, errorString_ ); + } + + std::ostringstream ost; + if ( portNumber >= nDest ) { + ost << "MidiOutCore::openPort: the 'portNumber' argument (" << portNumber << ") is invalid."; + errorString_ = ost.str(); + RtMidi::error( RtError::INVALID_PARAMETER, errorString_ ); + } + + MIDIPortRef port; + CoreMidiData *data = static_cast (apiData_); + OSStatus result = MIDIOutputPortCreate( data->client, + CFStringCreateWithCString( NULL, portName.c_str(), kCFStringEncodingASCII ), + &port ); + if ( result != noErr ) { + MIDIClientDispose( data->client ); + errorString_ = "MidiOutCore::openPort: error creating OS-X MIDI output port."; + RtMidi::error( RtError::DRIVER_ERROR, errorString_ ); + } + + // Get the desired output port identifier. + MIDIEndpointRef destination = MIDIGetDestination( portNumber ); + if ( destination == 0 ) { + MIDIPortDispose( port ); + MIDIClientDispose( data->client ); + errorString_ = "MidiOutCore::openPort: error getting MIDI output destination reference."; + RtMidi::error( RtError::DRIVER_ERROR, errorString_ ); + } + + // Save our api-specific connection information. + data->port = port; + data->destinationId = destination; + connected_ = true; +} + +void MidiOutCore :: closePort( void ) +{ + if ( connected_ ) { + CoreMidiData *data = static_cast (apiData_); + MIDIPortDispose( data->port ); + connected_ = false; + } +} + +void MidiOutCore :: openVirtualPort( std::string portName ) +{ + CoreMidiData *data = static_cast (apiData_); + + if ( data->endpoint ) { + errorString_ = "MidiOutCore::openVirtualPort: a virtual output port already exists!"; + RtMidi::error( RtError::WARNING, errorString_ ); + return; + } + + // Create a virtual MIDI output source. + MIDIEndpointRef endpoint; + OSStatus result = MIDISourceCreate( data->client, + CFStringCreateWithCString( NULL, portName.c_str(), kCFStringEncodingASCII ), + &endpoint ); + if ( result != noErr ) { + errorString_ = "MidiOutCore::initialize: error creating OS-X virtual MIDI source."; + RtMidi::error( RtError::DRIVER_ERROR, errorString_ ); + } + + // Save our api-specific connection information. + data->endpoint = endpoint; +} + +char *sysexBuffer = 0; + +void sysexCompletionProc( MIDISysexSendRequest * sreq ) +{ + //std::cout << "Completed SysEx send\n"; + delete sysexBuffer; + sysexBuffer = 0; +} + +void MidiOutCore :: sendMessage( std::vector *message ) +{ + // We use the MIDISendSysex() function to asynchronously send sysex + // messages. Otherwise, we use a single CoreMidi MIDIPacket. + unsigned int nBytes = message->size(); + if ( nBytes == 0 ) { + errorString_ = "MidiOutCore::sendMessage: no data in message argument!"; + RtMidi::error( RtError::WARNING, errorString_ ); + return; + } + + // unsigned int packetBytes, bytesLeft = nBytes; + // unsigned int messageIndex = 0; + MIDITimeStamp timeStamp = AudioGetCurrentHostTime(); + CoreMidiData *data = static_cast (apiData_); + OSStatus result; + + if ( message->at(0) == 0xF0 ) { + + while ( sysexBuffer != 0 ) usleep( 1000 ); // sleep 1 ms + + sysexBuffer = new char[nBytes]; + if ( sysexBuffer == NULL ) { + errorString_ = "MidiOutCore::sendMessage: error allocating sysex message memory!"; + RtMidi::error( RtError::MEMORY_ERROR, errorString_ ); + } + + // Copy data to buffer. + for ( unsigned int i=0; iat(i); + + data->sysexreq.destination = data->destinationId; + data->sysexreq.data = (Byte *)sysexBuffer; + data->sysexreq.bytesToSend = nBytes; + data->sysexreq.complete = 0; + data->sysexreq.completionProc = sysexCompletionProc; + data->sysexreq.completionRefCon = &(data->sysexreq); + + result = MIDISendSysex( &(data->sysexreq) ); + if ( result != noErr ) { + errorString_ = "MidiOutCore::sendMessage: error sending MIDI to virtual destinations."; + RtMidi::error( RtError::WARNING, errorString_ ); + } + return; + } + else if ( nBytes > 3 ) { + errorString_ = "MidiOutCore::sendMessage: message format problem ... not sysex but > 3 bytes?"; + RtMidi::error( RtError::WARNING, errorString_ ); + return; + } + + MIDIPacketList packetList; + MIDIPacket *packet = MIDIPacketListInit( &packetList ); + packet = MIDIPacketListAdd( &packetList, sizeof(packetList), packet, timeStamp, nBytes, (const Byte *) &message->at( 0 ) ); + if ( !packet ) { + errorString_ = "MidiOutCore::sendMessage: could not allocate packet list"; + RtMidi::error( RtError::DRIVER_ERROR, errorString_ ); + } + + // Send to any destinations that may have connected to us. + if ( data->endpoint ) { + result = MIDIReceived( data->endpoint, &packetList ); + if ( result != noErr ) { + errorString_ = "MidiOutCore::sendMessage: error sending MIDI to virtual destinations."; + RtMidi::error( RtError::WARNING, errorString_ ); + } + } + + // And send to an explicit destination port if we're connected. + if ( connected_ ) { + result = MIDISend( data->port, data->destinationId, &packetList ); + if ( result != noErr ) { + errorString_ = "MidiOutCore::sendMessage: error sending MIDI message to port."; + RtMidi::error( RtError::WARNING, errorString_ ); + } + } + +} + +#endif // __MACOSX_CORE__ + + +//*********************************************************************// +// API: LINUX ALSA SEQUENCER +//*********************************************************************// + +// API information found at: +// - http://www.alsa-project.org/documentation.php#Library + +#if defined(__LINUX_ALSA__) + +// The ALSA Sequencer API is based on the use of a callback function for +// MIDI input. +// +// Thanks to Pedro Lopez-Cabanillas for help with the ALSA sequencer +// time stamps and other assorted fixes!!! + +// If you don't need timestamping for incoming MIDI events, define the +// preprocessor definition AVOID_TIMESTAMPING to save resources +// associated with the ALSA sequencer queues. + +#include +#include + +// ALSA header file. +#include + +// Global sequencer instance created when first In/Out object is +// created, then destroyed when last In/Out is deleted. +static snd_seq_t *s_seq = NULL; + +// Variable to keep track of how many ports are open. +static unsigned int s_numPorts = 0; + +// The client name to use when creating the sequencer, which is +// currently set on the first call to createSequencer. +static std::string s_clientName = "RtMidi Client"; + +// A structure to hold variables related to the ALSA API +// implementation. +struct AlsaMidiData { + snd_seq_t *seq; + unsigned int portNum; + int vport; + snd_seq_port_subscribe_t *subscription; + snd_midi_event_t *coder; + unsigned int bufferSize; + unsigned char *buffer; + pthread_t thread; + pthread_t dummy_thread_id; + unsigned long long lastTime; + int queue_id; // an input queue is needed to get timestamped events + int trigger_fds[2]; +}; + +#define PORT_TYPE( pinfo, bits ) ((snd_seq_port_info_get_capability(pinfo) & (bits)) == (bits)) + +snd_seq_t* createSequencer( const std::string& clientName ) +{ + // Set up the ALSA sequencer client. + if ( s_seq == NULL ) { + int result = snd_seq_open(&s_seq, "default", SND_SEQ_OPEN_DUPLEX, SND_SEQ_NONBLOCK); + if ( result < 0 ) { + s_seq = NULL; + } + else { + // Set client name, use current name if given string is empty. + if ( clientName != "" ) { + s_clientName = clientName; + } + snd_seq_set_client_name( s_seq, s_clientName.c_str() ); + } + } + + // Increment port count. + s_numPorts++; + + return s_seq; +} + +void freeSequencer ( void ) +{ + s_numPorts--; + if ( s_numPorts == 0 && s_seq != NULL ) { + snd_seq_close( s_seq ); + s_seq = NULL; + } +} + +//*********************************************************************// +// API: LINUX ALSA +// Class Definitions: MidiInAlsa +//*********************************************************************// + +extern "C" void *alsaMidiHandler( void *ptr ) +{ + MidiInApi::RtMidiInData *data = static_cast (ptr); + AlsaMidiData *apiData = static_cast (data->apiData); + + long nBytes; + unsigned long long time, lastTime; + bool continueSysex = false; + bool doDecode = false; + MidiInApi::MidiMessage message; + int poll_fd_count; + struct pollfd *poll_fds; + + snd_seq_event_t *ev; + int result; + apiData->bufferSize = 32; + result = snd_midi_event_new( 0, &apiData->coder ); + if ( result < 0 ) { + data->doInput = false; + std::cerr << "\nMidiInAlsa::alsaMidiHandler: error initializing MIDI event parser!\n\n"; + return 0; + } + unsigned char *buffer = (unsigned char *) malloc( apiData->bufferSize ); + if ( buffer == NULL ) { + data->doInput = false; + snd_midi_event_free( apiData->coder ); + apiData->coder = 0; + std::cerr << "\nMidiInAlsa::alsaMidiHandler: error initializing buffer memory!\n\n"; + return 0; + } + snd_midi_event_init( apiData->coder ); + snd_midi_event_no_status( apiData->coder, 1 ); // suppress running status messages + + poll_fd_count = snd_seq_poll_descriptors_count( apiData->seq, POLLIN ) + 1; + poll_fds = (struct pollfd*)alloca( poll_fd_count * sizeof( struct pollfd )); + snd_seq_poll_descriptors( apiData->seq, poll_fds + 1, poll_fd_count - 1, POLLIN ); + poll_fds[0].fd = apiData->trigger_fds[0]; + poll_fds[0].events = POLLIN; + + while ( data->doInput ) { + + if ( snd_seq_event_input_pending( apiData->seq, 1 ) == 0 ) { + // No data pending + if ( poll( poll_fds, poll_fd_count, -1) >= 0 ) { + if ( poll_fds[0].revents & POLLIN ) { + bool dummy; + int res = read( poll_fds[0].fd, &dummy, sizeof(dummy) ); + (void) res; + } + } + continue; + } + + // If here, there should be data. + result = snd_seq_event_input( apiData->seq, &ev ); + if ( result == -ENOSPC ) { + std::cerr << "\nMidiInAlsa::alsaMidiHandler: MIDI input buffer overrun!\n\n"; + continue; + } + else if ( result <= 0 ) { + std::cerr << "MidiInAlsa::alsaMidiHandler: unknown MIDI input error!\n"; + continue; + } + + // This is a bit weird, but we now have to decode an ALSA MIDI + // event (back) into MIDI bytes. We'll ignore non-MIDI types. + if ( !continueSysex ) message.bytes.clear(); + + doDecode = false; + switch ( ev->type ) { + + case SND_SEQ_EVENT_PORT_SUBSCRIBED: +#if defined(__RTMIDI_DEBUG__) + std::cout << "MidiInAlsa::alsaMidiHandler: port connection made!\n"; +#endif + break; + + case SND_SEQ_EVENT_PORT_UNSUBSCRIBED: +#if defined(__RTMIDI_DEBUG__) + std::cerr << "MidiInAlsa::alsaMidiHandler: port connection has closed!\n"; + std::cout << "sender = " << (int) ev->data.connect.sender.client << ":" + << (int) ev->data.connect.sender.port + << ", dest = " << (int) ev->data.connect.dest.client << ":" + << (int) ev->data.connect.dest.port + << std::endl; +#endif + break; + + case SND_SEQ_EVENT_QFRAME: // MIDI time code + if ( !( data->ignoreFlags & 0x02 ) ) doDecode = true; + break; + + case SND_SEQ_EVENT_TICK: // MIDI timing tick + if ( !( data->ignoreFlags & 0x02 ) ) doDecode = true; + break; + + case SND_SEQ_EVENT_SENSING: // Active sensing + if ( !( data->ignoreFlags & 0x04 ) ) doDecode = true; + break; + + case SND_SEQ_EVENT_SYSEX: + if ( (data->ignoreFlags & 0x01) ) break; + if ( ev->data.ext.len > apiData->bufferSize ) { + apiData->bufferSize = ev->data.ext.len; + free( buffer ); + buffer = (unsigned char *) malloc( apiData->bufferSize ); + if ( buffer == NULL ) { + data->doInput = false; + std::cerr << "\nMidiInAlsa::alsaMidiHandler: error resizing buffer memory!\n\n"; + break; + } + } + + default: + doDecode = true; + } + + if ( doDecode ) { + + nBytes = snd_midi_event_decode( apiData->coder, buffer, apiData->bufferSize, ev ); + if ( nBytes > 0 ) { + // The ALSA sequencer has a maximum buffer size for MIDI sysex + // events of 256 bytes. If a device sends sysex messages larger + // than this, they are segmented into 256 byte chunks. So, + // we'll watch for this and concatenate sysex chunks into a + // single sysex message if necessary. + if ( !continueSysex ) + message.bytes.assign( buffer, &buffer[nBytes] ); + else + message.bytes.insert( message.bytes.end(), buffer, &buffer[nBytes] ); + + continueSysex = ( ( ev->type == SND_SEQ_EVENT_SYSEX ) && ( message.bytes.back() != 0xF7 ) ); + if ( !continueSysex ) { + + // Calculate the time stamp: + message.timeStamp = 0.0; + + // Method 1: Use the system time. + //(void)gettimeofday(&tv, (struct timezone *)NULL); + //time = (tv.tv_sec * 1000000) + tv.tv_usec; + + // Method 2: Use the ALSA sequencer event time data. + // (thanks to Pedro Lopez-Cabanillas!). + time = ( ev->time.time.tv_sec * 1000000 ) + ( ev->time.time.tv_nsec/1000 ); + lastTime = time; + time -= apiData->lastTime; + apiData->lastTime = lastTime; + if ( data->firstMessage == true ) + data->firstMessage = false; + else + message.timeStamp = time * 0.000001; + } + else { +#if defined(__RTMIDI_DEBUG__) + std::cerr << "\nMidiInAlsa::alsaMidiHandler: event parsing error or not a MIDI event!\n\n"; +#endif + } + } + } + + snd_seq_free_event( ev ); + if ( message.bytes.size() == 0 || continueSysex ) continue; + + if ( data->usingCallback ) { + RtMidiIn::RtMidiCallback callback = (RtMidiIn::RtMidiCallback) data->userCallback; + callback( message.timeStamp, &message.bytes, data->userData ); + } + else { + // As long as we haven't reached our queue size limit, push the message. + if ( data->queue.size < data->queue.ringSize ) { + data->queue.ring[data->queue.back++] = message; + if ( data->queue.back == data->queue.ringSize ) + data->queue.back = 0; + data->queue.size++; + } + else + std::cerr << "\nMidiInAlsa: message queue limit reached!!\n\n"; + } + } + + if ( buffer ) free( buffer ); + snd_midi_event_free( apiData->coder ); + apiData->coder = 0; + apiData->thread = apiData->dummy_thread_id; + return 0; +} + +MidiInAlsa :: MidiInAlsa( const std::string clientName, unsigned int queueSizeLimit ) : MidiInApi( queueSizeLimit ) +{ + initialize( clientName ); +} + +MidiInAlsa :: ~MidiInAlsa() +{ + // Close a connection if it exists. + closePort(); + + // Shutdown the input thread. + AlsaMidiData *data = static_cast (apiData_); + if ( inputData_.doInput ) { + inputData_.doInput = false; + int res = write( data->trigger_fds[1], &inputData_.doInput, sizeof(inputData_.doInput) ); + (void) res; + if ( !pthread_equal(data->thread, data->dummy_thread_id) ) + pthread_join( data->thread, NULL ); + } + + // Cleanup. + close ( data->trigger_fds[0] ); + close ( data->trigger_fds[1] ); + if ( data->vport >= 0 ) snd_seq_delete_port( data->seq, data->vport ); +#ifndef AVOID_TIMESTAMPING + snd_seq_free_queue( data->seq, data->queue_id ); +#endif + freeSequencer(); + delete data; +} + +void MidiInAlsa :: initialize( const std::string& clientName ) +{ + snd_seq_t* seq = createSequencer( clientName ); + if ( seq == NULL ) { + s_seq = NULL; + errorString_ = "MidiInAlsa::initialize: error creating ALSA sequencer client object."; + RtMidi::error( RtError::DRIVER_ERROR, errorString_ ); + } + + // Save our api-specific connection information. + AlsaMidiData *data = (AlsaMidiData *) new AlsaMidiData; + data->seq = seq; + data->portNum = -1; + data->vport = -1; + data->subscription = 0; + data->dummy_thread_id = pthread_self(); + data->thread = data->dummy_thread_id; + data->trigger_fds[0] = -1; + data->trigger_fds[1] = -1; + apiData_ = (void *) data; + inputData_.apiData = (void *) data; + + if ( pipe(data->trigger_fds) == -1 ) { + errorString_ = "MidiInAlsa::initialize: error creating pipe objects."; + RtMidi::error( RtError::DRIVER_ERROR, errorString_ ); + } + + // Create the input queue +#ifndef AVOID_TIMESTAMPING + data->queue_id = snd_seq_alloc_named_queue(s_seq, "RtMidi Queue"); + // Set arbitrary tempo (mm=100) and resolution (240) + snd_seq_queue_tempo_t *qtempo; + snd_seq_queue_tempo_alloca(&qtempo); + snd_seq_queue_tempo_set_tempo(qtempo, 600000); + snd_seq_queue_tempo_set_ppq(qtempo, 240); + snd_seq_set_queue_tempo(data->seq, data->queue_id, qtempo); + snd_seq_drain_output(data->seq); +#endif +} + +// This function is used to count or get the pinfo structure for a given port number. +unsigned int portInfo( snd_seq_t *seq, snd_seq_port_info_t *pinfo, unsigned int type, int portNumber ) +{ + snd_seq_client_info_t *cinfo; + int client; + int count = 0; + snd_seq_client_info_alloca( &cinfo ); + + snd_seq_client_info_set_client( cinfo, -1 ); + while ( snd_seq_query_next_client( seq, cinfo ) >= 0 ) { + client = snd_seq_client_info_get_client( cinfo ); + if ( client == 0 ) continue; + // Reset query info + snd_seq_port_info_set_client( pinfo, client ); + snd_seq_port_info_set_port( pinfo, -1 ); + while ( snd_seq_query_next_port( seq, pinfo ) >= 0 ) { + unsigned int atyp = snd_seq_port_info_get_type( pinfo ); + if ( ( atyp & SND_SEQ_PORT_TYPE_MIDI_GENERIC ) == 0 ) continue; + unsigned int caps = snd_seq_port_info_get_capability( pinfo ); + if ( ( caps & type ) != type ) continue; + if ( count == portNumber ) return 1; + ++count; + } + } + + // If a negative portNumber was used, return the port count. + if ( portNumber < 0 ) return count; + return 0; +} + +unsigned int MidiInAlsa :: getPortCount() +{ + snd_seq_port_info_t *pinfo; + snd_seq_port_info_alloca( &pinfo ); + + AlsaMidiData *data = static_cast (apiData_); + return portInfo( data->seq, pinfo, SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_SUBS_READ, -1 ); +} + +std::string MidiInAlsa :: getPortName( unsigned int portNumber ) +{ + snd_seq_client_info_t *cinfo; + snd_seq_port_info_t *pinfo; + snd_seq_client_info_alloca( &cinfo ); + snd_seq_port_info_alloca( &pinfo ); + + std::string stringName; + AlsaMidiData *data = static_cast (apiData_); + if ( portInfo( data->seq, pinfo, SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_SUBS_READ, (int) portNumber ) ) { + int cnum = snd_seq_port_info_get_client( pinfo ); + snd_seq_get_any_client_info( data->seq, cnum, cinfo ); + std::ostringstream os; + os << snd_seq_client_info_get_name( cinfo ); + os << " "; // GO: These lines added to make sure devices are listed + os << snd_seq_port_info_get_client( pinfo ); // GO: with full portnames added to ensure individual device names + os << ":"; + os << snd_seq_port_info_get_port( pinfo ); + stringName = os.str(); + return stringName; + } + + // If we get here, we didn't find a match. + errorString_ = "MidiInAlsa::getPortName: error looking for port name!"; + RtMidi::error( RtError::WARNING, errorString_ ); + return stringName; + //RtMidi::error( RtError::INVALID_PARAMETER, errorString_ ); +} + +void MidiInAlsa :: openPort( unsigned int portNumber, const std::string portName ) +{ + if ( connected_ ) { + errorString_ = "MidiInAlsa::openPort: a valid connection already exists!"; + RtMidi::error( RtError::WARNING, errorString_ ); + return; + } + + unsigned int nSrc = this->getPortCount(); + if (nSrc < 1) { + errorString_ = "MidiInAlsa::openPort: no MIDI input sources found!"; + RtMidi::error( RtError::NO_DEVICES_FOUND, errorString_ ); + } + + snd_seq_port_info_t *pinfo; + snd_seq_port_info_alloca( &pinfo ); + std::ostringstream ost; + AlsaMidiData *data = static_cast (apiData_); + if ( portInfo( data->seq, pinfo, SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_SUBS_READ, (int) portNumber ) == 0 ) { + ost << "MidiInAlsa::openPort: the 'portNumber' argument (" << portNumber << ") is invalid."; + errorString_ = ost.str(); + RtMidi::error( RtError::INVALID_PARAMETER, errorString_ ); + } + + + snd_seq_addr_t sender, receiver; + sender.client = snd_seq_port_info_get_client( pinfo ); + sender.port = snd_seq_port_info_get_port( pinfo ); + receiver.client = snd_seq_client_id( data->seq ); + if ( data->vport < 0 ) { + snd_seq_port_info_set_client( pinfo, 0 ); + snd_seq_port_info_set_port( pinfo, 0 ); + snd_seq_port_info_set_capability( pinfo, + SND_SEQ_PORT_CAP_WRITE | + SND_SEQ_PORT_CAP_SUBS_WRITE ); + snd_seq_port_info_set_type( pinfo, + SND_SEQ_PORT_TYPE_MIDI_GENERIC | + SND_SEQ_PORT_TYPE_APPLICATION ); + snd_seq_port_info_set_midi_channels(pinfo, 16); +#ifndef AVOID_TIMESTAMPING + snd_seq_port_info_set_timestamping(pinfo, 1); + snd_seq_port_info_set_timestamp_real(pinfo, 1); + snd_seq_port_info_set_timestamp_queue(pinfo, data->queue_id); +#endif + snd_seq_port_info_set_name(pinfo, portName.c_str() ); + data->vport = snd_seq_create_port(data->seq, pinfo); + + if ( data->vport < 0 ) { + errorString_ = "MidiInAlsa::openPort: ALSA error creating input port."; + RtMidi::error( RtError::DRIVER_ERROR, errorString_ ); + } + } + + receiver.port = data->vport; + + if ( !data->subscription ) { + // Make subscription + if (snd_seq_port_subscribe_malloc( &data->subscription ) < 0) { + errorString_ = "MidiInAlsa::openPort: ALSA error allocation port subscription."; + RtMidi::error( RtError::DRIVER_ERROR, errorString_ ); + } + snd_seq_port_subscribe_set_sender(data->subscription, &sender); + snd_seq_port_subscribe_set_dest(data->subscription, &receiver); + if ( snd_seq_subscribe_port(data->seq, data->subscription) ) { + snd_seq_port_subscribe_free( data->subscription ); + data->subscription = 0; + errorString_ = "MidiInAlsa::openPort: ALSA error making port connection."; + RtMidi::error( RtError::DRIVER_ERROR, errorString_ ); + } + } + + if ( inputData_.doInput == false ) { + // Start the input queue +#ifndef AVOID_TIMESTAMPING + snd_seq_start_queue( data->seq, data->queue_id, NULL ); + snd_seq_drain_output( data->seq ); +#endif + // Start our MIDI input thread. + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + pthread_attr_setschedpolicy(&attr, SCHED_OTHER); + + inputData_.doInput = true; + int err = pthread_create(&data->thread, &attr, alsaMidiHandler, &inputData_); + pthread_attr_destroy(&attr); + if ( err ) { + snd_seq_unsubscribe_port( data->seq, data->subscription ); + snd_seq_port_subscribe_free( data->subscription ); + data->subscription = 0; + inputData_.doInput = false; + errorString_ = "MidiInAlsa::openPort: error starting MIDI input thread!"; + RtMidi::error( RtError::THREAD_ERROR, errorString_ ); + } + } + + connected_ = true; +} + +void MidiInAlsa :: openVirtualPort( std::string portName ) +{ + AlsaMidiData *data = static_cast (apiData_); + if ( data->vport < 0 ) { + snd_seq_port_info_t *pinfo; + snd_seq_port_info_alloca( &pinfo ); + snd_seq_port_info_set_capability( pinfo, + SND_SEQ_PORT_CAP_WRITE | + SND_SEQ_PORT_CAP_SUBS_WRITE ); + snd_seq_port_info_set_type( pinfo, + SND_SEQ_PORT_TYPE_MIDI_GENERIC | + SND_SEQ_PORT_TYPE_APPLICATION ); + snd_seq_port_info_set_midi_channels(pinfo, 16); +#ifndef AVOID_TIMESTAMPING + snd_seq_port_info_set_timestamping(pinfo, 1); + snd_seq_port_info_set_timestamp_real(pinfo, 1); + snd_seq_port_info_set_timestamp_queue(pinfo, data->queue_id); +#endif + snd_seq_port_info_set_name(pinfo, portName.c_str()); + data->vport = snd_seq_create_port(data->seq, pinfo); + + if ( data->vport < 0 ) { + errorString_ = "MidiInAlsa::openVirtualPort: ALSA error creating virtual port."; + RtMidi::error( RtError::DRIVER_ERROR, errorString_ ); + } + } + + if ( inputData_.doInput == false ) { + // Wait for old thread to stop, if still running + if ( !pthread_equal(data->thread, data->dummy_thread_id) ) + pthread_join( data->thread, NULL ); + + // Start the input queue +#ifndef AVOID_TIMESTAMPING + snd_seq_start_queue( data->seq, data->queue_id, NULL ); + snd_seq_drain_output( data->seq ); +#endif + // Start our MIDI input thread. + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + pthread_attr_setschedpolicy(&attr, SCHED_OTHER); + + inputData_.doInput = true; + int err = pthread_create(&data->thread, &attr, alsaMidiHandler, &inputData_); + pthread_attr_destroy(&attr); + if ( err ) { + if ( data->subscription ) { + snd_seq_unsubscribe_port( data->seq, data->subscription ); + snd_seq_port_subscribe_free( data->subscription ); + data->subscription = 0; + } + inputData_.doInput = false; + errorString_ = "MidiInAlsa::openPort: error starting MIDI input thread!"; + RtMidi::error( RtError::THREAD_ERROR, errorString_ ); + } + } +} + +void MidiInAlsa :: closePort( void ) +{ + AlsaMidiData *data = static_cast (apiData_); + + if ( connected_ ) { + if ( data->subscription ) { + snd_seq_unsubscribe_port( data->seq, data->subscription ); + snd_seq_port_subscribe_free( data->subscription ); + data->subscription = 0; + } + // Stop the input queue +#ifndef AVOID_TIMESTAMPING + snd_seq_stop_queue( data->seq, data->queue_id, NULL ); + snd_seq_drain_output( data->seq ); +#endif + connected_ = false; + } + + // Stop thread to avoid triggering the callback, while the port is intended to be closed + if ( inputData_.doInput ) { + inputData_.doInput = false; + int res = write( data->trigger_fds[1], &inputData_.doInput, sizeof(inputData_.doInput) ); + (void) res; + if ( !pthread_equal(data->thread, data->dummy_thread_id) ) + pthread_join( data->thread, NULL ); + } +} + +//*********************************************************************// +// API: LINUX ALSA +// Class Definitions: MidiOutAlsa +//*********************************************************************// + +MidiOutAlsa :: MidiOutAlsa( const std::string clientName ) : MidiOutApi() +{ + initialize( clientName ); +} + +MidiOutAlsa :: ~MidiOutAlsa() +{ + // Close a connection if it exists. + closePort(); + + // Cleanup. + AlsaMidiData *data = static_cast (apiData_); + if ( data->vport >= 0 ) snd_seq_delete_port( data->seq, data->vport ); + if ( data->coder ) snd_midi_event_free( data->coder ); + if ( data->buffer ) free( data->buffer ); + freeSequencer(); + delete data; +} + +void MidiOutAlsa :: initialize( const std::string& clientName ) +{ + snd_seq_t* seq = createSequencer( clientName ); + if ( seq == NULL ) { + s_seq = NULL; + errorString_ = "MidiOutAlsa::initialize: error creating ALSA sequencer client object."; + RtMidi::error( RtError::DRIVER_ERROR, errorString_ ); + } + + // Save our api-specific connection information. + AlsaMidiData *data = (AlsaMidiData *) new AlsaMidiData; + data->seq = seq; + data->portNum = -1; + data->vport = -1; + data->bufferSize = 32; + data->coder = 0; + data->buffer = 0; + int result = snd_midi_event_new( data->bufferSize, &data->coder ); + if ( result < 0 ) { + delete data; + errorString_ = "MidiOutAlsa::initialize: error initializing MIDI event parser!\n\n"; + RtMidi::error( RtError::DRIVER_ERROR, errorString_ ); + } + data->buffer = (unsigned char *) malloc( data->bufferSize ); + if ( data->buffer == NULL ) { + delete data; + errorString_ = "MidiOutAlsa::initialize: error allocating buffer memory!\n\n"; + RtMidi::error( RtError::MEMORY_ERROR, errorString_ ); + } + snd_midi_event_init( data->coder ); + apiData_ = (void *) data; +} + +unsigned int MidiOutAlsa :: getPortCount() +{ + snd_seq_port_info_t *pinfo; + snd_seq_port_info_alloca( &pinfo ); + + AlsaMidiData *data = static_cast (apiData_); + return portInfo( data->seq, pinfo, SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE, -1 ); +} + +std::string MidiOutAlsa :: getPortName( unsigned int portNumber ) +{ + snd_seq_client_info_t *cinfo; + snd_seq_port_info_t *pinfo; + snd_seq_client_info_alloca( &cinfo ); + snd_seq_port_info_alloca( &pinfo ); + + std::string stringName; + AlsaMidiData *data = static_cast (apiData_); + if ( portInfo( data->seq, pinfo, SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE, (int) portNumber ) ) { + int cnum = snd_seq_port_info_get_client(pinfo); + snd_seq_get_any_client_info( data->seq, cnum, cinfo ); + std::ostringstream os; + os << snd_seq_client_info_get_name(cinfo); + os << ":"; + os << snd_seq_port_info_get_port(pinfo); + stringName = os.str(); + return stringName; + } + + // If we get here, we didn't find a match. + errorString_ = "MidiOutAlsa::getPortName: error looking for port name!"; + //RtMidi::error( RtError::INVALID_PARAMETER, errorString_ ); + RtMidi::error( RtError::WARNING, errorString_ ); + return stringName; +} + +void MidiOutAlsa :: openPort( unsigned int portNumber, const std::string portName ) +{ + if ( connected_ ) { + errorString_ = "MidiOutAlsa::openPort: a valid connection already exists!"; + RtMidi::error( RtError::WARNING, errorString_ ); + return; + } + + unsigned int nSrc = this->getPortCount(); + if (nSrc < 1) { + errorString_ = "MidiOutAlsa::openPort: no MIDI output sources found!"; + RtMidi::error( RtError::NO_DEVICES_FOUND, errorString_ ); + } + + snd_seq_port_info_t *pinfo; + snd_seq_port_info_alloca( &pinfo ); + std::ostringstream ost; + AlsaMidiData *data = static_cast (apiData_); + if ( portInfo( data->seq, pinfo, SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE, (int) portNumber ) == 0 ) { + ost << "MidiOutAlsa::openPort: the 'portNumber' argument (" << portNumber << ") is invalid."; + errorString_ = ost.str(); + RtMidi::error( RtError::INVALID_PARAMETER, errorString_ ); + } + + snd_seq_addr_t sender, receiver; + receiver.client = snd_seq_port_info_get_client( pinfo ); + receiver.port = snd_seq_port_info_get_port( pinfo ); + sender.client = snd_seq_client_id( data->seq ); + + if ( data->vport < 0 ) { + data->vport = snd_seq_create_simple_port( data->seq, portName.c_str(), + SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_SUBS_READ, + SND_SEQ_PORT_TYPE_MIDI_GENERIC|SND_SEQ_PORT_TYPE_APPLICATION ); + if ( data->vport < 0 ) { + errorString_ = "MidiOutAlsa::openPort: ALSA error creating output port."; + RtMidi::error( RtError::DRIVER_ERROR, errorString_ ); + } + } + + sender.port = data->vport; + + // Make subscription + if (snd_seq_port_subscribe_malloc( &data->subscription ) < 0) { + snd_seq_port_subscribe_free( data->subscription ); + errorString_ = "MidiOutAlsa::openPort: error allocation port subscribtion."; + RtMidi::error( RtError::DRIVER_ERROR, errorString_ ); + } + snd_seq_port_subscribe_set_sender(data->subscription, &sender); + snd_seq_port_subscribe_set_dest(data->subscription, &receiver); + snd_seq_port_subscribe_set_time_update(data->subscription, 1); + snd_seq_port_subscribe_set_time_real(data->subscription, 1); + if ( snd_seq_subscribe_port(data->seq, data->subscription) ) { + snd_seq_port_subscribe_free( data->subscription ); + errorString_ = "MidiOutAlsa::openPort: ALSA error making port connection."; + RtMidi::error( RtError::DRIVER_ERROR, errorString_ ); + } + + connected_ = true; +} + +void MidiOutAlsa :: closePort( void ) +{ + if ( connected_ ) { + AlsaMidiData *data = static_cast (apiData_); + snd_seq_unsubscribe_port( data->seq, data->subscription ); + snd_seq_port_subscribe_free( data->subscription ); + connected_ = false; + } +} + +void MidiOutAlsa :: openVirtualPort( std::string portName ) +{ + AlsaMidiData *data = static_cast (apiData_); + if ( data->vport < 0 ) { + data->vport = snd_seq_create_simple_port( data->seq, portName.c_str(), + SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_SUBS_READ, + SND_SEQ_PORT_TYPE_MIDI_GENERIC|SND_SEQ_PORT_TYPE_APPLICATION ); + + if ( data->vport < 0 ) { + errorString_ = "MidiOutAlsa::openVirtualPort: ALSA error creating virtual port."; + RtMidi::error( RtError::DRIVER_ERROR, errorString_ ); + } + } +} + +void MidiOutAlsa :: sendMessage( std::vector *message ) +{ + int result; + AlsaMidiData *data = static_cast (apiData_); + unsigned int nBytes = message->size(); + if ( nBytes > data->bufferSize ) { + data->bufferSize = nBytes; + result = snd_midi_event_resize_buffer ( data->coder, nBytes); + if ( result != 0 ) { + errorString_ = "MidiOutAlsa::sendMessage: ALSA error resizing MIDI event buffer."; + RtMidi::error( RtError::DRIVER_ERROR, errorString_ ); + } + free (data->buffer); + data->buffer = (unsigned char *) malloc( data->bufferSize ); + if ( data->buffer == NULL ) { + errorString_ = "MidiOutAlsa::initialize: error allocating buffer memory!\n\n"; + RtMidi::error( RtError::MEMORY_ERROR, errorString_ ); + } + } + + snd_seq_event_t ev; + snd_seq_ev_clear(&ev); + snd_seq_ev_set_source(&ev, data->vport); + snd_seq_ev_set_subs(&ev); + snd_seq_ev_set_direct(&ev); + for ( unsigned int i=0; ibuffer[i] = message->at(i); + result = snd_midi_event_encode( data->coder, data->buffer, (long)nBytes, &ev ); + if ( result < (int)nBytes ) { + errorString_ = "MidiOutAlsa::sendMessage: event parsing error!"; + RtMidi::error( RtError::WARNING, errorString_ ); + return; + } + + // Send the event. + result = snd_seq_event_output(data->seq, &ev); + if ( result < 0 ) { + errorString_ = "MidiOutAlsa::sendMessage: error sending MIDI message to port."; + RtMidi::error( RtError::WARNING, errorString_ ); + } + snd_seq_drain_output(data->seq); +} + +#endif // __LINUX_ALSA__ + + +//*********************************************************************// +// API: Windows Multimedia Library (MM) +//*********************************************************************// + +// API information deciphered from: +// - http://msdn.microsoft.com/library/default.asp?url=/library/en-us/multimed/htm/_win32_midi_reference.asp + +// Thanks to Jean-Baptiste Berruchon for the sysex code. + +#if defined(__WINDOWS_MM__) + +// The Windows MM API is based on the use of a callback function for +// MIDI input. We convert the system specific time stamps to delta +// time values. + +// Windows MM MIDI header files. +#include +#include + +#define RT_SYSEX_BUFFER_SIZE 1024 +#define RT_SYSEX_BUFFER_COUNT 4 + +// A structure to hold variables related to the CoreMIDI API +// implementation. +struct WinMidiData { + HMIDIIN inHandle; // Handle to Midi Input Device + HMIDIOUT outHandle; // Handle to Midi Output Device + DWORD lastTime; + MidiInApi::MidiMessage message; + LPMIDIHDR sysexBuffer[RT_SYSEX_BUFFER_COUNT]; +}; + +//*********************************************************************// +// API: Windows MM +// Class Definitions: MidiInWinMM +//*********************************************************************// + +static void CALLBACK midiInputCallback( HMIDIIN hmin, + UINT inputStatus, + DWORD_PTR instancePtr, + DWORD_PTR midiMessage, + DWORD timestamp ) +{ + if ( inputStatus != MIM_DATA && inputStatus != MIM_LONGDATA && inputStatus != MIM_LONGERROR ) return; + + //MidiInApi::RtMidiInData *data = static_cast (instancePtr); + MidiInApi::RtMidiInData *data = (MidiInApi::RtMidiInData *)instancePtr; + WinMidiData *apiData = static_cast (data->apiData); + + // Calculate time stamp. + if ( data->firstMessage == true ) { + apiData->message.timeStamp = 0.0; + data->firstMessage = false; + } + else apiData->message.timeStamp = (double) ( timestamp - apiData->lastTime ) * 0.001; + apiData->lastTime = timestamp; + + if ( inputStatus == MIM_DATA ) { // Channel or system message + + // Make sure the first byte is a status byte. + unsigned char status = (unsigned char) (midiMessage & 0x000000FF); + if ( !(status & 0x80) ) return; + + // Determine the number of bytes in the MIDI message. + unsigned short nBytes = 1; + if ( status < 0xC0 ) nBytes = 3; + else if ( status < 0xE0 ) nBytes = 2; + else if ( status < 0xF0 ) nBytes = 3; + else if ( status == 0xF1 ) { + if ( data->ignoreFlags & 0x02 ) return; + else nBytes = 2; + } + else if ( status == 0xF2 ) nBytes = 3; + else if ( status == 0xF3 ) nBytes = 2; + else if ( status == 0xF8 && (data->ignoreFlags & 0x02) ) { + // A MIDI timing tick message and we're ignoring it. + return; + } + else if ( status == 0xFE && (data->ignoreFlags & 0x04) ) { + // A MIDI active sensing message and we're ignoring it. + return; + } + + // Copy bytes to our MIDI message. + unsigned char *ptr = (unsigned char *) &midiMessage; + for ( int i=0; imessage.bytes.push_back( *ptr++ ); + } + else { // Sysex message ( MIM_LONGDATA or MIM_LONGERROR ) + MIDIHDR *sysex = ( MIDIHDR *) midiMessage; + if ( !( data->ignoreFlags & 0x01 ) && inputStatus != MIM_LONGERROR ) { + // Sysex message and we're not ignoring it + for ( int i=0; i<(int)sysex->dwBytesRecorded; ++i ) + apiData->message.bytes.push_back( sysex->lpData[i] ); + } + + // The WinMM API requires that the sysex buffer be requeued after + // input of each sysex message. Even if we are ignoring sysex + // messages, we still need to requeue the buffer in case the user + // decides to not ignore sysex messages in the future. However, + // it seems that WinMM calls this function with an empty sysex + // buffer when an application closes and in this case, we should + // avoid requeueing it, else the computer suddenly reboots after + // one or two minutes. + if ( apiData->sysexBuffer[sysex->dwUser]->dwBytesRecorded > 0 ) { + //if ( sysex->dwBytesRecorded > 0 ) { + MMRESULT result = midiInAddBuffer( apiData->inHandle, apiData->sysexBuffer[sysex->dwUser], sizeof(MIDIHDR) ); + if ( result != MMSYSERR_NOERROR ) + std::cerr << "\nRtMidiIn::midiInputCallback: error sending sysex to Midi device!!\n\n"; + + if ( data->ignoreFlags & 0x01 ) return; + } + else return; + } + + if ( data->usingCallback ) { + RtMidiIn::RtMidiCallback callback = (RtMidiIn::RtMidiCallback) data->userCallback; + callback( apiData->message.timeStamp, &apiData->message.bytes, data->userData ); + } + else { + // As long as we haven't reached our queue size limit, push the message. + if ( data->queue.size < data->queue.ringSize ) { + data->queue.ring[data->queue.back++] = apiData->message; + if ( data->queue.back == data->queue.ringSize ) + data->queue.back = 0; + data->queue.size++; + } + else + std::cerr << "\nRtMidiIn: message queue limit reached!!\n\n"; + } + + // Clear the vector for the next input message. + apiData->message.bytes.clear(); +} + +MidiInWinMM :: MidiInWinMM( const std::string clientName, unsigned int queueSizeLimit ) : MidiInApi( queueSizeLimit ) +{ + initialize( clientName ); +} + +MidiInWinMM :: ~MidiInWinMM() +{ + // Close a connection if it exists. + closePort(); + + // Cleanup. + WinMidiData *data = static_cast (apiData_); + delete data; +} + +void MidiInWinMM :: initialize( const std::string& /*clientName*/ ) +{ + // We'll issue a warning here if no devices are available but not + // throw an error since the user can plugin something later. + unsigned int nDevices = midiInGetNumDevs(); + if ( nDevices == 0 ) { + errorString_ = "MidiInWinMM::initialize: no MIDI input devices currently available."; + RtMidi::error( RtError::WARNING, errorString_ ); + } + + // Save our api-specific connection information. + WinMidiData *data = (WinMidiData *) new WinMidiData; + apiData_ = (void *) data; + inputData_.apiData = (void *) data; + data->message.bytes.clear(); // needs to be empty for first input message +} + +void MidiInWinMM :: openPort( unsigned int portNumber, const std::string /*portName*/ ) +{ + if ( connected_ ) { + errorString_ = "MidiInWinMM::openPort: a valid connection already exists!"; + RtMidi::error( RtError::WARNING, errorString_ ); + return; + } + + unsigned int nDevices = midiInGetNumDevs(); + if (nDevices == 0) { + errorString_ = "MidiInWinMM::openPort: no MIDI input sources found!"; + RtMidi::error( RtError::NO_DEVICES_FOUND, errorString_ ); + } + + std::ostringstream ost; + if ( portNumber >= nDevices ) { + ost << "MidiInWinMM::openPort: the 'portNumber' argument (" << portNumber << ") is invalid."; + errorString_ = ost.str(); + RtMidi::error( RtError::INVALID_PARAMETER, errorString_ ); + } + + WinMidiData *data = static_cast (apiData_); + MMRESULT result = midiInOpen( &data->inHandle, + portNumber, + (DWORD_PTR)&midiInputCallback, + (DWORD_PTR)&inputData_, + CALLBACK_FUNCTION ); + if ( result != MMSYSERR_NOERROR ) { + errorString_ = "MidiInWinMM::openPort: error creating Windows MM MIDI input port."; + RtMidi::error( RtError::DRIVER_ERROR, errorString_ ); + } + + // Allocate and init the sysex buffers. + for ( int i=0; isysexBuffer[i] = (MIDIHDR*) new char[ sizeof(MIDIHDR) ]; + data->sysexBuffer[i]->lpData = new char[ RT_SYSEX_BUFFER_SIZE ]; + data->sysexBuffer[i]->dwBufferLength = RT_SYSEX_BUFFER_SIZE; + data->sysexBuffer[i]->dwUser = i; // We use the dwUser parameter as buffer indicator + data->sysexBuffer[i]->dwFlags = 0; + + result = midiInPrepareHeader( data->inHandle, data->sysexBuffer[i], sizeof(MIDIHDR) ); + if ( result != MMSYSERR_NOERROR ) { + midiInClose( data->inHandle ); + errorString_ = "MidiInWinMM::openPort: error starting Windows MM MIDI input port (PrepareHeader)."; + RtMidi::error( RtError::DRIVER_ERROR, errorString_ ); + } + + // Register the buffer. + result = midiInAddBuffer( data->inHandle, data->sysexBuffer[i], sizeof(MIDIHDR) ); + if ( result != MMSYSERR_NOERROR ) { + midiInClose( data->inHandle ); + errorString_ = "MidiInWinMM::openPort: error starting Windows MM MIDI input port (AddBuffer)."; + RtMidi::error( RtError::DRIVER_ERROR, errorString_ ); + } + } + + result = midiInStart( data->inHandle ); + if ( result != MMSYSERR_NOERROR ) { + midiInClose( data->inHandle ); + errorString_ = "MidiInWinMM::openPort: error starting Windows MM MIDI input port."; + RtMidi::error( RtError::DRIVER_ERROR, errorString_ ); + } + + connected_ = true; +} + +void MidiInWinMM :: openVirtualPort( std::string portName ) +{ + // This function cannot be implemented for the Windows MM MIDI API. + errorString_ = "MidiInWinMM::openVirtualPort: cannot be implemented in Windows MM MIDI API!"; + RtMidi::error( RtError::WARNING, errorString_ ); +} + +void MidiInWinMM :: closePort( void ) +{ + if ( connected_ ) { + WinMidiData *data = static_cast (apiData_); + midiInReset( data->inHandle ); + midiInStop( data->inHandle ); + + for ( int i=0; iinHandle, data->sysexBuffer[i], sizeof(MIDIHDR)); + delete [] data->sysexBuffer[i]->lpData; + delete [] data->sysexBuffer[i]; + if ( result != MMSYSERR_NOERROR ) { + midiInClose( data->inHandle ); + errorString_ = "MidiInWinMM::openPort: error closing Windows MM MIDI input port (midiInUnprepareHeader)."; + RtMidi::error( RtError::DRIVER_ERROR, errorString_ ); + } + } + + midiInClose( data->inHandle ); + connected_ = false; + } +} + +unsigned int MidiInWinMM :: getPortCount() +{ + return midiInGetNumDevs(); +} + +std::string MidiInWinMM :: getPortName( unsigned int portNumber ) +{ + std::string stringName; + unsigned int nDevices = midiInGetNumDevs(); + if ( portNumber >= nDevices ) { + std::ostringstream ost; + ost << "MidiInWinMM::getPortName: the 'portNumber' argument (" << portNumber << ") is invalid."; + errorString_ = ost.str(); + //RtMidi::error( RtError::INVALID_PARAMETER, errorString_ ); + RtMidi::error( RtError::WARNING, errorString_ ); + return stringName; + } + + MIDIINCAPS deviceCaps; + midiInGetDevCaps( portNumber, &deviceCaps, sizeof(MIDIINCAPS)); + +#if defined( UNICODE ) || defined( _UNICODE ) + int length = WideCharToMultiByte(CP_UTF8, 0, deviceCaps.szPname, -1, NULL, 0, NULL, NULL); + stringName.assign( length, 0 ); + length = WideCharToMultiByte(CP_UTF8, 0, deviceCaps.szPname, wcslen(deviceCaps.szPname), &stringName[0], length, NULL, NULL); +#else + stringName = std::string( deviceCaps.szPname ); +#endif + + // Next lines added to add the portNumber to the name so that + // the device's names are sure to be listed with individual names + // even when they have the same brand name + std::ostringstream os; + os << " "; + os << portNumber; + stringName += os.str(); + + return stringName; +} + +//*********************************************************************// +// API: Windows MM +// Class Definitions: MidiOutWinMM +//*********************************************************************// + +MidiOutWinMM :: MidiOutWinMM( const std::string clientName ) : MidiOutApi() +{ + initialize( clientName ); +} + +MidiOutWinMM :: ~MidiOutWinMM() +{ + // Close a connection if it exists. + closePort(); + + // Cleanup. + WinMidiData *data = static_cast (apiData_); + delete data; +} + +void MidiOutWinMM :: initialize( const std::string& /*clientName*/ ) +{ + // We'll issue a warning here if no devices are available but not + // throw an error since the user can plug something in later. + unsigned int nDevices = midiOutGetNumDevs(); + if ( nDevices == 0 ) { + errorString_ = "MidiOutWinMM::initialize: no MIDI output devices currently available."; + RtMidi::error( RtError::WARNING, errorString_ ); + } + + // Save our api-specific connection information. + WinMidiData *data = (WinMidiData *) new WinMidiData; + apiData_ = (void *) data; +} + +unsigned int MidiOutWinMM :: getPortCount() +{ + return midiOutGetNumDevs(); +} + +std::string MidiOutWinMM :: getPortName( unsigned int portNumber ) +{ + std::string stringName; + unsigned int nDevices = midiOutGetNumDevs(); + if ( portNumber >= nDevices ) { + std::ostringstream ost; + ost << "MidiOutWinMM::getPortName: the 'portNumber' argument (" << portNumber << ") is invalid."; + errorString_ = ost.str(); + //RtMidi::error( RtError::INVALID_PARAMETER, errorString_ ); + RtMidi::error( RtError::WARNING, errorString_ ); + return stringName; + } + + MIDIOUTCAPS deviceCaps; + midiOutGetDevCaps( portNumber, &deviceCaps, sizeof(MIDIOUTCAPS)); + +#if defined( UNICODE ) || defined( _UNICODE ) + int length = WideCharToMultiByte(CP_UTF8, 0, deviceCaps.szPname, -1, NULL, 0, NULL, NULL); + stringName.assign( length, 0 ); + length = WideCharToMultiByte(CP_UTF8, 0, deviceCaps.szPname, wcslen(deviceCaps.szPname), &stringName[0], length, NULL, NULL); +#else + stringName = std::string( deviceCaps.szPname ); +#endif + + return stringName; +} + +void MidiOutWinMM :: openPort( unsigned int portNumber, const std::string /*portName*/ ) +{ + if ( connected_ ) { + errorString_ = "MidiOutWinMM::openPort: a valid connection already exists!"; + RtMidi::error( RtError::WARNING, errorString_ ); + return; + } + + unsigned int nDevices = midiOutGetNumDevs(); + if (nDevices < 1) { + errorString_ = "MidiOutWinMM::openPort: no MIDI output destinations found!"; + RtMidi::error( RtError::NO_DEVICES_FOUND, errorString_ ); + } + + std::ostringstream ost; + if ( portNumber >= nDevices ) { + ost << "MidiOutWinMM::openPort: the 'portNumber' argument (" << portNumber << ") is invalid."; + errorString_ = ost.str(); + RtMidi::error( RtError::INVALID_PARAMETER, errorString_ ); + } + + WinMidiData *data = static_cast (apiData_); + MMRESULT result = midiOutOpen( &data->outHandle, + portNumber, + (DWORD)NULL, + (DWORD)NULL, + CALLBACK_NULL ); + if ( result != MMSYSERR_NOERROR ) { + errorString_ = "MidiOutWinMM::openPort: error creating Windows MM MIDI output port."; + RtMidi::error( RtError::DRIVER_ERROR, errorString_ ); + } + + connected_ = true; +} + +void MidiOutWinMM :: closePort( void ) +{ + if ( connected_ ) { + WinMidiData *data = static_cast (apiData_); + midiOutReset( data->outHandle ); + midiOutClose( data->outHandle ); + connected_ = false; + } +} + +void MidiOutWinMM :: openVirtualPort( std::string portName ) +{ + // This function cannot be implemented for the Windows MM MIDI API. + errorString_ = "MidiOutWinMM::openVirtualPort: cannot be implemented in Windows MM MIDI API!"; + RtMidi::error( RtError::WARNING, errorString_ ); +} + +void MidiOutWinMM :: sendMessage( std::vector *message ) +{ + unsigned int nBytes = static_cast(message->size()); + if ( nBytes == 0 ) { + errorString_ = "MidiOutWinMM::sendMessage: message argument is empty!"; + RtMidi::error( RtError::WARNING, errorString_ ); + return; + } + + MMRESULT result; + WinMidiData *data = static_cast (apiData_); + if ( message->at(0) == 0xF0 ) { // Sysex message + + // Allocate buffer for sysex data. + char *buffer = (char *) malloc( nBytes ); + if ( buffer == NULL ) { + errorString_ = "MidiOutWinMM::sendMessage: error allocating sysex message memory!"; + RtMidi::error( RtError::MEMORY_ERROR, errorString_ ); + } + + // Copy data to buffer. + for ( unsigned int i=0; iat(i); + + // Create and prepare MIDIHDR structure. + MIDIHDR sysex; + sysex.lpData = (LPSTR) buffer; + sysex.dwBufferLength = nBytes; + sysex.dwFlags = 0; + result = midiOutPrepareHeader( data->outHandle, &sysex, sizeof(MIDIHDR) ); + if ( result != MMSYSERR_NOERROR ) { + free( buffer ); + errorString_ = "MidiOutWinMM::sendMessage: error preparing sysex header."; + RtMidi::error( RtError::DRIVER_ERROR, errorString_ ); + } + + // Send the message. + result = midiOutLongMsg( data->outHandle, &sysex, sizeof(MIDIHDR) ); + if ( result != MMSYSERR_NOERROR ) { + free( buffer ); + errorString_ = "MidiOutWinMM::sendMessage: error sending sysex message."; + RtMidi::error( RtError::DRIVER_ERROR, errorString_ ); + } + + // Unprepare the buffer and MIDIHDR. + while ( MIDIERR_STILLPLAYING == midiOutUnprepareHeader( data->outHandle, &sysex, sizeof (MIDIHDR) ) ) Sleep( 1 ); + free( buffer ); + + } + else { // Channel or system message. + + // Make sure the message size isn't too big. + if ( nBytes > 3 ) { + errorString_ = "MidiOutWinMM::sendMessage: message size is greater than 3 bytes (and not sysex)!"; + RtMidi::error( RtError::WARNING, errorString_ ); + return; + } + + // Pack MIDI bytes into double word. + DWORD packet; + unsigned char *ptr = (unsigned char *) &packet; + for ( unsigned int i=0; iat(i); + ++ptr; + } + + // Send the message immediately. + result = midiOutShortMsg( data->outHandle, packet ); + if ( result != MMSYSERR_NOERROR ) { + errorString_ = "MidiOutWinMM::sendMessage: error sending MIDI message."; + RtMidi::error( RtError::DRIVER_ERROR, errorString_ ); + } + } +} + +#endif // __WINDOWS_MM__ + +// *********************************************************************// +// API: WINDOWS Kernel Streaming +// +// Written by Sebastien Alaiwan, 2012. +// +// NOTE BY GARY: much of the KS-specific code below probably should go in a separate file. +// +// *********************************************************************// + +#if defined(__WINDOWS_KS__) + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ks.h" +#include "ksmedia.h" + +#define INSTANTIATE_GUID(a) GUID const a = { STATIC_ ## a } + +INSTANTIATE_GUID(GUID_NULL); +INSTANTIATE_GUID(KSPROPSETID_Pin); +INSTANTIATE_GUID(KSPROPSETID_Connection); +INSTANTIATE_GUID(KSPROPSETID_Topology); +INSTANTIATE_GUID(KSINTERFACESETID_Standard); +INSTANTIATE_GUID(KSMEDIUMSETID_Standard); +INSTANTIATE_GUID(KSDATAFORMAT_TYPE_MUSIC); +INSTANTIATE_GUID(KSDATAFORMAT_SUBTYPE_MIDI); +INSTANTIATE_GUID(KSDATAFORMAT_SPECIFIER_NONE); + +#undef INSTANTIATE_GUID + +typedef std::basic_string tstring; + +inline bool IsValid(HANDLE handle) +{ + return handle != NULL && handle != INVALID_HANDLE_VALUE; +} + +class ComException : public std::runtime_error +{ +private: + static std::string MakeString(std::string const& s, HRESULT hr) + { + std::stringstream ss; + ss << "(error 0x" << std::hex << hr << ")"; + return s + ss.str(); + } + +public: + ComException(std::string const& s, HRESULT hr) : + std::runtime_error(MakeString(s, hr)) + { + } +}; + +template +class CKsEnumFilters +{ +public: + ~CKsEnumFilters() + { + DestroyLists(); + } + + void EnumFilters(GUID const* categories, size_t numCategories) + { + DestroyLists(); + + if (categories == 0) + { + printf ("Error: CKsEnumFilters: invalid argument\n"); + assert(0); + } + // Get a handle to the device set specified by the guid + HDEVINFO hDevInfo = ::SetupDiGetClassDevs(&categories[0], NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); + if (!IsValid(hDevInfo)) + { + printf ("Error: CKsEnumFilters: no devices found"); + assert (0); + } + + // Loop through members of the set and get details for each + for (int iClassMember=0;;iClassMember++) { + { + SP_DEVICE_INTERFACE_DATA DID; + DID.cbSize = sizeof(DID); + DID.Reserved = 0; + + bool fRes = ::SetupDiEnumDeviceInterfaces(hDevInfo, NULL, &categories[0], iClassMember, &DID); + if (!fRes) + break; + + // Get filter friendly name + HKEY hRegKey = ::SetupDiOpenDeviceInterfaceRegKey(hDevInfo, &DID, 0, KEY_READ); + if (hRegKey == INVALID_HANDLE_VALUE) + { + assert(0); + printf "CKsEnumFilters: interface has no registry\n"); + } + char friendlyName[256]; + DWORD dwSize = sizeof friendlyName; + LONG lval = ::RegQueryValueEx(hRegKey, TEXT("FriendlyName"), NULL, NULL, (LPBYTE)friendlyName, &dwSize); + ::RegCloseKey(hRegKey); + if (lval != ERROR_SUCCESS) + { + assert(0); + printf ("CKsEnumFilters: interface has no friendly name"); + } + // Get details for the device registered in this class + DWORD const cbItfDetails = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA) + MAX_PATH * sizeof(WCHAR); + std::vector buffer(cbItfDetails); + + SP_DEVICE_INTERFACE_DETAIL_DATA* pDevInterfaceDetails = reinterpret_cast(&buffer[0]); + pDevInterfaceDetails->cbSize = sizeof(*pDevInterfaceDetails); + + SP_DEVINFO_DATA DevInfoData; + DevInfoData.cbSize = sizeof(DevInfoData); + DevInfoData.Reserved = 0; + + fRes = ::SetupDiGetDeviceInterfaceDetail(hDevInfo, &DID, pDevInterfaceDetails, cbItfDetails, NULL, &DevInfoData); + if (!fRes) + { + printf("CKsEnumFilters: could not get interface details"); + assert(0); + } + // check additional category guids which may (or may not) have been supplied + for (size_t i=1; i < numCategories; ++i) { + SP_DEVICE_INTERFACE_DATA DIDAlias; + DIDAlias.cbSize = sizeof(DIDAlias); + DIDAlias.Reserved = 0; + + fRes = ::SetupDiGetDeviceInterfaceAlias(hDevInfo, &DID, &categories[i], &DIDAlias); + if (!fRes) + { + printf("CKsEnumFilters: could not get interface alias"); + assert(0); + } + // Check if the this interface alias is enabled. + if (!DIDAlias.Flags || (DIDAlias.Flags & SPINT_REMOVED)) + { + printf("CKsEnumFilters: interface alias is not enabled"); + assert(0); + } + } + + std::auto_ptr pFilter(new TFilterType(pDevInterfaceDetails->DevicePath, friendlyName)); + + pFilter->Instantiate(); + pFilter->FindMidiPins(); + pFilter->Validate(); + + m_Filters.push_back(pFilter.release()); + } + } + + ::SetupDiDestroyDeviceInfoList(hDevInfo); + } + +private: + void DestroyLists() + { + for (size_t i=0;i < m_Filters.size();++i) + delete m_Filters[i]; + m_Filters.clear(); + } + +public: + // TODO: make this private. + std::vector m_Filters; +}; + +class CKsObject +{ +public: + CKsObject(HANDLE handle) : m_handle(handle) + { + } + +protected: + HANDLE m_handle; + + void SetProperty(REFGUID guidPropertySet, ULONG nProperty, void* pvValue, ULONG cbValue) + { + KSPROPERTY ksProperty; + memset(&ksProperty, 0, sizeof ksProperty); + ksProperty.Set = guidPropertySet; + ksProperty.Id = nProperty; + ksProperty.Flags = KSPROPERTY_TYPE_SET; + + HRESULT hr = DeviceIoControlKsProperty(ksProperty, pvValue, cbValue); + if (FAILED(hr)) + { + printf("CKsObject::SetProperty: could not set property"); + exit(0); + } + } + +private: + + HRESULT DeviceIoControlKsProperty(KSPROPERTY& ksProperty, void* pvValue, ULONG cbValue) + { + ULONG ulReturned; + return ::DeviceIoControl( + m_handle, + IOCTL_KS_PROPERTY, + &ksProperty, + sizeof(ksProperty), + pvValue, + cbValue, + &ulReturned, + NULL); + } +}; + +class CKsPin; + +class CKsFilter : public CKsObject +{ + friend class CKsPin; + +public: + CKsFilter(tstring const& name, std::string const& sFriendlyName); + virtual ~CKsFilter(); + + virtual void Instantiate(); + + template + T GetPinProperty(ULONG nPinId, ULONG nProperty) + { + ULONG ulReturned = 0; + T value; + + KSP_PIN ksPProp; + ksPProp.Property.Set = KSPROPSETID_Pin; + ksPProp.Property.Id = nProperty; + ksPProp.Property.Flags = KSPROPERTY_TYPE_GET; + ksPProp.PinId = nPinId; + ksPProp.Reserved = 0; + + HRESULT hr = ::DeviceIoControl( + m_handle, + IOCTL_KS_PROPERTY, + &ksPProp, + sizeof(KSP_PIN), + &value, + sizeof(value), + &ulReturned, + NULL); + if (FAILED(hr)) + { + printf("CKsFilter::GetPinProperty: failed to retrieve property"); + exit(0); + } + + return value; + } + + void GetPinPropertyMulti(ULONG nPinId, REFGUID guidPropertySet, ULONG nProperty, PKSMULTIPLE_ITEM* ppKsMultipleItem) + { + HRESULT hr; + + KSP_PIN ksPProp; + ksPProp.Property.Set = guidPropertySet; + ksPProp.Property.Id = nProperty; + ksPProp.Property.Flags = KSPROPERTY_TYPE_GET; + ksPProp.PinId = nPinId; + ksPProp.Reserved = 0; + + ULONG cbMultipleItem = 0; + hr = ::DeviceIoControl(m_handle, + IOCTL_KS_PROPERTY, + &ksPProp.Property, + sizeof(KSP_PIN), + NULL, + 0, + &cbMultipleItem, + NULL); + if (FAILED(hr)) + { + printf("CKsFilter::GetPinPropertyMulti: cannot get property"); + exit(0); + } + + *ppKsMultipleItem = (PKSMULTIPLE_ITEM) new BYTE[cbMultipleItem]; + + ULONG ulReturned = 0; + hr = ::DeviceIoControl( + m_handle, + IOCTL_KS_PROPERTY, + &ksPProp, + sizeof(KSP_PIN), + (PVOID)*ppKsMultipleItem, + cbMultipleItem, + &ulReturned, + NULL); + if (FAILED(hr)) + { + printf("CKsFilter::GetPinPropertyMulti: cannot get property"); + exit(0); + } + } + + std::string const& GetFriendlyName() const + { + return m_sFriendlyName; + } + +protected: + + std::vector m_Pins; // this list owns the pins. + + std::vector m_RenderPins; + std::vector m_CapturePins; + +private: + std::string const m_sFriendlyName; // friendly name eg "Virus TI Synth" + tstring const m_sName; // Filter path, eg "\\?\usb#vid_133e&pid_0815...\vtimidi02" +}; + +class CKsPin : public CKsObject +{ +public: + CKsPin(CKsFilter* pFilter, ULONG nId); + virtual ~CKsPin(); + + virtual void Instantiate(); + + void ClosePin(); + + void SetState(KSSTATE ksState); + + void WriteData(KSSTREAM_HEADER* pKSSTREAM_HEADER, OVERLAPPED* pOVERLAPPED); + void ReadData(KSSTREAM_HEADER* pKSSTREAM_HEADER, OVERLAPPED* pOVERLAPPED); + + KSPIN_DATAFLOW GetDataFlow() const + { + return m_DataFlow; + } + + bool IsSink() const + { + return m_Communication == KSPIN_COMMUNICATION_SINK + || m_Communication == KSPIN_COMMUNICATION_BOTH; + } + + +protected: + PKSPIN_CONNECT m_pKsPinConnect; // creation parameters of pin + CKsFilter* const m_pFilter; + + ULONG m_cInterfaces; + PKSIDENTIFIER m_pInterfaces; + PKSMULTIPLE_ITEM m_pmiInterfaces; + + ULONG m_cMediums; + PKSIDENTIFIER m_pMediums; + PKSMULTIPLE_ITEM m_pmiMediums; + + ULONG m_cDataRanges; + PKSDATARANGE m_pDataRanges; + PKSMULTIPLE_ITEM m_pmiDataRanges; + + KSPIN_DATAFLOW m_DataFlow; + KSPIN_COMMUNICATION m_Communication; +}; + +CKsFilter::CKsFilter(tstring const& sName, std::string const& sFriendlyName) : + CKsObject(INVALID_HANDLE_VALUE), + m_sFriendlyName(sFriendlyName), + m_sName(sName) +{ + if (sName.empty()) + { + printf("CKsFilter::CKsFilter: name can't be empty"); + assert(0); + } +} + +CKsFilter::~CKsFilter() +{ + for (size_t i=0;i < m_Pins.size();++i) + delete m_Pins[i]; + + if (IsValid(m_handle)) + ::CloseHandle(m_handle); +} + +void CKsFilter::Instantiate() +{ + m_handle = CreateFile( + m_sName.c_str(), + GENERIC_READ | GENERIC_WRITE, + 0, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, + NULL); + + if (!IsValid(m_handle)) + { + DWORD const dwError = GetLastError(); + throw ComException("CKsFilter::Instantiate: can't open driver", HRESULT_FROM_WIN32(dwError)); + } +} + +CKsPin::CKsPin(CKsFilter* pFilter, ULONG PinId) : + CKsObject(INVALID_HANDLE_VALUE), + m_pKsPinConnect(NULL), + m_pFilter(pFilter) +{ + m_Communication = m_pFilter->GetPinProperty(PinId, KSPROPERTY_PIN_COMMUNICATION); + m_DataFlow = m_pFilter->GetPinProperty(PinId, KSPROPERTY_PIN_DATAFLOW); + + // Interfaces + m_pFilter->GetPinPropertyMulti( + PinId, + KSPROPSETID_Pin, + KSPROPERTY_PIN_INTERFACES, + &m_pmiInterfaces); + + m_cInterfaces = m_pmiInterfaces->Count; + m_pInterfaces = (PKSPIN_INTERFACE)(m_pmiInterfaces + 1); + + // Mediums + m_pFilter->GetPinPropertyMulti( + PinId, + KSPROPSETID_Pin, + KSPROPERTY_PIN_MEDIUMS, + &m_pmiMediums); + + m_cMediums = m_pmiMediums->Count; + m_pMediums = (PKSPIN_MEDIUM)(m_pmiMediums + 1); + + // Data ranges + m_pFilter->GetPinPropertyMulti( + PinId, + KSPROPSETID_Pin, + KSPROPERTY_PIN_DATARANGES, + &m_pmiDataRanges); + + m_cDataRanges = m_pmiDataRanges->Count; + m_pDataRanges = (PKSDATARANGE)(m_pmiDataRanges + 1); +} + +CKsPin::~CKsPin() +{ + ClosePin(); + + delete[] (BYTE*)m_pKsPinConnect; + delete[] (BYTE*)m_pmiDataRanges; + delete[] (BYTE*)m_pmiInterfaces; + delete[] (BYTE*)m_pmiMediums; +} + +void CKsPin::ClosePin() +{ + if (IsValid(m_handle)) { + SetState(KSSTATE_STOP); + ::CloseHandle(m_handle); + } + m_handle = INVALID_HANDLE_VALUE; +} + +void CKsPin::SetState(KSSTATE ksState) +{ + SetProperty(KSPROPSETID_Connection, KSPROPERTY_CONNECTION_STATE, &ksState, sizeof(ksState)); +} + +void CKsPin::Instantiate() +{ + if (!m_pKsPinConnect) + { + printf("CKsPin::Instanciate: abstract pin"); + assert(0); + } + DWORD const dwResult = KsCreatePin(m_pFilter->m_handle, m_pKsPinConnect, GENERIC_WRITE | GENERIC_READ, &m_handle); + if (dwResult != ERROR_SUCCESS) + throw ComException("CKsMidiCapFilter::CreateRenderPin: Pin instanciation failed", HRESULT_FROM_WIN32(dwResult)); +} + +void CKsPin::WriteData(KSSTREAM_HEADER* pKSSTREAM_HEADER, OVERLAPPED* pOVERLAPPED) +{ + DWORD cbWritten; + BOOL fRes = ::DeviceIoControl( + m_handle, + IOCTL_KS_WRITE_STREAM, + NULL, + 0, + pKSSTREAM_HEADER, + pKSSTREAM_HEADER->Size, + &cbWritten, + pOVERLAPPED); + if (!fRes) { + DWORD const dwError = GetLastError(); + if (dwError != ERROR_IO_PENDING) + throw ComException("CKsPin::WriteData: DeviceIoControl failed", HRESULT_FROM_WIN32(dwError)); + } +} + +void CKsPin::ReadData(KSSTREAM_HEADER* pKSSTREAM_HEADER, OVERLAPPED* pOVERLAPPED) +{ + DWORD cbReturned; + BOOL fRes = ::DeviceIoControl( + m_handle, + IOCTL_KS_READ_STREAM, + NULL, + 0, + pKSSTREAM_HEADER, + pKSSTREAM_HEADER->Size, + &cbReturned, + pOVERLAPPED); + if (!fRes) { + DWORD const dwError = GetLastError(); + if (dwError != ERROR_IO_PENDING) + throw ComException("CKsPin::ReadData: DeviceIoControl failed", HRESULT_FROM_WIN32(dwError)); + } +} + +class CKsMidiFilter : public CKsFilter +{ +public: + void FindMidiPins(); + +protected: + CKsMidiFilter(tstring const& sPath, std::string const& sFriendlyName); +}; + +class CKsMidiPin : public CKsPin +{ +public: + CKsMidiPin(CKsFilter* pFilter, ULONG nId); +}; + +class CKsMidiRenFilter : public CKsMidiFilter +{ +public: + CKsMidiRenFilter(tstring const& sPath, std::string const& sFriendlyName); + CKsMidiPin* CreateRenderPin(); + + void Validate() + { + if (m_RenderPins.empty()) + { + printf("Could not find a MIDI render pin"); + assert(0); + } + } +}; + +class CKsMidiCapFilter : public CKsMidiFilter +{ +public: + CKsMidiCapFilter(tstring const& sPath, std::string const& sFriendlyName); + CKsMidiPin* CreateCapturePin(); + + void Validate() + { + if (m_CapturePins.empty()) + { + assert(0); + printf("Could not find a MIDI capture pin"); + } + } +}; + +CKsMidiFilter::CKsMidiFilter(tstring const& sPath, std::string const& sFriendlyName) : + CKsFilter(sPath, sFriendlyName) +{ +} + +void CKsMidiFilter::FindMidiPins() +{ + ULONG numPins = GetPinProperty(0, KSPROPERTY_PIN_CTYPES); + + for (ULONG iPin = 0; iPin < numPins; ++iPin) { + { + KSPIN_COMMUNICATION com = GetPinProperty(iPin, KSPROPERTY_PIN_COMMUNICATION); + if (com != KSPIN_COMMUNICATION_SINK && com != KSPIN_COMMUNICATION_BOTH) + { + printf("Unknown pin communication value"); + assert(0); + } + + m_Pins.push_back(new CKsMidiPin(this, iPin)); + } + + } + + m_RenderPins.clear(); + m_CapturePins.clear(); + + for (size_t i = 0; i < m_Pins.size(); ++i) { + CKsPin* const pPin = m_Pins[i]; + + if (pPin->IsSink()) { + if (pPin->GetDataFlow() == KSPIN_DATAFLOW_IN) + m_RenderPins.push_back(pPin); + else + m_CapturePins.push_back(pPin); + } + } + + if (m_RenderPins.empty() && m_CapturePins.empty()) + { + printf("No valid pins found on the filter."); + assert(0); + + } +} + +CKsMidiRenFilter::CKsMidiRenFilter(tstring const& sPath, std::string const& sFriendlyName) : + CKsMidiFilter(sPath, sFriendlyName) +{ +} + +CKsMidiPin* CKsMidiRenFilter::CreateRenderPin() +{ + if (m_RenderPins.empty()) + { + printf("Could not find a MIDI render pin"); + assert(0); + } + + CKsMidiPin* pPin = (CKsMidiPin*)m_RenderPins[0]; + pPin->Instantiate(); + return pPin; +} + +CKsMidiCapFilter::CKsMidiCapFilter(tstring const& sPath, std::string const& sFriendlyName) : + CKsMidiFilter(sPath, sFriendlyName) +{ +} + +CKsMidiPin* CKsMidiCapFilter::CreateCapturePin() +{ + if (m_CapturePins.empty()) + { + printf("Could not find a MIDI capture pin"); + assert(0); + } + CKsMidiPin* pPin = (CKsMidiPin*)m_CapturePins[0]; + pPin->Instantiate(); + return pPin; +} + +CKsMidiPin::CKsMidiPin(CKsFilter* pFilter, ULONG nId) : + CKsPin(pFilter, nId) +{ + DWORD const cbPinCreateSize = sizeof(KSPIN_CONNECT) + sizeof(KSDATAFORMAT); + m_pKsPinConnect = (PKSPIN_CONNECT) new BYTE[cbPinCreateSize]; + + m_pKsPinConnect->Interface.Set = KSINTERFACESETID_Standard; + m_pKsPinConnect->Interface.Id = KSINTERFACE_STANDARD_STREAMING; + m_pKsPinConnect->Interface.Flags = 0; + m_pKsPinConnect->Medium.Set = KSMEDIUMSETID_Standard; + m_pKsPinConnect->Medium.Id = KSMEDIUM_TYPE_ANYINSTANCE; + m_pKsPinConnect->Medium.Flags = 0; + m_pKsPinConnect->PinId = nId; + m_pKsPinConnect->PinToHandle = NULL; + m_pKsPinConnect->Priority.PriorityClass = KSPRIORITY_NORMAL; + m_pKsPinConnect->Priority.PrioritySubClass = 1; + + // point m_pDataFormat to just after the pConnect struct + KSDATAFORMAT* m_pDataFormat = (KSDATAFORMAT*)(m_pKsPinConnect + 1); + m_pDataFormat->FormatSize = sizeof(KSDATAFORMAT); + m_pDataFormat->Flags = 0; + m_pDataFormat->SampleSize = 0; + m_pDataFormat->Reserved = 0; + m_pDataFormat->MajorFormat = GUID(KSDATAFORMAT_TYPE_MUSIC); + m_pDataFormat->SubFormat = GUID(KSDATAFORMAT_SUBTYPE_MIDI); + m_pDataFormat->Specifier = GUID(KSDATAFORMAT_SPECIFIER_NONE); + + bool hasStdStreamingInterface = false; + bool hasStdStreamingMedium = false; + + for ( ULONG i = 0; i < m_cInterfaces; i++ ) { + if (m_pInterfaces[i].Set == KSINTERFACESETID_Standard + && m_pInterfaces[i].Id == KSINTERFACE_STANDARD_STREAMING) + hasStdStreamingInterface = true; + } + + for (ULONG i = 0; i < m_cMediums; i++) { + if (m_pMediums[i].Set == KSMEDIUMSETID_Standard + && m_pMediums[i].Id == KSMEDIUM_STANDARD_DEVIO) + hasStdStreamingMedium = true; + } + + if (!hasStdStreamingInterface) // No standard streaming interfaces on the pin + { + printf("CKsMidiPin::CKsMidiPin: no standard streaming interface"); + assert(0); + } + + if (!hasStdStreamingMedium) // No standard streaming mediums on the pin + { + printf("CKsMidiPin::CKsMidiPin: no standard streaming medium") + assert(0); + }; + + bool hasMidiDataRange = false; + + BYTE const* pDataRangePtr = reinterpret_cast(m_pDataRanges); + + for (ULONG i = 0; i < m_cDataRanges; ++i) { + KSDATARANGE const* pDataRange = reinterpret_cast(pDataRangePtr); + + if (pDataRange->SubFormat == KSDATAFORMAT_SUBTYPE_MIDI) { + hasMidiDataRange = true; + break; + } + + pDataRangePtr += pDataRange->FormatSize; + } + + if (!hasMidiDataRange) // No MIDI dataranges on the pin + { + printf("CKsMidiPin::CKsMidiPin: no MIDI datarange"); + assert(0); + } +} + + +struct WindowsKsData +{ + WindowsKsData() : m_pPin(NULL), m_Buffer(1024), m_hInputThread(NULL) + { + memset(&overlapped, 0, sizeof(OVERLAPPED)); + m_hExitEvent = ::CreateEvent(NULL, FALSE, FALSE, NULL); + overlapped.hEvent = ::CreateEvent(NULL, FALSE, FALSE, NULL); + m_hInputThread = NULL; + } + + ~WindowsKsData() + { + ::CloseHandle(overlapped.hEvent); + ::CloseHandle(m_hExitEvent); + } + + OVERLAPPED overlapped; + CKsPin* m_pPin; + std::vector m_Buffer; + std::auto_ptr > m_pCaptureEnum; + std::auto_ptr > m_pRenderEnum; + HANDLE m_hInputThread; + HANDLE m_hExitEvent; +}; + +// *********************************************************************// +// API: WINDOWS Kernel Streaming +// Class Definitions: MidiInWinKS +// *********************************************************************// + +DWORD WINAPI midiKsInputThread(VOID* pUser) +{ + MidiInApi::RtMidiInData* data = static_cast(pUser); + WindowsKsData* apiData = static_cast(data->apiData); + + HANDLE hEvents[] = { apiData->overlapped.hEvent, apiData->m_hExitEvent }; + + while ( true ) { + KSSTREAM_HEADER packet; + memset(&packet, 0, sizeof packet); + packet.Size = sizeof(KSSTREAM_HEADER); + packet.PresentationTime.Time = 0; + packet.PresentationTime.Numerator = 1; + packet.PresentationTime.Denominator = 1; + packet.Data = &apiData->m_Buffer[0]; + packet.DataUsed = 0; + packet.FrameExtent = apiData->m_Buffer.size(); + apiData->m_pPin->ReadData(&packet, &apiData->overlapped); + + DWORD dwRet = ::WaitForMultipleObjects(2, hEvents, FALSE, INFINITE); + + if ( dwRet == WAIT_OBJECT_0 ) { + // parse packet + unsigned char* pData = (unsigned char*)packet.Data; + unsigned int iOffset = 0; + + while ( iOffset < packet.DataUsed ) { + KSMUSICFORMAT* pMusic = (KSMUSICFORMAT*)&pData[iOffset]; + iOffset += sizeof(KSMUSICFORMAT); + + MidiInApi::MidiMessage message; + message.timeStamp = 0; + for(size_t i=0;i < pMusic->ByteCount;++i) + message.bytes.push_back(pData[iOffset+i]); + + if ( data->usingCallback ) { + RtMidiIn::RtMidiCallback callback = (RtMidiIn::RtMidiCallback)data->userCallback; + callback(message.timeStamp, &message.bytes, data->userData); + } + else { + // As long as we haven't reached our queue size limit, push the message. + if ( data->queue.size < data->queue.ringSize ) { + data->queue.ring[data->queue.back++] = message; + if(data->queue.back == data->queue.ringSize) + data->queue.back = 0; + data->queue.size++; + } + else + std::cerr << "\nRtMidiIn: message queue limit reached!!\n\n"; + } + + iOffset += pMusic->ByteCount; + + // re-align on 32 bits + if ( iOffset % 4 != 0 ) + iOffset += (4 - iOffset % 4); + } + } + else + break; + } + return 0; +} + +MidiInWinKS :: MidiInWinKS( const std::string clientName, unsigned int queueSizeLimit ) : MidiInApi( queueSizeLimit ) +{ + initialize( clientName ); +} + +void MidiInWinKS :: initialize( const std::string& clientName ) +{ + WindowsKsData* data = new WindowsKsData; + apiData_ = (void*)data; + inputData_.apiData = data; + + GUID const aguidEnumCats[] = + { + { STATIC_KSCATEGORY_AUDIO }, { STATIC_KSCATEGORY_CAPTURE } + }; + data->m_pCaptureEnum.reset(new CKsEnumFilters ); + data->m_pCaptureEnum->EnumFilters(aguidEnumCats, 2); +} + +MidiInWinKS :: ~MidiInWinKS() +{ + WindowsKsData* data = static_cast(apiData_); + { + if ( data->m_pPin ) + closePort(); + } + + delete data; +} + +void MidiInWinKS :: openPort( unsigned int portNumber, const std::string portName ) +{ + WindowsKsData* data = static_cast(apiData_); + + if ( portNumber < 0 || portNumber >= data->m_pCaptureEnum->m_Filters.size() ) { + std::stringstream ost; + ost << "MidiInWinKS::openPort: the 'portNumber' argument (" << portNumber << ") is invalid."; + errorString_ = ost.str(); + RtMidi::error( RtError::WARNING, errorString_ ); + } + + CKsMidiCapFilter* pFilter = data->m_pCaptureEnum->m_Filters[portNumber]; + data->m_pPin = pFilter->CreateCapturePin(); + + if ( data->m_pPin == NULL ) { + std::stringstream ost; + ost << "MidiInWinKS::openPort: KS error opening port (could not create pin)"; + errorString_ = ost.str(); + RtMidi::error( RtError::WARNING, errorString_ ); + } + + data->m_pPin->SetState(KSSTATE_RUN); + + DWORD threadId; + data->m_hInputThread = ::CreateThread(NULL, 0, &midiKsInputThread, &inputData_, 0, &threadId); + if ( data->m_hInputThread == NULL ) { + std::stringstream ost; + ost << "MidiInWinKS::initialize: Could not create input thread : Windows error " << GetLastError() << std::endl;; + errorString_ = ost.str(); + RtMidi::error( RtError::WARNING, errorString_ ); + } + + connected_ = true; +} + +void MidiInWinKS :: openVirtualPort( const std::string portName ) +{ + // This function cannot be implemented for the Windows KS MIDI API. + errorString_ = "MidiInWinKS::openVirtualPort: cannot be implemented in Windows KS MIDI API!"; + RtMidi::error( RtError::WARNING, errorString_ ); +} + +unsigned int MidiInWinKS :: getPortCount() +{ + WindowsKsData* data = static_cast(apiData_); + return (unsigned int)data->m_pCaptureEnum->m_Filters.size(); +} + +std::string MidiInWinKS :: getPortName(unsigned int portNumber) +{ + WindowsKsData* data = static_cast(apiData_); + + if(portNumber < 0 || portNumber >= data->m_pCaptureEnum->m_Filters.size()) { + std::stringstream ost; + ost << "MidiInWinKS::getPortName: the 'portNumber' argument (" << portNumber << ") is invalid."; + errorString_ = ost.str(); + RtMidi::error( RtError::WARNING, errorString_ ); + } + + CKsMidiCapFilter* pFilter = data->m_pCaptureEnum->m_Filters[portNumber]; + return pFilter->GetFriendlyName(); +} + +void MidiInWinKS :: closePort() +{ + WindowsKsData* data = static_cast(apiData_); + connected_ = false; + + if(data->m_hInputThread) { + ::SignalObjectAndWait(data->m_hExitEvent, data->m_hInputThread, INFINITE, FALSE); + ::CloseHandle(data->m_hInputThread); + } + + if(data->m_pPin) { + data->m_pPin->SetState(KSSTATE_PAUSE); + data->m_pPin->SetState(KSSTATE_STOP); + data->m_pPin->ClosePin(); + data->m_pPin = NULL; + } +} + +// *********************************************************************// +// API: WINDOWS Kernel Streaming +// Class Definitions: MidiOutWinKS +// *********************************************************************// + +MidiOutWinKS :: MidiOutWinKS( const std::string clientName ) : MidiOutApi() +{ + initialize( clientName ); +} + +void MidiOutWinKS :: initialize( const std::string& clientName ) +{ + WindowsKsData* data = new WindowsKsData; + + data->m_pPin = NULL; + data->m_pRenderEnum.reset(new CKsEnumFilters ); + GUID const aguidEnumCats[] = + { + { STATIC_KSCATEGORY_AUDIO }, { STATIC_KSCATEGORY_RENDER } + }; + data->m_pRenderEnum->EnumFilters(aguidEnumCats, 2); + + apiData_ = (void*)data; +} + +MidiOutWinKS :: ~MidiOutWinKS() +{ + // Close a connection if it exists. + closePort(); + + // Cleanup. + WindowsKsData* data = static_cast(apiData_); + delete data; +} + +void MidiOutWinKS :: openPort( unsigned int portNumber, const std::string portName ) +{ + WindowsKsData* data = static_cast(apiData_); + + if(portNumber < 0 || portNumber >= data->m_pRenderEnum->m_Filters.size()) { + std::stringstream ost; + ost << "MidiOutWinKS::openPort: the 'portNumber' argument (" << portNumber << ") is invalid."; + errorString_ = ost.str(); + RtMidi::error( RtError::WARNING, errorString_ ); + } + + CKsMidiRenFilter* pFilter = data->m_pRenderEnum->m_Filters[portNumber]; + data->m_pPin = pFilter->CreateRenderPin(); + + if(data->m_pPin == NULL) { + std::stringstream ost; + ost << "MidiOutWinKS::openPort: KS error opening port (could not create pin)"; + errorString_ = ost.str(); + RtMidi::error( RtError::WARNING, errorString_ ); + } + + data->m_pPin->SetState(KSSTATE_RUN); + connected_ = true; +} + +void MidiOutWinKS :: openVirtualPort( const std::string portName ) +{ + // This function cannot be implemented for the Windows KS MIDI API. + errorString_ = "MidiOutWinKS::openVirtualPort: cannot be implemented in Windows KS MIDI API!"; + RtMidi::error( RtError::WARNING, errorString_ ); +} + +unsigned int MidiOutWinKS :: getPortCount() +{ + WindowsKsData* data = static_cast(apiData_); + + return (unsigned int)data->m_pRenderEnum->m_Filters.size(); +} + +std::string MidiOutWinKS :: getPortName( unsigned int portNumber ) +{ + WindowsKsData* data = static_cast(apiData_); + + if ( portNumber < 0 || portNumber >= data->m_pRenderEnum->m_Filters.size() ) { + std::stringstream ost; + ost << "MidiOutWinKS::getPortName: the 'portNumber' argument (" << portNumber << ") is invalid."; + errorString_ = ost.str(); + RtMidi::error( RtError::WARNING, errorString_ ); + } + + CKsMidiRenFilter* pFilter = data->m_pRenderEnum->m_Filters[portNumber]; + return pFilter->GetFriendlyName(); +} + +void MidiOutWinKS :: closePort() +{ + WindowsKsData* data = static_cast(apiData_); + connected_ = false; + + if ( data->m_pPin ) { + data->m_pPin->SetState(KSSTATE_PAUSE); + data->m_pPin->SetState(KSSTATE_STOP); + data->m_pPin->ClosePin(); + data->m_pPin = NULL; + } +} + +void MidiOutWinKS :: sendMessage(std::vector* pMessage) +{ + std::vector const& msg = *pMessage; + WindowsKsData* data = static_cast(apiData_); + size_t iNumMidiBytes = msg.size(); + size_t pos = 0; + + // write header + KSMUSICFORMAT* pKsMusicFormat = reinterpret_cast(&data->m_Buffer[pos]); + pKsMusicFormat->TimeDeltaMs = 0; + pKsMusicFormat->ByteCount = iNumMidiBytes; + pos += sizeof(KSMUSICFORMAT); + + // write MIDI bytes + if ( pos + iNumMidiBytes > data->m_Buffer.size() ) { + std::stringstream ost; + ost << "KsMidiInput::Write: MIDI buffer too small. Required " << pos + iNumMidiBytes << " bytes, only has " << data->m_Buffer.size(); + errorString_ = ost.str(); + RtMidi::error( RtError::WARNING, errorString_ ); + } + + if ( data->m_pPin == NULL ) { + std::stringstream ost; + ost << "MidiOutWinKS::sendMessage: port is not open"; + errorString_ = ost.str(); + RtMidi::error( RtError::WARNING, errorString_ ); + } + + memcpy(&data->m_Buffer[pos], &msg[0], iNumMidiBytes); + pos += iNumMidiBytes; + + KSSTREAM_HEADER packet; + memset(&packet, 0, sizeof packet); + packet.Size = sizeof(packet); + packet.PresentationTime.Time = 0; + packet.PresentationTime.Numerator = 1; + packet.PresentationTime.Denominator = 1; + packet.Data = const_cast(&data->m_Buffer[0]); + packet.DataUsed = ((pos+3)/4)*4; + packet.FrameExtent = data->m_Buffer.size(); + + data->m_pPin->WriteData(&packet, NULL); +} + +#endif // __WINDOWS_KS__ + +//*********************************************************************// +// API: UNIX JACK +// +// Written primarily by Alexander Svetalkin, with updates for delta +// time by Gary Scavone, April 2011. +// +// *********************************************************************// + +#if defined(__UNIX_JACK__) + +// JACK header files +#include +#include +#include + +#define JACK_RINGBUFFER_SIZE 16384 // Default size for ringbuffer + +struct JackMidiData { + jack_client_t *client; + jack_port_t *port; + jack_ringbuffer_t *buffSize; + jack_ringbuffer_t *buffMessage; + jack_time_t lastTime; + MidiInApi :: RtMidiInData *rtMidiIn; + }; + +//*********************************************************************// +// API: JACK +// Class Definitions: MidiInJack +//*********************************************************************// + +int jackProcessIn( jack_nframes_t nframes, void *arg ) +{ + JackMidiData *jData = (JackMidiData *) arg; + MidiInApi :: RtMidiInData *rtData = jData->rtMidiIn; + jack_midi_event_t event; + jack_time_t long long time; + + // Is port created? + if ( jData->port == NULL ) return 0; + void *buff = jack_port_get_buffer( jData->port, nframes ); + + // We have midi events in buffer + int evCount = jack_midi_get_event_count( buff ); + if ( evCount > 0 ) { + MidiInApi::MidiMessage message; + message.bytes.clear(); + + jack_midi_event_get( &event, buff, 0 ); + + for (unsigned int i = 0; i < event.size; i++ ) + message.bytes.push_back( event.buffer[i] ); + + // Compute the delta time. + time = jack_get_time(); + if ( rtData->firstMessage == true ) + rtData->firstMessage = false; + else + message.timeStamp = ( time - jData->lastTime ) * 0.000001; + + jData->lastTime = time; + + if ( !rtData->continueSysex ) { + if ( rtData->usingCallback ) { + RtMidiIn::RtMidiCallback callback = (RtMidiIn::RtMidiCallback) rtData->userCallback; + callback( message.timeStamp, &message.bytes, rtData->userData ); + } + else { + // As long as we haven't reached our queue size limit, push the message. + if ( rtData->queue.size < rtData->queue.ringSize ) { + rtData->queue.ring[rtData->queue.back++] = message; + if ( rtData->queue.back == rtData->queue.ringSize ) + rtData->queue.back = 0; + rtData->queue.size++; + } + else + std::cerr << "\nMidiInJack: message queue limit reached!!\n\n"; + } + } + } + + return 0; +} + +MidiInJack :: MidiInJack( const std::string clientName, unsigned int queueSizeLimit ) : MidiInApi( queueSizeLimit ) +{ + initialize( clientName ); +} + +void MidiInJack :: initialize( const std::string& clientName ) +{ + JackMidiData *data = new JackMidiData; + apiData_ = (void *) data; + + // Initialize JACK client + if (( data->client = jack_client_open( clientName.c_str(), JackNullOption, NULL )) == 0) { + errorString_ = "MidiInJack::initialize: JACK server not running?"; + RtMidi::error( RtError::DRIVER_ERROR, errorString_ ); + return; + } + + data->rtMidiIn = &inputData_; + data->port = NULL; + + jack_set_process_callback( data->client, jackProcessIn, data ); + jack_activate( data->client ); +} + +MidiInJack :: ~MidiInJack() +{ + JackMidiData *data = static_cast (apiData_); + closePort(); + + jack_client_close( data->client ); +} + +void MidiInJack :: openPort( unsigned int portNumber, const std::string portName ) +{ + JackMidiData *data = static_cast (apiData_); + + // Creating new port + if ( data->port == NULL) + data->port = jack_port_register( data->client, portName.c_str(), + JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0 ); + + if ( data->port == NULL) { + errorString_ = "MidiInJack::openVirtualPort: JACK error creating virtual port"; + RtMidi::error( RtError::DRIVER_ERROR, errorString_ ); + } + + // Connecting to the output + std::string name = getPortName( portNumber ); + jack_connect( data->client, name.c_str(), jack_port_name( data->port ) ); +} + +void MidiInJack :: openVirtualPort( const std::string portName ) +{ + JackMidiData *data = static_cast (apiData_); + + if ( data->port == NULL ) + data->port = jack_port_register( data->client, portName.c_str(), + JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0 ); + + if ( data->port == NULL ) { + errorString_ = "MidiInJack::openVirtualPort: JACK error creating virtual port"; + RtMidi::error( RtError::DRIVER_ERROR, errorString_ ); + } +} + +unsigned int MidiInJack :: getPortCount() +{ + int count = 0; + JackMidiData *data = static_cast (apiData_); + + // List of available ports + const char **ports = jack_get_ports( data->client, NULL, JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput ); + + if ( ports == NULL ) return 0; + while ( ports[count] != NULL ) + count++; + + free( ports ); + + return count; +} + +std::string MidiInJack :: getPortName( unsigned int portNumber ) +{ + JackMidiData *data = static_cast (apiData_); + std::ostringstream ost; + std::string retStr(""); + + // List of available ports + const char **ports = jack_get_ports( data->client, NULL, + JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput ); + + // Check port validity + if ( ports == NULL ) { + errorString_ = "MidiInJack::getPortName: no ports available!"; + RtMidi::error( RtError::WARNING, errorString_ ); + return retStr; + } + + if ( ports[portNumber] == NULL ) { + ost << "MidiInJack::getPortName: the 'portNumber' argument (" << portNumber << ") is invalid."; + errorString_ = ost.str(); + RtMidi::error( RtError::WARNING, errorString_ ); + } + else retStr.assign( ports[portNumber] ); + + free( ports ); + + return retStr; +} + +void MidiInJack :: closePort() +{ + JackMidiData *data = static_cast (apiData_); + + if ( data->port == NULL ) return; + jack_port_unregister( data->client, data->port ); + data->port = NULL; +} + +//*********************************************************************// +// API: JACK +// Class Definitions: MidiOutJack +//*********************************************************************// + +// Jack process callback +int jackProcessOut( jack_nframes_t nframes, void *arg ) +{ + JackMidiData *data = (JackMidiData *) arg; + jack_midi_data_t *midiData; + int space; + + // Is port created? + if ( data->port == NULL ) return 0; + + void *buff = jack_port_get_buffer( data->port, nframes ); + jack_midi_clear_buffer( buff ); + + while ( jack_ringbuffer_read_space( data->buffSize ) > 0 ) { + jack_ringbuffer_read( data->buffSize, (char *) &space, (size_t) sizeof(space) ); + midiData = jack_midi_event_reserve( buff, 0, space ); + + jack_ringbuffer_read( data->buffMessage, (char *) midiData, (size_t) space ); + } + + return 0; +} + +MidiOutJack :: MidiOutJack( const std::string clientName ) : MidiOutApi() +{ + initialize( clientName ); +} + +void MidiOutJack :: initialize( const std::string& clientName ) +{ + JackMidiData *data = new JackMidiData; + + data->port = NULL; + + // Initialize JACK client + if (( data->client = jack_client_open( clientName.c_str(), JackNullOption, NULL )) == 0) { + errorString_ = "MidiOutJack::initialize: JACK server not running?"; + RtMidi::error( RtError::DRIVER_ERROR, errorString_ ); + return; + } + + jack_set_process_callback( data->client, jackProcessOut, data ); + data->buffSize = jack_ringbuffer_create( JACK_RINGBUFFER_SIZE ); + data->buffMessage = jack_ringbuffer_create( JACK_RINGBUFFER_SIZE ); + jack_activate( data->client ); + + apiData_ = (void *) data; +} + +MidiOutJack :: ~MidiOutJack() +{ + JackMidiData *data = static_cast (apiData_); + closePort(); + + // Cleanup + jack_client_close( data->client ); + jack_ringbuffer_free( data->buffSize ); + jack_ringbuffer_free( data->buffMessage ); + + delete data; +} + +void MidiOutJack :: openPort( unsigned int portNumber, const std::string portName ) +{ + JackMidiData *data = static_cast (apiData_); + + // Creating new port + if ( data->port == NULL ) + data->port = jack_port_register( data->client, portName.c_str(), + JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0 ); + + if ( data->port == NULL ) { + errorString_ = "MidiOutJack::openVirtualPort: JACK error creating virtual port"; + RtMidi::error( RtError::DRIVER_ERROR, errorString_ ); + } + + // Connecting to the output + std::string name = getPortName( portNumber ); + jack_connect( data->client, jack_port_name( data->port ), name.c_str() ); +} + +void MidiOutJack :: openVirtualPort( const std::string portName ) +{ + JackMidiData *data = static_cast (apiData_); + + if ( data->port == NULL ) + data->port = jack_port_register( data->client, portName.c_str(), + JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0 ); + + if ( data->port == NULL ) { + errorString_ = "MidiOutJack::openVirtualPort: JACK error creating virtual port"; + RtMidi::error( RtError::DRIVER_ERROR, errorString_ ); + } +} + +unsigned int MidiOutJack :: getPortCount() +{ + int count = 0; + JackMidiData *data = static_cast (apiData_); + + // List of available ports + const char **ports = jack_get_ports( data->client, NULL, + JACK_DEFAULT_MIDI_TYPE, JackPortIsInput ); + + if ( ports == NULL ) return 0; + while ( ports[count] != NULL ) + count++; + + free( ports ); + + return count; +} + +std::string MidiOutJack :: getPortName( unsigned int portNumber ) +{ + JackMidiData *data = static_cast (apiData_); + std::ostringstream ost; + std::string retStr(""); + + // List of available ports + const char **ports = jack_get_ports( data->client, NULL, + JACK_DEFAULT_MIDI_TYPE, JackPortIsInput ); + + // Check port validity + if ( ports == NULL) { + errorString_ = "MidiOutJack::getPortName: no ports available!"; + RtMidi::error( RtError::WARNING, errorString_ ); + return retStr; + } + + if ( ports[portNumber] == NULL) { + ost << "MidiOutJack::getPortName: the 'portNumber' argument (" << portNumber << ") is invalid."; + errorString_ = ost.str(); + RtMidi::error( RtError::WARNING, errorString_ ); + } + else retStr.assign( ports[portNumber] ); + + free( ports ); + + return retStr; +} + +void MidiOutJack :: closePort() +{ + JackMidiData *data = static_cast (apiData_); + + if ( data->port == NULL ) return; + jack_port_unregister( data->client, data->port ); + data->port = NULL; +} + +void MidiOutJack :: sendMessage( std::vector *message ) +{ + int nBytes = message->size(); + JackMidiData *data = static_cast (apiData_); + + // Write full message to buffer + jack_ringbuffer_write( data->buffMessage, ( const char * ) &( *message )[0], + message->size() ); + jack_ringbuffer_write( data->buffSize, ( char * ) &nBytes, sizeof( nBytes ) ); +} + +#endif // __UNIX_JACK__ \ No newline at end of file diff --git a/examples/ThirdPartyLibs/midi/RtMidi.h b/examples/ThirdPartyLibs/midi/RtMidi.h new file mode 100644 index 000000000..66eb4fc3c --- /dev/null +++ b/examples/ThirdPartyLibs/midi/RtMidi.h @@ -0,0 +1,675 @@ +/**********************************************************************/ +/*! \class RtMidi + \brief An abstract base class for realtime MIDI input/output. + + This class implements some common functionality for the realtime + MIDI input/output subclasses RtMidiIn and RtMidiOut. + + RtMidi WWW site: http://music.mcgill.ca/~gary/rtmidi/ + + RtMidi: realtime MIDI i/o C++ classes + Copyright (c) 2003-2012 Gary P. Scavone + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation files + (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of the Software, + and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + Any person wishing to distribute modifications to the Software is + asked to send the modifications to the original developer so that + they can be incorporated into the canonical version. This is, + however, not a binding provision of this license. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ +/**********************************************************************/ + +/*! + \file RtMidi.h + */ + +// RtMidi: Version 2.0.1 + +#ifndef RTMIDI_H +#define RTMIDI_H + +#include "RtError.h" +#include +#include + +class RtMidi +{ + public: + + //! MIDI API specifier arguments. + enum Api { + UNSPECIFIED, /*!< Search for a working compiled API. */ + MACOSX_CORE, /*!< Macintosh OS-X Core Midi API. */ + LINUX_ALSA, /*!< The Advanced Linux Sound Architecture API. */ + UNIX_JACK, /*!< The Jack Low-Latency MIDI Server API. */ + WINDOWS_MM, /*!< The Microsoft Multimedia MIDI API. */ + WINDOWS_KS, /*!< The Microsoft Kernel Streaming MIDI API. */ + RTMIDI_DUMMY /*!< A compilable but non-functional API. */ + }; + + //! A static function to determine the available compiled MIDI APIs. + /*! + The values returned in the std::vector can be compared against + the enumerated list values. Note that there can be more than one + API compiled for certain operating systems. + */ + static void getCompiledApi( std::vector &apis ); + + //! Pure virtual openPort() function. + virtual void openPort( unsigned int portNumber = 0, const std::string portName = std::string( "RtMidi" ) ) = 0; + + //! Pure virtual openVirtualPort() function. + virtual void openVirtualPort( const std::string portName = std::string( "RtMidi" ) ) = 0; + + //! Pure virtual getPortCount() function. + virtual unsigned int getPortCount() = 0; + + //! Pure virtual getPortName() function. + virtual std::string getPortName( unsigned int portNumber = 0 ) = 0; + + //! Pure virtual closePort() function. + virtual void closePort( void ) = 0; + + //! A basic error reporting function for RtMidi classes. + static void error( RtError::Type type, std::string errorString ); + + protected: + + RtMidi() {}; + virtual ~RtMidi() {}; +}; + +/**********************************************************************/ +/*! \class RtMidiIn + \brief A realtime MIDI input class. + + This class provides a common, platform-independent API for + realtime MIDI input. It allows access to a single MIDI input + port. Incoming MIDI messages are either saved to a queue for + retrieval using the getMessage() function or immediately passed to + a user-specified callback function. Create multiple instances of + this class to connect to more than one MIDI device at the same + time. With the OS-X and Linux ALSA MIDI APIs, it is also possible + to open a virtual input port to which other MIDI software clients + can connect. + + by Gary P. Scavone, 2003-2012. +*/ +/**********************************************************************/ + +// **************************************************************** // +// +// RtMidiIn and RtMidiOut class declarations. +// +// RtMidiIn / RtMidiOut are "controllers" used to select an available +// MIDI input or output interface. They present common APIs for the +// user to call but all functionality is implemented by the classes +// MidiInApi, MidiOutApi and their subclasses. RtMidiIn and RtMidiOut +// each create an instance of a MidiInApi or MidiOutApi subclass based +// on the user's API choice. If no choice is made, they attempt to +// make a "logical" API selection. +// +// **************************************************************** // + +class MidiInApi; +class MidiOutApi; + +class RtMidiIn : public RtMidi +{ + public: + + //! User callback function type definition. + typedef void (*RtMidiCallback)( double timeStamp, std::vector *message, void *userData); + + //! Default constructor that allows an optional api, client name and queue size. + /*! + An assert will be fired if a MIDI system initialization + error occurs. The queue size defines the maximum number of + messages that can be held in the MIDI queue (when not using a + callback function). If the queue size limit is reached, + incoming messages will be ignored. + + If no API argument is specified and multiple API support has been + compiled, the default order of use is JACK, ALSA (Linux) and CORE, + Jack (OS-X). + */ + RtMidiIn( RtMidi::Api api=UNSPECIFIED, + const std::string clientName = std::string( "RtMidi Input Client"), + unsigned int queueSizeLimit = 100 ); + + //! If a MIDI connection is still open, it will be closed by the destructor. + ~RtMidiIn ( void ); + + //! Returns the MIDI API specifier for the current instance of RtMidiIn. + RtMidi::Api getCurrentApi( void ); + + //! Open a MIDI input connection. + /*! + An optional port number greater than 0 can be specified. + Otherwise, the default or first port found is opened. + */ + void openPort( unsigned int portNumber = 0, const std::string portName = std::string( "RtMidi Input" ) ); + + //! Create a virtual input port, with optional name, to allow software connections (OS X and ALSA only). + /*! + This function creates a virtual MIDI input port to which other + software applications can connect. This type of functionality + is currently only supported by the Macintosh OS-X and Linux ALSA + APIs (the function does nothing for the other APIs). + */ + void openVirtualPort( const std::string portName = std::string( "RtMidi Input" ) ); + + //! Set a callback function to be invoked for incoming MIDI messages. + /*! + The callback function will be called whenever an incoming MIDI + message is received. While not absolutely necessary, it is best + to set the callback function before opening a MIDI port to avoid + leaving some messages in the queue. + */ + void setCallback( RtMidiCallback callback, void *userData = 0 ); + + //! Cancel use of the current callback function (if one exists). + /*! + Subsequent incoming MIDI messages will be written to the queue + and can be retrieved with the \e getMessage function. + */ + void cancelCallback(); + + //! Close an open MIDI connection (if one exists). + void closePort( void ); + + //! Return the number of available MIDI input ports. + unsigned int getPortCount(); + + //! Return a string identifier for the specified MIDI input port number. + /*! + An empty string is returned if an invalid port specifier is provided. + */ + std::string getPortName( unsigned int portNumber = 0 ); + + //! Specify whether certain MIDI message types should be queued or ignored during input. + /*! + o By default, MIDI timing and active sensing messages are ignored + during message input because of their relative high data rates. + MIDI sysex messages are ignored by default as well. Variable + values of "true" imply that the respective message type will be + ignored. + */ + void ignoreTypes( bool midiSysex = true, bool midiTime = true, bool midiSense = true ); + + //! Fill the user-provided vector with the data bytes for the next available MIDI message in the input queue and return the event delta-time in seconds. + /*! + This function returns immediately whether a new message is + available or not. A valid message is indicated by a non-zero + vector size. An assert is fired if an error occurs during + message retrieval or an input connection was not previously + established. + */ + double getMessage( std::vector *message ); + + protected: + void openMidiApi( RtMidi::Api api, const std::string clientName, unsigned int queueSizeLimit ); + MidiInApi *rtapi_; + +}; + +/**********************************************************************/ +/*! \class RtMidiOut + \brief A realtime MIDI output class. + + This class provides a common, platform-independent API for MIDI + output. It allows one to probe available MIDI output ports, to + connect to one such port, and to send MIDI bytes immediately over + the connection. Create multiple instances of this class to + connect to more than one MIDI device at the same time. With the + OS-X and Linux ALSA MIDI APIs, it is also possible to open a + virtual port to which other MIDI software clients can connect. + + by Gary P. Scavone, 2003-2012. +*/ +/**********************************************************************/ + +class RtMidiOut : public RtMidi +{ + public: + + //! Default constructor that allows an optional client name. + /*! + An exception will be thrown if a MIDI system initialization error occurs. + + If no API argument is specified and multiple API support has been + compiled, the default order of use is JACK, ALSA (Linux) and CORE, + Jack (OS-X). + */ + RtMidiOut( RtMidi::Api api=UNSPECIFIED, + const std::string clientName = std::string( "RtMidi Output Client") ); + + //! The destructor closes any open MIDI connections. + ~RtMidiOut( void ); + + //! Returns the MIDI API specifier for the current instance of RtMidiOut. + RtMidi::Api getCurrentApi( void ); + + //! Open a MIDI output connection. + /*! + An optional port number greater than 0 can be specified. + Otherwise, the default or first port found is opened. An + exception is thrown if an error occurs while attempting to make + the port connection. + */ + void openPort( unsigned int portNumber = 0, const std::string portName = std::string( "RtMidi Output" ) ); + + //! Close an open MIDI connection (if one exists). + void closePort( void ); + + //! Create a virtual output port, with optional name, to allow software connections (OS X and ALSA only). + /*! + This function creates a virtual MIDI output port to which other + software applications can connect. This type of functionality + is currently only supported by the Macintosh OS-X and Linux ALSA + APIs (the function does nothing with the other APIs). An + exception is thrown if an error occurs while attempting to create + the virtual port. + */ + void openVirtualPort( const std::string portName = std::string( "RtMidi Output" ) ); + + //! Return the number of available MIDI output ports. + unsigned int getPortCount( void ); + + //! Return a string identifier for the specified MIDI port type and number. + /*! + An empty string is returned if an invalid port specifier is provided. + */ + std::string getPortName( unsigned int portNumber = 0 ); + + //! Immediately send a single message out an open MIDI output port. + /*! + An exception is thrown if an error occurs during output or an + output connection was not previously established. + */ + void sendMessage( std::vector *message ); + + protected: + void openMidiApi( RtMidi::Api api, const std::string clientName ); + MidiOutApi *rtapi_; +}; + + +// **************************************************************** // +// +// MidiInApi / MidiOutApi class declarations. +// +// Subclasses of MidiInApi and MidiOutApi contain all API- and +// OS-specific code necessary to fully implement the RtMidi API. +// +// Note that MidiInApi and MidiOutApi are abstract base classes and +// cannot be explicitly instantiated. RtMidiIn and RtMidiOut will +// create instances of a MidiInApi or MidiOutApi subclass. +// +// **************************************************************** // + +class MidiInApi +{ + public: + + MidiInApi( unsigned int queueSizeLimit ); + virtual ~MidiInApi( void ); + virtual RtMidi::Api getCurrentApi( void ) = 0; + virtual void openPort( unsigned int portNumber, const std::string portName ) = 0; + virtual void openVirtualPort( const std::string portName ) = 0; + virtual void closePort( void ) = 0; + void setCallback( RtMidiIn::RtMidiCallback callback, void *userData ); + void cancelCallback( void ); + virtual unsigned int getPortCount( void ) = 0; + virtual std::string getPortName( unsigned int portNumber ) = 0; + virtual void ignoreTypes( bool midiSysex, bool midiTime, bool midiSense ); + double getMessage( std::vector *message ); + + // A MIDI structure used internally by the class to store incoming + // messages. Each message represents one and only one MIDI message. + struct MidiMessage { + std::vector bytes; + double timeStamp; + + // Default constructor. + MidiMessage() + :bytes(0), timeStamp(0.0) {} + }; + + struct MidiQueue { + unsigned int front; + unsigned int back; + unsigned int size; + unsigned int ringSize; + MidiMessage *ring; + + // Default constructor. + MidiQueue() + :front(0), back(0), size(0), ringSize(0) {} + }; + + // The RtMidiInData structure is used to pass private class data to + // the MIDI input handling function or thread. + struct RtMidiInData { + MidiQueue queue; + MidiMessage message; + unsigned char ignoreFlags; + bool doInput; + bool firstMessage; + void *apiData; + bool usingCallback; + void *userCallback; + void *userData; + bool continueSysex; + + // Default constructor. + RtMidiInData() + : ignoreFlags(7), doInput(false), firstMessage(true), + apiData(0), usingCallback(false), userCallback(0), userData(0), + continueSysex(false) {} + }; + + protected: + virtual void initialize( const std::string& clientName ) = 0; + RtMidiInData inputData_; + + void *apiData_; + bool connected_; + std::string errorString_; +}; + +class MidiOutApi +{ + public: + + MidiOutApi( void ); + virtual ~MidiOutApi( void ); + virtual RtMidi::Api getCurrentApi( void ) = 0; + virtual void openPort( unsigned int portNumber, const std::string portName ) = 0; + virtual void openVirtualPort( const std::string portName ) = 0; + virtual void closePort( void ) = 0; + virtual unsigned int getPortCount( void ) = 0; + virtual std::string getPortName( unsigned int portNumber ) = 0; + virtual void sendMessage( std::vector *message ) = 0; + + protected: + virtual void initialize( const std::string& clientName ) = 0; + + void *apiData_; + bool connected_; + std::string errorString_; +}; + +// **************************************************************** // +// +// Inline RtMidiIn and RtMidiOut definitions. +// +// **************************************************************** // + +inline RtMidi::Api RtMidiIn :: getCurrentApi( void ) { return rtapi_->getCurrentApi(); } +inline void RtMidiIn :: openPort( unsigned int portNumber, const std::string portName ) { return rtapi_->openPort( portNumber, portName ); } +inline void RtMidiIn :: openVirtualPort( const std::string portName ) { return rtapi_->openVirtualPort( portName ); } +inline void RtMidiIn :: closePort( void ) { return rtapi_->closePort(); } +inline void RtMidiIn :: setCallback( RtMidiCallback callback, void *userData ) { return rtapi_->setCallback( callback, userData ); } +inline void RtMidiIn :: cancelCallback( void ) { return rtapi_->cancelCallback(); } +inline unsigned int RtMidiIn :: getPortCount( void ) { return rtapi_->getPortCount(); } +inline std::string RtMidiIn :: getPortName( unsigned int portNumber ) { return rtapi_->getPortName( portNumber ); } +inline void RtMidiIn :: ignoreTypes( bool midiSysex, bool midiTime, bool midiSense ) { return rtapi_->ignoreTypes( midiSysex, midiTime, midiSense ); } +inline double RtMidiIn :: getMessage( std::vector *message ) { return rtapi_->getMessage( message ); } + +inline RtMidi::Api RtMidiOut :: getCurrentApi( void ) { return rtapi_->getCurrentApi(); } +inline void RtMidiOut :: openPort( unsigned int portNumber, const std::string portName ) { return rtapi_->openPort( portNumber, portName ); } +inline void RtMidiOut :: openVirtualPort( const std::string portName ) { return rtapi_->openVirtualPort( portName ); } +inline void RtMidiOut :: closePort( void ) { return rtapi_->closePort(); } +inline unsigned int RtMidiOut :: getPortCount( void ) { return rtapi_->getPortCount(); } +inline std::string RtMidiOut :: getPortName( unsigned int portNumber ) { return rtapi_->getPortName( portNumber ); } +inline void RtMidiOut :: sendMessage( std::vector *message ) { return rtapi_->sendMessage( message ); } + +// **************************************************************** // +// +// MidiInApi and MidiOutApi subclass prototypes. +// +// **************************************************************** // + +#if !defined(__LINUX_ALSA__) && !defined(__UNIX_JACK__) && !defined(__MACOSX_CORE__) && !defined(__WINDOWS_MM__) && !defined(__WINDOWS_KS__) + #define __RTMIDI_DUMMY__ +#endif + +#if defined(__MACOSX_CORE__) + +class MidiInCore: public MidiInApi +{ + public: + MidiInCore( const std::string clientName, unsigned int queueSizeLimit ); + ~MidiInCore( void ); + RtMidi::Api getCurrentApi( void ) { return RtMidi::MACOSX_CORE; }; + void openPort( unsigned int portNumber, const std::string portName ); + void openVirtualPort( const std::string portName ); + void closePort( void ); + unsigned int getPortCount( void ); + std::string getPortName( unsigned int portNumber ); + + protected: + void initialize( const std::string& clientName ); +}; + +class MidiOutCore: public MidiOutApi +{ + public: + MidiOutCore( const std::string clientName ); + ~MidiOutCore( void ); + RtMidi::Api getCurrentApi( void ) { return RtMidi::MACOSX_CORE; }; + void openPort( unsigned int portNumber, const std::string portName ); + void openVirtualPort( const std::string portName ); + void closePort( void ); + unsigned int getPortCount( void ); + std::string getPortName( unsigned int portNumber ); + void sendMessage( std::vector *message ); + + protected: + void initialize( const std::string& clientName ); +}; + +#endif + +#if defined(__UNIX_JACK__) + +class MidiInJack: public MidiInApi +{ + public: + MidiInJack( const std::string clientName, unsigned int queueSizeLimit ); + ~MidiInJack( void ); + RtMidi::Api getCurrentApi( void ) { return RtMidi::UNIX_JACK; }; + void openPort( unsigned int portNumber, const std::string portName ); + void openVirtualPort( const std::string portName ); + void closePort( void ); + unsigned int getPortCount( void ); + std::string getPortName( unsigned int portNumber ); + + protected: + void initialize( const std::string& clientName ); +}; + +class MidiOutJack: public MidiOutApi +{ + public: + MidiOutJack( const std::string clientName ); + ~MidiOutJack( void ); + RtMidi::Api getCurrentApi( void ) { return RtMidi::UNIX_JACK; }; + void openPort( unsigned int portNumber, const std::string portName ); + void openVirtualPort( const std::string portName ); + void closePort( void ); + unsigned int getPortCount( void ); + std::string getPortName( unsigned int portNumber ); + void sendMessage( std::vector *message ); + + protected: + void initialize( const std::string& clientName ); +}; + +#endif + +#if defined(__LINUX_ALSA__) + +class MidiInAlsa: public MidiInApi +{ + public: + MidiInAlsa( const std::string clientName, unsigned int queueSizeLimit ); + ~MidiInAlsa( void ); + RtMidi::Api getCurrentApi( void ) { return RtMidi::LINUX_ALSA; }; + void openPort( unsigned int portNumber, const std::string portName ); + void openVirtualPort( const std::string portName ); + void closePort( void ); + unsigned int getPortCount( void ); + std::string getPortName( unsigned int portNumber ); + + protected: + void initialize( const std::string& clientName ); +}; + +class MidiOutAlsa: public MidiOutApi +{ + public: + MidiOutAlsa( const std::string clientName ); + ~MidiOutAlsa( void ); + RtMidi::Api getCurrentApi( void ) { return RtMidi::LINUX_ALSA; }; + void openPort( unsigned int portNumber, const std::string portName ); + void openVirtualPort( const std::string portName ); + void closePort( void ); + unsigned int getPortCount( void ); + std::string getPortName( unsigned int portNumber ); + void sendMessage( std::vector *message ); + + protected: + void initialize( const std::string& clientName ); +}; + +#endif + +#if defined(__WINDOWS_MM__) + +class MidiInWinMM: public MidiInApi +{ + public: + MidiInWinMM( const std::string clientName, unsigned int queueSizeLimit ); + ~MidiInWinMM( void ); + RtMidi::Api getCurrentApi( void ) { return RtMidi::WINDOWS_MM; }; + void openPort( unsigned int portNumber, const std::string portName ); + void openVirtualPort( const std::string portName ); + void closePort( void ); + unsigned int getPortCount( void ); + std::string getPortName( unsigned int portNumber ); + + protected: + void initialize( const std::string& clientName ); +}; + +class MidiOutWinMM: public MidiOutApi +{ + public: + MidiOutWinMM( const std::string clientName ); + ~MidiOutWinMM( void ); + RtMidi::Api getCurrentApi( void ) { return RtMidi::WINDOWS_MM; }; + void openPort( unsigned int portNumber, const std::string portName ); + void openVirtualPort( const std::string portName ); + void closePort( void ); + unsigned int getPortCount( void ); + std::string getPortName( unsigned int portNumber ); + void sendMessage( std::vector *message ); + + protected: + void initialize( const std::string& clientName ); +}; + +#endif + +#if defined(__WINDOWS_KS__) + +class MidiInWinKS: public MidiInApi +{ + public: + MidiInWinKS( const std::string clientName, unsigned int queueSizeLimit ); + ~MidiInWinKS( void ); + RtMidi::Api getCurrentApi( void ) { return RtMidi::WINDOWS_KS; }; + void openPort( unsigned int portNumber, const std::string portName ); + void openVirtualPort( const std::string portName ); + void closePort( void ); + unsigned int getPortCount( void ); + std::string getPortName( unsigned int portNumber ); + + protected: + void initialize( const std::string& clientName ); +}; + +class MidiOutWinKS: public MidiOutApi +{ + public: + MidiOutWinKS( const std::string clientName ); + ~MidiOutWinKS( void ); + RtMidi::Api getCurrentApi( void ) { return RtMidi::WINDOWS_KS; }; + void openPort( unsigned int portNumber, const std::string portName ); + void openVirtualPort( const std::string portName ); + void closePort( void ); + unsigned int getPortCount( void ); + std::string getPortName( unsigned int portNumber ); + void sendMessage( std::vector *message ); + + protected: + void initialize( const std::string& clientName ); +}; + +#endif + +#if defined(__RTMIDI_DUMMY__) + +class MidiInDummy: public MidiInApi +{ + public: + MidiInDummy( const std::string clientName, unsigned int queueSizeLimit ) : MidiInApi( queueSizeLimit ) { errorString_ = "MidiInDummy: This class provides no functionality."; RtMidi::error( RtError::WARNING, errorString_ ); }; + RtMidi::Api getCurrentApi( void ) { return RtMidi::RTMIDI_DUMMY; }; + void openPort( unsigned int portNumber, const std::string portName ) {}; + void openVirtualPort( const std::string portName ) {}; + void closePort( void ) {}; + unsigned int getPortCount( void ) { return 0; }; + std::string getPortName( unsigned int portNumber ) { return ""; }; + + protected: + void initialize( const std::string& clientName ) {}; +}; + +class MidiOutDummy: public MidiOutApi +{ + public: + MidiOutDummy( const std::string clientName ) { errorString_ = "MidiOutDummy: This class provides no functionality."; RtMidi::error( RtError::WARNING, errorString_ ); }; + RtMidi::Api getCurrentApi( void ) { return RtMidi::RTMIDI_DUMMY; }; + void openPort( unsigned int portNumber, const std::string portName ) {}; + void openVirtualPort( const std::string portName ) {}; + void closePort( void ) {}; + unsigned int getPortCount( void ) { return 0; }; + std::string getPortName( unsigned int portNumber ) { return ""; }; + void sendMessage( std::vector *message ) {}; + + protected: + void initialize( const std::string& clientName ) {}; +}; + +#endif + +#endif \ No newline at end of file diff --git a/examples/ThirdPartyLibs/midi/cmidiin.cpp b/examples/ThirdPartyLibs/midi/cmidiin.cpp new file mode 100644 index 000000000..75d2958b0 --- /dev/null +++ b/examples/ThirdPartyLibs/midi/cmidiin.cpp @@ -0,0 +1,112 @@ +//*****************************************// +// cmidiin.cpp +// by Gary Scavone, 2003-2004. +// +// Simple program to test MIDI input and +// use of a user callback function. +// +//*****************************************// + +#include +#include +#include "RtMidi.h" + +void usage( void ) { + // Error function in case of incorrect command-line + // argument specifications. + std::cout << "\nuseage: cmidiin \n"; + std::cout << " where port = the device to use (default = 0).\n\n"; + exit( 0 ); +} + +void mycallback( double deltatime, std::vector< unsigned char > *message, void *userData ) +{ + unsigned int nBytes = message->size(); + for ( unsigned int i=0; i 0 ) + std::cout << "stamp = " << deltatime << std::endl; +} + +// This function should be embedded in a try/catch block in case of +// an exception. It offers the user a choice of MIDI ports to open. +// It returns false if there are no ports available. +bool chooseMidiPort( RtMidiIn *rtmidi ); + +int main( int argc, char *argv[] ) +{ + RtMidiIn *midiin = 0; + + // Minimal command-line check. + if ( argc > 2 ) usage(); + + + // RtMidiIn constructor + midiin = new RtMidiIn(); + + // Call function to select port. + if ( chooseMidiPort( midiin ) == false ) goto cleanup; + + // Set our callback function. This should be done immediately after + // opening the port to avoid having incoming messages written to the + // queue instead of sent to the callback function. + midiin->setCallback( &mycallback ); + + // Don't ignore sysex, timing, or active sensing messages. + midiin->ignoreTypes( false, false, false ); + + std::cout << "\nReading MIDI input ... press to quit.\n"; + char input; + std::cin.get(input); + std::cin.get(input); + + + + cleanup: + + delete midiin; + + return 0; +} + +bool chooseMidiPort( RtMidiIn *rtmidi ) +{ + /* + + std::cout << "\nWould you like to open a virtual input port? [y/N] "; + + std::string keyHit; + std::getline( std::cin, keyHit ); + if ( keyHit == "y" ) { + rtmidi->openVirtualPort(); + return true; + } + */ + + std::string portName; + unsigned int i = 0, nPorts = rtmidi->getPortCount(); + if ( nPorts == 0 ) { + std::cout << "No input ports available!" << std::endl; + return false; + } + + if ( nPorts == 1 ) { + std::cout << "\nOpening " << rtmidi->getPortName() << std::endl; + } + else { + for ( i=0; igetPortName(i); + std::cout << " Input port #" << i << ": " << portName << '\n'; + } + + do { + std::cout << "\nChoose a port number: "; + std::cin >> i; + } while ( i >= nPorts ); + } + +// std::getline( std::cin, keyHit ); // used to clear out stdin + rtmidi->openPort( i ); + + return true; +} \ No newline at end of file diff --git a/examples/ThirdPartyLibs/midi/premake4.lua b/examples/ThirdPartyLibs/midi/premake4.lua new file mode 100644 index 000000000..f71f8dba9 --- /dev/null +++ b/examples/ThirdPartyLibs/midi/premake4.lua @@ -0,0 +1,35 @@ + + project "rtMidiTest" + + kind "ConsoleApp" + +-- defines { } + + + includedirs + { + ".", + } + + +-- links { } + + + files { + "**.cpp", + "**.h" + } + if os.is("Windows") then + links {"winmm"} + defines {"__WINDOWS_MM__", "WIN32"} + end + + if os.is("Linux") then + defines {"__LINUX_ALSA__"} + links {"asound","pthread"} + end + + if os.is("MacOSX") then + links{"CoreAudio.framework", "coreMIDI.framework", "Cocoa.framework"} + defines {"__MACOSX_CORE__"} + end \ No newline at end of file diff --git a/examples/ThirdPartyLibs/openvr/bin/linux32/libopenvr_api.so b/examples/ThirdPartyLibs/openvr/bin/linux32/libopenvr_api.so deleted file mode 100644 index a25054508..000000000 Binary files a/examples/ThirdPartyLibs/openvr/bin/linux32/libopenvr_api.so and /dev/null differ diff --git a/examples/ThirdPartyLibs/openvr/bin/linux64/libopenvr_api.so b/examples/ThirdPartyLibs/openvr/bin/linux64/libopenvr_api.so index c3c6d47ca..a7d57c658 100644 Binary files a/examples/ThirdPartyLibs/openvr/bin/linux64/libopenvr_api.so and b/examples/ThirdPartyLibs/openvr/bin/linux64/libopenvr_api.so differ diff --git a/examples/ThirdPartyLibs/openvr/bin/osx32/libopenvr_api.dylib b/examples/ThirdPartyLibs/openvr/bin/osx32/libopenvr_api.dylib index b296e20b8..2ac282b69 100644 Binary files a/examples/ThirdPartyLibs/openvr/bin/osx32/libopenvr_api.dylib and b/examples/ThirdPartyLibs/openvr/bin/osx32/libopenvr_api.dylib differ diff --git a/examples/ThirdPartyLibs/openvr/bin/win32/openvr_api.dll b/examples/ThirdPartyLibs/openvr/bin/win32/openvr_api.dll index d2b37d56b..0b0cc0ef9 100644 Binary files a/examples/ThirdPartyLibs/openvr/bin/win32/openvr_api.dll and b/examples/ThirdPartyLibs/openvr/bin/win32/openvr_api.dll differ diff --git a/examples/ThirdPartyLibs/openvr/bin/win64/openvr_api.dll b/examples/ThirdPartyLibs/openvr/bin/win64/openvr_api.dll index d13791a39..8b33ebb2d 100644 Binary files a/examples/ThirdPartyLibs/openvr/bin/win64/openvr_api.dll and b/examples/ThirdPartyLibs/openvr/bin/win64/openvr_api.dll differ diff --git a/examples/ThirdPartyLibs/openvr/headers/openvr.h b/examples/ThirdPartyLibs/openvr/headers/openvr.h index df727a3b5..d9d7deed7 100644 --- a/examples/ThirdPartyLibs/openvr/headers/openvr.h +++ b/examples/ThirdPartyLibs/openvr/headers/openvr.h @@ -13,7 +13,13 @@ // vrtypes.h #ifndef _INCLUDE_VRTYPES_H -#define _INCLUDE_VRTYPES_H +#define _INCLUDE_VRTYPES_H + +// Forward declarations to avoid requiring vulkan.h +struct VkDevice_T; +struct VkPhysicalDevice_T; +struct VkInstance_T; +struct VkQueue_T; namespace vr { @@ -125,6 +131,10 @@ struct Texture_t EColorSpace eColorSpace; }; +// Handle to a shared texture (HANDLE on Windows obtained using OpenSharedResource). +typedef uint64_t SharedTextureHandle_t; +#define INVALID_SHARED_TEXTURE_HANDLE ((vr::SharedTextureHandle_t)0) + enum ETrackingResult { TrackingResult_Uninitialized = 1, @@ -136,7 +146,6 @@ enum ETrackingResult TrackingResult_Running_OutOfRange = 201, }; -static const uint32_t k_unTrackingStringSize = 32; static const uint32_t k_unMaxDriverDebugResponseSize = 32768; /** Used to pass device IDs to API calls */ @@ -154,6 +163,8 @@ enum ETrackedDeviceClass TrackedDeviceClass_Controller = 2, // Tracked controllers TrackedDeviceClass_TrackingReference = 4, // Camera and base stations that serve as tracking reference points + TrackedDeviceClass_Count, // This isn't a class that will ever be returned. It is used for allocating arrays and such + TrackedDeviceClass_Other = 1000, }; @@ -229,6 +240,7 @@ enum ETrackedDeviceProperty Prop_HasCamera_Bool = 1030, Prop_DriverVersion_String = 1031, Prop_Firmware_ForceUpdateRequired_Bool = 1032, + Prop_ViveSystemButtonFixRequired_Bool = 1033, // Properties that are unique to TrackedDeviceClass_HMD Prop_ReportsTimeSinceVSync_Bool = 2000, @@ -268,6 +280,7 @@ enum ETrackedDeviceProperty Prop_ScreenshotHorizontalFieldOfViewDegrees_Float = 2034, Prop_ScreenshotVerticalFieldOfViewDegrees_Float = 2035, Prop_DisplaySuppressed_Bool = 2036, + Prop_DisplayAllowNightMode_Bool = 2037, // Properties that are unique to TrackedDeviceClass_Controller Prop_AttachedDeviceId_String = 3000, @@ -277,6 +290,7 @@ enum ETrackedDeviceProperty Prop_Axis2Type_Int32 = 3004, // Return value is of type EVRControllerAxisType Prop_Axis3Type_Int32 = 3005, // Return value is of type EVRControllerAxisType Prop_Axis4Type_Int32 = 3006, // Return value is of type EVRControllerAxisType + Prop_ControllerRoleHint_Int32 = 3007, // Return value is of type ETrackedControllerRole // Properties that are unique to TrackedDeviceClass_TrackingReference Prop_FieldOfViewLeftDegrees_Float = 4000, @@ -287,6 +301,17 @@ enum ETrackedDeviceProperty Prop_TrackingRangeMaximumMeters_Float = 4005, Prop_ModeLabel_String = 4006, + // Properties that are used for user interface like icons names + Prop_IconPathName_String = 5000, // usually a directory named "icons" + Prop_NamedIconPathDeviceOff_String = 5001, // PNG for static icon, or GIF for animation, 50x32 for headsets and 32x32 for others + Prop_NamedIconPathDeviceSearching_String = 5002, // PNG for static icon, or GIF for animation, 50x32 for headsets and 32x32 for others + Prop_NamedIconPathDeviceSearchingAlert_String = 5003, // PNG for static icon, or GIF for animation, 50x32 for headsets and 32x32 for others + Prop_NamedIconPathDeviceReady_String = 5004, // PNG for static icon, or GIF for animation, 50x32 for headsets and 32x32 for others + Prop_NamedIconPathDeviceReadyAlert_String = 5005, // PNG for static icon, or GIF for animation, 50x32 for headsets and 32x32 for others + Prop_NamedIconPathDeviceNotReady_String = 5006, // PNG for static icon, or GIF for animation, 50x32 for headsets and 32x32 for others + Prop_NamedIconPathDeviceStandby_String = 5007, // PNG for static icon, or GIF for animation, 50x32 for headsets and 32x32 for others + Prop_NamedIconPathDeviceAlertLow_String = 5008, // PNG for static icon, or GIF for animation, 50x32 for headsets and 32x32 for others + // Vendors are free to expose private debug data in this reserved region Prop_VendorSpecific_Reserved_Start = 10000, Prop_VendorSpecific_Reserved_End = 10999, @@ -332,6 +357,22 @@ enum EVRSubmitFlags // If the texture pointer passed in is actually a renderbuffer (e.g. for MSAA in OpenGL) then set this flag. Submit_GlRenderBuffer = 0x02, + + // Handle is pointer to VulkanData_t + Submit_VulkanTexture = 0x04, +}; + +/** Data required for passing Vulkan textures to IVRCompositor::Submit. +* Be sure to call OpenVR_Shutdown before destroying these resources. */ +struct VulkanData_t +{ + uint64_t m_nImage; // VkImage + VkDevice_T *m_pDevice; + VkPhysicalDevice_T *m_pPhysicalDevice; + VkInstance_T *m_pInstance; + VkQueue_T *m_pQueue; + uint32_t m_nQueueFamilyIndex; + uint32_t m_nWidth, m_nHeight, m_nFormat, m_nSampleCount; }; @@ -346,6 +387,7 @@ enum EVRState VRState_Ready_Alert = 4, VRState_NotReady = 5, VRState_Standby = 6, + VRState_Ready_Alert_Low = 7, }; /** The types of events that could be posted (and what the parameters mean for each event type) */ @@ -362,6 +404,8 @@ enum EVREventType VREvent_EnterStandbyMode = 106, VREvent_LeaveStandbyMode = 107, VREvent_TrackedDeviceRoleChanged = 108, + VREvent_WatchdogWakeUpRequested = 109, + VREvent_LensDistortionChanged = 110, VREvent_ButtonPress = 200, // data is controller VREvent_ButtonUnpress = 201, // data is controller @@ -375,6 +419,7 @@ enum EVREventType VREvent_FocusLeave = 304, // data is overlay VREvent_Scroll = 305, // data is mouse VREvent_TouchPadMove = 306, // data is mouse + VREvent_OverlayFocusChanged = 307, // data is overlay, global event VREvent_InputFocusCaptured = 400, // data is process DEPRECATED VREvent_InputFocusReleased = 401, // data is process DEPRECATED @@ -406,12 +451,14 @@ enum EVREventType VREvent_DashboardGuideButtonUp = 515, VREvent_ScreenshotTriggered = 516, // Screenshot button combo was pressed, Dashboard should request a screenshot VREvent_ImageFailed = 517, // Sent to overlays when a SetOverlayRaw or SetOverlayfromFail fails to load + VREvent_DashboardOverlayCreated = 518, // Screenshot API VREvent_RequestScreenshot = 520, // Sent by vrclient application to compositor to take a screenshot VREvent_ScreenshotTaken = 521, // Sent by compositor to the application that the screenshot has been taken VREvent_ScreenshotFailed = 522, // Sent by compositor to the application that the screenshot failed to be taken VREvent_SubmitScreenshotToDashboard = 523, // Sent by compositor to the dashboard that a completed screenshot was submitted + VREvent_ScreenshotProgressToDashboard = 524, // Sent by compositor to the dashboard that a completed screenshot was submitted VREvent_Notification_Shown = 600, VREvent_Notification_Hidden = 601, @@ -437,6 +484,7 @@ enum EVREventType VREvent_ReprojectionSettingHasChanged = 852, VREvent_ModelSkinSettingsHaveChanged = 853, VREvent_EnvironmentSettingsHaveChanged = 854, + VREvent_PowerSettingsHaveChanged = 855, VREvent_StatusUpdate = 900, @@ -453,6 +501,7 @@ enum EVREventType VREvent_ApplicationTransitionAborted = 1301, VREvent_ApplicationTransitionNewAppStarted = 1302, VREvent_ApplicationListUpdated = 1303, + VREvent_ApplicationMimeTypeLoad = 1304, VREvent_Compositor_MirrorWindowShown = 1400, VREvent_Compositor_MirrorWindowHidden = 1401, @@ -463,6 +512,7 @@ enum EVREventType VREvent_TrackedCamera_StopVideoStream = 1501, VREvent_TrackedCamera_PauseVideoStream = 1502, VREvent_TrackedCamera_ResumeVideoStream = 1503, + VREvent_TrackedCamera_EditingSurface = 1550, VREvent_PerformanceTest_EnableCapture = 1600, VREvent_PerformanceTest_DisableCapture = 1601, @@ -496,6 +546,8 @@ enum EVRButtonId k_EButton_DPad_Right = 5, k_EButton_DPad_Down = 6, k_EButton_A = 7, + + k_EButton_ProximitySensor = 31, k_EButton_Axis0 = 32, k_EButton_Axis1 = 33, @@ -634,7 +686,24 @@ struct VREvent_Screenshot_t uint32_t type; }; -/** If you change this you must manually update openvr_interop.cs.py */ +struct VREvent_ScreenshotProgress_t +{ + float progress; +}; + +struct VREvent_ApplicationLaunch_t +{ + uint32_t pid; + uint32_t unArgsHandle; +}; + +struct VREvent_EditingCameraSurface_t +{ + uint64_t overlayHandle; + uint32_t nVisualMode; +}; + +/** NOTE!!! If you change this you MUST manually update openvr_interop.cs.py */ typedef union { VREvent_Reserved_t reserved; @@ -652,6 +721,9 @@ typedef union VREvent_TouchPadMove_t touchPadMove; VREvent_SeatedZeroPoseReset_t seatedZeroPoseReset; VREvent_Screenshot_t screenshot; + VREvent_ScreenshotProgress_t screenshotProgress; + VREvent_ApplicationLaunch_t applicationLaunch; + VREvent_EditingCameraSurface_t cameraSurface; } VREvent_Data_t; /** An event posted by the server to all running applications */ @@ -678,6 +750,14 @@ struct HiddenAreaMesh_t }; +enum EHiddenAreaMeshType +{ + k_eHiddenAreaMesh_Standard = 0, + k_eHiddenAreaMesh_Inverse = 1, + k_eHiddenAreaMesh_LineLoop = 2, +}; + + /** Identifies what kind of axis is on the controller at index n. Read this type * with pVRSystem->Get( nControllerDeviceIndex, Prop_Axis0Type_Int32 + n ); */ @@ -761,26 +841,28 @@ static const VROverlayHandle_t k_ulOverlayHandleInvalid = 0; /** Errors that can occur around VR overlays */ enum EVROverlayError { - VROverlayError_None = 0, + VROverlayError_None = 0, - VROverlayError_UnknownOverlay = 10, - VROverlayError_InvalidHandle = 11, - VROverlayError_PermissionDenied = 12, - VROverlayError_OverlayLimitExceeded = 13, // No more overlays could be created because the maximum number already exist - VROverlayError_WrongVisibilityType = 14, - VROverlayError_KeyTooLong = 15, - VROverlayError_NameTooLong = 16, - VROverlayError_KeyInUse = 17, - VROverlayError_WrongTransformType = 18, - VROverlayError_InvalidTrackedDevice = 19, - VROverlayError_InvalidParameter = 20, - VROverlayError_ThumbnailCantBeDestroyed = 21, - VROverlayError_ArrayTooSmall = 22, - VROverlayError_RequestFailed = 23, - VROverlayError_InvalidTexture = 24, - VROverlayError_UnableToLoadFile = 25, - VROVerlayError_KeyboardAlreadyInUse = 26, - VROverlayError_NoNeighbor = 27, + VROverlayError_UnknownOverlay = 10, + VROverlayError_InvalidHandle = 11, + VROverlayError_PermissionDenied = 12, + VROverlayError_OverlayLimitExceeded = 13, // No more overlays could be created because the maximum number already exist + VROverlayError_WrongVisibilityType = 14, + VROverlayError_KeyTooLong = 15, + VROverlayError_NameTooLong = 16, + VROverlayError_KeyInUse = 17, + VROverlayError_WrongTransformType = 18, + VROverlayError_InvalidTrackedDevice = 19, + VROverlayError_InvalidParameter = 20, + VROverlayError_ThumbnailCantBeDestroyed = 21, + VROverlayError_ArrayTooSmall = 22, + VROverlayError_RequestFailed = 23, + VROverlayError_InvalidTexture = 24, + VROverlayError_UnableToLoadFile = 25, + VROverlayError_KeyboardAlreadyInUse = 26, + VROverlayError_NoNeighbor = 27, + VROverlayError_TooManyMaskPrimitives = 29, + VROverlayError_BadMaskPrimitive = 30, }; /** enum values to pass in to VR_Init to identify whether the application will @@ -795,6 +877,9 @@ enum EVRApplicationType VRApplication_Utility = 4, // Init should not try to load any drivers. The application needs access to utility // interfaces (like IVRSettings and IVRApplications) but not hardware. VRApplication_VRMonitor = 5, // Reserved for vrmonitor + VRApplication_SteamWatchdog = 6,// Reserved for Steam + + VRApplication_Max }; @@ -851,6 +936,14 @@ enum EVRInitError VRInitError_Init_NotSupportedWithCompositor = 122, VRInitError_Init_NotAvailableToUtilityApps = 123, VRInitError_Init_Internal = 124, + VRInitError_Init_HmdDriverIdIsNone = 125, + VRInitError_Init_HmdNotFoundPresenceFailed = 126, + VRInitError_Init_VRMonitorNotFound = 127, + VRInitError_Init_VRMonitorStartupFailed = 128, + VRInitError_Init_LowPowerWatchdogNotSupported = 129, + VRInitError_Init_InvalidApplicationType = 130, + VRInitError_Init_NotAvailableToWatchdogApps = 131, + VRInitError_Init_WatchdogDisabledInSettings = 132, VRInitError_Driver_Failed = 200, VRInitError_Driver_Unknown = 201, @@ -861,13 +954,20 @@ enum EVRInitError VRInitError_Driver_NotCalibrated = 206, VRInitError_Driver_CalibrationInvalid = 207, VRInitError_Driver_HmdDisplayNotFound = 208, - + VRInitError_Driver_TrackedDeviceInterfaceUnknown = 209, + // VRInitError_Driver_HmdDisplayNotFoundAfterFix = 210, // not needed: here for historic reasons + VRInitError_Driver_HmdDriverIdOutOfBounds = 211, + VRInitError_Driver_HmdDisplayMirrored = 212, + VRInitError_IPC_ServerInitFailed = 300, VRInitError_IPC_ConnectFailed = 301, VRInitError_IPC_SharedStateInitFailed = 302, VRInitError_IPC_CompositorInitFailed = 303, VRInitError_IPC_MutexInitFailed = 304, VRInitError_IPC_Failed = 305, + VRInitError_IPC_CompositorConnectFailed = 306, + VRInitError_IPC_CompositorInvalidConnectResponse = 307, + VRInitError_IPC_ConnectFailedAfterMultipleAttempts = 308, VRInitError_Compositor_Failed = 400, VRInitError_Compositor_D3D11HardwareRequired = 401, @@ -971,7 +1071,7 @@ static const uint32_t k_unScreenshotHandleInvalid = 0; #define VR_INTERFACE extern "C" __declspec( dllimport ) #endif -#elif defined(GNUC) || defined(COMPILER_GCC) || defined(__APPLE__) +#elif defined(__GNUC__) || defined(COMPILER_GCC) || defined(__APPLE__) #ifdef VR_API_EXPORT #define VR_INTERFACE extern "C" __attribute__((visibility("default"))) @@ -1037,9 +1137,10 @@ public: * application is doing something fancy like infinite Z */ virtual void GetProjectionRaw( EVREye eEye, float *pfLeft, float *pfRight, float *pfTop, float *pfBottom ) = 0; - /** Returns the result of the distortion function for the specified eye and input UVs. UVs go from 0,0 in - * the upper left of that eye's viewport and 1,1 in the lower right of that eye's viewport. */ - virtual DistortionCoordinates_t ComputeDistortion( EVREye eEye, float fU, float fV ) = 0; + /** Gets the result of the distortion function for the specified eye and input UVs. UVs go from 0,0 in + * the upper left of that eye's viewport and 1,1 in the lower right of that eye's viewport. + * Returns true for success. Otherwise, returns false, and distortion coordinates are not suitable. */ + virtual bool ComputeDistortion( EVREye eEye, float fU, float fV, DistortionCoordinates_t *pDistortionCoordinates ) = 0; /** Returns the transform from eye space to the head space. Eye space is the per-eye flavor of head * space that provides stereo disparity. Instead of Model * View * Projection the sequence is Model * View * Eye^-1 * Projection. @@ -1060,8 +1161,10 @@ public: virtual int32_t GetD3D9AdapterIndex() = 0; /** [D3D10/11 Only] - * Returns the adapter index and output index that the user should pass into EnumAdapters and EnumOutputs - * to create the device and swap chain in DX10 and DX11. If an error occurs both indices will be set to -1. + * Returns the adapter index that the user should pass into EnumAdapters to create the device + * and swap chain in DX10 and DX11. If an error occurs the index will be set to -1. The index will + * also be -1 if the headset is in direct mode on the driver side instead of using the compositor's + * builtin direct mode support. */ virtual void GetDXGIOutputInfo( int32_t *pnAdapterIndex ) = 0; @@ -1173,7 +1276,7 @@ public: /** Returns a string property. If the device index is not valid or the property is not a string type this function will * return 0. Otherwise it returns the length of the number of bytes necessary to hold this string including the trailing - * null. Strings will generally fit in buffers of k_unTrackingStringSize characters. */ + * null. Strings will always fit in buffers of k_unMaxPropertyStringSize characters. */ virtual uint32_t GetStringTrackedDeviceProperty( vr::TrackedDeviceIndex_t unDeviceIndex, ETrackedDeviceProperty prop, VR_OUT_STRING() char *pchValue, uint32_t unBufferSize, ETrackedPropertyError *pError = 0L ) = 0; /** returns a string that corresponds with the specified property error. The string will be the name @@ -1201,14 +1304,15 @@ public: // Rendering helper methods // ------------------------------------ - /** Returns the stencil mesh information for the current HMD. If this HMD does not have a stencil mesh the vertex data and count will be - * NULL and 0 respectively. This mesh is meant to be rendered into the stencil buffer (or into the depth buffer setting nearz) before rendering - * each eye's view. The pixels covered by this mesh will never be seen by the user after the lens distortion is applied and based on visibility to the panels. - * This will improve perf by letting the GPU early-reject pixels the user will never see before running the pixel shader. + /** Returns the hidden area mesh for the current HMD. The pixels covered by this mesh will never be seen by the user after the lens distortion is + * applied based on visibility to the panels. If this HMD does not have a hidden area mesh, the vertex data and count will be NULL and 0 respectively. + * This mesh is meant to be rendered into the stencil buffer (or into the depth buffer setting nearz) before rendering each eye's view. + * This will improve performance by letting the GPU early-reject pixels the user will never see before running the pixel shader. * NOTE: Render this mesh with backface culling disabled since the winding order of the vertices can be different per-HMD or per-eye. + * Setting the bInverse argument to true will produce the visible area mesh that is commonly used in place of full-screen quads. The visible area mesh covers all of the pixels the hidden area mesh does not cover. + * Setting the bLineLoop argument will return a line loop of vertices in HiddenAreaMesh_t->pVertexData with HiddenAreaMesh_t->unTriangleCount set to the number of vertices. */ - virtual HiddenAreaMesh_t GetHiddenAreaMesh( EVREye eEye ) = 0; - + virtual HiddenAreaMesh_t GetHiddenAreaMesh( EVREye eEye, EHiddenAreaMeshType type = k_eHiddenAreaMesh_Standard ) = 0; // ------------------------------------ // Controller methods @@ -1216,12 +1320,12 @@ public: /** Fills the supplied struct with the current state of the controller. Returns false if the controller index * is invalid. */ - virtual bool GetControllerState( vr::TrackedDeviceIndex_t unControllerDeviceIndex, vr::VRControllerState_t *pControllerState ) = 0; + virtual bool GetControllerState( vr::TrackedDeviceIndex_t unControllerDeviceIndex, vr::VRControllerState_t *pControllerState, uint32_t unControllerStateSize ) = 0; /** fills the supplied struct with the current state of the controller and the provided pose with the pose of * the controller when the controller state was updated most recently. Use this form if you need a precise controller * pose as input to your application when the user presses or releases a button. */ - virtual bool GetControllerStateWithPose( ETrackingUniverseOrigin eOrigin, vr::TrackedDeviceIndex_t unControllerDeviceIndex, vr::VRControllerState_t *pControllerState, TrackedDevicePose_t *pTrackedDevicePose ) = 0; + virtual bool GetControllerStateWithPose( ETrackingUniverseOrigin eOrigin, vr::TrackedDeviceIndex_t unControllerDeviceIndex, vr::VRControllerState_t *pControllerState, uint32_t unControllerStateSize, TrackedDevicePose_t *pTrackedDevicePose ) = 0; /** Trigger a single haptic pulse on a controller. After this call the application may not trigger another haptic pulse on this controller * and axis combination for 5ms. */ @@ -1254,7 +1358,6 @@ public: * The size of the response including its terminating null is returned. */ virtual uint32_t DriverDebugRequest( vr::TrackedDeviceIndex_t unDeviceIndex, const char *pchRequest, char *pchResponseBuffer, uint32_t unResponseBufferSize ) = 0; - // ------------------------------------ // Firmware methods // ------------------------------------ @@ -1266,7 +1369,6 @@ public: * Prop_Firmware_ManualUpdateURL_String should point to an URL describing the manual update process */ virtual vr::EVRFirmwareError PerformFirmwareUpdate( vr::TrackedDeviceIndex_t unDeviceIndex ) = 0; - // ------------------------------------ // Application life cycle methods // ------------------------------------ @@ -1282,7 +1384,7 @@ public: }; -static const char * const IVRSystem_Version = "IVRSystem_012"; +static const char * const IVRSystem_Version = "IVRSystem_014"; } @@ -1361,6 +1463,10 @@ namespace vr const char *pchValue; }; + /** Currently recognized mime types */ + static const char * const k_pch_MimeType_HomeApp = "vr/home"; + static const char * const k_pch_MimeType_GameTheater = "vr/game_theater"; + class IVRApplications { public: @@ -1383,7 +1489,7 @@ namespace vr /** Returns the key of the specified application. The index is at least 0 and is less than the return * value of GetApplicationCount(). The buffer should be at least k_unMaxApplicationKeyLength in order to * fit the key. */ - virtual EVRApplicationError GetApplicationKeyByIndex( uint32_t unApplicationIndex, char *pchAppKeyBuffer, uint32_t unAppKeyBufferLen ) = 0; + virtual EVRApplicationError GetApplicationKeyByIndex( uint32_t unApplicationIndex, VR_OUT_STRING() char *pchAppKeyBuffer, uint32_t unAppKeyBufferLen ) = 0; /** Returns the key of the application for the specified Process Id. The buffer should be at least * k_unMaxApplicationKeyLength in order to fit the key. */ @@ -1398,6 +1504,9 @@ namespace vr */ virtual EVRApplicationError LaunchTemplateApplication( const char *pchTemplateAppKey, const char *pchNewAppKey, VR_ARRAY_COUNT( unKeys ) const AppOverrideKeys_t *pKeys, uint32_t unKeys ) = 0; + /** launches the application currently associated with this mime type and passes it the option args, typically the filename or object name of the item being launched */ + virtual vr::EVRApplicationError LaunchApplicationFromMimeType( const char *pchMimeType, const char *pchArgs ) = 0; + /** Launches the dashboard overlay application if it is not already running. This call is only valid for * dashboard overlay applications. */ virtual EVRApplicationError LaunchDashboardOverlay( const char *pchAppKey ) = 0; @@ -1420,7 +1529,7 @@ namespace vr // --------------- Application properties --------------- // /** Returns a value for an application property. The required buffer size to fit this value will be returned. */ - virtual uint32_t GetApplicationPropertyString( const char *pchAppKey, EVRApplicationProperty eProperty, char *pchPropertyValueBuffer, uint32_t unPropertyValueBufferLen, EVRApplicationError *peError = nullptr ) = 0; + virtual uint32_t GetApplicationPropertyString( const char *pchAppKey, EVRApplicationProperty eProperty, VR_OUT_STRING() char *pchPropertyValueBuffer, uint32_t unPropertyValueBufferLen, EVRApplicationError *peError = nullptr ) = 0; /** Returns a bool value for an application property. Returns false in all error cases. */ virtual bool GetApplicationPropertyBool( const char *pchAppKey, EVRApplicationProperty eProperty, EVRApplicationError *peError = nullptr ) = 0; @@ -1434,6 +1543,21 @@ namespace vr /** Gets the application auto-launch flag. This is only valid for applications which return true for VRApplicationProperty_IsDashboardOverlay_Bool. */ virtual bool GetApplicationAutoLaunch( const char *pchAppKey ) = 0; + /** Adds this mime-type to the list of supported mime types for this application*/ + virtual EVRApplicationError SetDefaultApplicationForMimeType( const char *pchAppKey, const char *pchMimeType ) = 0; + + /** return the app key that will open this mime type */ + virtual bool GetDefaultApplicationForMimeType( const char *pchMimeType, char *pchAppKeyBuffer, uint32_t unAppKeyBufferLen ) = 0; + + /** Get the list of supported mime types for this application, comma-delimited */ + virtual bool GetApplicationSupportedMimeTypes( const char *pchAppKey, char *pchMimeTypesBuffer, uint32_t unMimeTypesBuffer ) = 0; + + /** Get the list of app-keys that support this mime type, comma-delimited, the return value is number of bytes you need to return the full string */ + virtual uint32_t GetApplicationsThatSupportMimeType( const char *pchMimeType, char *pchAppKeysThatSupportBuffer, uint32_t unAppKeysThatSupportBuffer ) = 0; + + /** Get the args list from an app launch that had the process already running, you call this when you get a VREvent_ApplicationMimeTypeLoad */ + virtual uint32_t GetApplicationLaunchArguments( uint32_t unHandle, char *pchArgs, uint32_t unArgs ) = 0; + // --------------- Transition methods --------------- // /** Returns the app key for the application that is starting up */ @@ -1467,7 +1591,7 @@ namespace vr virtual EVRApplicationError LaunchInternalProcess( const char *pchBinaryPath, const char *pchArguments, const char *pchWorkingDirectory ) = 0; }; - static const char * const IVRApplications_Version = "IVRApplications_005"; + static const char * const IVRApplications_Version = "IVRApplications_006"; } // namespace vr @@ -1480,6 +1604,8 @@ namespace vr VRSettingsError_IPCFailed = 1, VRSettingsError_WriteFailed = 2, VRSettingsError_ReadFailed = 3, + VRSettingsError_JsonParseFailed = 4, + VRSettingsError_UnsetSettingHasNoDefault = 5, // This will be returned if the setting does not appear in the appropriate default file and has not been set }; // The maximum length of a settings key @@ -1493,21 +1619,24 @@ namespace vr // Returns true if file sync occurred (force or settings dirty) virtual bool Sync( bool bForce = false, EVRSettingsError *peError = nullptr ) = 0; - virtual bool GetBool( const char *pchSection, const char *pchSettingsKey, bool bDefaultValue, EVRSettingsError *peError = nullptr ) = 0; virtual void SetBool( const char *pchSection, const char *pchSettingsKey, bool bValue, EVRSettingsError *peError = nullptr ) = 0; - virtual int32_t GetInt32( const char *pchSection, const char *pchSettingsKey, int32_t nDefaultValue, EVRSettingsError *peError = nullptr ) = 0; virtual void SetInt32( const char *pchSection, const char *pchSettingsKey, int32_t nValue, EVRSettingsError *peError = nullptr ) = 0; - virtual float GetFloat( const char *pchSection, const char *pchSettingsKey, float flDefaultValue, EVRSettingsError *peError = nullptr ) = 0; virtual void SetFloat( const char *pchSection, const char *pchSettingsKey, float flValue, EVRSettingsError *peError = nullptr ) = 0; - virtual void GetString( const char *pchSection, const char *pchSettingsKey, char *pchValue, uint32_t unValueLen, const char *pchDefaultValue, EVRSettingsError *peError = nullptr ) = 0; virtual void SetString( const char *pchSection, const char *pchSettingsKey, const char *pchValue, EVRSettingsError *peError = nullptr ) = 0; - + + // Users of the system need to provide a proper default in default.vrsettings in the resources/settings/ directory + // of either the runtime or the driver_xxx directory. Otherwise the default will be false, 0, 0.0 or "" + virtual bool GetBool( const char *pchSection, const char *pchSettingsKey, EVRSettingsError *peError = nullptr ) = 0; + virtual int32_t GetInt32( const char *pchSection, const char *pchSettingsKey, EVRSettingsError *peError = nullptr ) = 0; + virtual float GetFloat( const char *pchSection, const char *pchSettingsKey, EVRSettingsError *peError = nullptr ) = 0; + virtual void GetString( const char *pchSection, const char *pchSettingsKey, VR_OUT_STRING() char *pchValue, uint32_t unValueLen, EVRSettingsError *peError = nullptr ) = 0; + virtual void RemoveSection( const char *pchSection, EVRSettingsError *peError = nullptr ) = 0; virtual void RemoveKeyInSection( const char *pchSection, const char *pchSettingsKey, EVRSettingsError *peError = nullptr ) = 0; }; //----------------------------------------------------------------------------- - static const char * const IVRSettings_Version = "IVRSettings_001"; + static const char * const IVRSettings_Version = "IVRSettings_002"; //----------------------------------------------------------------------------- // steamvr keys @@ -1525,16 +1654,13 @@ namespace vr static const char * const k_pch_SteamVR_LogLevel_Int32 = "loglevel"; static const char * const k_pch_SteamVR_IPD_Float = "ipd"; static const char * const k_pch_SteamVR_Background_String = "background"; + static const char * const k_pch_SteamVR_BackgroundUseDomeProjection_Bool = "backgroundUseDomeProjection"; static const char * const k_pch_SteamVR_BackgroundCameraHeight_Float = "backgroundCameraHeight"; static const char * const k_pch_SteamVR_BackgroundDomeRadius_Float = "backgroundDomeRadius"; - static const char * const k_pch_SteamVR_Environment_String = "environment"; static const char * const k_pch_SteamVR_GridColor_String = "gridColor"; static const char * const k_pch_SteamVR_PlayAreaColor_String = "playAreaColor"; static const char * const k_pch_SteamVR_ShowStage_Bool = "showStage"; static const char * const k_pch_SteamVR_ActivateMultipleDrivers_Bool = "activateMultipleDrivers"; - static const char * const k_pch_SteamVR_PowerOffOnExit_Bool = "powerOffOnExit"; - static const char * const k_pch_SteamVR_StandbyAppRunningTimeout_Float = "standbyAppRunningTimeout"; - static const char * const k_pch_SteamVR_StandbyNoAppTimeout_Float = "standbyNoAppTimeout"; static const char * const k_pch_SteamVR_DirectMode_Bool = "directMode"; static const char * const k_pch_SteamVR_DirectModeEdidVid_Int32 = "directModeEdidVid"; static const char * const k_pch_SteamVR_DirectModeEdidPid_Int32 = "directModeEdidPid"; @@ -1543,11 +1669,20 @@ namespace vr static const char * const k_pch_SteamVR_BaseStationPowerManagement_Bool = "basestationPowerManagement"; static const char * const k_pch_SteamVR_NeverKillProcesses_Bool = "neverKillProcesses"; static const char * const k_pch_SteamVR_RenderTargetMultiplier_Float = "renderTargetMultiplier"; - static const char * const k_pch_SteamVR_AllowReprojection_Bool = "allowReprojection"; + static const char * const k_pch_SteamVR_AllowAsyncReprojection_Bool = "allowAsyncReprojection"; + static const char * const k_pch_SteamVR_AllowReprojection_Bool = "allowInterleavedReprojection"; static const char * const k_pch_SteamVR_ForceReprojection_Bool = "forceReprojection"; static const char * const k_pch_SteamVR_ForceFadeOnBadTracking_Bool = "forceFadeOnBadTracking"; static const char * const k_pch_SteamVR_DefaultMirrorView_Int32 = "defaultMirrorView"; static const char * const k_pch_SteamVR_ShowMirrorView_Bool = "showMirrorView"; + static const char * const k_pch_SteamVR_MirrorViewGeometry_String = "mirrorViewGeometry"; + static const char * const k_pch_SteamVR_StartMonitorFromAppLaunch = "startMonitorFromAppLaunch"; + static const char * const k_pch_SteamVR_EnableHomeApp = "enableHomeApp"; + static const char * const k_pch_SteamVR_SetInitialDefaultHomeApp = "setInitialDefaultHomeApp"; + static const char * const k_pch_SteamVR_CycleBackgroundImageTimeSec_Int32 = "CycleBackgroundImageTimeSec"; + static const char * const k_pch_SteamVR_RetailDemo_Bool = "retailDemo"; + static const char * const k_pch_SteamVR_IpdOffset_Float = "ipdOffset"; + //----------------------------------------------------------------------------- // lighthouse keys @@ -1558,9 +1693,6 @@ namespace vr static const char * const k_pch_Lighthouse_DisambiguationDebug_Int32 = "disambiguationdebug"; static const char * const k_pch_Lighthouse_PrimaryBasestation_Int32 = "primarybasestation"; - static const char * const k_pch_Lighthouse_LighthouseName_String = "lighthousename"; - static const char * const k_pch_Lighthouse_MaxIncidenceAngleDegrees_Float = "maxincidenceangledegrees"; - static const char * const k_pch_Lighthouse_UseLighthouseDirect_Bool = "uselighthousedirect"; static const char * const k_pch_Lighthouse_DBHistory_Bool = "dbhistory"; //----------------------------------------------------------------------------- @@ -1583,7 +1715,9 @@ namespace vr // user interface keys static const char * const k_pch_UserInterface_Section = "userinterface"; static const char * const k_pch_UserInterface_StatusAlwaysOnTop_Bool = "StatusAlwaysOnTop"; - static const char * const k_pch_UserInterface_EnableScreenshots_Bool = "EnableScreenshots"; + static const char * const k_pch_UserInterface_MinimizeToTray_Bool = "MinimizeToTray"; + static const char * const k_pch_UserInterface_Screenshots_Bool = "screenshots"; + static const char * const k_pch_UserInterface_ScreenshotType_Int = "screenshotType"; //----------------------------------------------------------------------------- // notification keys @@ -1635,6 +1769,7 @@ namespace vr static const char * const k_pch_Camera_BoundsColorGammaG_Int32 = "cameraBoundsColorGammaG"; static const char * const k_pch_Camera_BoundsColorGammaB_Int32 = "cameraBoundsColorGammaB"; static const char * const k_pch_Camera_BoundsColorGammaA_Int32 = "cameraBoundsColorGammaA"; + static const char * const k_pch_Camera_BoundsStrength_Int32 = "cameraBoundsStrength"; //----------------------------------------------------------------------------- // audio keys @@ -1646,6 +1781,21 @@ namespace vr static const char * const k_pch_audio_OffRecordDevice_String = "offRecordDevice"; static const char * const k_pch_audio_VIVEHDMIGain = "viveHDMIGain"; + //----------------------------------------------------------------------------- + // power management keys + static const char * const k_pch_Power_Section = "power"; + static const char * const k_pch_Power_PowerOffOnExit_Bool = "powerOffOnExit"; + static const char * const k_pch_Power_TurnOffScreensTimeout_Float = "turnOffScreensTimeout"; + static const char * const k_pch_Power_TurnOffControllersTimeout_Float = "turnOffControllersTimeout"; + static const char * const k_pch_Power_ReturnToWatchdogTimeout_Float = "returnToWatchdogTimeout"; + static const char * const k_pch_Power_AutoLaunchSteamVROnButtonPress = "autoLaunchSteamVROnButtonPress"; + + //----------------------------------------------------------------------------- + // dashboard keys + static const char * const k_pch_Dashboard_Section = "dashboard"; + static const char * const k_pch_Dashboard_EnableDashboard_Bool = "enableDashboard"; + static const char * const k_pch_Dashboard_ArcadeMode_Bool = "arcadeMode"; + //----------------------------------------------------------------------------- // model skin keys static const char * const k_pch_modelskin_Section = "modelskins"; @@ -1850,10 +2000,17 @@ enum EVRCompositorError VRCompositorError_TextureUsesUnsupportedFormat = 105, VRCompositorError_SharedTexturesNotSupported = 106, VRCompositorError_IndexOutOfRange = 107, + VRCompositorError_AlreadySubmitted = 108, }; const uint32_t VRCompositor_ReprojectionReason_Cpu = 0x01; const uint32_t VRCompositor_ReprojectionReason_Gpu = 0x02; +const uint32_t VRCompositor_ReprojectionAsync = 0x04; // This flag indicates the async reprojection mode is active, + // but does not indicate if reprojection actually happened or not. + // Use the ReprojectionReason flags above to check if reprojection + // was actually applied (i.e. scene texture was reused). + // NumFramePresents > 1 also indicates the scene texture was reused, + // and also the number of times that it was presented in total. /** Provides a single frame's timing information to the app */ struct Compositor_FrameTiming @@ -1861,7 +2018,9 @@ struct Compositor_FrameTiming uint32_t m_nSize; // Set to sizeof( Compositor_FrameTiming ) uint32_t m_nFrameIndex; uint32_t m_nNumFramePresents; // number of times this frame was presented + uint32_t m_nNumMisPresented; // number of times this frame was presented on a vsync other than it was originally predicted to uint32_t m_nNumDroppedFrames; // number of additional times previous frame was scanned out + uint32_t m_nReprojectionFlags; /** Absolute time reference for comparing frames. This aligns with the vsync that running start is relative to. */ double m_flSystemTimeInSeconds; @@ -1870,7 +2029,8 @@ struct Compositor_FrameTiming * The fewer packets of work these are broken up into, the less likely this will happen. * GPU work can be broken up by calling Flush. This can sometimes be useful to get the GPU started * processing that work earlier in the frame. */ - float m_flSceneRenderGpuMs; // time spent rendering the scene + float m_flPreSubmitGpuMs; // time spent rendering the scene (gpu work submitted between WaitGetPoses and second Submit) + float m_flPostSubmitGpuMs; // additional time spent rendering by application (e.g. companion window) float m_flTotalRenderGpuMs; // time between work submitted immediately after present (ideally vsync) until the end of compositor submitted work float m_flCompositorRenderGpuMs; // time spend performing distortion correction, rendering chaperone, overlays, etc. float m_flCompositorRenderCpuMs; // time spent on cpu submitting the above work for this frame @@ -1891,9 +2051,6 @@ struct Compositor_FrameTiming float m_flCompositorRenderStartMs; vr::TrackedDevicePose_t m_HmdPose; // pose used by app to render this frame - int32_t m_nFidelityLevel; // app reported value - - uint32_t m_nReprojectionFlags; }; /** Cumulative stats for current application. These are not cleared until a new app connects, @@ -1903,7 +2060,7 @@ struct Compositor_CumulativeStats uint32_t m_nPid; // Process id associated with these stats (may no longer be running). uint32_t m_nNumFramePresents; // total number of times we called present (includes reprojected frames) uint32_t m_nNumDroppedFrames; // total number of times an old frame was re-scanned out (without reprojection) - uint32_t m_nNumReprojectedFrames; // total number of times a frame was scanned out a second time with reprojection + uint32_t m_nNumReprojectedFrames; // total number of times a frame was scanned out a second time (with reprojection) /** Values recorded at startup before application has fully faded in the first time. */ uint32_t m_nNumFramePresentsOnStartup; @@ -1938,7 +2095,14 @@ public: /** Gets current tracking space returned by WaitGetPoses */ virtual ETrackingUniverseOrigin GetTrackingSpace() = 0; - /** Returns pose(s) to use to render scene (and optionally poses predicted two frames out for gameplay). */ + /** Scene applications should call this function to get poses to render with (and optionally poses predicted an additional frame out to use for gameplay). + * This function will block until "running start" milliseconds before the start of the frame, and should be called at the last moment before needing to + * start rendering. + * + * Return codes: + * - IsNotSceneApplication (make sure to call VR_Init with VRApplicaiton_Scene) + * - DoNotHaveFocus (some other app has taken focus - this will throttle the call to 10hz to reduce the impact on that app) + */ virtual EVRCompositorError WaitGetPoses( VR_ARRAY_COUNT(unRenderPoseArrayCount) TrackedDevicePose_t* pRenderPoseArray, uint32_t unRenderPoseArrayCount, VR_ARRAY_COUNT(unGamePoseArrayCount) TrackedDevicePose_t* pGamePoseArray, uint32_t unGamePoseArrayCount ) = 0; @@ -1956,6 +2120,15 @@ public: * * OpenGL dirty state: * glBindTexture + * + * Return codes: + * - IsNotSceneApplication (make sure to call VR_Init with VRApplicaiton_Scene) + * - DoNotHaveFocus (some other app has taken focus) + * - TextureIsOnWrongDevice (application did not use proper AdapterIndex - see IVRSystem.GetDXGIOutputInfo) + * - SharedTexturesNotSupported (application needs to call CreateDXGIFactory1 or later before creating DX device) + * - TextureUsesUnsupportedFormat (scene textures must be compatible with DXGI sharing rules - e.g. uncompressed, no mips, etc.) + * - InvalidTexture (usually means bad arguments passed in) + * - AlreadySubmitted (app has submitted two left textures or two right textures in a single frame - i.e. before calling WaitGetPoses again) */ virtual EVRCompositorError Submit( EVREye eEye, const Texture_t *pTexture, const VRTextureBounds_t* pBounds = 0, EVRSubmitFlags nSubmitFlags = Submit_Default ) = 0; @@ -1974,6 +2147,10 @@ public: * Be sure to set timing.size = sizeof(Compositor_FrameTiming) on struct passed in before calling this function. */ virtual bool GetFrameTiming( Compositor_FrameTiming *pTiming, uint32_t unFramesAgo = 0 ) = 0; + /** Interface for copying a range of timing data. Frames are returned in ascending order (oldest to newest) with the last being the most recent frame. + * Only the first entry's m_nSize needs to be set, as the rest will be inferred from that. Returns total number of entries filled out. */ + virtual uint32_t GetFrameTimings( Compositor_FrameTiming *pTiming, uint32_t nFrames ) = 0; + /** Returns the time in seconds left in the current (as identified by FrameTiming's frameIndex) frame. * Due to "running start", this value may roll over to the next frame before ever reaching 0.0. */ virtual float GetFrameTimeRemaining() = 0; @@ -1986,9 +2163,15 @@ public: * would be FadeToColor( 0.0, 0.0, 0.0, 0.0, 0.0 ). Values are in un-premultiplied alpha space. */ virtual void FadeToColor( float fSeconds, float fRed, float fGreen, float fBlue, float fAlpha, bool bBackground = false ) = 0; + /** Get current fade color value. */ + virtual HmdColor_t GetCurrentFadeColor( bool bBackground = false ) = 0; + /** Fading the Grid in or out in fSeconds */ virtual void FadeGrid( float fSeconds, bool bFadeIn ) = 0; + /** Get current alpha value of grid. */ + virtual float GetCurrentGridAlpha() = 0; + /** Override the skybox used in the compositor (e.g. for during level loads when the app can't feed scene images fast enough) * Order is Front, Back, Left, Right, Top, Bottom. If only a single texture is passed, it is assumed in lat-long format. * If two are passed, it is assumed a lat-long stereo pair. */ @@ -2045,14 +2228,6 @@ public: /** Temporarily suspends rendering (useful for finer control over scene transitions). */ virtual void SuspendRendering( bool bSuspend ) = 0; - /** Screenshot support */ - - /** These functions are no longer used and will be removed in - * a future update. Use the functions via the - * IVRScreenshots interface */ - virtual vr::EVRCompositorError RequestScreenshot( vr::EVRScreenshotType type, const char *pchDestinationFileName, const char *pchVRDestinationFileName ) = 0; - virtual vr::EVRScreenshotType GetCurrentScreenshotType() = 0; - /** Opens a shared D3D11 texture with the undistorted composited image for each eye. */ virtual vr::EVRCompositorError GetMirrorTextureD3D11( vr::EVREye eEye, void *pD3D11DeviceOrResource, void **ppD3D11ShaderResourceView ) = 0; @@ -2063,7 +2238,7 @@ public: virtual void UnlockGLSharedTextureForAccess( vr::glSharedTextureHandle_t glSharedTextureHandle ) = 0; }; -static const char * const IVRCompositor_Version = "IVRCompositor_015"; +static const char * const IVRCompositor_Version = "IVRCompositor_018"; } // namespace vr @@ -2178,7 +2353,10 @@ namespace vr static const uint32_t k_unVROverlayMaxNameLength = 128; /** The maximum number of overlays that can exist in the system at one time. */ - static const uint32_t k_unMaxOverlayCount = 32; + static const uint32_t k_unMaxOverlayCount = 64; + + /** The maximum number of overlay intersection mask primitives per overlay */ + static const uint32_t k_unMaxOverlayIntersectionMaskPrimitivesCount = 32; /** Types of input supported by VR Overlays */ enum VROverlayInputMethod @@ -2232,6 +2410,10 @@ namespace vr VROverlayFlags_Panorama = 12, // Texture is a panorama VROverlayFlags_StereoPanorama = 13, // Texture is a stereo panorama + + // If this is set on an overlay owned by the scene application that overlay + // will be sorted with the "Other" overlays on top of all other scene overlays + VROverlayFlags_SortWithNonSceneOverlays = 14, }; struct VROverlayIntersectionParams_t @@ -2275,6 +2457,40 @@ namespace vr OverlayDirection_Count = 4, }; + enum EVROverlayIntersectionMaskPrimitiveType + { + OverlayIntersectionPrimitiveType_Rectangle, + OverlayIntersectionPrimitiveType_Circle, + }; + + struct IntersectionMaskRectangle_t + { + float m_flTopLeftX; + float m_flTopLeftY; + float m_flWidth; + float m_flHeight; + }; + + struct IntersectionMaskCircle_t + { + float m_flCenterX; + float m_flCenterY; + float m_flRadius; + }; + + /** NOTE!!! If you change this you MUST manually update openvr_interop.cs.py and openvr_api_flat.h.py */ + typedef union + { + IntersectionMaskRectangle_t m_Rectangle; + IntersectionMaskCircle_t m_Circle; + } VROverlayIntersectionMaskPrimitive_Data_t; + + struct VROverlayIntersectionMaskPrimitive_t + { + EVROverlayIntersectionMaskPrimitiveType m_nPrimitiveType; + VROverlayIntersectionMaskPrimitive_Data_t m_Primitive; + }; + class IVROverlay { public: @@ -2350,6 +2566,26 @@ namespace vr /** Gets the alpha of the overlay quad. By default overlays are rendering at 100 percent alpha (1.0). */ virtual EVROverlayError GetOverlayAlpha( VROverlayHandle_t ulOverlayHandle, float *pfAlpha ) = 0; + /** Sets the aspect ratio of the texels in the overlay. 1.0 means the texels are square. 2.0 means the texels + * are twice as wide as they are tall. Defaults to 1.0. */ + virtual EVROverlayError SetOverlayTexelAspect( VROverlayHandle_t ulOverlayHandle, float fTexelAspect ) = 0; + + /** Gets the aspect ratio of the texels in the overlay. Defaults to 1.0 */ + virtual EVROverlayError GetOverlayTexelAspect( VROverlayHandle_t ulOverlayHandle, float *pfTexelAspect ) = 0; + + /** Sets the rendering sort order for the overlay. Overlays are rendered this order: + * Overlays owned by the scene application + * Overlays owned by some other application + * + * Within a category overlays are rendered lowest sort order to highest sort order. Overlays with the same + * sort order are rendered back to front base on distance from the HMD. + * + * Sort order defaults to 0. */ + virtual EVROverlayError SetOverlaySortOrder( VROverlayHandle_t ulOverlayHandle, uint32_t unSortOrder ) = 0; + + /** Gets the sort order of the overlay. See SetOverlaySortOrder for how this works. */ + virtual EVROverlayError GetOverlaySortOrder( VROverlayHandle_t ulOverlayHandle, uint32_t *punSortOrder ) = 0; + /** Sets the width of the overlay quad in meters. By default overlays are rendered on a quad that is 1 meter across */ virtual EVROverlayError SetOverlayWidthInMeters( VROverlayHandle_t ulOverlayHandle, float fWidthInMeters ) = 0; @@ -2551,9 +2787,16 @@ namespace vr /** Set the position of the keyboard in overlay space by telling it to avoid a rectangle in the overlay. Rectangle coords have (0,0) in the bottom left **/ virtual void SetKeyboardPositionForOverlay( VROverlayHandle_t ulOverlayHandle, HmdRect2_t avoidRect ) = 0; + // --------------------------------------------- + // Overlay input methods + // --------------------------------------------- + + /** Sets a list of primitives to be used for controller ray intersection + * typically the size of the underlying UI in pixels (not in world space). */ + virtual EVROverlayError SetOverlayIntersectionMask( VROverlayHandle_t ulOverlayHandle, VROverlayIntersectionMaskPrimitive_t *pMaskPrimitives, uint32_t unNumMaskPrimitives, uint32_t unPrimitiveSize = sizeof( VROverlayIntersectionMaskPrimitive_t ) ) = 0; }; - static const char * const IVROverlay_Version = "IVROverlay_012"; + static const char * const IVROverlay_Version = "IVROverlay_013"; } // namespace vr @@ -2758,7 +3001,7 @@ namespace vr { /** NOTE: Use of this interface is not recommended in production applications. It will not work for displays which use - * direct-to-display mode. It is also incompatible with the VR compositor and is not available when the compositor is running. */ + * direct-to-display mode. Creating our own window is also incompatible with the VR compositor and is not available when the compositor is running. */ class IVRExtendedDisplay { public: @@ -2815,6 +3058,16 @@ public: * If there is no frame available yet, due to initial camera spinup or re-activation, the error will be VRTrackedCameraError_NoFrameAvailable. * Ideally a caller should be polling at ~16ms intervals */ virtual vr::EVRTrackedCameraError GetVideoStreamFrameBuffer( vr::TrackedCameraHandle_t hTrackedCamera, vr::EVRTrackedCameraFrameType eFrameType, void *pFrameBuffer, uint32_t nFrameBufferSize, vr::CameraVideoStreamFrameHeader_t *pFrameHeader, uint32_t nFrameHeaderSize ) = 0; + + /** Gets size of the image frame. */ + virtual vr::EVRTrackedCameraError GetVideoStreamTextureSize( vr::TrackedDeviceIndex_t nDeviceIndex, vr::EVRTrackedCameraFrameType eFrameType, vr::VRTextureBounds_t *pTextureBounds, uint32_t *pnWidth, uint32_t *pnHeight ) = 0; + + /** Access a shared D3D11 texture for the specified tracked camera stream */ + virtual vr::EVRTrackedCameraError GetVideoStreamTextureD3D11( vr::TrackedCameraHandle_t hTrackedCamera, vr::EVRTrackedCameraFrameType eFrameType, void *pD3D11DeviceOrResource, void **ppD3D11ShaderResourceView, vr::CameraVideoStreamFrameHeader_t *pFrameHeader, uint32_t nFrameHeaderSize ) = 0; + + /** Access a shared GL texture for the specified tracked camera stream */ + virtual vr::EVRTrackedCameraError GetVideoStreamTextureGL( vr::TrackedCameraHandle_t hTrackedCamera, vr::EVRTrackedCameraFrameType eFrameType, vr::glUInt_t *pglTextureId, vr::CameraVideoStreamFrameHeader_t *pFrameHeader, uint32_t nFrameHeaderSize ) = 0; + virtual vr::EVRTrackedCameraError ReleaseVideoStreamTextureGL( vr::TrackedCameraHandle_t hTrackedCamera, vr::glUInt_t glTextureId ) = 0; }; static const char * const IVRTrackedCamera_Version = "IVRTrackedCamera_003"; @@ -2929,7 +3182,33 @@ static const char * const IVRScreenshots_Version = "IVRScreenshots_001"; } // namespace vr -// End + +// ivrresources.h +namespace vr +{ + +class IVRResources +{ +public: + + // ------------------------------------ + // Shared Resource Methods + // ------------------------------------ + + /** Loads the specified resource into the provided buffer if large enough. + * Returns the size in bytes of the buffer required to hold the specified resource. */ + virtual uint32_t LoadSharedResource( const char *pchResourceName, char *pchBuffer, uint32_t unBufferLen ) = 0; + + /** Provides the full path to the specified resource. Resource names can include named directories for + * drivers and other things, and this resolves all of those and returns the actual physical path. + * pchResourceTypeDirectory is the subdirectory of resources to look in. */ + virtual uint32_t GetResourceFullPath( const char *pchResourceName, const char *pchResourceTypeDirectory, char *pchPathBuffer, uint32_t unBufferLen ) = 0; +}; + +static const char * const IVRResources_Version = "IVRResources_001"; + + +}// End #endif // _OPENVR_API @@ -3074,6 +3353,17 @@ namespace vr return m_pVROverlay; } + IVRResources *VRResources() + { + CheckClear(); + if ( m_pVRResources == nullptr ) + { + EVRInitError eError; + m_pVRResources = (IVRResources *)VR_GetGenericInterface( IVRResources_Version, &eError ); + } + return m_pVRResources; + } + IVRScreenshots *VRScreenshots() { CheckClear(); @@ -3146,6 +3436,7 @@ namespace vr IVRChaperoneSetup *m_pVRChaperoneSetup; IVRCompositor *m_pVRCompositor; IVROverlay *m_pVROverlay; + IVRResources *m_pVRResources; IVRRenderModels *m_pVRRenderModels; IVRExtendedDisplay *m_pVRExtendedDisplay; IVRSettings *m_pVRSettings; @@ -3169,6 +3460,7 @@ namespace vr inline IVRRenderModels *VR_CALLTYPE VRRenderModels() { return OpenVRInternal_ModuleContext().VRRenderModels(); } inline IVRApplications *VR_CALLTYPE VRApplications() { return OpenVRInternal_ModuleContext().VRApplications(); } inline IVRSettings *VR_CALLTYPE VRSettings() { return OpenVRInternal_ModuleContext().VRSettings(); } + inline IVRResources *VR_CALLTYPE VRResources() { return OpenVRInternal_ModuleContext().VRResources(); } inline IVRExtendedDisplay *VR_CALLTYPE VRExtendedDisplay() { return OpenVRInternal_ModuleContext().VRExtendedDisplay(); } inline IVRTrackedCamera *VR_CALLTYPE VRTrackedCamera() { return OpenVRInternal_ModuleContext().VRTrackedCamera(); } @@ -3184,6 +3476,7 @@ namespace vr m_pVRSettings = nullptr; m_pVRApplications = nullptr; m_pVRTrackedCamera = nullptr; + m_pVRResources = nullptr; m_pVRScreenshots = nullptr; } diff --git a/examples/ThirdPartyLibs/openvr/headers/openvr_api.cs b/examples/ThirdPartyLibs/openvr/headers/openvr_api.cs index a4d71f826..517e2af93 100644 --- a/examples/ThirdPartyLibs/openvr/headers/openvr_api.cs +++ b/examples/ThirdPartyLibs/openvr/headers/openvr_api.cs @@ -31,7 +31,7 @@ public struct IVRSystem internal _GetProjectionRaw GetProjectionRaw; [UnmanagedFunctionPointer(CallingConvention.StdCall)] - internal delegate DistortionCoordinates_t _ComputeDistortion(EVREye eEye, float fU, float fV); + internal delegate bool _ComputeDistortion(EVREye eEye, float fU, float fV, ref DistortionCoordinates_t pDistortionCoordinates); [MarshalAs(UnmanagedType.FunctionPtr)] internal _ComputeDistortion ComputeDistortion; @@ -171,17 +171,17 @@ public struct IVRSystem internal _GetEventTypeNameFromEnum GetEventTypeNameFromEnum; [UnmanagedFunctionPointer(CallingConvention.StdCall)] - internal delegate HiddenAreaMesh_t _GetHiddenAreaMesh(EVREye eEye); + internal delegate HiddenAreaMesh_t _GetHiddenAreaMesh(EVREye eEye, EHiddenAreaMeshType type); [MarshalAs(UnmanagedType.FunctionPtr)] internal _GetHiddenAreaMesh GetHiddenAreaMesh; [UnmanagedFunctionPointer(CallingConvention.StdCall)] - internal delegate bool _GetControllerState(uint unControllerDeviceIndex, ref VRControllerState_t pControllerState); + internal delegate bool _GetControllerState(uint unControllerDeviceIndex, ref VRControllerState_t pControllerState, uint unControllerStateSize); [MarshalAs(UnmanagedType.FunctionPtr)] internal _GetControllerState GetControllerState; [UnmanagedFunctionPointer(CallingConvention.StdCall)] - internal delegate bool _GetControllerStateWithPose(ETrackingUniverseOrigin eOrigin, uint unControllerDeviceIndex, ref VRControllerState_t pControllerState, ref TrackedDevicePose_t pTrackedDevicePose); + internal delegate bool _GetControllerStateWithPose(ETrackingUniverseOrigin eOrigin, uint unControllerDeviceIndex, ref VRControllerState_t pControllerState, uint unControllerStateSize, ref TrackedDevicePose_t pTrackedDevicePose); [MarshalAs(UnmanagedType.FunctionPtr)] internal _GetControllerStateWithPose GetControllerStateWithPose; @@ -300,6 +300,26 @@ public struct IVRTrackedCamera [MarshalAs(UnmanagedType.FunctionPtr)] internal _GetVideoStreamFrameBuffer GetVideoStreamFrameBuffer; + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + internal delegate EVRTrackedCameraError _GetVideoStreamTextureSize(uint nDeviceIndex, EVRTrackedCameraFrameType eFrameType, ref VRTextureBounds_t pTextureBounds, ref uint pnWidth, ref uint pnHeight); + [MarshalAs(UnmanagedType.FunctionPtr)] + internal _GetVideoStreamTextureSize GetVideoStreamTextureSize; + + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + internal delegate EVRTrackedCameraError _GetVideoStreamTextureD3D11(ulong hTrackedCamera, EVRTrackedCameraFrameType eFrameType, IntPtr pD3D11DeviceOrResource, ref IntPtr ppD3D11ShaderResourceView, ref CameraVideoStreamFrameHeader_t pFrameHeader, uint nFrameHeaderSize); + [MarshalAs(UnmanagedType.FunctionPtr)] + internal _GetVideoStreamTextureD3D11 GetVideoStreamTextureD3D11; + + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + internal delegate EVRTrackedCameraError _GetVideoStreamTextureGL(ulong hTrackedCamera, EVRTrackedCameraFrameType eFrameType, ref uint pglTextureId, ref CameraVideoStreamFrameHeader_t pFrameHeader, uint nFrameHeaderSize); + [MarshalAs(UnmanagedType.FunctionPtr)] + internal _GetVideoStreamTextureGL GetVideoStreamTextureGL; + + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + internal delegate EVRTrackedCameraError _ReleaseVideoStreamTextureGL(ulong hTrackedCamera, uint glTextureId); + [MarshalAs(UnmanagedType.FunctionPtr)] + internal _ReleaseVideoStreamTextureGL ReleaseVideoStreamTextureGL; + } [StructLayout(LayoutKind.Sequential)] @@ -326,7 +346,7 @@ public struct IVRApplications internal _GetApplicationCount GetApplicationCount; [UnmanagedFunctionPointer(CallingConvention.StdCall)] - internal delegate EVRApplicationError _GetApplicationKeyByIndex(uint unApplicationIndex, string pchAppKeyBuffer, uint unAppKeyBufferLen); + internal delegate EVRApplicationError _GetApplicationKeyByIndex(uint unApplicationIndex, System.Text.StringBuilder pchAppKeyBuffer, uint unAppKeyBufferLen); [MarshalAs(UnmanagedType.FunctionPtr)] internal _GetApplicationKeyByIndex GetApplicationKeyByIndex; @@ -345,6 +365,11 @@ public struct IVRApplications [MarshalAs(UnmanagedType.FunctionPtr)] internal _LaunchTemplateApplication LaunchTemplateApplication; + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + internal delegate EVRApplicationError _LaunchApplicationFromMimeType(string pchMimeType, string pchArgs); + [MarshalAs(UnmanagedType.FunctionPtr)] + internal _LaunchApplicationFromMimeType LaunchApplicationFromMimeType; + [UnmanagedFunctionPointer(CallingConvention.StdCall)] internal delegate EVRApplicationError _LaunchDashboardOverlay(string pchAppKey); [MarshalAs(UnmanagedType.FunctionPtr)] @@ -371,7 +396,7 @@ public struct IVRApplications internal _GetApplicationsErrorNameFromEnum GetApplicationsErrorNameFromEnum; [UnmanagedFunctionPointer(CallingConvention.StdCall)] - internal delegate uint _GetApplicationPropertyString(string pchAppKey, EVRApplicationProperty eProperty, string pchPropertyValueBuffer, uint unPropertyValueBufferLen, ref EVRApplicationError peError); + internal delegate uint _GetApplicationPropertyString(string pchAppKey, EVRApplicationProperty eProperty, System.Text.StringBuilder pchPropertyValueBuffer, uint unPropertyValueBufferLen, ref EVRApplicationError peError); [MarshalAs(UnmanagedType.FunctionPtr)] internal _GetApplicationPropertyString GetApplicationPropertyString; @@ -395,6 +420,31 @@ public struct IVRApplications [MarshalAs(UnmanagedType.FunctionPtr)] internal _GetApplicationAutoLaunch GetApplicationAutoLaunch; + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + internal delegate EVRApplicationError _SetDefaultApplicationForMimeType(string pchAppKey, string pchMimeType); + [MarshalAs(UnmanagedType.FunctionPtr)] + internal _SetDefaultApplicationForMimeType SetDefaultApplicationForMimeType; + + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + internal delegate bool _GetDefaultApplicationForMimeType(string pchMimeType, string pchAppKeyBuffer, uint unAppKeyBufferLen); + [MarshalAs(UnmanagedType.FunctionPtr)] + internal _GetDefaultApplicationForMimeType GetDefaultApplicationForMimeType; + + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + internal delegate bool _GetApplicationSupportedMimeTypes(string pchAppKey, string pchMimeTypesBuffer, uint unMimeTypesBuffer); + [MarshalAs(UnmanagedType.FunctionPtr)] + internal _GetApplicationSupportedMimeTypes GetApplicationSupportedMimeTypes; + + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + internal delegate uint _GetApplicationsThatSupportMimeType(string pchMimeType, string pchAppKeysThatSupportBuffer, uint unAppKeysThatSupportBuffer); + [MarshalAs(UnmanagedType.FunctionPtr)] + internal _GetApplicationsThatSupportMimeType GetApplicationsThatSupportMimeType; + + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + internal delegate uint _GetApplicationLaunchArguments(uint unHandle, string pchArgs, uint unArgs); + [MarshalAs(UnmanagedType.FunctionPtr)] + internal _GetApplicationLaunchArguments GetApplicationLaunchArguments; + [UnmanagedFunctionPointer(CallingConvention.StdCall)] internal delegate EVRApplicationError _GetStartingApplication(string pchAppKeyBuffer, uint unAppKeyBufferLen); [MarshalAs(UnmanagedType.FunctionPtr)] @@ -625,6 +675,11 @@ public struct IVRCompositor [MarshalAs(UnmanagedType.FunctionPtr)] internal _GetFrameTiming GetFrameTiming; + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + internal delegate uint _GetFrameTimings(ref Compositor_FrameTiming pTiming, uint nFrames); + [MarshalAs(UnmanagedType.FunctionPtr)] + internal _GetFrameTimings GetFrameTimings; + [UnmanagedFunctionPointer(CallingConvention.StdCall)] internal delegate float _GetFrameTimeRemaining(); [MarshalAs(UnmanagedType.FunctionPtr)] @@ -640,11 +695,21 @@ public struct IVRCompositor [MarshalAs(UnmanagedType.FunctionPtr)] internal _FadeToColor FadeToColor; + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + internal delegate HmdColor_t _GetCurrentFadeColor(bool bBackground); + [MarshalAs(UnmanagedType.FunctionPtr)] + internal _GetCurrentFadeColor GetCurrentFadeColor; + [UnmanagedFunctionPointer(CallingConvention.StdCall)] internal delegate void _FadeGrid(float fSeconds, bool bFadeIn); [MarshalAs(UnmanagedType.FunctionPtr)] internal _FadeGrid FadeGrid; + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + internal delegate float _GetCurrentGridAlpha(); + [MarshalAs(UnmanagedType.FunctionPtr)] + internal _GetCurrentGridAlpha GetCurrentGridAlpha; + [UnmanagedFunctionPointer(CallingConvention.StdCall)] internal delegate EVRCompositorError _SetSkyboxOverride([In, Out] Texture_t[] pTextures, uint unTextureCount); [MarshalAs(UnmanagedType.FunctionPtr)] @@ -730,16 +795,6 @@ public struct IVRCompositor [MarshalAs(UnmanagedType.FunctionPtr)] internal _SuspendRendering SuspendRendering; - [UnmanagedFunctionPointer(CallingConvention.StdCall)] - internal delegate EVRCompositorError _RequestScreenshot(EVRScreenshotType type, string pchDestinationFileName, string pchVRDestinationFileName); - [MarshalAs(UnmanagedType.FunctionPtr)] - internal _RequestScreenshot RequestScreenshot; - - [UnmanagedFunctionPointer(CallingConvention.StdCall)] - internal delegate EVRScreenshotType _GetCurrentScreenshotType(); - [MarshalAs(UnmanagedType.FunctionPtr)] - internal _GetCurrentScreenshotType GetCurrentScreenshotType; - [UnmanagedFunctionPointer(CallingConvention.StdCall)] internal delegate EVRCompositorError _GetMirrorTextureD3D11(EVREye eEye, IntPtr pD3D11DeviceOrResource, ref IntPtr ppD3D11ShaderResourceView); [MarshalAs(UnmanagedType.FunctionPtr)] @@ -855,6 +910,26 @@ public struct IVROverlay [MarshalAs(UnmanagedType.FunctionPtr)] internal _GetOverlayAlpha GetOverlayAlpha; + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + internal delegate EVROverlayError _SetOverlayTexelAspect(ulong ulOverlayHandle, float fTexelAspect); + [MarshalAs(UnmanagedType.FunctionPtr)] + internal _SetOverlayTexelAspect SetOverlayTexelAspect; + + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + internal delegate EVROverlayError _GetOverlayTexelAspect(ulong ulOverlayHandle, ref float pfTexelAspect); + [MarshalAs(UnmanagedType.FunctionPtr)] + internal _GetOverlayTexelAspect GetOverlayTexelAspect; + + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + internal delegate EVROverlayError _SetOverlaySortOrder(ulong ulOverlayHandle, uint unSortOrder); + [MarshalAs(UnmanagedType.FunctionPtr)] + internal _SetOverlaySortOrder SetOverlaySortOrder; + + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + internal delegate EVROverlayError _GetOverlaySortOrder(ulong ulOverlayHandle, ref uint punSortOrder); + [MarshalAs(UnmanagedType.FunctionPtr)] + internal _GetOverlaySortOrder GetOverlaySortOrder; + [UnmanagedFunctionPointer(CallingConvention.StdCall)] internal delegate EVROverlayError _SetOverlayWidthInMeters(ulong ulOverlayHandle, float fWidthInMeters); [MarshalAs(UnmanagedType.FunctionPtr)] @@ -1110,6 +1185,11 @@ public struct IVROverlay [MarshalAs(UnmanagedType.FunctionPtr)] internal _SetKeyboardPositionForOverlay SetKeyboardPositionForOverlay; + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + internal delegate EVROverlayError _SetOverlayIntersectionMask(ulong ulOverlayHandle, ref VROverlayIntersectionMaskPrimitive_t pMaskPrimitives, uint unNumMaskPrimitives, uint unPrimitiveSize); + [MarshalAs(UnmanagedType.FunctionPtr)] + internal _SetOverlayIntersectionMask SetOverlayIntersectionMask; + } [StructLayout(LayoutKind.Sequential)] @@ -1235,46 +1315,46 @@ public struct IVRSettings [MarshalAs(UnmanagedType.FunctionPtr)] internal _Sync Sync; - [UnmanagedFunctionPointer(CallingConvention.StdCall)] - internal delegate bool _GetBool(string pchSection, string pchSettingsKey, bool bDefaultValue, ref EVRSettingsError peError); - [MarshalAs(UnmanagedType.FunctionPtr)] - internal _GetBool GetBool; - [UnmanagedFunctionPointer(CallingConvention.StdCall)] internal delegate void _SetBool(string pchSection, string pchSettingsKey, bool bValue, ref EVRSettingsError peError); [MarshalAs(UnmanagedType.FunctionPtr)] internal _SetBool SetBool; - [UnmanagedFunctionPointer(CallingConvention.StdCall)] - internal delegate int _GetInt32(string pchSection, string pchSettingsKey, int nDefaultValue, ref EVRSettingsError peError); - [MarshalAs(UnmanagedType.FunctionPtr)] - internal _GetInt32 GetInt32; - [UnmanagedFunctionPointer(CallingConvention.StdCall)] internal delegate void _SetInt32(string pchSection, string pchSettingsKey, int nValue, ref EVRSettingsError peError); [MarshalAs(UnmanagedType.FunctionPtr)] internal _SetInt32 SetInt32; - [UnmanagedFunctionPointer(CallingConvention.StdCall)] - internal delegate float _GetFloat(string pchSection, string pchSettingsKey, float flDefaultValue, ref EVRSettingsError peError); - [MarshalAs(UnmanagedType.FunctionPtr)] - internal _GetFloat GetFloat; - [UnmanagedFunctionPointer(CallingConvention.StdCall)] internal delegate void _SetFloat(string pchSection, string pchSettingsKey, float flValue, ref EVRSettingsError peError); [MarshalAs(UnmanagedType.FunctionPtr)] internal _SetFloat SetFloat; - [UnmanagedFunctionPointer(CallingConvention.StdCall)] - internal delegate void _GetString(string pchSection, string pchSettingsKey, string pchValue, uint unValueLen, string pchDefaultValue, ref EVRSettingsError peError); - [MarshalAs(UnmanagedType.FunctionPtr)] - internal _GetString GetString; - [UnmanagedFunctionPointer(CallingConvention.StdCall)] internal delegate void _SetString(string pchSection, string pchSettingsKey, string pchValue, ref EVRSettingsError peError); [MarshalAs(UnmanagedType.FunctionPtr)] internal _SetString SetString; + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + internal delegate bool _GetBool(string pchSection, string pchSettingsKey, ref EVRSettingsError peError); + [MarshalAs(UnmanagedType.FunctionPtr)] + internal _GetBool GetBool; + + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + internal delegate int _GetInt32(string pchSection, string pchSettingsKey, ref EVRSettingsError peError); + [MarshalAs(UnmanagedType.FunctionPtr)] + internal _GetInt32 GetInt32; + + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + internal delegate float _GetFloat(string pchSection, string pchSettingsKey, ref EVRSettingsError peError); + [MarshalAs(UnmanagedType.FunctionPtr)] + internal _GetFloat GetFloat; + + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + internal delegate void _GetString(string pchSection, string pchSettingsKey, System.Text.StringBuilder pchValue, uint unValueLen, ref EVRSettingsError peError); + [MarshalAs(UnmanagedType.FunctionPtr)] + internal _GetString GetString; + [UnmanagedFunctionPointer(CallingConvention.StdCall)] internal delegate void _RemoveSection(string pchSection, ref EVRSettingsError peError); [MarshalAs(UnmanagedType.FunctionPtr)] @@ -1327,6 +1407,21 @@ public struct IVRScreenshots } +[StructLayout(LayoutKind.Sequential)] +public struct IVRResources +{ + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + internal delegate uint _LoadSharedResource(string pchResourceName, string pchBuffer, uint unBufferLen); + [MarshalAs(UnmanagedType.FunctionPtr)] + internal _LoadSharedResource LoadSharedResource; + + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + internal delegate uint _GetResourceFullPath(string pchResourceName, string pchResourceTypeDirectory, string pchPathBuffer, uint unBufferLen); + [MarshalAs(UnmanagedType.FunctionPtr)] + internal _GetResourceFullPath GetResourceFullPath; + +} + public class CVRSystem { @@ -1354,9 +1449,9 @@ public class CVRSystem pfBottom = 0; FnTable.GetProjectionRaw(eEye,ref pfLeft,ref pfRight,ref pfTop,ref pfBottom); } - public DistortionCoordinates_t ComputeDistortion(EVREye eEye,float fU,float fV) + public bool ComputeDistortion(EVREye eEye,float fU,float fV,ref DistortionCoordinates_t pDistortionCoordinates) { - DistortionCoordinates_t result = FnTable.ComputeDistortion(eEye,fU,fV); + bool result = FnTable.ComputeDistortion(eEye,fU,fV,ref pDistortionCoordinates); return result; } public HmdMatrix34_t GetEyeToHeadTransform(EVREye eEye) @@ -1493,19 +1588,19 @@ public class CVRSystem IntPtr result = FnTable.GetEventTypeNameFromEnum(eType); return Marshal.PtrToStringAnsi(result); } - public HiddenAreaMesh_t GetHiddenAreaMesh(EVREye eEye) + public HiddenAreaMesh_t GetHiddenAreaMesh(EVREye eEye,EHiddenAreaMeshType type) { - HiddenAreaMesh_t result = FnTable.GetHiddenAreaMesh(eEye); + HiddenAreaMesh_t result = FnTable.GetHiddenAreaMesh(eEye,type); return result; } - public bool GetControllerState(uint unControllerDeviceIndex,ref VRControllerState_t pControllerState) + public bool GetControllerState(uint unControllerDeviceIndex,ref VRControllerState_t pControllerState,uint unControllerStateSize) { - bool result = FnTable.GetControllerState(unControllerDeviceIndex,ref pControllerState); + bool result = FnTable.GetControllerState(unControllerDeviceIndex,ref pControllerState,unControllerStateSize); return result; } - public bool GetControllerStateWithPose(ETrackingUniverseOrigin eOrigin,uint unControllerDeviceIndex,ref VRControllerState_t pControllerState,ref TrackedDevicePose_t pTrackedDevicePose) + public bool GetControllerStateWithPose(ETrackingUniverseOrigin eOrigin,uint unControllerDeviceIndex,ref VRControllerState_t pControllerState,uint unControllerStateSize,ref TrackedDevicePose_t pTrackedDevicePose) { - bool result = FnTable.GetControllerStateWithPose(eOrigin,unControllerDeviceIndex,ref pControllerState,ref pTrackedDevicePose); + bool result = FnTable.GetControllerStateWithPose(eOrigin,unControllerDeviceIndex,ref pControllerState,unControllerStateSize,ref pTrackedDevicePose); return result; } public void TriggerHapticPulse(uint unControllerDeviceIndex,uint unAxisId,char usDurationMicroSec) @@ -1641,6 +1736,29 @@ public class CVRTrackedCamera EVRTrackedCameraError result = FnTable.GetVideoStreamFrameBuffer(hTrackedCamera,eFrameType,pFrameBuffer,nFrameBufferSize,ref pFrameHeader,nFrameHeaderSize); return result; } + public EVRTrackedCameraError GetVideoStreamTextureSize(uint nDeviceIndex,EVRTrackedCameraFrameType eFrameType,ref VRTextureBounds_t pTextureBounds,ref uint pnWidth,ref uint pnHeight) + { + pnWidth = 0; + pnHeight = 0; + EVRTrackedCameraError result = FnTable.GetVideoStreamTextureSize(nDeviceIndex,eFrameType,ref pTextureBounds,ref pnWidth,ref pnHeight); + return result; + } + public EVRTrackedCameraError GetVideoStreamTextureD3D11(ulong hTrackedCamera,EVRTrackedCameraFrameType eFrameType,IntPtr pD3D11DeviceOrResource,ref IntPtr ppD3D11ShaderResourceView,ref CameraVideoStreamFrameHeader_t pFrameHeader,uint nFrameHeaderSize) + { + EVRTrackedCameraError result = FnTable.GetVideoStreamTextureD3D11(hTrackedCamera,eFrameType,pD3D11DeviceOrResource,ref ppD3D11ShaderResourceView,ref pFrameHeader,nFrameHeaderSize); + return result; + } + public EVRTrackedCameraError GetVideoStreamTextureGL(ulong hTrackedCamera,EVRTrackedCameraFrameType eFrameType,ref uint pglTextureId,ref CameraVideoStreamFrameHeader_t pFrameHeader,uint nFrameHeaderSize) + { + pglTextureId = 0; + EVRTrackedCameraError result = FnTable.GetVideoStreamTextureGL(hTrackedCamera,eFrameType,ref pglTextureId,ref pFrameHeader,nFrameHeaderSize); + return result; + } + public EVRTrackedCameraError ReleaseVideoStreamTextureGL(ulong hTrackedCamera,uint glTextureId) + { + EVRTrackedCameraError result = FnTable.ReleaseVideoStreamTextureGL(hTrackedCamera,glTextureId); + return result; + } } @@ -1671,7 +1789,7 @@ public class CVRApplications uint result = FnTable.GetApplicationCount(); return result; } - public EVRApplicationError GetApplicationKeyByIndex(uint unApplicationIndex,string pchAppKeyBuffer,uint unAppKeyBufferLen) + public EVRApplicationError GetApplicationKeyByIndex(uint unApplicationIndex,System.Text.StringBuilder pchAppKeyBuffer,uint unAppKeyBufferLen) { EVRApplicationError result = FnTable.GetApplicationKeyByIndex(unApplicationIndex,pchAppKeyBuffer,unAppKeyBufferLen); return result; @@ -1691,6 +1809,11 @@ public class CVRApplications EVRApplicationError result = FnTable.LaunchTemplateApplication(pchTemplateAppKey,pchNewAppKey,pKeys,(uint) pKeys.Length); return result; } + public EVRApplicationError LaunchApplicationFromMimeType(string pchMimeType,string pchArgs) + { + EVRApplicationError result = FnTable.LaunchApplicationFromMimeType(pchMimeType,pchArgs); + return result; + } public EVRApplicationError LaunchDashboardOverlay(string pchAppKey) { EVRApplicationError result = FnTable.LaunchDashboardOverlay(pchAppKey); @@ -1716,7 +1839,7 @@ public class CVRApplications IntPtr result = FnTable.GetApplicationsErrorNameFromEnum(error); return Marshal.PtrToStringAnsi(result); } - public uint GetApplicationPropertyString(string pchAppKey,EVRApplicationProperty eProperty,string pchPropertyValueBuffer,uint unPropertyValueBufferLen,ref EVRApplicationError peError) + public uint GetApplicationPropertyString(string pchAppKey,EVRApplicationProperty eProperty,System.Text.StringBuilder pchPropertyValueBuffer,uint unPropertyValueBufferLen,ref EVRApplicationError peError) { uint result = FnTable.GetApplicationPropertyString(pchAppKey,eProperty,pchPropertyValueBuffer,unPropertyValueBufferLen,ref peError); return result; @@ -1741,6 +1864,31 @@ public class CVRApplications bool result = FnTable.GetApplicationAutoLaunch(pchAppKey); return result; } + public EVRApplicationError SetDefaultApplicationForMimeType(string pchAppKey,string pchMimeType) + { + EVRApplicationError result = FnTable.SetDefaultApplicationForMimeType(pchAppKey,pchMimeType); + return result; + } + public bool GetDefaultApplicationForMimeType(string pchMimeType,string pchAppKeyBuffer,uint unAppKeyBufferLen) + { + bool result = FnTable.GetDefaultApplicationForMimeType(pchMimeType,pchAppKeyBuffer,unAppKeyBufferLen); + return result; + } + public bool GetApplicationSupportedMimeTypes(string pchAppKey,string pchMimeTypesBuffer,uint unMimeTypesBuffer) + { + bool result = FnTable.GetApplicationSupportedMimeTypes(pchAppKey,pchMimeTypesBuffer,unMimeTypesBuffer); + return result; + } + public uint GetApplicationsThatSupportMimeType(string pchMimeType,string pchAppKeysThatSupportBuffer,uint unAppKeysThatSupportBuffer) + { + uint result = FnTable.GetApplicationsThatSupportMimeType(pchMimeType,pchAppKeysThatSupportBuffer,unAppKeysThatSupportBuffer); + return result; + } + public uint GetApplicationLaunchArguments(uint unHandle,string pchArgs,uint unArgs) + { + uint result = FnTable.GetApplicationLaunchArguments(unHandle,pchArgs,unArgs); + return result; + } public EVRApplicationError GetStartingApplication(string pchAppKeyBuffer,uint unAppKeyBufferLen) { EVRApplicationError result = FnTable.GetStartingApplication(pchAppKeyBuffer,unAppKeyBufferLen); @@ -1989,6 +2137,11 @@ public class CVRCompositor bool result = FnTable.GetFrameTiming(ref pTiming,unFramesAgo); return result; } + public uint GetFrameTimings(ref Compositor_FrameTiming pTiming,uint nFrames) + { + uint result = FnTable.GetFrameTimings(ref pTiming,nFrames); + return result; + } public float GetFrameTimeRemaining() { float result = FnTable.GetFrameTimeRemaining(); @@ -2002,10 +2155,20 @@ public class CVRCompositor { FnTable.FadeToColor(fSeconds,fRed,fGreen,fBlue,fAlpha,bBackground); } + public HmdColor_t GetCurrentFadeColor(bool bBackground) + { + HmdColor_t result = FnTable.GetCurrentFadeColor(bBackground); + return result; + } public void FadeGrid(float fSeconds,bool bFadeIn) { FnTable.FadeGrid(fSeconds,bFadeIn); } + public float GetCurrentGridAlpha() + { + float result = FnTable.GetCurrentGridAlpha(); + return result; + } public EVRCompositorError SetSkyboxOverride(Texture_t [] pTextures) { EVRCompositorError result = FnTable.SetSkyboxOverride(pTextures,(uint) pTextures.Length); @@ -2081,16 +2244,6 @@ public class CVRCompositor { FnTable.SuspendRendering(bSuspend); } - public EVRCompositorError RequestScreenshot(EVRScreenshotType type,string pchDestinationFileName,string pchVRDestinationFileName) - { - EVRCompositorError result = FnTable.RequestScreenshot(type,pchDestinationFileName,pchVRDestinationFileName); - return result; - } - public EVRScreenshotType GetCurrentScreenshotType() - { - EVRScreenshotType result = FnTable.GetCurrentScreenshotType(); - return result; - } public EVRCompositorError GetMirrorTextureD3D11(EVREye eEye,IntPtr pD3D11DeviceOrResource,ref IntPtr ppD3D11ShaderResourceView) { EVRCompositorError result = FnTable.GetMirrorTextureD3D11(eEye,pD3D11DeviceOrResource,ref ppD3D11ShaderResourceView); @@ -2219,6 +2372,28 @@ public class CVROverlay EVROverlayError result = FnTable.GetOverlayAlpha(ulOverlayHandle,ref pfAlpha); return result; } + public EVROverlayError SetOverlayTexelAspect(ulong ulOverlayHandle,float fTexelAspect) + { + EVROverlayError result = FnTable.SetOverlayTexelAspect(ulOverlayHandle,fTexelAspect); + return result; + } + public EVROverlayError GetOverlayTexelAspect(ulong ulOverlayHandle,ref float pfTexelAspect) + { + pfTexelAspect = 0; + EVROverlayError result = FnTable.GetOverlayTexelAspect(ulOverlayHandle,ref pfTexelAspect); + return result; + } + public EVROverlayError SetOverlaySortOrder(ulong ulOverlayHandle,uint unSortOrder) + { + EVROverlayError result = FnTable.SetOverlaySortOrder(ulOverlayHandle,unSortOrder); + return result; + } + public EVROverlayError GetOverlaySortOrder(ulong ulOverlayHandle,ref uint punSortOrder) + { + punSortOrder = 0; + EVROverlayError result = FnTable.GetOverlaySortOrder(ulOverlayHandle,ref punSortOrder); + return result; + } public EVROverlayError SetOverlayWidthInMeters(ulong ulOverlayHandle,float fWidthInMeters) { EVROverlayError result = FnTable.SetOverlayWidthInMeters(ulOverlayHandle,fWidthInMeters); @@ -2483,6 +2658,11 @@ public class CVROverlay { FnTable.SetKeyboardPositionForOverlay(ulOverlayHandle,avoidRect); } + public EVROverlayError SetOverlayIntersectionMask(ulong ulOverlayHandle,ref VROverlayIntersectionMaskPrimitive_t pMaskPrimitives,uint unNumMaskPrimitives,uint unPrimitiveSize) + { + EVROverlayError result = FnTable.SetOverlayIntersectionMask(ulOverlayHandle,ref pMaskPrimitives,unNumMaskPrimitives,unPrimitiveSize); + return result; + } } @@ -2621,41 +2801,41 @@ public class CVRSettings bool result = FnTable.Sync(bForce,ref peError); return result; } - public bool GetBool(string pchSection,string pchSettingsKey,bool bDefaultValue,ref EVRSettingsError peError) - { - bool result = FnTable.GetBool(pchSection,pchSettingsKey,bDefaultValue,ref peError); - return result; - } public void SetBool(string pchSection,string pchSettingsKey,bool bValue,ref EVRSettingsError peError) { FnTable.SetBool(pchSection,pchSettingsKey,bValue,ref peError); } - public int GetInt32(string pchSection,string pchSettingsKey,int nDefaultValue,ref EVRSettingsError peError) - { - int result = FnTable.GetInt32(pchSection,pchSettingsKey,nDefaultValue,ref peError); - return result; - } public void SetInt32(string pchSection,string pchSettingsKey,int nValue,ref EVRSettingsError peError) { FnTable.SetInt32(pchSection,pchSettingsKey,nValue,ref peError); } - public float GetFloat(string pchSection,string pchSettingsKey,float flDefaultValue,ref EVRSettingsError peError) - { - float result = FnTable.GetFloat(pchSection,pchSettingsKey,flDefaultValue,ref peError); - return result; - } public void SetFloat(string pchSection,string pchSettingsKey,float flValue,ref EVRSettingsError peError) { FnTable.SetFloat(pchSection,pchSettingsKey,flValue,ref peError); } - public void GetString(string pchSection,string pchSettingsKey,string pchValue,uint unValueLen,string pchDefaultValue,ref EVRSettingsError peError) - { - FnTable.GetString(pchSection,pchSettingsKey,pchValue,unValueLen,pchDefaultValue,ref peError); - } public void SetString(string pchSection,string pchSettingsKey,string pchValue,ref EVRSettingsError peError) { FnTable.SetString(pchSection,pchSettingsKey,pchValue,ref peError); } + public bool GetBool(string pchSection,string pchSettingsKey,ref EVRSettingsError peError) + { + bool result = FnTable.GetBool(pchSection,pchSettingsKey,ref peError); + return result; + } + public int GetInt32(string pchSection,string pchSettingsKey,ref EVRSettingsError peError) + { + int result = FnTable.GetInt32(pchSection,pchSettingsKey,ref peError); + return result; + } + public float GetFloat(string pchSection,string pchSettingsKey,ref EVRSettingsError peError) + { + float result = FnTable.GetFloat(pchSection,pchSettingsKey,ref peError); + return result; + } + public void GetString(string pchSection,string pchSettingsKey,System.Text.StringBuilder pchValue,uint unValueLen,ref EVRSettingsError peError) + { + FnTable.GetString(pchSection,pchSettingsKey,pchValue,unValueLen,ref peError); + } public void RemoveSection(string pchSection,ref EVRSettingsError peError) { FnTable.RemoveSection(pchSection,ref peError); @@ -2714,23 +2894,43 @@ public class CVRScreenshots } +public class CVRResources +{ + IVRResources FnTable; + internal CVRResources(IntPtr pInterface) + { + FnTable = (IVRResources)Marshal.PtrToStructure(pInterface, typeof(IVRResources)); + } + public uint LoadSharedResource(string pchResourceName,string pchBuffer,uint unBufferLen) + { + uint result = FnTable.LoadSharedResource(pchResourceName,pchBuffer,unBufferLen); + return result; + } + public uint GetResourceFullPath(string pchResourceName,string pchResourceTypeDirectory,string pchPathBuffer,uint unBufferLen) + { + uint result = FnTable.GetResourceFullPath(pchResourceName,pchResourceTypeDirectory,pchPathBuffer,unBufferLen); + return result; + } +} + + public class OpenVRInterop { - [DllImportAttribute("openvr_api", EntryPoint = "VR_InitInternal")] + [DllImportAttribute("openvr_api", EntryPoint = "VR_InitInternal", CallingConvention = CallingConvention.Cdecl)] internal static extern uint InitInternal(ref EVRInitError peError, EVRApplicationType eApplicationType); - [DllImportAttribute("openvr_api", EntryPoint = "VR_ShutdownInternal")] + [DllImportAttribute("openvr_api", EntryPoint = "VR_ShutdownInternal", CallingConvention = CallingConvention.Cdecl)] internal static extern void ShutdownInternal(); - [DllImportAttribute("openvr_api", EntryPoint = "VR_IsHmdPresent")] + [DllImportAttribute("openvr_api", EntryPoint = "VR_IsHmdPresent", CallingConvention = CallingConvention.Cdecl)] internal static extern bool IsHmdPresent(); - [DllImportAttribute("openvr_api", EntryPoint = "VR_IsRuntimeInstalled")] + [DllImportAttribute("openvr_api", EntryPoint = "VR_IsRuntimeInstalled", CallingConvention = CallingConvention.Cdecl)] internal static extern bool IsRuntimeInstalled(); - [DllImportAttribute("openvr_api", EntryPoint = "VR_GetStringForHmdError")] + [DllImportAttribute("openvr_api", EntryPoint = "VR_GetStringForHmdError", CallingConvention = CallingConvention.Cdecl)] internal static extern IntPtr GetStringForHmdError(EVRInitError error); - [DllImportAttribute("openvr_api", EntryPoint = "VR_GetGenericInterface")] + [DllImportAttribute("openvr_api", EntryPoint = "VR_GetGenericInterface", CallingConvention = CallingConvention.Cdecl)] internal static extern IntPtr GetGenericInterface([In, MarshalAs(UnmanagedType.LPStr)] string pchInterfaceVersion, ref EVRInitError peError); - [DllImportAttribute("openvr_api", EntryPoint = "VR_IsInterfaceVersionValid")] + [DllImportAttribute("openvr_api", EntryPoint = "VR_IsInterfaceVersionValid", CallingConvention = CallingConvention.Cdecl)] internal static extern bool IsInterfaceVersionValid([In, MarshalAs(UnmanagedType.LPStr)] string pchInterfaceVersion); - [DllImportAttribute("openvr_api", EntryPoint = "VR_GetInitToken")] + [DllImportAttribute("openvr_api", EntryPoint = "VR_GetInitToken", CallingConvention = CallingConvention.Cdecl)] internal static extern uint GetInitToken(); } @@ -2765,6 +2965,7 @@ public enum ETrackedDeviceClass HMD = 1, Controller = 2, TrackingReference = 4, + Count = 5, Other = 1000, } public enum ETrackedControllerRole @@ -2814,6 +3015,7 @@ public enum ETrackedDeviceProperty Prop_HasCamera_Bool = 1030, Prop_DriverVersion_String = 1031, Prop_Firmware_ForceUpdateRequired_Bool = 1032, + Prop_ViveSystemButtonFixRequired_Bool = 1033, Prop_ReportsTimeSinceVSync_Bool = 2000, Prop_SecondsFromVsyncToPhotons_Float = 2001, Prop_DisplayFrequency_Float = 2002, @@ -2851,6 +3053,7 @@ public enum ETrackedDeviceProperty Prop_ScreenshotHorizontalFieldOfViewDegrees_Float = 2034, Prop_ScreenshotVerticalFieldOfViewDegrees_Float = 2035, Prop_DisplaySuppressed_Bool = 2036, + Prop_DisplayAllowNightMode_Bool = 2037, Prop_AttachedDeviceId_String = 3000, Prop_SupportedButtons_Uint64 = 3001, Prop_Axis0Type_Int32 = 3002, @@ -2858,6 +3061,7 @@ public enum ETrackedDeviceProperty Prop_Axis2Type_Int32 = 3004, Prop_Axis3Type_Int32 = 3005, Prop_Axis4Type_Int32 = 3006, + Prop_ControllerRoleHint_Int32 = 3007, Prop_FieldOfViewLeftDegrees_Float = 4000, Prop_FieldOfViewRightDegrees_Float = 4001, Prop_FieldOfViewTopDegrees_Float = 4002, @@ -2865,6 +3069,15 @@ public enum ETrackedDeviceProperty Prop_TrackingRangeMinimumMeters_Float = 4004, Prop_TrackingRangeMaximumMeters_Float = 4005, Prop_ModeLabel_String = 4006, + Prop_IconPathName_String = 5000, + Prop_NamedIconPathDeviceOff_String = 5001, + Prop_NamedIconPathDeviceSearching_String = 5002, + Prop_NamedIconPathDeviceSearchingAlert_String = 5003, + Prop_NamedIconPathDeviceReady_String = 5004, + Prop_NamedIconPathDeviceReadyAlert_String = 5005, + Prop_NamedIconPathDeviceNotReady_String = 5006, + Prop_NamedIconPathDeviceStandby_String = 5007, + Prop_NamedIconPathDeviceAlertLow_String = 5008, Prop_VendorSpecific_Reserved_Start = 10000, Prop_VendorSpecific_Reserved_End = 10999, } @@ -2886,6 +3099,7 @@ public enum EVRSubmitFlags Submit_Default = 0, Submit_LensDistortionAlreadyApplied = 1, Submit_GlRenderBuffer = 2, + Submit_VulkanTexture = 4, } public enum EVRState { @@ -2897,6 +3111,7 @@ public enum EVRState Ready_Alert = 4, NotReady = 5, Standby = 6, + Ready_Alert_Low = 7, } public enum EVREventType { @@ -2910,6 +3125,8 @@ public enum EVREventType VREvent_EnterStandbyMode = 106, VREvent_LeaveStandbyMode = 107, VREvent_TrackedDeviceRoleChanged = 108, + VREvent_WatchdogWakeUpRequested = 109, + VREvent_LensDistortionChanged = 110, VREvent_ButtonPress = 200, VREvent_ButtonUnpress = 201, VREvent_ButtonTouch = 202, @@ -2921,6 +3138,7 @@ public enum EVREventType VREvent_FocusLeave = 304, VREvent_Scroll = 305, VREvent_TouchPadMove = 306, + VREvent_OverlayFocusChanged = 307, VREvent_InputFocusCaptured = 400, VREvent_InputFocusReleased = 401, VREvent_SceneFocusLost = 402, @@ -2949,10 +3167,12 @@ public enum EVREventType VREvent_DashboardGuideButtonUp = 515, VREvent_ScreenshotTriggered = 516, VREvent_ImageFailed = 517, + VREvent_DashboardOverlayCreated = 518, VREvent_RequestScreenshot = 520, VREvent_ScreenshotTaken = 521, VREvent_ScreenshotFailed = 522, VREvent_SubmitScreenshotToDashboard = 523, + VREvent_ScreenshotProgressToDashboard = 524, VREvent_Notification_Shown = 600, VREvent_Notification_Hidden = 601, VREvent_Notification_BeginInteraction = 602, @@ -2973,6 +3193,7 @@ public enum EVREventType VREvent_ReprojectionSettingHasChanged = 852, VREvent_ModelSkinSettingsHaveChanged = 853, VREvent_EnvironmentSettingsHaveChanged = 854, + VREvent_PowerSettingsHaveChanged = 855, VREvent_StatusUpdate = 900, VREvent_MCImageUpdated = 1000, VREvent_FirmwareUpdateStarted = 1100, @@ -2984,6 +3205,7 @@ public enum EVREventType VREvent_ApplicationTransitionAborted = 1301, VREvent_ApplicationTransitionNewAppStarted = 1302, VREvent_ApplicationListUpdated = 1303, + VREvent_ApplicationMimeTypeLoad = 1304, VREvent_Compositor_MirrorWindowShown = 1400, VREvent_Compositor_MirrorWindowHidden = 1401, VREvent_Compositor_ChaperoneBoundsShown = 1410, @@ -2992,6 +3214,7 @@ public enum EVREventType VREvent_TrackedCamera_StopVideoStream = 1501, VREvent_TrackedCamera_PauseVideoStream = 1502, VREvent_TrackedCamera_ResumeVideoStream = 1503, + VREvent_TrackedCamera_EditingSurface = 1550, VREvent_PerformanceTest_EnableCapture = 1600, VREvent_PerformanceTest_DisableCapture = 1601, VREvent_PerformanceTest_FidelityLevel = 1602, @@ -3016,6 +3239,7 @@ public enum EVRButtonId k_EButton_DPad_Right = 5, k_EButton_DPad_Down = 6, k_EButton_A = 7, + k_EButton_ProximitySensor = 31, k_EButton_Axis0 = 32, k_EButton_Axis1 = 33, k_EButton_Axis2 = 34, @@ -3032,6 +3256,12 @@ public enum EVRMouseButton Right = 2, Middle = 4, } +public enum EHiddenAreaMeshType +{ + k_eHiddenAreaMesh_Standard = 0, + k_eHiddenAreaMesh_Inverse = 1, + k_eHiddenAreaMesh_LineLoop = 2, +} public enum EVRControllerAxisType { k_eControllerAxis_None = 0, @@ -3072,8 +3302,10 @@ public enum EVROverlayError RequestFailed = 23, InvalidTexture = 24, UnableToLoadFile = 25, - VROVerlayError_KeyboardAlreadyInUse = 26, + KeyboardAlreadyInUse = 26, NoNeighbor = 27, + TooManyMaskPrimitives = 29, + BadMaskPrimitive = 30, } public enum EVRApplicationType { @@ -3083,6 +3315,8 @@ public enum EVRApplicationType VRApplication_Background = 3, VRApplication_Utility = 4, VRApplication_VRMonitor = 5, + VRApplication_SteamWatchdog = 6, + VRApplication_Max = 7, } public enum EVRFirmwareError { @@ -3127,6 +3361,14 @@ public enum EVRInitError Init_NotSupportedWithCompositor = 122, Init_NotAvailableToUtilityApps = 123, Init_Internal = 124, + Init_HmdDriverIdIsNone = 125, + Init_HmdNotFoundPresenceFailed = 126, + Init_VRMonitorNotFound = 127, + Init_VRMonitorStartupFailed = 128, + Init_LowPowerWatchdogNotSupported = 129, + Init_InvalidApplicationType = 130, + Init_NotAvailableToWatchdogApps = 131, + Init_WatchdogDisabledInSettings = 132, Driver_Failed = 200, Driver_Unknown = 201, Driver_HmdUnknown = 202, @@ -3136,12 +3378,18 @@ public enum EVRInitError Driver_NotCalibrated = 206, Driver_CalibrationInvalid = 207, Driver_HmdDisplayNotFound = 208, + Driver_TrackedDeviceInterfaceUnknown = 209, + Driver_HmdDriverIdOutOfBounds = 211, + Driver_HmdDisplayMirrored = 212, IPC_ServerInitFailed = 300, IPC_ConnectFailed = 301, IPC_SharedStateInitFailed = 302, IPC_CompositorInitFailed = 303, IPC_MutexInitFailed = 304, IPC_Failed = 305, + IPC_CompositorConnectFailed = 306, + IPC_CompositorInvalidConnectResponse = 307, + IPC_ConnectFailedAfterMultipleAttempts = 308, Compositor_Failed = 400, Compositor_D3D11HardwareRequired = 401, Compositor_FirmwareRequiresUpdate = 402, @@ -3285,6 +3533,7 @@ public enum EVRCompositorError TextureUsesUnsupportedFormat = 105, SharedTexturesNotSupported = 106, IndexOutOfRange = 107, + AlreadySubmitted = 108, } public enum VROverlayInputMethod { @@ -3314,6 +3563,7 @@ public enum VROverlayFlags SideBySide_Crossed = 11, Panorama = 12, StereoPanorama = 13, + SortWithNonSceneOverlays = 14, } public enum EGamepadTextInputMode { @@ -3334,6 +3584,11 @@ public enum EOverlayDirection Right = 3, Count = 4, } +public enum EVROverlayIntersectionMaskPrimitiveType +{ + OverlayIntersectionPrimitiveType_Rectangle = 0, + OverlayIntersectionPrimitiveType_Circle = 1, +} public enum EVRRenderModelError { None = 0, @@ -3378,6 +3633,8 @@ public enum EVRSettingsError IPCFailed = 1, WriteFailed = 2, ReadFailed = 3, + JsonParseFailed = 4, + UnsetSettingHasNoDefault = 5, } public enum EVRScreenshotError { @@ -3408,6 +3665,13 @@ public enum EVRScreenshotError [FieldOffset(0)] public VREvent_Keyboard_t keyboard; // This has to be at the end due to a mono bug } + +[StructLayout(LayoutKind.Explicit)] public struct VROverlayIntersectionMaskPrimitive_Data_t +{ + [FieldOffset(0)] public IntersectionMaskRectangle_t m_Rectangle; + [FieldOffset(0)] public IntersectionMaskCircle_t m_Circle; +} + [StructLayout(LayoutKind.Sequential)] public struct HmdMatrix34_t { public float m0; //float[3][4] @@ -3525,6 +3789,19 @@ public enum EVRScreenshotError public float uMax; public float vMax; } +[StructLayout(LayoutKind.Sequential)] public struct VulkanData_t +{ + public ulong m_nImage; + public IntPtr m_pDevice; // struct VkDevice_T * + public IntPtr m_pPhysicalDevice; // struct VkPhysicalDevice_T * + public IntPtr m_pInstance; // struct VkInstance_T * + public IntPtr m_pQueue; // struct VkQueue_T * + public uint m_nQueueFamilyIndex; + public uint m_nWidth; + public uint m_nHeight; + public uint m_nFormat; + public uint m_nSampleCount; +} [StructLayout(LayoutKind.Sequential)] public struct VREvent_Controller_t { public uint button; @@ -3604,6 +3881,20 @@ public enum EVRScreenshotError public uint handle; public uint type; } +[StructLayout(LayoutKind.Sequential)] public struct VREvent_ScreenshotProgress_t +{ + public float progress; +} +[StructLayout(LayoutKind.Sequential)] public struct VREvent_ApplicationLaunch_t +{ + public uint pid; + public uint unArgsHandle; +} +[StructLayout(LayoutKind.Sequential)] public struct VREvent_EditingCameraSurface_t +{ + public ulong overlayHandle; + public uint nVisualMode; +} [StructLayout(LayoutKind.Sequential)] public struct VREvent_t { public uint eventType; @@ -3670,9 +3961,12 @@ public enum EVRScreenshotError public uint m_nSize; public uint m_nFrameIndex; public uint m_nNumFramePresents; + public uint m_nNumMisPresented; public uint m_nNumDroppedFrames; + public uint m_nReprojectionFlags; public double m_flSystemTimeInSeconds; - public float m_flSceneRenderGpuMs; + public float m_flPreSubmitGpuMs; + public float m_flPostSubmitGpuMs; public float m_flTotalRenderGpuMs; public float m_flCompositorRenderGpuMs; public float m_flCompositorRenderCpuMs; @@ -3688,8 +3982,6 @@ public enum EVRScreenshotError public float m_flCompositorUpdateEndMs; public float m_flCompositorRenderStartMs; public TrackedDevicePose_t m_HmdPose; - public int m_nFidelityLevel; - public uint m_nReprojectionFlags; } [StructLayout(LayoutKind.Sequential)] public struct Compositor_CumulativeStats { @@ -3722,6 +4014,24 @@ public enum EVRScreenshotError public HmdVector2_t vUVs; public float fDistance; } +[StructLayout(LayoutKind.Sequential)] public struct IntersectionMaskRectangle_t +{ + public float m_flTopLeftX; + public float m_flTopLeftY; + public float m_flWidth; + public float m_flHeight; +} +[StructLayout(LayoutKind.Sequential)] public struct IntersectionMaskCircle_t +{ + public float m_flCenterX; + public float m_flCenterY; + public float m_flRadius; +} +[StructLayout(LayoutKind.Sequential)] public struct VROverlayIntersectionMaskPrimitive_t +{ + public EVROverlayIntersectionMaskPrimitiveType m_nPrimitiveType; + public VROverlayIntersectionMaskPrimitive_Data_t m_Primitive; +} [StructLayout(LayoutKind.Sequential)] public struct RenderModel_ComponentState_t { public HmdMatrix34_t mTrackingToComponentRenderModel; @@ -3768,6 +4078,7 @@ public enum EVRScreenshotError public IntPtr m_pVRChaperoneSetup; // class vr::IVRChaperoneSetup * public IntPtr m_pVRCompositor; // class vr::IVRCompositor * public IntPtr m_pVROverlay; // class vr::IVROverlay * + public IntPtr m_pVRResources; // class vr::IVRResources * public IntPtr m_pVRRenderModels; // class vr::IVRRenderModels * public IntPtr m_pVRExtendedDisplay; // class vr::IVRExtendedDisplay * public IntPtr m_pVRSettings; // class vr::IVRSettings * @@ -3819,7 +4130,6 @@ public class OpenVR return OpenVRInterop.GetInitToken(); } - public const uint k_unTrackingStringSize = 32; public const uint k_unMaxDriverDebugResponseSize = 32768; public const uint k_unTrackedDeviceIndex_Hmd = 0; public const uint k_unMaxTrackedDeviceCount = 16; @@ -3829,18 +4139,21 @@ public class OpenVR public const uint k_unControllerStateAxisCount = 5; public const ulong k_ulOverlayHandleInvalid = 0; public const uint k_unScreenshotHandleInvalid = 0; - public const string IVRSystem_Version = "IVRSystem_012"; + public const string IVRSystem_Version = "IVRSystem_014"; public const string IVRExtendedDisplay_Version = "IVRExtendedDisplay_001"; public const string IVRTrackedCamera_Version = "IVRTrackedCamera_003"; public const uint k_unMaxApplicationKeyLength = 128; - public const string IVRApplications_Version = "IVRApplications_005"; + public const string k_pch_MimeType_HomeApp = "vr/home"; + public const string k_pch_MimeType_GameTheater = "vr/game_theater"; + public const string IVRApplications_Version = "IVRApplications_006"; public const string IVRChaperone_Version = "IVRChaperone_003"; public const string IVRChaperoneSetup_Version = "IVRChaperoneSetup_005"; - public const string IVRCompositor_Version = "IVRCompositor_015"; + public const string IVRCompositor_Version = "IVRCompositor_018"; public const uint k_unVROverlayMaxKeyLength = 128; public const uint k_unVROverlayMaxNameLength = 128; - public const uint k_unMaxOverlayCount = 32; - public const string IVROverlay_Version = "IVROverlay_012"; + public const uint k_unMaxOverlayCount = 64; + public const uint k_unMaxOverlayIntersectionMaskPrimitivesCount = 32; + public const string IVROverlay_Version = "IVROverlay_013"; public const string k_pch_Controller_Component_GDC2015 = "gdc2015"; public const string k_pch_Controller_Component_Base = "base"; public const string k_pch_Controller_Component_Tip = "tip"; @@ -3850,7 +4163,7 @@ public class OpenVR public const uint k_unNotificationTextMaxSize = 256; public const string IVRNotifications_Version = "IVRNotifications_002"; public const uint k_unMaxSettingsKeyLength = 128; - public const string IVRSettings_Version = "IVRSettings_001"; + public const string IVRSettings_Version = "IVRSettings_002"; public const string k_pch_SteamVR_Section = "steamvr"; public const string k_pch_SteamVR_RequireHmd_String = "requireHmd"; public const string k_pch_SteamVR_ForcedDriverKey_String = "forcedDriver"; @@ -3864,16 +4177,13 @@ public class OpenVR public const string k_pch_SteamVR_LogLevel_Int32 = "loglevel"; public const string k_pch_SteamVR_IPD_Float = "ipd"; public const string k_pch_SteamVR_Background_String = "background"; + public const string k_pch_SteamVR_BackgroundUseDomeProjection_Bool = "backgroundUseDomeProjection"; public const string k_pch_SteamVR_BackgroundCameraHeight_Float = "backgroundCameraHeight"; public const string k_pch_SteamVR_BackgroundDomeRadius_Float = "backgroundDomeRadius"; - public const string k_pch_SteamVR_Environment_String = "environment"; public const string k_pch_SteamVR_GridColor_String = "gridColor"; public const string k_pch_SteamVR_PlayAreaColor_String = "playAreaColor"; public const string k_pch_SteamVR_ShowStage_Bool = "showStage"; public const string k_pch_SteamVR_ActivateMultipleDrivers_Bool = "activateMultipleDrivers"; - public const string k_pch_SteamVR_PowerOffOnExit_Bool = "powerOffOnExit"; - public const string k_pch_SteamVR_StandbyAppRunningTimeout_Float = "standbyAppRunningTimeout"; - public const string k_pch_SteamVR_StandbyNoAppTimeout_Float = "standbyNoAppTimeout"; public const string k_pch_SteamVR_DirectMode_Bool = "directMode"; public const string k_pch_SteamVR_DirectModeEdidVid_Int32 = "directModeEdidVid"; public const string k_pch_SteamVR_DirectModeEdidPid_Int32 = "directModeEdidPid"; @@ -3882,19 +4192,24 @@ public class OpenVR public const string k_pch_SteamVR_BaseStationPowerManagement_Bool = "basestationPowerManagement"; public const string k_pch_SteamVR_NeverKillProcesses_Bool = "neverKillProcesses"; public const string k_pch_SteamVR_RenderTargetMultiplier_Float = "renderTargetMultiplier"; - public const string k_pch_SteamVR_AllowReprojection_Bool = "allowReprojection"; + public const string k_pch_SteamVR_AllowAsyncReprojection_Bool = "allowAsyncReprojection"; + public const string k_pch_SteamVR_AllowReprojection_Bool = "allowInterleavedReprojection"; public const string k_pch_SteamVR_ForceReprojection_Bool = "forceReprojection"; public const string k_pch_SteamVR_ForceFadeOnBadTracking_Bool = "forceFadeOnBadTracking"; public const string k_pch_SteamVR_DefaultMirrorView_Int32 = "defaultMirrorView"; public const string k_pch_SteamVR_ShowMirrorView_Bool = "showMirrorView"; + public const string k_pch_SteamVR_MirrorViewGeometry_String = "mirrorViewGeometry"; + public const string k_pch_SteamVR_StartMonitorFromAppLaunch = "startMonitorFromAppLaunch"; + public const string k_pch_SteamVR_EnableHomeApp = "enableHomeApp"; + public const string k_pch_SteamVR_SetInitialDefaultHomeApp = "setInitialDefaultHomeApp"; + public const string k_pch_SteamVR_CycleBackgroundImageTimeSec_Int32 = "CycleBackgroundImageTimeSec"; + public const string k_pch_SteamVR_RetailDemo_Bool = "retailDemo"; + public const string k_pch_SteamVR_IpdOffset_Float = "ipdOffset"; public const string k_pch_Lighthouse_Section = "driver_lighthouse"; public const string k_pch_Lighthouse_DisableIMU_Bool = "disableimu"; public const string k_pch_Lighthouse_UseDisambiguation_String = "usedisambiguation"; public const string k_pch_Lighthouse_DisambiguationDebug_Int32 = "disambiguationdebug"; public const string k_pch_Lighthouse_PrimaryBasestation_Int32 = "primarybasestation"; - public const string k_pch_Lighthouse_LighthouseName_String = "lighthousename"; - public const string k_pch_Lighthouse_MaxIncidenceAngleDegrees_Float = "maxincidenceangledegrees"; - public const string k_pch_Lighthouse_UseLighthouseDirect_Bool = "uselighthousedirect"; public const string k_pch_Lighthouse_DBHistory_Bool = "dbhistory"; public const string k_pch_Null_Section = "driver_null"; public const string k_pch_Null_EnableNullDriver_Bool = "enable"; @@ -3910,7 +4225,9 @@ public class OpenVR public const string k_pch_Null_DisplayFrequency_Float = "displayFrequency"; public const string k_pch_UserInterface_Section = "userinterface"; public const string k_pch_UserInterface_StatusAlwaysOnTop_Bool = "StatusAlwaysOnTop"; - public const string k_pch_UserInterface_EnableScreenshots_Bool = "EnableScreenshots"; + public const string k_pch_UserInterface_MinimizeToTray_Bool = "MinimizeToTray"; + public const string k_pch_UserInterface_Screenshots_Bool = "screenshots"; + public const string k_pch_UserInterface_ScreenshotType_Int = "screenshotType"; public const string k_pch_Notifications_Section = "notifications"; public const string k_pch_Notifications_DoNotDisturb_Bool = "DoNotDisturb"; public const string k_pch_Keyboard_Section = "keyboard"; @@ -3947,6 +4264,7 @@ public class OpenVR public const string k_pch_Camera_BoundsColorGammaG_Int32 = "cameraBoundsColorGammaG"; public const string k_pch_Camera_BoundsColorGammaB_Int32 = "cameraBoundsColorGammaB"; public const string k_pch_Camera_BoundsColorGammaA_Int32 = "cameraBoundsColorGammaA"; + public const string k_pch_Camera_BoundsStrength_Int32 = "cameraBoundsStrength"; public const string k_pch_audio_Section = "audio"; public const string k_pch_audio_OnPlaybackDevice_String = "onPlaybackDevice"; public const string k_pch_audio_OnRecordDevice_String = "onRecordDevice"; @@ -3954,8 +4272,18 @@ public class OpenVR public const string k_pch_audio_OffPlaybackDevice_String = "offPlaybackDevice"; public const string k_pch_audio_OffRecordDevice_String = "offRecordDevice"; public const string k_pch_audio_VIVEHDMIGain = "viveHDMIGain"; + public const string k_pch_Power_Section = "power"; + public const string k_pch_Power_PowerOffOnExit_Bool = "powerOffOnExit"; + public const string k_pch_Power_TurnOffScreensTimeout_Float = "turnOffScreensTimeout"; + public const string k_pch_Power_TurnOffControllersTimeout_Float = "turnOffControllersTimeout"; + public const string k_pch_Power_ReturnToWatchdogTimeout_Float = "returnToWatchdogTimeout"; + public const string k_pch_Power_AutoLaunchSteamVROnButtonPress = "autoLaunchSteamVROnButtonPress"; + public const string k_pch_Dashboard_Section = "dashboard"; + public const string k_pch_Dashboard_EnableDashboard_Bool = "enableDashboard"; + public const string k_pch_Dashboard_ArcadeMode_Bool = "arcadeMode"; public const string k_pch_modelskin_Section = "modelskins"; public const string IVRScreenshots_Version = "IVRScreenshots_001"; + public const string IVRResources_Version = "IVRResources_001"; static uint VRToken { get; set; } @@ -3977,6 +4305,7 @@ public class OpenVR m_pVRSettings = null; m_pVRApplications = null; m_pVRScreenshots = null; + m_pVRTrackedCamera = null; } void CheckClear() @@ -4118,6 +4447,19 @@ public class OpenVR return m_pVRScreenshots; } + public CVRTrackedCamera VRTrackedCamera() + { + CheckClear(); + if (m_pVRTrackedCamera == null) + { + var eError = EVRInitError.None; + var pInterface = OpenVRInterop.GetGenericInterface(FnTable_Prefix+IVRTrackedCamera_Version, ref eError); + if (pInterface != IntPtr.Zero && eError == EVRInitError.None) + m_pVRTrackedCamera = new CVRTrackedCamera(pInterface); + } + return m_pVRTrackedCamera; + } + private CVRSystem m_pVRSystem; private CVRChaperone m_pVRChaperone; private CVRChaperoneSetup m_pVRChaperoneSetup; @@ -4128,6 +4470,7 @@ public class OpenVR private CVRSettings m_pVRSettings; private CVRApplications m_pVRApplications; private CVRScreenshots m_pVRScreenshots; + private CVRTrackedCamera m_pVRTrackedCamera; }; private static COpenVRContext _OpenVRInternal_ModuleContext = null; @@ -4147,10 +4490,11 @@ public class OpenVR public static CVRCompositor Compositor { get { return OpenVRInternal_ModuleContext.VRCompositor(); } } public static CVROverlay Overlay { get { return OpenVRInternal_ModuleContext.VROverlay(); } } public static CVRRenderModels RenderModels { get { return OpenVRInternal_ModuleContext.VRRenderModels(); } } - public static CVRApplications Applications { get { return OpenVRInternal_ModuleContext.VRApplications(); } } - public static CVRSettings Settings { get { return OpenVRInternal_ModuleContext.VRSettings(); } } public static CVRExtendedDisplay ExtendedDisplay { get { return OpenVRInternal_ModuleContext.VRExtendedDisplay(); } } + public static CVRSettings Settings { get { return OpenVRInternal_ModuleContext.VRSettings(); } } + public static CVRApplications Applications { get { return OpenVRInternal_ModuleContext.VRApplications(); } } public static CVRScreenshots Screenshots { get { return OpenVRInternal_ModuleContext.VRScreenshots(); } } + public static CVRTrackedCamera TrackedCamera { get { return OpenVRInternal_ModuleContext.VRTrackedCamera(); } } /** Finds the active installation of vrclient.dll and initializes it */ public static CVRSystem Init(ref EVRInitError peError, EVRApplicationType eApplicationType = EVRApplicationType.VRApplication_Scene) diff --git a/examples/ThirdPartyLibs/openvr/headers/openvr_api.json b/examples/ThirdPartyLibs/openvr/headers/openvr_api.json index c72b2c415..d16771ddf 100644 --- a/examples/ThirdPartyLibs/openvr/headers/openvr_api.json +++ b/examples/ThirdPartyLibs/openvr/headers/openvr_api.json @@ -1,12 +1,14 @@ {"typedefs":[{"typedef": "vr::glSharedTextureHandle_t","type": "void *"} ,{"typedef": "vr::glInt_t","type": "int32_t"} ,{"typedef": "vr::glUInt_t","type": "uint32_t"} +,{"typedef": "vr::SharedTextureHandle_t","type": "uint64_t"} ,{"typedef": "vr::TrackedDeviceIndex_t","type": "uint32_t"} ,{"typedef": "vr::VREvent_Data_t","type": "union VREvent_Data_t"} ,{"typedef": "vr::VRControllerState_t","type": "struct vr::VRControllerState001_t"} ,{"typedef": "vr::VROverlayHandle_t","type": "uint64_t"} ,{"typedef": "vr::TrackedCameraHandle_t","type": "uint64_t"} ,{"typedef": "vr::ScreenshotHandle_t","type": "uint32_t"} +,{"typedef": "vr::VROverlayIntersectionMaskPrimitive_Data_t","type": "union VROverlayIntersectionMaskPrimitive_Data_t"} ,{"typedef": "vr::VRComponentProperties","type": "uint32_t"} ,{"typedef": "vr::TextureID_t","type": "int32_t"} ,{"typedef": "vr::VRNotificationId","type": "uint32_t"} @@ -53,6 +55,7 @@ ,{"name": "TrackedDeviceClass_HMD","value": "1"} ,{"name": "TrackedDeviceClass_Controller","value": "2"} ,{"name": "TrackedDeviceClass_TrackingReference","value": "4"} + ,{"name": "TrackedDeviceClass_Count","value": "5"} ,{"name": "TrackedDeviceClass_Other","value": "1000"} ]} , {"enumname": "vr::ETrackedControllerRole","values": [ @@ -99,6 +102,7 @@ ,{"name": "Prop_HasCamera_Bool","value": "1030"} ,{"name": "Prop_DriverVersion_String","value": "1031"} ,{"name": "Prop_Firmware_ForceUpdateRequired_Bool","value": "1032"} + ,{"name": "Prop_ViveSystemButtonFixRequired_Bool","value": "1033"} ,{"name": "Prop_ReportsTimeSinceVSync_Bool","value": "2000"} ,{"name": "Prop_SecondsFromVsyncToPhotons_Float","value": "2001"} ,{"name": "Prop_DisplayFrequency_Float","value": "2002"} @@ -136,6 +140,7 @@ ,{"name": "Prop_ScreenshotHorizontalFieldOfViewDegrees_Float","value": "2034"} ,{"name": "Prop_ScreenshotVerticalFieldOfViewDegrees_Float","value": "2035"} ,{"name": "Prop_DisplaySuppressed_Bool","value": "2036"} + ,{"name": "Prop_DisplayAllowNightMode_Bool","value": "2037"} ,{"name": "Prop_AttachedDeviceId_String","value": "3000"} ,{"name": "Prop_SupportedButtons_Uint64","value": "3001"} ,{"name": "Prop_Axis0Type_Int32","value": "3002"} @@ -143,6 +148,7 @@ ,{"name": "Prop_Axis2Type_Int32","value": "3004"} ,{"name": "Prop_Axis3Type_Int32","value": "3005"} ,{"name": "Prop_Axis4Type_Int32","value": "3006"} + ,{"name": "Prop_ControllerRoleHint_Int32","value": "3007"} ,{"name": "Prop_FieldOfViewLeftDegrees_Float","value": "4000"} ,{"name": "Prop_FieldOfViewRightDegrees_Float","value": "4001"} ,{"name": "Prop_FieldOfViewTopDegrees_Float","value": "4002"} @@ -150,6 +156,15 @@ ,{"name": "Prop_TrackingRangeMinimumMeters_Float","value": "4004"} ,{"name": "Prop_TrackingRangeMaximumMeters_Float","value": "4005"} ,{"name": "Prop_ModeLabel_String","value": "4006"} + ,{"name": "Prop_IconPathName_String","value": "5000"} + ,{"name": "Prop_NamedIconPathDeviceOff_String","value": "5001"} + ,{"name": "Prop_NamedIconPathDeviceSearching_String","value": "5002"} + ,{"name": "Prop_NamedIconPathDeviceSearchingAlert_String","value": "5003"} + ,{"name": "Prop_NamedIconPathDeviceReady_String","value": "5004"} + ,{"name": "Prop_NamedIconPathDeviceReadyAlert_String","value": "5005"} + ,{"name": "Prop_NamedIconPathDeviceNotReady_String","value": "5006"} + ,{"name": "Prop_NamedIconPathDeviceStandby_String","value": "5007"} + ,{"name": "Prop_NamedIconPathDeviceAlertLow_String","value": "5008"} ,{"name": "Prop_VendorSpecific_Reserved_Start","value": "10000"} ,{"name": "Prop_VendorSpecific_Reserved_End","value": "10999"} ]} @@ -169,6 +184,7 @@ {"name": "Submit_Default","value": "0"} ,{"name": "Submit_LensDistortionAlreadyApplied","value": "1"} ,{"name": "Submit_GlRenderBuffer","value": "2"} + ,{"name": "Submit_VulkanTexture","value": "4"} ]} , {"enumname": "vr::EVRState","values": [ {"name": "VRState_Undefined","value": "-1"} @@ -179,6 +195,7 @@ ,{"name": "VRState_Ready_Alert","value": "4"} ,{"name": "VRState_NotReady","value": "5"} ,{"name": "VRState_Standby","value": "6"} + ,{"name": "VRState_Ready_Alert_Low","value": "7"} ]} , {"enumname": "vr::EVREventType","values": [ {"name": "VREvent_None","value": "0"} @@ -191,6 +208,8 @@ ,{"name": "VREvent_EnterStandbyMode","value": "106"} ,{"name": "VREvent_LeaveStandbyMode","value": "107"} ,{"name": "VREvent_TrackedDeviceRoleChanged","value": "108"} + ,{"name": "VREvent_WatchdogWakeUpRequested","value": "109"} + ,{"name": "VREvent_LensDistortionChanged","value": "110"} ,{"name": "VREvent_ButtonPress","value": "200"} ,{"name": "VREvent_ButtonUnpress","value": "201"} ,{"name": "VREvent_ButtonTouch","value": "202"} @@ -202,6 +221,7 @@ ,{"name": "VREvent_FocusLeave","value": "304"} ,{"name": "VREvent_Scroll","value": "305"} ,{"name": "VREvent_TouchPadMove","value": "306"} + ,{"name": "VREvent_OverlayFocusChanged","value": "307"} ,{"name": "VREvent_InputFocusCaptured","value": "400"} ,{"name": "VREvent_InputFocusReleased","value": "401"} ,{"name": "VREvent_SceneFocusLost","value": "402"} @@ -230,10 +250,12 @@ ,{"name": "VREvent_DashboardGuideButtonUp","value": "515"} ,{"name": "VREvent_ScreenshotTriggered","value": "516"} ,{"name": "VREvent_ImageFailed","value": "517"} + ,{"name": "VREvent_DashboardOverlayCreated","value": "518"} ,{"name": "VREvent_RequestScreenshot","value": "520"} ,{"name": "VREvent_ScreenshotTaken","value": "521"} ,{"name": "VREvent_ScreenshotFailed","value": "522"} ,{"name": "VREvent_SubmitScreenshotToDashboard","value": "523"} + ,{"name": "VREvent_ScreenshotProgressToDashboard","value": "524"} ,{"name": "VREvent_Notification_Shown","value": "600"} ,{"name": "VREvent_Notification_Hidden","value": "601"} ,{"name": "VREvent_Notification_BeginInteraction","value": "602"} @@ -254,6 +276,7 @@ ,{"name": "VREvent_ReprojectionSettingHasChanged","value": "852"} ,{"name": "VREvent_ModelSkinSettingsHaveChanged","value": "853"} ,{"name": "VREvent_EnvironmentSettingsHaveChanged","value": "854"} + ,{"name": "VREvent_PowerSettingsHaveChanged","value": "855"} ,{"name": "VREvent_StatusUpdate","value": "900"} ,{"name": "VREvent_MCImageUpdated","value": "1000"} ,{"name": "VREvent_FirmwareUpdateStarted","value": "1100"} @@ -265,6 +288,7 @@ ,{"name": "VREvent_ApplicationTransitionAborted","value": "1301"} ,{"name": "VREvent_ApplicationTransitionNewAppStarted","value": "1302"} ,{"name": "VREvent_ApplicationListUpdated","value": "1303"} + ,{"name": "VREvent_ApplicationMimeTypeLoad","value": "1304"} ,{"name": "VREvent_Compositor_MirrorWindowShown","value": "1400"} ,{"name": "VREvent_Compositor_MirrorWindowHidden","value": "1401"} ,{"name": "VREvent_Compositor_ChaperoneBoundsShown","value": "1410"} @@ -273,6 +297,7 @@ ,{"name": "VREvent_TrackedCamera_StopVideoStream","value": "1501"} ,{"name": "VREvent_TrackedCamera_PauseVideoStream","value": "1502"} ,{"name": "VREvent_TrackedCamera_ResumeVideoStream","value": "1503"} + ,{"name": "VREvent_TrackedCamera_EditingSurface","value": "1550"} ,{"name": "VREvent_PerformanceTest_EnableCapture","value": "1600"} ,{"name": "VREvent_PerformanceTest_DisableCapture","value": "1601"} ,{"name": "VREvent_PerformanceTest_FidelityLevel","value": "1602"} @@ -295,6 +320,7 @@ ,{"name": "k_EButton_DPad_Right","value": "5"} ,{"name": "k_EButton_DPad_Down","value": "6"} ,{"name": "k_EButton_A","value": "7"} + ,{"name": "k_EButton_ProximitySensor","value": "31"} ,{"name": "k_EButton_Axis0","value": "32"} ,{"name": "k_EButton_Axis1","value": "33"} ,{"name": "k_EButton_Axis2","value": "34"} @@ -310,6 +336,11 @@ ,{"name": "VRMouseButton_Right","value": "2"} ,{"name": "VRMouseButton_Middle","value": "4"} ]} +, {"enumname": "vr::EHiddenAreaMeshType","values": [ + {"name": "k_eHiddenAreaMesh_Standard","value": "0"} + ,{"name": "k_eHiddenAreaMesh_Inverse","value": "1"} + ,{"name": "k_eHiddenAreaMesh_LineLoop","value": "2"} +]} , {"enumname": "vr::EVRControllerAxisType","values": [ {"name": "k_eControllerAxis_None","value": "0"} ,{"name": "k_eControllerAxis_TrackPad","value": "1"} @@ -346,8 +377,10 @@ ,{"name": "VROverlayError_RequestFailed","value": "23"} ,{"name": "VROverlayError_InvalidTexture","value": "24"} ,{"name": "VROverlayError_UnableToLoadFile","value": "25"} - ,{"name": "VROVerlayError_KeyboardAlreadyInUse","value": "26"} + ,{"name": "VROverlayError_KeyboardAlreadyInUse","value": "26"} ,{"name": "VROverlayError_NoNeighbor","value": "27"} + ,{"name": "VROverlayError_TooManyMaskPrimitives","value": "29"} + ,{"name": "VROverlayError_BadMaskPrimitive","value": "30"} ]} , {"enumname": "vr::EVRApplicationType","values": [ {"name": "VRApplication_Other","value": "0"} @@ -356,6 +389,8 @@ ,{"name": "VRApplication_Background","value": "3"} ,{"name": "VRApplication_Utility","value": "4"} ,{"name": "VRApplication_VRMonitor","value": "5"} + ,{"name": "VRApplication_SteamWatchdog","value": "6"} + ,{"name": "VRApplication_Max","value": "7"} ]} , {"enumname": "vr::EVRFirmwareError","values": [ {"name": "VRFirmwareError_None","value": "0"} @@ -397,6 +432,14 @@ ,{"name": "VRInitError_Init_NotSupportedWithCompositor","value": "122"} ,{"name": "VRInitError_Init_NotAvailableToUtilityApps","value": "123"} ,{"name": "VRInitError_Init_Internal","value": "124"} + ,{"name": "VRInitError_Init_HmdDriverIdIsNone","value": "125"} + ,{"name": "VRInitError_Init_HmdNotFoundPresenceFailed","value": "126"} + ,{"name": "VRInitError_Init_VRMonitorNotFound","value": "127"} + ,{"name": "VRInitError_Init_VRMonitorStartupFailed","value": "128"} + ,{"name": "VRInitError_Init_LowPowerWatchdogNotSupported","value": "129"} + ,{"name": "VRInitError_Init_InvalidApplicationType","value": "130"} + ,{"name": "VRInitError_Init_NotAvailableToWatchdogApps","value": "131"} + ,{"name": "VRInitError_Init_WatchdogDisabledInSettings","value": "132"} ,{"name": "VRInitError_Driver_Failed","value": "200"} ,{"name": "VRInitError_Driver_Unknown","value": "201"} ,{"name": "VRInitError_Driver_HmdUnknown","value": "202"} @@ -406,12 +449,18 @@ ,{"name": "VRInitError_Driver_NotCalibrated","value": "206"} ,{"name": "VRInitError_Driver_CalibrationInvalid","value": "207"} ,{"name": "VRInitError_Driver_HmdDisplayNotFound","value": "208"} + ,{"name": "VRInitError_Driver_TrackedDeviceInterfaceUnknown","value": "209"} + ,{"name": "VRInitError_Driver_HmdDriverIdOutOfBounds","value": "211"} + ,{"name": "VRInitError_Driver_HmdDisplayMirrored","value": "212"} ,{"name": "VRInitError_IPC_ServerInitFailed","value": "300"} ,{"name": "VRInitError_IPC_ConnectFailed","value": "301"} ,{"name": "VRInitError_IPC_SharedStateInitFailed","value": "302"} ,{"name": "VRInitError_IPC_CompositorInitFailed","value": "303"} ,{"name": "VRInitError_IPC_MutexInitFailed","value": "304"} ,{"name": "VRInitError_IPC_Failed","value": "305"} + ,{"name": "VRInitError_IPC_CompositorConnectFailed","value": "306"} + ,{"name": "VRInitError_IPC_CompositorInvalidConnectResponse","value": "307"} + ,{"name": "VRInitError_IPC_ConnectFailedAfterMultipleAttempts","value": "308"} ,{"name": "VRInitError_Compositor_Failed","value": "400"} ,{"name": "VRInitError_Compositor_D3D11HardwareRequired","value": "401"} ,{"name": "VRInitError_Compositor_FirmwareRequiresUpdate","value": "402"} @@ -544,6 +593,7 @@ ,{"name": "VRCompositorError_TextureUsesUnsupportedFormat","value": "105"} ,{"name": "VRCompositorError_SharedTexturesNotSupported","value": "106"} ,{"name": "VRCompositorError_IndexOutOfRange","value": "107"} + ,{"name": "VRCompositorError_AlreadySubmitted","value": "108"} ]} , {"enumname": "vr::VROverlayInputMethod","values": [ {"name": "VROverlayInputMethod_None","value": "0"} @@ -570,6 +620,7 @@ ,{"name": "VROverlayFlags_SideBySide_Crossed","value": "11"} ,{"name": "VROverlayFlags_Panorama","value": "12"} ,{"name": "VROverlayFlags_StereoPanorama","value": "13"} + ,{"name": "VROverlayFlags_SortWithNonSceneOverlays","value": "14"} ]} , {"enumname": "vr::EGamepadTextInputMode","values": [ {"name": "k_EGamepadTextInputModeNormal","value": "0"} @@ -587,6 +638,10 @@ ,{"name": "OverlayDirection_Right","value": "3"} ,{"name": "OverlayDirection_Count","value": "4"} ]} +, {"enumname": "vr::EVROverlayIntersectionMaskPrimitiveType","values": [ + {"name": "OverlayIntersectionPrimitiveType_Rectangle","value": "0"} + ,{"name": "OverlayIntersectionPrimitiveType_Circle","value": "1"} +]} , {"enumname": "vr::EVRRenderModelError","values": [ {"name": "VRRenderModelError_None","value": "0"} ,{"name": "VRRenderModelError_Loading","value": "100"} @@ -626,6 +681,8 @@ ,{"name": "VRSettingsError_IPCFailed","value": "1"} ,{"name": "VRSettingsError_WriteFailed","value": "2"} ,{"name": "VRSettingsError_ReadFailed","value": "3"} + ,{"name": "VRSettingsError_JsonParseFailed","value": "4"} + ,{"name": "VRSettingsError_UnsetSettingHasNoDefault","value": "5"} ]} , {"enumname": "vr::EVRScreenshotError","values": [ {"name": "VRScreenshotError_None","value": "0"} @@ -637,8 +694,6 @@ ]} ], "consts":[{ - "constname": "k_unTrackingStringSize","consttype": "const uint32_t", "constval": "32"} -,{ "constname": "k_unMaxDriverDebugResponseSize","consttype": "const uint32_t", "constval": "32768"} ,{ "constname": "k_unTrackedDeviceIndex_Hmd","consttype": "const uint32_t", "constval": "0"} @@ -657,7 +712,7 @@ ,{ "constname": "k_unScreenshotHandleInvalid","consttype": "const uint32_t", "constval": "0"} ,{ - "constname": "IVRSystem_Version","consttype": "const char *const", "constval": "IVRSystem_012"} + "constname": "IVRSystem_Version","consttype": "const char *const", "constval": "IVRSystem_014"} ,{ "constname": "IVRExtendedDisplay_Version","consttype": "const char *const", "constval": "IVRExtendedDisplay_001"} ,{ @@ -665,21 +720,27 @@ ,{ "constname": "k_unMaxApplicationKeyLength","consttype": "const uint32_t", "constval": "128"} ,{ - "constname": "IVRApplications_Version","consttype": "const char *const", "constval": "IVRApplications_005"} + "constname": "k_pch_MimeType_HomeApp","consttype": "const char *const", "constval": "vr/home"} +,{ + "constname": "k_pch_MimeType_GameTheater","consttype": "const char *const", "constval": "vr/game_theater"} +,{ + "constname": "IVRApplications_Version","consttype": "const char *const", "constval": "IVRApplications_006"} ,{ "constname": "IVRChaperone_Version","consttype": "const char *const", "constval": "IVRChaperone_003"} ,{ "constname": "IVRChaperoneSetup_Version","consttype": "const char *const", "constval": "IVRChaperoneSetup_005"} ,{ - "constname": "IVRCompositor_Version","consttype": "const char *const", "constval": "IVRCompositor_015"} + "constname": "IVRCompositor_Version","consttype": "const char *const", "constval": "IVRCompositor_018"} ,{ "constname": "k_unVROverlayMaxKeyLength","consttype": "const uint32_t", "constval": "128"} ,{ "constname": "k_unVROverlayMaxNameLength","consttype": "const uint32_t", "constval": "128"} ,{ - "constname": "k_unMaxOverlayCount","consttype": "const uint32_t", "constval": "32"} + "constname": "k_unMaxOverlayCount","consttype": "const uint32_t", "constval": "64"} ,{ - "constname": "IVROverlay_Version","consttype": "const char *const", "constval": "IVROverlay_012"} + "constname": "k_unMaxOverlayIntersectionMaskPrimitivesCount","consttype": "const uint32_t", "constval": "32"} +,{ + "constname": "IVROverlay_Version","consttype": "const char *const", "constval": "IVROverlay_013"} ,{ "constname": "k_pch_Controller_Component_GDC2015","consttype": "const char *const", "constval": "gdc2015"} ,{ @@ -699,7 +760,7 @@ ,{ "constname": "k_unMaxSettingsKeyLength","consttype": "const uint32_t", "constval": "128"} ,{ - "constname": "IVRSettings_Version","consttype": "const char *const", "constval": "IVRSettings_001"} + "constname": "IVRSettings_Version","consttype": "const char *const", "constval": "IVRSettings_002"} ,{ "constname": "k_pch_SteamVR_Section","consttype": "const char *const", "constval": "steamvr"} ,{ @@ -726,12 +787,12 @@ "constname": "k_pch_SteamVR_IPD_Float","consttype": "const char *const", "constval": "ipd"} ,{ "constname": "k_pch_SteamVR_Background_String","consttype": "const char *const", "constval": "background"} +,{ + "constname": "k_pch_SteamVR_BackgroundUseDomeProjection_Bool","consttype": "const char *const", "constval": "backgroundUseDomeProjection"} ,{ "constname": "k_pch_SteamVR_BackgroundCameraHeight_Float","consttype": "const char *const", "constval": "backgroundCameraHeight"} ,{ "constname": "k_pch_SteamVR_BackgroundDomeRadius_Float","consttype": "const char *const", "constval": "backgroundDomeRadius"} -,{ - "constname": "k_pch_SteamVR_Environment_String","consttype": "const char *const", "constval": "environment"} ,{ "constname": "k_pch_SteamVR_GridColor_String","consttype": "const char *const", "constval": "gridColor"} ,{ @@ -740,12 +801,6 @@ "constname": "k_pch_SteamVR_ShowStage_Bool","consttype": "const char *const", "constval": "showStage"} ,{ "constname": "k_pch_SteamVR_ActivateMultipleDrivers_Bool","consttype": "const char *const", "constval": "activateMultipleDrivers"} -,{ - "constname": "k_pch_SteamVR_PowerOffOnExit_Bool","consttype": "const char *const", "constval": "powerOffOnExit"} -,{ - "constname": "k_pch_SteamVR_StandbyAppRunningTimeout_Float","consttype": "const char *const", "constval": "standbyAppRunningTimeout"} -,{ - "constname": "k_pch_SteamVR_StandbyNoAppTimeout_Float","consttype": "const char *const", "constval": "standbyNoAppTimeout"} ,{ "constname": "k_pch_SteamVR_DirectMode_Bool","consttype": "const char *const", "constval": "directMode"} ,{ @@ -763,7 +818,9 @@ ,{ "constname": "k_pch_SteamVR_RenderTargetMultiplier_Float","consttype": "const char *const", "constval": "renderTargetMultiplier"} ,{ - "constname": "k_pch_SteamVR_AllowReprojection_Bool","consttype": "const char *const", "constval": "allowReprojection"} + "constname": "k_pch_SteamVR_AllowAsyncReprojection_Bool","consttype": "const char *const", "constval": "allowAsyncReprojection"} +,{ + "constname": "k_pch_SteamVR_AllowReprojection_Bool","consttype": "const char *const", "constval": "allowInterleavedReprojection"} ,{ "constname": "k_pch_SteamVR_ForceReprojection_Bool","consttype": "const char *const", "constval": "forceReprojection"} ,{ @@ -772,6 +829,20 @@ "constname": "k_pch_SteamVR_DefaultMirrorView_Int32","consttype": "const char *const", "constval": "defaultMirrorView"} ,{ "constname": "k_pch_SteamVR_ShowMirrorView_Bool","consttype": "const char *const", "constval": "showMirrorView"} +,{ + "constname": "k_pch_SteamVR_MirrorViewGeometry_String","consttype": "const char *const", "constval": "mirrorViewGeometry"} +,{ + "constname": "k_pch_SteamVR_StartMonitorFromAppLaunch","consttype": "const char *const", "constval": "startMonitorFromAppLaunch"} +,{ + "constname": "k_pch_SteamVR_EnableHomeApp","consttype": "const char *const", "constval": "enableHomeApp"} +,{ + "constname": "k_pch_SteamVR_SetInitialDefaultHomeApp","consttype": "const char *const", "constval": "setInitialDefaultHomeApp"} +,{ + "constname": "k_pch_SteamVR_CycleBackgroundImageTimeSec_Int32","consttype": "const char *const", "constval": "CycleBackgroundImageTimeSec"} +,{ + "constname": "k_pch_SteamVR_RetailDemo_Bool","consttype": "const char *const", "constval": "retailDemo"} +,{ + "constname": "k_pch_SteamVR_IpdOffset_Float","consttype": "const char *const", "constval": "ipdOffset"} ,{ "constname": "k_pch_Lighthouse_Section","consttype": "const char *const", "constval": "driver_lighthouse"} ,{ @@ -782,12 +853,6 @@ "constname": "k_pch_Lighthouse_DisambiguationDebug_Int32","consttype": "const char *const", "constval": "disambiguationdebug"} ,{ "constname": "k_pch_Lighthouse_PrimaryBasestation_Int32","consttype": "const char *const", "constval": "primarybasestation"} -,{ - "constname": "k_pch_Lighthouse_LighthouseName_String","consttype": "const char *const", "constval": "lighthousename"} -,{ - "constname": "k_pch_Lighthouse_MaxIncidenceAngleDegrees_Float","consttype": "const char *const", "constval": "maxincidenceangledegrees"} -,{ - "constname": "k_pch_Lighthouse_UseLighthouseDirect_Bool","consttype": "const char *const", "constval": "uselighthousedirect"} ,{ "constname": "k_pch_Lighthouse_DBHistory_Bool","consttype": "const char *const", "constval": "dbhistory"} ,{ @@ -819,7 +884,11 @@ ,{ "constname": "k_pch_UserInterface_StatusAlwaysOnTop_Bool","consttype": "const char *const", "constval": "StatusAlwaysOnTop"} ,{ - "constname": "k_pch_UserInterface_EnableScreenshots_Bool","consttype": "const char *const", "constval": "EnableScreenshots"} + "constname": "k_pch_UserInterface_MinimizeToTray_Bool","consttype": "const char *const", "constval": "MinimizeToTray"} +,{ + "constname": "k_pch_UserInterface_Screenshots_Bool","consttype": "const char *const", "constval": "screenshots"} +,{ + "constname": "k_pch_UserInterface_ScreenshotType_Int","consttype": "const char *const", "constval": "screenshotType"} ,{ "constname": "k_pch_Notifications_Section","consttype": "const char *const", "constval": "notifications"} ,{ @@ -892,6 +961,8 @@ "constname": "k_pch_Camera_BoundsColorGammaB_Int32","consttype": "const char *const", "constval": "cameraBoundsColorGammaB"} ,{ "constname": "k_pch_Camera_BoundsColorGammaA_Int32","consttype": "const char *const", "constval": "cameraBoundsColorGammaA"} +,{ + "constname": "k_pch_Camera_BoundsStrength_Int32","consttype": "const char *const", "constval": "cameraBoundsStrength"} ,{ "constname": "k_pch_audio_Section","consttype": "const char *const", "constval": "audio"} ,{ @@ -906,10 +977,30 @@ "constname": "k_pch_audio_OffRecordDevice_String","consttype": "const char *const", "constval": "offRecordDevice"} ,{ "constname": "k_pch_audio_VIVEHDMIGain","consttype": "const char *const", "constval": "viveHDMIGain"} +,{ + "constname": "k_pch_Power_Section","consttype": "const char *const", "constval": "power"} +,{ + "constname": "k_pch_Power_PowerOffOnExit_Bool","consttype": "const char *const", "constval": "powerOffOnExit"} +,{ + "constname": "k_pch_Power_TurnOffScreensTimeout_Float","consttype": "const char *const", "constval": "turnOffScreensTimeout"} +,{ + "constname": "k_pch_Power_TurnOffControllersTimeout_Float","consttype": "const char *const", "constval": "turnOffControllersTimeout"} +,{ + "constname": "k_pch_Power_ReturnToWatchdogTimeout_Float","consttype": "const char *const", "constval": "returnToWatchdogTimeout"} +,{ + "constname": "k_pch_Power_AutoLaunchSteamVROnButtonPress","consttype": "const char *const", "constval": "autoLaunchSteamVROnButtonPress"} +,{ + "constname": "k_pch_Dashboard_Section","consttype": "const char *const", "constval": "dashboard"} +,{ + "constname": "k_pch_Dashboard_EnableDashboard_Bool","consttype": "const char *const", "constval": "enableDashboard"} +,{ + "constname": "k_pch_Dashboard_ArcadeMode_Bool","consttype": "const char *const", "constval": "arcadeMode"} ,{ "constname": "k_pch_modelskin_Section","consttype": "const char *const", "constval": "modelskins"} ,{ "constname": "IVRScreenshots_Version","consttype": "const char *const", "constval": "IVRScreenshots_001"} +,{ + "constname": "IVRResources_Version","consttype": "const char *const", "constval": "IVRResources_001"} ], "structs":[{"struct": "vr::HmdMatrix34_t","fields": [ { "fieldname": "m", "fieldtype": "float [3][4]"}]} @@ -958,6 +1049,17 @@ { "fieldname": "vMin", "fieldtype": "float"}, { "fieldname": "uMax", "fieldtype": "float"}, { "fieldname": "vMax", "fieldtype": "float"}]} +,{"struct": "vr::VulkanData_t","fields": [ +{ "fieldname": "m_nImage", "fieldtype": "uint64_t"}, +{ "fieldname": "m_pDevice", "fieldtype": "struct VkDevice_T *"}, +{ "fieldname": "m_pPhysicalDevice", "fieldtype": "struct VkPhysicalDevice_T *"}, +{ "fieldname": "m_pInstance", "fieldtype": "struct VkInstance_T *"}, +{ "fieldname": "m_pQueue", "fieldtype": "struct VkQueue_T *"}, +{ "fieldname": "m_nQueueFamilyIndex", "fieldtype": "uint32_t"}, +{ "fieldname": "m_nWidth", "fieldtype": "uint32_t"}, +{ "fieldname": "m_nHeight", "fieldtype": "uint32_t"}, +{ "fieldname": "m_nFormat", "fieldtype": "uint32_t"}, +{ "fieldname": "m_nSampleCount", "fieldtype": "uint32_t"}]} ,{"struct": "vr::VREvent_Controller_t","fields": [ { "fieldname": "button", "fieldtype": "uint32_t"}]} ,{"struct": "vr::VREvent_Mouse_t","fields": [ @@ -1004,6 +1106,14 @@ ,{"struct": "vr::VREvent_Screenshot_t","fields": [ { "fieldname": "handle", "fieldtype": "uint32_t"}, { "fieldname": "type", "fieldtype": "uint32_t"}]} +,{"struct": "vr::VREvent_ScreenshotProgress_t","fields": [ +{ "fieldname": "progress", "fieldtype": "float"}]} +,{"struct": "vr::VREvent_ApplicationLaunch_t","fields": [ +{ "fieldname": "pid", "fieldtype": "uint32_t"}, +{ "fieldname": "unArgsHandle", "fieldtype": "uint32_t"}]} +,{"struct": "vr::VREvent_EditingCameraSurface_t","fields": [ +{ "fieldname": "overlayHandle", "fieldtype": "uint64_t"}, +{ "fieldname": "nVisualMode", "fieldtype": "uint32_t"}]} ,{"struct": "vr::(anonymous)","fields": [ { "fieldname": "reserved", "fieldtype": "struct vr::VREvent_Reserved_t"}, { "fieldname": "controller", "fieldtype": "struct vr::VREvent_Controller_t"}, @@ -1019,7 +1129,10 @@ { "fieldname": "performanceTest", "fieldtype": "struct vr::VREvent_PerformanceTest_t"}, { "fieldname": "touchPadMove", "fieldtype": "struct vr::VREvent_TouchPadMove_t"}, { "fieldname": "seatedZeroPoseReset", "fieldtype": "struct vr::VREvent_SeatedZeroPoseReset_t"}, -{ "fieldname": "screenshot", "fieldtype": "struct vr::VREvent_Screenshot_t"}]} +{ "fieldname": "screenshot", "fieldtype": "struct vr::VREvent_Screenshot_t"}, +{ "fieldname": "screenshotProgress", "fieldtype": "struct vr::VREvent_ScreenshotProgress_t"}, +{ "fieldname": "applicationLaunch", "fieldtype": "struct vr::VREvent_ApplicationLaunch_t"}, +{ "fieldname": "cameraSurface", "fieldtype": "struct vr::VREvent_EditingCameraSurface_t"}]} ,{"struct": "vr::VREvent_t","fields": [ { "fieldname": "eventType", "fieldtype": "uint32_t"}, { "fieldname": "trackedDeviceIndex", "fieldtype": "TrackedDeviceIndex_t"}, @@ -1065,9 +1178,12 @@ { "fieldname": "m_nSize", "fieldtype": "uint32_t"}, { "fieldname": "m_nFrameIndex", "fieldtype": "uint32_t"}, { "fieldname": "m_nNumFramePresents", "fieldtype": "uint32_t"}, +{ "fieldname": "m_nNumMisPresented", "fieldtype": "uint32_t"}, { "fieldname": "m_nNumDroppedFrames", "fieldtype": "uint32_t"}, +{ "fieldname": "m_nReprojectionFlags", "fieldtype": "uint32_t"}, { "fieldname": "m_flSystemTimeInSeconds", "fieldtype": "double"}, -{ "fieldname": "m_flSceneRenderGpuMs", "fieldtype": "float"}, +{ "fieldname": "m_flPreSubmitGpuMs", "fieldtype": "float"}, +{ "fieldname": "m_flPostSubmitGpuMs", "fieldtype": "float"}, { "fieldname": "m_flTotalRenderGpuMs", "fieldtype": "float"}, { "fieldname": "m_flCompositorRenderGpuMs", "fieldtype": "float"}, { "fieldname": "m_flCompositorRenderCpuMs", "fieldtype": "float"}, @@ -1082,9 +1198,7 @@ { "fieldname": "m_flCompositorUpdateStartMs", "fieldtype": "float"}, { "fieldname": "m_flCompositorUpdateEndMs", "fieldtype": "float"}, { "fieldname": "m_flCompositorRenderStartMs", "fieldtype": "float"}, -{ "fieldname": "m_HmdPose", "fieldtype": "vr::TrackedDevicePose_t"}, -{ "fieldname": "m_nFidelityLevel", "fieldtype": "int32_t"}, -{ "fieldname": "m_nReprojectionFlags", "fieldtype": "uint32_t"}]} +{ "fieldname": "m_HmdPose", "fieldtype": "vr::TrackedDevicePose_t"}]} ,{"struct": "vr::Compositor_CumulativeStats","fields": [ { "fieldname": "m_nPid", "fieldtype": "uint32_t"}, { "fieldname": "m_nNumFramePresents", "fieldtype": "uint32_t"}, @@ -1110,6 +1224,21 @@ { "fieldname": "vNormal", "fieldtype": "struct vr::HmdVector3_t"}, { "fieldname": "vUVs", "fieldtype": "struct vr::HmdVector2_t"}, { "fieldname": "fDistance", "fieldtype": "float"}]} +,{"struct": "vr::IntersectionMaskRectangle_t","fields": [ +{ "fieldname": "m_flTopLeftX", "fieldtype": "float"}, +{ "fieldname": "m_flTopLeftY", "fieldtype": "float"}, +{ "fieldname": "m_flWidth", "fieldtype": "float"}, +{ "fieldname": "m_flHeight", "fieldtype": "float"}]} +,{"struct": "vr::IntersectionMaskCircle_t","fields": [ +{ "fieldname": "m_flCenterX", "fieldtype": "float"}, +{ "fieldname": "m_flCenterY", "fieldtype": "float"}, +{ "fieldname": "m_flRadius", "fieldtype": "float"}]} +,{"struct": "vr::(anonymous)","fields": [ +{ "fieldname": "m_Rectangle", "fieldtype": "struct vr::IntersectionMaskRectangle_t"}, +{ "fieldname": "m_Circle", "fieldtype": "struct vr::IntersectionMaskCircle_t"}]} +,{"struct": "vr::VROverlayIntersectionMaskPrimitive_t","fields": [ +{ "fieldname": "m_nPrimitiveType", "fieldtype": "enum vr::EVROverlayIntersectionMaskPrimitiveType"}, +{ "fieldname": "m_Primitive", "fieldtype": "VROverlayIntersectionMaskPrimitive_Data_t"}]} ,{"struct": "vr::RenderModel_ComponentState_t","fields": [ { "fieldname": "mTrackingToComponentRenderModel", "fieldtype": "struct vr::HmdMatrix34_t"}, { "fieldname": "mTrackingToComponentLocal", "fieldtype": "struct vr::HmdMatrix34_t"}, @@ -1141,6 +1270,7 @@ { "fieldname": "m_pVRChaperoneSetup", "fieldtype": "class vr::IVRChaperoneSetup *"}, { "fieldname": "m_pVRCompositor", "fieldtype": "class vr::IVRCompositor *"}, { "fieldname": "m_pVROverlay", "fieldtype": "class vr::IVROverlay *"}, +{ "fieldname": "m_pVRResources", "fieldtype": "class vr::IVRResources *"}, { "fieldname": "m_pVRRenderModels", "fieldtype": "class vr::IVRRenderModels *"}, { "fieldname": "m_pVRExtendedDisplay", "fieldtype": "class vr::IVRExtendedDisplay *"}, { "fieldname": "m_pVRSettings", "fieldtype": "class vr::IVRSettings *"}, @@ -1183,11 +1313,12 @@ ,{ "classname": "vr::IVRSystem", "methodname": "ComputeDistortion", - "returntype": "struct vr::DistortionCoordinates_t", + "returntype": "bool", "params": [ { "paramname": "eEye" ,"paramtype": "vr::EVREye"}, { "paramname": "fU" ,"paramtype": "float"}, -{ "paramname": "fV" ,"paramtype": "float"} +{ "paramname": "fV" ,"paramtype": "float"}, +{ "paramname": "pDistortionCoordinates" ,"paramtype": "struct vr::DistortionCoordinates_t *"} ] } ,{ @@ -1423,7 +1554,8 @@ "methodname": "GetHiddenAreaMesh", "returntype": "struct vr::HiddenAreaMesh_t", "params": [ -{ "paramname": "eEye" ,"paramtype": "vr::EVREye"} +{ "paramname": "eEye" ,"paramtype": "vr::EVREye"}, +{ "paramname": "type" ,"paramtype": "vr::EHiddenAreaMeshType"} ] } ,{ @@ -1432,7 +1564,8 @@ "returntype": "bool", "params": [ { "paramname": "unControllerDeviceIndex" ,"paramtype": "vr::TrackedDeviceIndex_t"}, -{ "paramname": "pControllerState" ,"paramtype": "vr::VRControllerState_t *"} +{ "paramname": "pControllerState" ,"paramtype": "vr::VRControllerState_t *"}, +{ "paramname": "unControllerStateSize" ,"paramtype": "uint32_t"} ] } ,{ @@ -1443,6 +1576,7 @@ { "paramname": "eOrigin" ,"paramtype": "vr::ETrackingUniverseOrigin"}, { "paramname": "unControllerDeviceIndex" ,"paramtype": "vr::TrackedDeviceIndex_t"}, { "paramname": "pControllerState" ,"paramtype": "vr::VRControllerState_t *"}, +{ "paramname": "unControllerStateSize" ,"paramtype": "uint32_t"}, { "paramname": "pTrackedDevicePose" ,"paramtype": "struct vr::TrackedDevicePose_t *"} ] } @@ -1630,6 +1764,52 @@ { "paramname": "nFrameHeaderSize" ,"paramtype": "uint32_t"} ] } +,{ + "classname": "vr::IVRTrackedCamera", + "methodname": "GetVideoStreamTextureSize", + "returntype": "vr::EVRTrackedCameraError", + "params": [ +{ "paramname": "nDeviceIndex" ,"paramtype": "vr::TrackedDeviceIndex_t"}, +{ "paramname": "eFrameType" ,"paramtype": "vr::EVRTrackedCameraFrameType"}, +{ "paramname": "pTextureBounds" ,"paramtype": "vr::VRTextureBounds_t *"}, +{ "paramname": "pnWidth" ,"paramtype": "uint32_t *"}, +{ "paramname": "pnHeight" ,"paramtype": "uint32_t *"} + ] +} +,{ + "classname": "vr::IVRTrackedCamera", + "methodname": "GetVideoStreamTextureD3D11", + "returntype": "vr::EVRTrackedCameraError", + "params": [ +{ "paramname": "hTrackedCamera" ,"paramtype": "vr::TrackedCameraHandle_t"}, +{ "paramname": "eFrameType" ,"paramtype": "vr::EVRTrackedCameraFrameType"}, +{ "paramname": "pD3D11DeviceOrResource" ,"paramtype": "void *"}, +{ "paramname": "ppD3D11ShaderResourceView" ,"paramtype": "void **"}, +{ "paramname": "pFrameHeader" ,"paramtype": "vr::CameraVideoStreamFrameHeader_t *"}, +{ "paramname": "nFrameHeaderSize" ,"paramtype": "uint32_t"} + ] +} +,{ + "classname": "vr::IVRTrackedCamera", + "methodname": "GetVideoStreamTextureGL", + "returntype": "vr::EVRTrackedCameraError", + "params": [ +{ "paramname": "hTrackedCamera" ,"paramtype": "vr::TrackedCameraHandle_t"}, +{ "paramname": "eFrameType" ,"paramtype": "vr::EVRTrackedCameraFrameType"}, +{ "paramname": "pglTextureId" ,"paramtype": "vr::glUInt_t *"}, +{ "paramname": "pFrameHeader" ,"paramtype": "vr::CameraVideoStreamFrameHeader_t *"}, +{ "paramname": "nFrameHeaderSize" ,"paramtype": "uint32_t"} + ] +} +,{ + "classname": "vr::IVRTrackedCamera", + "methodname": "ReleaseVideoStreamTextureGL", + "returntype": "vr::EVRTrackedCameraError", + "params": [ +{ "paramname": "hTrackedCamera" ,"paramtype": "vr::TrackedCameraHandle_t"}, +{ "paramname": "glTextureId" ,"paramtype": "vr::glUInt_t"} + ] +} ,{ "classname": "vr::IVRApplications", "methodname": "AddApplicationManifest", @@ -1666,7 +1846,7 @@ "returntype": "vr::EVRApplicationError", "params": [ { "paramname": "unApplicationIndex" ,"paramtype": "uint32_t"}, -{ "paramname": "pchAppKeyBuffer" ,"paramtype": "char *"}, +{ "paramname": "pchAppKeyBuffer" ,"out_string": " " ,"paramtype": "char *"}, { "paramname": "unAppKeyBufferLen" ,"paramtype": "uint32_t"} ] } @@ -1699,6 +1879,15 @@ { "paramname": "unKeys" ,"paramtype": "uint32_t"} ] } +,{ + "classname": "vr::IVRApplications", + "methodname": "LaunchApplicationFromMimeType", + "returntype": "vr::EVRApplicationError", + "params": [ +{ "paramname": "pchMimeType" ,"paramtype": "const char *"}, +{ "paramname": "pchArgs" ,"paramtype": "const char *"} + ] +} ,{ "classname": "vr::IVRApplications", "methodname": "LaunchDashboardOverlay", @@ -1747,7 +1936,7 @@ "params": [ { "paramname": "pchAppKey" ,"paramtype": "const char *"}, { "paramname": "eProperty" ,"paramtype": "vr::EVRApplicationProperty"}, -{ "paramname": "pchPropertyValueBuffer" ,"paramtype": "char *"}, +{ "paramname": "pchPropertyValueBuffer" ,"out_string": " " ,"paramtype": "char *"}, { "paramname": "unPropertyValueBufferLen" ,"paramtype": "uint32_t"}, { "paramname": "peError" ,"paramtype": "vr::EVRApplicationError *"} ] @@ -1789,6 +1978,55 @@ { "paramname": "pchAppKey" ,"paramtype": "const char *"} ] } +,{ + "classname": "vr::IVRApplications", + "methodname": "SetDefaultApplicationForMimeType", + "returntype": "vr::EVRApplicationError", + "params": [ +{ "paramname": "pchAppKey" ,"paramtype": "const char *"}, +{ "paramname": "pchMimeType" ,"paramtype": "const char *"} + ] +} +,{ + "classname": "vr::IVRApplications", + "methodname": "GetDefaultApplicationForMimeType", + "returntype": "bool", + "params": [ +{ "paramname": "pchMimeType" ,"paramtype": "const char *"}, +{ "paramname": "pchAppKeyBuffer" ,"paramtype": "char *"}, +{ "paramname": "unAppKeyBufferLen" ,"paramtype": "uint32_t"} + ] +} +,{ + "classname": "vr::IVRApplications", + "methodname": "GetApplicationSupportedMimeTypes", + "returntype": "bool", + "params": [ +{ "paramname": "pchAppKey" ,"paramtype": "const char *"}, +{ "paramname": "pchMimeTypesBuffer" ,"paramtype": "char *"}, +{ "paramname": "unMimeTypesBuffer" ,"paramtype": "uint32_t"} + ] +} +,{ + "classname": "vr::IVRApplications", + "methodname": "GetApplicationsThatSupportMimeType", + "returntype": "uint32_t", + "params": [ +{ "paramname": "pchMimeType" ,"paramtype": "const char *"}, +{ "paramname": "pchAppKeysThatSupportBuffer" ,"paramtype": "char *"}, +{ "paramname": "unAppKeysThatSupportBuffer" ,"paramtype": "uint32_t"} + ] +} +,{ + "classname": "vr::IVRApplications", + "methodname": "GetApplicationLaunchArguments", + "returntype": "uint32_t", + "params": [ +{ "paramname": "unHandle" ,"paramtype": "uint32_t"}, +{ "paramname": "pchArgs" ,"paramtype": "char *"}, +{ "paramname": "unArgs" ,"paramtype": "uint32_t"} + ] +} ,{ "classname": "vr::IVRApplications", "methodname": "GetStartingApplication", @@ -2136,6 +2374,15 @@ { "paramname": "unFramesAgo" ,"paramtype": "uint32_t"} ] } +,{ + "classname": "vr::IVRCompositor", + "methodname": "GetFrameTimings", + "returntype": "uint32_t", + "params": [ +{ "paramname": "pTiming" ,"paramtype": "struct vr::Compositor_FrameTiming *"}, +{ "paramname": "nFrames" ,"paramtype": "uint32_t"} + ] +} ,{ "classname": "vr::IVRCompositor", "methodname": "GetFrameTimeRemaining", @@ -2163,6 +2410,14 @@ { "paramname": "bBackground" ,"paramtype": "bool"} ] } +,{ + "classname": "vr::IVRCompositor", + "methodname": "GetCurrentFadeColor", + "returntype": "struct vr::HmdColor_t", + "params": [ +{ "paramname": "bBackground" ,"paramtype": "bool"} + ] +} ,{ "classname": "vr::IVRCompositor", "methodname": "FadeGrid", @@ -2172,6 +2427,11 @@ { "paramname": "bFadeIn" ,"paramtype": "bool"} ] } +,{ + "classname": "vr::IVRCompositor", + "methodname": "GetCurrentGridAlpha", + "returntype": "float" +} ,{ "classname": "vr::IVRCompositor", "methodname": "SetSkyboxOverride", @@ -2267,21 +2527,6 @@ { "paramname": "bSuspend" ,"paramtype": "bool"} ] } -,{ - "classname": "vr::IVRCompositor", - "methodname": "RequestScreenshot", - "returntype": "vr::EVRCompositorError", - "params": [ -{ "paramname": "type" ,"paramtype": "vr::EVRScreenshotType"}, -{ "paramname": "pchDestinationFileName" ,"paramtype": "const char *"}, -{ "paramname": "pchVRDestinationFileName" ,"paramtype": "const char *"} - ] -} -,{ - "classname": "vr::IVRCompositor", - "methodname": "GetCurrentScreenshotType", - "returntype": "vr::EVRScreenshotType" -} ,{ "classname": "vr::IVRCompositor", "methodname": "GetMirrorTextureD3D11", @@ -2486,6 +2731,42 @@ { "paramname": "pfAlpha" ,"paramtype": "float *"} ] } +,{ + "classname": "vr::IVROverlay", + "methodname": "SetOverlayTexelAspect", + "returntype": "vr::EVROverlayError", + "params": [ +{ "paramname": "ulOverlayHandle" ,"paramtype": "vr::VROverlayHandle_t"}, +{ "paramname": "fTexelAspect" ,"paramtype": "float"} + ] +} +,{ + "classname": "vr::IVROverlay", + "methodname": "GetOverlayTexelAspect", + "returntype": "vr::EVROverlayError", + "params": [ +{ "paramname": "ulOverlayHandle" ,"paramtype": "vr::VROverlayHandle_t"}, +{ "paramname": "pfTexelAspect" ,"paramtype": "float *"} + ] +} +,{ + "classname": "vr::IVROverlay", + "methodname": "SetOverlaySortOrder", + "returntype": "vr::EVROverlayError", + "params": [ +{ "paramname": "ulOverlayHandle" ,"paramtype": "vr::VROverlayHandle_t"}, +{ "paramname": "unSortOrder" ,"paramtype": "uint32_t"} + ] +} +,{ + "classname": "vr::IVROverlay", + "methodname": "GetOverlaySortOrder", + "returntype": "vr::EVROverlayError", + "params": [ +{ "paramname": "ulOverlayHandle" ,"paramtype": "vr::VROverlayHandle_t"}, +{ "paramname": "punSortOrder" ,"paramtype": "uint32_t *"} + ] +} ,{ "classname": "vr::IVROverlay", "methodname": "SetOverlayWidthInMeters", @@ -2958,6 +3239,17 @@ { "paramname": "avoidRect" ,"paramtype": "struct vr::HmdRect2_t"} ] } +,{ + "classname": "vr::IVROverlay", + "methodname": "SetOverlayIntersectionMask", + "returntype": "vr::EVROverlayError", + "params": [ +{ "paramname": "ulOverlayHandle" ,"paramtype": "vr::VROverlayHandle_t"}, +{ "paramname": "pMaskPrimitives" ,"paramtype": "struct vr::VROverlayIntersectionMaskPrimitive_t *"}, +{ "paramname": "unNumMaskPrimitives" ,"paramtype": "uint32_t"}, +{ "paramname": "unPrimitiveSize" ,"paramtype": "uint32_t"} + ] +} ,{ "classname": "vr::IVRRenderModels", "methodname": "LoadRenderModel_Async", @@ -3163,17 +3455,6 @@ { "paramname": "peError" ,"paramtype": "vr::EVRSettingsError *"} ] } -,{ - "classname": "vr::IVRSettings", - "methodname": "GetBool", - "returntype": "bool", - "params": [ -{ "paramname": "pchSection" ,"paramtype": "const char *"}, -{ "paramname": "pchSettingsKey" ,"paramtype": "const char *"}, -{ "paramname": "bDefaultValue" ,"paramtype": "bool"}, -{ "paramname": "peError" ,"paramtype": "vr::EVRSettingsError *"} - ] -} ,{ "classname": "vr::IVRSettings", "methodname": "SetBool", @@ -3185,17 +3466,6 @@ { "paramname": "peError" ,"paramtype": "vr::EVRSettingsError *"} ] } -,{ - "classname": "vr::IVRSettings", - "methodname": "GetInt32", - "returntype": "int32_t", - "params": [ -{ "paramname": "pchSection" ,"paramtype": "const char *"}, -{ "paramname": "pchSettingsKey" ,"paramtype": "const char *"}, -{ "paramname": "nDefaultValue" ,"paramtype": "int32_t"}, -{ "paramname": "peError" ,"paramtype": "vr::EVRSettingsError *"} - ] -} ,{ "classname": "vr::IVRSettings", "methodname": "SetInt32", @@ -3207,17 +3477,6 @@ { "paramname": "peError" ,"paramtype": "vr::EVRSettingsError *"} ] } -,{ - "classname": "vr::IVRSettings", - "methodname": "GetFloat", - "returntype": "float", - "params": [ -{ "paramname": "pchSection" ,"paramtype": "const char *"}, -{ "paramname": "pchSettingsKey" ,"paramtype": "const char *"}, -{ "paramname": "flDefaultValue" ,"paramtype": "float"}, -{ "paramname": "peError" ,"paramtype": "vr::EVRSettingsError *"} - ] -} ,{ "classname": "vr::IVRSettings", "methodname": "SetFloat", @@ -3229,19 +3488,6 @@ { "paramname": "peError" ,"paramtype": "vr::EVRSettingsError *"} ] } -,{ - "classname": "vr::IVRSettings", - "methodname": "GetString", - "returntype": "void", - "params": [ -{ "paramname": "pchSection" ,"paramtype": "const char *"}, -{ "paramname": "pchSettingsKey" ,"paramtype": "const char *"}, -{ "paramname": "pchValue" ,"paramtype": "char *"}, -{ "paramname": "unValueLen" ,"paramtype": "uint32_t"}, -{ "paramname": "pchDefaultValue" ,"paramtype": "const char *"}, -{ "paramname": "peError" ,"paramtype": "vr::EVRSettingsError *"} - ] -} ,{ "classname": "vr::IVRSettings", "methodname": "SetString", @@ -3253,6 +3499,48 @@ { "paramname": "peError" ,"paramtype": "vr::EVRSettingsError *"} ] } +,{ + "classname": "vr::IVRSettings", + "methodname": "GetBool", + "returntype": "bool", + "params": [ +{ "paramname": "pchSection" ,"paramtype": "const char *"}, +{ "paramname": "pchSettingsKey" ,"paramtype": "const char *"}, +{ "paramname": "peError" ,"paramtype": "vr::EVRSettingsError *"} + ] +} +,{ + "classname": "vr::IVRSettings", + "methodname": "GetInt32", + "returntype": "int32_t", + "params": [ +{ "paramname": "pchSection" ,"paramtype": "const char *"}, +{ "paramname": "pchSettingsKey" ,"paramtype": "const char *"}, +{ "paramname": "peError" ,"paramtype": "vr::EVRSettingsError *"} + ] +} +,{ + "classname": "vr::IVRSettings", + "methodname": "GetFloat", + "returntype": "float", + "params": [ +{ "paramname": "pchSection" ,"paramtype": "const char *"}, +{ "paramname": "pchSettingsKey" ,"paramtype": "const char *"}, +{ "paramname": "peError" ,"paramtype": "vr::EVRSettingsError *"} + ] +} +,{ + "classname": "vr::IVRSettings", + "methodname": "GetString", + "returntype": "void", + "params": [ +{ "paramname": "pchSection" ,"paramtype": "const char *"}, +{ "paramname": "pchSettingsKey" ,"paramtype": "const char *"}, +{ "paramname": "pchValue" ,"out_string": " " ,"paramtype": "char *"}, +{ "paramname": "unValueLen" ,"paramtype": "uint32_t"}, +{ "paramname": "peError" ,"paramtype": "vr::EVRSettingsError *"} + ] +} ,{ "classname": "vr::IVRSettings", "methodname": "RemoveSection", @@ -3343,5 +3631,26 @@ { "paramname": "pchSourceVRFilename" ,"paramtype": "const char *"} ] } +,{ + "classname": "vr::IVRResources", + "methodname": "LoadSharedResource", + "returntype": "uint32_t", + "params": [ +{ "paramname": "pchResourceName" ,"paramtype": "const char *"}, +{ "paramname": "pchBuffer" ,"paramtype": "char *"}, +{ "paramname": "unBufferLen" ,"paramtype": "uint32_t"} + ] +} +,{ + "classname": "vr::IVRResources", + "methodname": "GetResourceFullPath", + "returntype": "uint32_t", + "params": [ +{ "paramname": "pchResourceName" ,"paramtype": "const char *"}, +{ "paramname": "pchResourceTypeDirectory" ,"paramtype": "const char *"}, +{ "paramname": "pchPathBuffer" ,"paramtype": "char *"}, +{ "paramname": "unBufferLen" ,"paramtype": "uint32_t"} + ] +} ] } \ No newline at end of file diff --git a/examples/ThirdPartyLibs/openvr/headers/openvr_capi.h b/examples/ThirdPartyLibs/openvr/headers/openvr_capi.h index 76eafd4d6..6ecbffd0b 100644 --- a/examples/ThirdPartyLibs/openvr/headers/openvr_capi.h +++ b/examples/ThirdPartyLibs/openvr/headers/openvr_capi.h @@ -28,7 +28,7 @@ #else #define S_API extern "C" __declspec( dllimport ) #endif // OPENVR_API_EXPORTS -#elif defined( GNUC ) +#elif defined( __GNUC__ ) #if defined( OPENVR_API_EXPORTS ) #define S_API EXTERN_C __attribute__ ((visibility("default"))) #else @@ -46,12 +46,13 @@ #if defined( __WIN32 ) typedef char bool; +#else +#include #endif // OpenVR Constants -static const unsigned int k_unTrackingStringSize = 32; static const unsigned int k_unMaxDriverDebugResponseSize = 32768; static const unsigned int k_unTrackedDeviceIndex_Hmd = 0; static const unsigned int k_unMaxTrackedDeviceCount = 16; @@ -61,18 +62,21 @@ static const unsigned int k_unMaxPropertyStringSize = 32768; static const unsigned int k_unControllerStateAxisCount = 5; static const unsigned long k_ulOverlayHandleInvalid = 0; static const unsigned int k_unScreenshotHandleInvalid = 0; -static const char * IVRSystem_Version = "IVRSystem_012"; +static const char * IVRSystem_Version = "IVRSystem_014"; static const char * IVRExtendedDisplay_Version = "IVRExtendedDisplay_001"; static const char * IVRTrackedCamera_Version = "IVRTrackedCamera_003"; static const unsigned int k_unMaxApplicationKeyLength = 128; -static const char * IVRApplications_Version = "IVRApplications_005"; +static const char * k_pch_MimeType_HomeApp = "vr/home"; +static const char * k_pch_MimeType_GameTheater = "vr/game_theater"; +static const char * IVRApplications_Version = "IVRApplications_006"; static const char * IVRChaperone_Version = "IVRChaperone_003"; static const char * IVRChaperoneSetup_Version = "IVRChaperoneSetup_005"; -static const char * IVRCompositor_Version = "IVRCompositor_015"; +static const char * IVRCompositor_Version = "IVRCompositor_018"; static const unsigned int k_unVROverlayMaxKeyLength = 128; static const unsigned int k_unVROverlayMaxNameLength = 128; -static const unsigned int k_unMaxOverlayCount = 32; -static const char * IVROverlay_Version = "IVROverlay_012"; +static const unsigned int k_unMaxOverlayCount = 64; +static const unsigned int k_unMaxOverlayIntersectionMaskPrimitivesCount = 32; +static const char * IVROverlay_Version = "IVROverlay_013"; static const char * k_pch_Controller_Component_GDC2015 = "gdc2015"; static const char * k_pch_Controller_Component_Base = "base"; static const char * k_pch_Controller_Component_Tip = "tip"; @@ -82,7 +86,7 @@ static const char * IVRRenderModels_Version = "IVRRenderModels_005"; static const unsigned int k_unNotificationTextMaxSize = 256; static const char * IVRNotifications_Version = "IVRNotifications_002"; static const unsigned int k_unMaxSettingsKeyLength = 128; -static const char * IVRSettings_Version = "IVRSettings_001"; +static const char * IVRSettings_Version = "IVRSettings_002"; static const char * k_pch_SteamVR_Section = "steamvr"; static const char * k_pch_SteamVR_RequireHmd_String = "requireHmd"; static const char * k_pch_SteamVR_ForcedDriverKey_String = "forcedDriver"; @@ -96,16 +100,13 @@ static const char * k_pch_SteamVR_SendSystemButtonToAllApps_Bool = "sendSystemBu static const char * k_pch_SteamVR_LogLevel_Int32 = "loglevel"; static const char * k_pch_SteamVR_IPD_Float = "ipd"; static const char * k_pch_SteamVR_Background_String = "background"; +static const char * k_pch_SteamVR_BackgroundUseDomeProjection_Bool = "backgroundUseDomeProjection"; static const char * k_pch_SteamVR_BackgroundCameraHeight_Float = "backgroundCameraHeight"; static const char * k_pch_SteamVR_BackgroundDomeRadius_Float = "backgroundDomeRadius"; -static const char * k_pch_SteamVR_Environment_String = "environment"; static const char * k_pch_SteamVR_GridColor_String = "gridColor"; static const char * k_pch_SteamVR_PlayAreaColor_String = "playAreaColor"; static const char * k_pch_SteamVR_ShowStage_Bool = "showStage"; static const char * k_pch_SteamVR_ActivateMultipleDrivers_Bool = "activateMultipleDrivers"; -static const char * k_pch_SteamVR_PowerOffOnExit_Bool = "powerOffOnExit"; -static const char * k_pch_SteamVR_StandbyAppRunningTimeout_Float = "standbyAppRunningTimeout"; -static const char * k_pch_SteamVR_StandbyNoAppTimeout_Float = "standbyNoAppTimeout"; static const char * k_pch_SteamVR_DirectMode_Bool = "directMode"; static const char * k_pch_SteamVR_DirectModeEdidVid_Int32 = "directModeEdidVid"; static const char * k_pch_SteamVR_DirectModeEdidPid_Int32 = "directModeEdidPid"; @@ -114,19 +115,24 @@ static const char * k_pch_SteamVR_SpeakersForwardYawOffsetDegrees_Float = "speak static const char * k_pch_SteamVR_BaseStationPowerManagement_Bool = "basestationPowerManagement"; static const char * k_pch_SteamVR_NeverKillProcesses_Bool = "neverKillProcesses"; static const char * k_pch_SteamVR_RenderTargetMultiplier_Float = "renderTargetMultiplier"; -static const char * k_pch_SteamVR_AllowReprojection_Bool = "allowReprojection"; +static const char * k_pch_SteamVR_AllowAsyncReprojection_Bool = "allowAsyncReprojection"; +static const char * k_pch_SteamVR_AllowReprojection_Bool = "allowInterleavedReprojection"; static const char * k_pch_SteamVR_ForceReprojection_Bool = "forceReprojection"; static const char * k_pch_SteamVR_ForceFadeOnBadTracking_Bool = "forceFadeOnBadTracking"; static const char * k_pch_SteamVR_DefaultMirrorView_Int32 = "defaultMirrorView"; static const char * k_pch_SteamVR_ShowMirrorView_Bool = "showMirrorView"; +static const char * k_pch_SteamVR_MirrorViewGeometry_String = "mirrorViewGeometry"; +static const char * k_pch_SteamVR_StartMonitorFromAppLaunch = "startMonitorFromAppLaunch"; +static const char * k_pch_SteamVR_EnableHomeApp = "enableHomeApp"; +static const char * k_pch_SteamVR_SetInitialDefaultHomeApp = "setInitialDefaultHomeApp"; +static const char * k_pch_SteamVR_CycleBackgroundImageTimeSec_Int32 = "CycleBackgroundImageTimeSec"; +static const char * k_pch_SteamVR_RetailDemo_Bool = "retailDemo"; +static const char * k_pch_SteamVR_IpdOffset_Float = "ipdOffset"; static const char * k_pch_Lighthouse_Section = "driver_lighthouse"; static const char * k_pch_Lighthouse_DisableIMU_Bool = "disableimu"; static const char * k_pch_Lighthouse_UseDisambiguation_String = "usedisambiguation"; static const char * k_pch_Lighthouse_DisambiguationDebug_Int32 = "disambiguationdebug"; static const char * k_pch_Lighthouse_PrimaryBasestation_Int32 = "primarybasestation"; -static const char * k_pch_Lighthouse_LighthouseName_String = "lighthousename"; -static const char * k_pch_Lighthouse_MaxIncidenceAngleDegrees_Float = "maxincidenceangledegrees"; -static const char * k_pch_Lighthouse_UseLighthouseDirect_Bool = "uselighthousedirect"; static const char * k_pch_Lighthouse_DBHistory_Bool = "dbhistory"; static const char * k_pch_Null_Section = "driver_null"; static const char * k_pch_Null_EnableNullDriver_Bool = "enable"; @@ -142,7 +148,9 @@ static const char * k_pch_Null_SecondsFromVsyncToPhotons_Float = "secondsFromVsy static const char * k_pch_Null_DisplayFrequency_Float = "displayFrequency"; static const char * k_pch_UserInterface_Section = "userinterface"; static const char * k_pch_UserInterface_StatusAlwaysOnTop_Bool = "StatusAlwaysOnTop"; -static const char * k_pch_UserInterface_EnableScreenshots_Bool = "EnableScreenshots"; +static const char * k_pch_UserInterface_MinimizeToTray_Bool = "MinimizeToTray"; +static const char * k_pch_UserInterface_Screenshots_Bool = "screenshots"; +static const char * k_pch_UserInterface_ScreenshotType_Int = "screenshotType"; static const char * k_pch_Notifications_Section = "notifications"; static const char * k_pch_Notifications_DoNotDisturb_Bool = "DoNotDisturb"; static const char * k_pch_Keyboard_Section = "keyboard"; @@ -179,6 +187,7 @@ static const char * k_pch_Camera_BoundsColorGammaR_Int32 = "cameraBoundsColorGam static const char * k_pch_Camera_BoundsColorGammaG_Int32 = "cameraBoundsColorGammaG"; static const char * k_pch_Camera_BoundsColorGammaB_Int32 = "cameraBoundsColorGammaB"; static const char * k_pch_Camera_BoundsColorGammaA_Int32 = "cameraBoundsColorGammaA"; +static const char * k_pch_Camera_BoundsStrength_Int32 = "cameraBoundsStrength"; static const char * k_pch_audio_Section = "audio"; static const char * k_pch_audio_OnPlaybackDevice_String = "onPlaybackDevice"; static const char * k_pch_audio_OnRecordDevice_String = "onRecordDevice"; @@ -186,8 +195,18 @@ static const char * k_pch_audio_OnPlaybackMirrorDevice_String = "onPlaybackMirro static const char * k_pch_audio_OffPlaybackDevice_String = "offPlaybackDevice"; static const char * k_pch_audio_OffRecordDevice_String = "offRecordDevice"; static const char * k_pch_audio_VIVEHDMIGain = "viveHDMIGain"; +static const char * k_pch_Power_Section = "power"; +static const char * k_pch_Power_PowerOffOnExit_Bool = "powerOffOnExit"; +static const char * k_pch_Power_TurnOffScreensTimeout_Float = "turnOffScreensTimeout"; +static const char * k_pch_Power_TurnOffControllersTimeout_Float = "turnOffControllersTimeout"; +static const char * k_pch_Power_ReturnToWatchdogTimeout_Float = "returnToWatchdogTimeout"; +static const char * k_pch_Power_AutoLaunchSteamVROnButtonPress = "autoLaunchSteamVROnButtonPress"; +static const char * k_pch_Dashboard_Section = "dashboard"; +static const char * k_pch_Dashboard_EnableDashboard_Bool = "enableDashboard"; +static const char * k_pch_Dashboard_ArcadeMode_Bool = "arcadeMode"; static const char * k_pch_modelskin_Section = "modelskins"; static const char * IVRScreenshots_Version = "IVRScreenshots_001"; +static const char * IVRResources_Version = "IVRResources_001"; // OpenVR Enums @@ -225,6 +244,7 @@ typedef enum ETrackedDeviceClass ETrackedDeviceClass_TrackedDeviceClass_HMD = 1, ETrackedDeviceClass_TrackedDeviceClass_Controller = 2, ETrackedDeviceClass_TrackedDeviceClass_TrackingReference = 4, + ETrackedDeviceClass_TrackedDeviceClass_Count = 5, ETrackedDeviceClass_TrackedDeviceClass_Other = 1000, } ETrackedDeviceClass; @@ -277,6 +297,7 @@ typedef enum ETrackedDeviceProperty ETrackedDeviceProperty_Prop_HasCamera_Bool = 1030, ETrackedDeviceProperty_Prop_DriverVersion_String = 1031, ETrackedDeviceProperty_Prop_Firmware_ForceUpdateRequired_Bool = 1032, + ETrackedDeviceProperty_Prop_ViveSystemButtonFixRequired_Bool = 1033, ETrackedDeviceProperty_Prop_ReportsTimeSinceVSync_Bool = 2000, ETrackedDeviceProperty_Prop_SecondsFromVsyncToPhotons_Float = 2001, ETrackedDeviceProperty_Prop_DisplayFrequency_Float = 2002, @@ -314,6 +335,7 @@ typedef enum ETrackedDeviceProperty ETrackedDeviceProperty_Prop_ScreenshotHorizontalFieldOfViewDegrees_Float = 2034, ETrackedDeviceProperty_Prop_ScreenshotVerticalFieldOfViewDegrees_Float = 2035, ETrackedDeviceProperty_Prop_DisplaySuppressed_Bool = 2036, + ETrackedDeviceProperty_Prop_DisplayAllowNightMode_Bool = 2037, ETrackedDeviceProperty_Prop_AttachedDeviceId_String = 3000, ETrackedDeviceProperty_Prop_SupportedButtons_Uint64 = 3001, ETrackedDeviceProperty_Prop_Axis0Type_Int32 = 3002, @@ -321,6 +343,7 @@ typedef enum ETrackedDeviceProperty ETrackedDeviceProperty_Prop_Axis2Type_Int32 = 3004, ETrackedDeviceProperty_Prop_Axis3Type_Int32 = 3005, ETrackedDeviceProperty_Prop_Axis4Type_Int32 = 3006, + ETrackedDeviceProperty_Prop_ControllerRoleHint_Int32 = 3007, ETrackedDeviceProperty_Prop_FieldOfViewLeftDegrees_Float = 4000, ETrackedDeviceProperty_Prop_FieldOfViewRightDegrees_Float = 4001, ETrackedDeviceProperty_Prop_FieldOfViewTopDegrees_Float = 4002, @@ -328,6 +351,15 @@ typedef enum ETrackedDeviceProperty ETrackedDeviceProperty_Prop_TrackingRangeMinimumMeters_Float = 4004, ETrackedDeviceProperty_Prop_TrackingRangeMaximumMeters_Float = 4005, ETrackedDeviceProperty_Prop_ModeLabel_String = 4006, + ETrackedDeviceProperty_Prop_IconPathName_String = 5000, + ETrackedDeviceProperty_Prop_NamedIconPathDeviceOff_String = 5001, + ETrackedDeviceProperty_Prop_NamedIconPathDeviceSearching_String = 5002, + ETrackedDeviceProperty_Prop_NamedIconPathDeviceSearchingAlert_String = 5003, + ETrackedDeviceProperty_Prop_NamedIconPathDeviceReady_String = 5004, + ETrackedDeviceProperty_Prop_NamedIconPathDeviceReadyAlert_String = 5005, + ETrackedDeviceProperty_Prop_NamedIconPathDeviceNotReady_String = 5006, + ETrackedDeviceProperty_Prop_NamedIconPathDeviceStandby_String = 5007, + ETrackedDeviceProperty_Prop_NamedIconPathDeviceAlertLow_String = 5008, ETrackedDeviceProperty_Prop_VendorSpecific_Reserved_Start = 10000, ETrackedDeviceProperty_Prop_VendorSpecific_Reserved_End = 10999, } ETrackedDeviceProperty; @@ -351,6 +383,7 @@ typedef enum EVRSubmitFlags EVRSubmitFlags_Submit_Default = 0, EVRSubmitFlags_Submit_LensDistortionAlreadyApplied = 1, EVRSubmitFlags_Submit_GlRenderBuffer = 2, + EVRSubmitFlags_Submit_VulkanTexture = 4, } EVRSubmitFlags; typedef enum EVRState @@ -363,6 +396,7 @@ typedef enum EVRState EVRState_VRState_Ready_Alert = 4, EVRState_VRState_NotReady = 5, EVRState_VRState_Standby = 6, + EVRState_VRState_Ready_Alert_Low = 7, } EVRState; typedef enum EVREventType @@ -377,6 +411,8 @@ typedef enum EVREventType EVREventType_VREvent_EnterStandbyMode = 106, EVREventType_VREvent_LeaveStandbyMode = 107, EVREventType_VREvent_TrackedDeviceRoleChanged = 108, + EVREventType_VREvent_WatchdogWakeUpRequested = 109, + EVREventType_VREvent_LensDistortionChanged = 110, EVREventType_VREvent_ButtonPress = 200, EVREventType_VREvent_ButtonUnpress = 201, EVREventType_VREvent_ButtonTouch = 202, @@ -388,6 +424,7 @@ typedef enum EVREventType EVREventType_VREvent_FocusLeave = 304, EVREventType_VREvent_Scroll = 305, EVREventType_VREvent_TouchPadMove = 306, + EVREventType_VREvent_OverlayFocusChanged = 307, EVREventType_VREvent_InputFocusCaptured = 400, EVREventType_VREvent_InputFocusReleased = 401, EVREventType_VREvent_SceneFocusLost = 402, @@ -416,10 +453,12 @@ typedef enum EVREventType EVREventType_VREvent_DashboardGuideButtonUp = 515, EVREventType_VREvent_ScreenshotTriggered = 516, EVREventType_VREvent_ImageFailed = 517, + EVREventType_VREvent_DashboardOverlayCreated = 518, EVREventType_VREvent_RequestScreenshot = 520, EVREventType_VREvent_ScreenshotTaken = 521, EVREventType_VREvent_ScreenshotFailed = 522, EVREventType_VREvent_SubmitScreenshotToDashboard = 523, + EVREventType_VREvent_ScreenshotProgressToDashboard = 524, EVREventType_VREvent_Notification_Shown = 600, EVREventType_VREvent_Notification_Hidden = 601, EVREventType_VREvent_Notification_BeginInteraction = 602, @@ -440,6 +479,7 @@ typedef enum EVREventType EVREventType_VREvent_ReprojectionSettingHasChanged = 852, EVREventType_VREvent_ModelSkinSettingsHaveChanged = 853, EVREventType_VREvent_EnvironmentSettingsHaveChanged = 854, + EVREventType_VREvent_PowerSettingsHaveChanged = 855, EVREventType_VREvent_StatusUpdate = 900, EVREventType_VREvent_MCImageUpdated = 1000, EVREventType_VREvent_FirmwareUpdateStarted = 1100, @@ -451,6 +491,7 @@ typedef enum EVREventType EVREventType_VREvent_ApplicationTransitionAborted = 1301, EVREventType_VREvent_ApplicationTransitionNewAppStarted = 1302, EVREventType_VREvent_ApplicationListUpdated = 1303, + EVREventType_VREvent_ApplicationMimeTypeLoad = 1304, EVREventType_VREvent_Compositor_MirrorWindowShown = 1400, EVREventType_VREvent_Compositor_MirrorWindowHidden = 1401, EVREventType_VREvent_Compositor_ChaperoneBoundsShown = 1410, @@ -459,6 +500,7 @@ typedef enum EVREventType EVREventType_VREvent_TrackedCamera_StopVideoStream = 1501, EVREventType_VREvent_TrackedCamera_PauseVideoStream = 1502, EVREventType_VREvent_TrackedCamera_ResumeVideoStream = 1503, + EVREventType_VREvent_TrackedCamera_EditingSurface = 1550, EVREventType_VREvent_PerformanceTest_EnableCapture = 1600, EVREventType_VREvent_PerformanceTest_DisableCapture = 1601, EVREventType_VREvent_PerformanceTest_FidelityLevel = 1602, @@ -485,6 +527,7 @@ typedef enum EVRButtonId EVRButtonId_k_EButton_DPad_Right = 5, EVRButtonId_k_EButton_DPad_Down = 6, EVRButtonId_k_EButton_A = 7, + EVRButtonId_k_EButton_ProximitySensor = 31, EVRButtonId_k_EButton_Axis0 = 32, EVRButtonId_k_EButton_Axis1 = 33, EVRButtonId_k_EButton_Axis2 = 34, @@ -503,6 +546,13 @@ typedef enum EVRMouseButton EVRMouseButton_VRMouseButton_Middle = 4, } EVRMouseButton; +typedef enum EHiddenAreaMeshType +{ + EHiddenAreaMeshType_k_eHiddenAreaMesh_Standard = 0, + EHiddenAreaMeshType_k_eHiddenAreaMesh_Inverse = 1, + EHiddenAreaMeshType_k_eHiddenAreaMesh_LineLoop = 2, +} EHiddenAreaMeshType; + typedef enum EVRControllerAxisType { EVRControllerAxisType_k_eControllerAxis_None = 0, @@ -546,8 +596,10 @@ typedef enum EVROverlayError EVROverlayError_VROverlayError_RequestFailed = 23, EVROverlayError_VROverlayError_InvalidTexture = 24, EVROverlayError_VROverlayError_UnableToLoadFile = 25, - EVROverlayError_VROVerlayError_KeyboardAlreadyInUse = 26, + EVROverlayError_VROverlayError_KeyboardAlreadyInUse = 26, EVROverlayError_VROverlayError_NoNeighbor = 27, + EVROverlayError_VROverlayError_TooManyMaskPrimitives = 29, + EVROverlayError_VROverlayError_BadMaskPrimitive = 30, } EVROverlayError; typedef enum EVRApplicationType @@ -558,6 +610,8 @@ typedef enum EVRApplicationType EVRApplicationType_VRApplication_Background = 3, EVRApplicationType_VRApplication_Utility = 4, EVRApplicationType_VRApplication_VRMonitor = 5, + EVRApplicationType_VRApplication_SteamWatchdog = 6, + EVRApplicationType_VRApplication_Max = 7, } EVRApplicationType; typedef enum EVRFirmwareError @@ -605,6 +659,14 @@ typedef enum EVRInitError EVRInitError_VRInitError_Init_NotSupportedWithCompositor = 122, EVRInitError_VRInitError_Init_NotAvailableToUtilityApps = 123, EVRInitError_VRInitError_Init_Internal = 124, + EVRInitError_VRInitError_Init_HmdDriverIdIsNone = 125, + EVRInitError_VRInitError_Init_HmdNotFoundPresenceFailed = 126, + EVRInitError_VRInitError_Init_VRMonitorNotFound = 127, + EVRInitError_VRInitError_Init_VRMonitorStartupFailed = 128, + EVRInitError_VRInitError_Init_LowPowerWatchdogNotSupported = 129, + EVRInitError_VRInitError_Init_InvalidApplicationType = 130, + EVRInitError_VRInitError_Init_NotAvailableToWatchdogApps = 131, + EVRInitError_VRInitError_Init_WatchdogDisabledInSettings = 132, EVRInitError_VRInitError_Driver_Failed = 200, EVRInitError_VRInitError_Driver_Unknown = 201, EVRInitError_VRInitError_Driver_HmdUnknown = 202, @@ -614,12 +676,18 @@ typedef enum EVRInitError EVRInitError_VRInitError_Driver_NotCalibrated = 206, EVRInitError_VRInitError_Driver_CalibrationInvalid = 207, EVRInitError_VRInitError_Driver_HmdDisplayNotFound = 208, + EVRInitError_VRInitError_Driver_TrackedDeviceInterfaceUnknown = 209, + EVRInitError_VRInitError_Driver_HmdDriverIdOutOfBounds = 211, + EVRInitError_VRInitError_Driver_HmdDisplayMirrored = 212, EVRInitError_VRInitError_IPC_ServerInitFailed = 300, EVRInitError_VRInitError_IPC_ConnectFailed = 301, EVRInitError_VRInitError_IPC_SharedStateInitFailed = 302, EVRInitError_VRInitError_IPC_CompositorInitFailed = 303, EVRInitError_VRInitError_IPC_MutexInitFailed = 304, EVRInitError_VRInitError_IPC_Failed = 305, + EVRInitError_VRInitError_IPC_CompositorConnectFailed = 306, + EVRInitError_VRInitError_IPC_CompositorInvalidConnectResponse = 307, + EVRInitError_VRInitError_IPC_ConnectFailedAfterMultipleAttempts = 308, EVRInitError_VRInitError_Compositor_Failed = 400, EVRInitError_VRInitError_Compositor_D3D11HardwareRequired = 401, EVRInitError_VRInitError_Compositor_FirmwareRequiresUpdate = 402, @@ -774,6 +842,7 @@ typedef enum EVRCompositorError EVRCompositorError_VRCompositorError_TextureUsesUnsupportedFormat = 105, EVRCompositorError_VRCompositorError_SharedTexturesNotSupported = 106, EVRCompositorError_VRCompositorError_IndexOutOfRange = 107, + EVRCompositorError_VRCompositorError_AlreadySubmitted = 108, } EVRCompositorError; typedef enum VROverlayInputMethod @@ -806,6 +875,7 @@ typedef enum VROverlayFlags VROverlayFlags_SideBySide_Crossed = 11, VROverlayFlags_Panorama = 12, VROverlayFlags_StereoPanorama = 13, + VROverlayFlags_SortWithNonSceneOverlays = 14, } VROverlayFlags; typedef enum EGamepadTextInputMode @@ -830,6 +900,12 @@ typedef enum EOverlayDirection EOverlayDirection_OverlayDirection_Count = 4, } EOverlayDirection; +typedef enum EVROverlayIntersectionMaskPrimitiveType +{ + EVROverlayIntersectionMaskPrimitiveType_OverlayIntersectionPrimitiveType_Rectangle = 0, + EVROverlayIntersectionMaskPrimitiveType_OverlayIntersectionPrimitiveType_Circle = 1, +} EVROverlayIntersectionMaskPrimitiveType; + typedef enum EVRRenderModelError { EVRRenderModelError_VRRenderModelError_None = 0, @@ -878,6 +954,8 @@ typedef enum EVRSettingsError EVRSettingsError_VRSettingsError_IPCFailed = 1, EVRSettingsError_VRSettingsError_WriteFailed = 2, EVRSettingsError_VRSettingsError_ReadFailed = 3, + EVRSettingsError_VRSettingsError_JsonParseFailed = 4, + EVRSettingsError_VRSettingsError_UnsetSettingHasNoDefault = 5, } EVRSettingsError; typedef enum EVRScreenshotError @@ -899,6 +977,7 @@ typedef uint64_t VROverlayHandle_t; typedef void * glSharedTextureHandle_t; typedef int32_t glInt_t; typedef uint32_t glUInt_t; +typedef uint64_t SharedTextureHandle_t; typedef uint32_t TrackedDeviceIndex_t; typedef uint64_t VROverlayHandle_t; typedef uint64_t TrackedCameraHandle_t; @@ -1014,6 +1093,20 @@ typedef struct VRTextureBounds_t float vMax; } VRTextureBounds_t; +typedef struct VulkanData_t +{ + uint64_t m_nImage; + struct VkDevice_T * m_pDevice; // struct VkDevice_T * + struct VkPhysicalDevice_T * m_pPhysicalDevice; // struct VkPhysicalDevice_T * + struct VkInstance_T * m_pInstance; // struct VkInstance_T * + struct VkQueue_T * m_pQueue; // struct VkQueue_T * + uint32_t m_nQueueFamilyIndex; + uint32_t m_nWidth; + uint32_t m_nHeight; + uint32_t m_nFormat; + uint32_t m_nSampleCount; +} VulkanData_t; + typedef struct VREvent_Controller_t { uint32_t button; @@ -1105,6 +1198,23 @@ typedef struct VREvent_Screenshot_t uint32_t type; } VREvent_Screenshot_t; +typedef struct VREvent_ScreenshotProgress_t +{ + float progress; +} VREvent_ScreenshotProgress_t; + +typedef struct VREvent_ApplicationLaunch_t +{ + uint32_t pid; + uint32_t unArgsHandle; +} VREvent_ApplicationLaunch_t; + +typedef struct VREvent_EditingCameraSurface_t +{ + uint64_t overlayHandle; + uint32_t nVisualMode; +} VREvent_EditingCameraSurface_t; + typedef struct HiddenAreaMesh_t { struct HmdVector2_t * pVertexData; // const struct vr::HmdVector2_t * @@ -1164,9 +1274,12 @@ typedef struct Compositor_FrameTiming uint32_t m_nSize; uint32_t m_nFrameIndex; uint32_t m_nNumFramePresents; + uint32_t m_nNumMisPresented; uint32_t m_nNumDroppedFrames; + uint32_t m_nReprojectionFlags; double m_flSystemTimeInSeconds; - float m_flSceneRenderGpuMs; + float m_flPreSubmitGpuMs; + float m_flPostSubmitGpuMs; float m_flTotalRenderGpuMs; float m_flCompositorRenderGpuMs; float m_flCompositorRenderCpuMs; @@ -1182,8 +1295,6 @@ typedef struct Compositor_FrameTiming float m_flCompositorUpdateEndMs; float m_flCompositorRenderStartMs; TrackedDevicePose_t m_HmdPose; - int32_t m_nFidelityLevel; - uint32_t m_nReprojectionFlags; } Compositor_FrameTiming; typedef struct Compositor_CumulativeStats @@ -1220,6 +1331,21 @@ typedef struct VROverlayIntersectionResults_t float fDistance; } VROverlayIntersectionResults_t; +typedef struct IntersectionMaskRectangle_t +{ + float m_flTopLeftX; + float m_flTopLeftY; + float m_flWidth; + float m_flHeight; +} IntersectionMaskRectangle_t; + +typedef struct IntersectionMaskCircle_t +{ + float m_flCenterX; + float m_flCenterY; + float m_flRadius; +} IntersectionMaskCircle_t; + typedef struct RenderModel_ComponentState_t { struct HmdMatrix34_t mTrackingToComponentRenderModel; @@ -1270,6 +1396,7 @@ typedef struct COpenVRContext intptr_t m_pVRChaperoneSetup; // class vr::IVRChaperoneSetup * intptr_t m_pVRCompositor; // class vr::IVRCompositor * intptr_t m_pVROverlay; // class vr::IVROverlay * + intptr_t m_pVRResources; // class vr::IVRResources * intptr_t m_pVRRenderModels; // class vr::IVRRenderModels * intptr_t m_pVRExtendedDisplay; // class vr::IVRExtendedDisplay * intptr_t m_pVRSettings; // class vr::IVRSettings * @@ -1308,6 +1435,19 @@ struct VREvent_t }; +typedef union +{ + IntersectionMaskRectangle_t m_Rectangle; + IntersectionMaskCircle_t m_Circle; +} VROverlayIntersectionMaskPrimitive_Data_t; + +struct VROverlayIntersectionMaskPrimitive_t +{ + EVROverlayIntersectionMaskPrimitiveType m_nPrimitiveType; + VROverlayIntersectionMaskPrimitive_Data_t m_Primitive; +}; + + // OpenVR Function Pointer Tables struct VR_IVRSystem_FnTable @@ -1315,7 +1455,7 @@ struct VR_IVRSystem_FnTable void (OPENVR_FNTABLE_CALLTYPE *GetRecommendedRenderTargetSize)(uint32_t * pnWidth, uint32_t * pnHeight); struct HmdMatrix44_t (OPENVR_FNTABLE_CALLTYPE *GetProjectionMatrix)(EVREye eEye, float fNearZ, float fFarZ, EGraphicsAPIConvention eProjType); void (OPENVR_FNTABLE_CALLTYPE *GetProjectionRaw)(EVREye eEye, float * pfLeft, float * pfRight, float * pfTop, float * pfBottom); - struct DistortionCoordinates_t (OPENVR_FNTABLE_CALLTYPE *ComputeDistortion)(EVREye eEye, float fU, float fV); + bool (OPENVR_FNTABLE_CALLTYPE *ComputeDistortion)(EVREye eEye, float fU, float fV, struct DistortionCoordinates_t * pDistortionCoordinates); struct HmdMatrix34_t (OPENVR_FNTABLE_CALLTYPE *GetEyeToHeadTransform)(EVREye eEye); bool (OPENVR_FNTABLE_CALLTYPE *GetTimeSinceLastVsync)(float * pfSecondsSinceLastVsync, uint64_t * pulFrameCounter); int32_t (OPENVR_FNTABLE_CALLTYPE *GetD3D9AdapterIndex)(); @@ -1343,9 +1483,9 @@ struct VR_IVRSystem_FnTable bool (OPENVR_FNTABLE_CALLTYPE *PollNextEvent)(struct VREvent_t * pEvent, uint32_t uncbVREvent); bool (OPENVR_FNTABLE_CALLTYPE *PollNextEventWithPose)(ETrackingUniverseOrigin eOrigin, struct VREvent_t * pEvent, uint32_t uncbVREvent, TrackedDevicePose_t * pTrackedDevicePose); char * (OPENVR_FNTABLE_CALLTYPE *GetEventTypeNameFromEnum)(EVREventType eType); - struct HiddenAreaMesh_t (OPENVR_FNTABLE_CALLTYPE *GetHiddenAreaMesh)(EVREye eEye); - bool (OPENVR_FNTABLE_CALLTYPE *GetControllerState)(TrackedDeviceIndex_t unControllerDeviceIndex, VRControllerState_t * pControllerState); - bool (OPENVR_FNTABLE_CALLTYPE *GetControllerStateWithPose)(ETrackingUniverseOrigin eOrigin, TrackedDeviceIndex_t unControllerDeviceIndex, VRControllerState_t * pControllerState, struct TrackedDevicePose_t * pTrackedDevicePose); + struct HiddenAreaMesh_t (OPENVR_FNTABLE_CALLTYPE *GetHiddenAreaMesh)(EVREye eEye, EHiddenAreaMeshType type); + bool (OPENVR_FNTABLE_CALLTYPE *GetControllerState)(TrackedDeviceIndex_t unControllerDeviceIndex, VRControllerState_t * pControllerState, uint32_t unControllerStateSize); + bool (OPENVR_FNTABLE_CALLTYPE *GetControllerStateWithPose)(ETrackingUniverseOrigin eOrigin, TrackedDeviceIndex_t unControllerDeviceIndex, VRControllerState_t * pControllerState, uint32_t unControllerStateSize, struct TrackedDevicePose_t * pTrackedDevicePose); void (OPENVR_FNTABLE_CALLTYPE *TriggerHapticPulse)(TrackedDeviceIndex_t unControllerDeviceIndex, uint32_t unAxisId, unsigned short usDurationMicroSec); char * (OPENVR_FNTABLE_CALLTYPE *GetButtonIdNameFromEnum)(EVRButtonId eButtonId); char * (OPENVR_FNTABLE_CALLTYPE *GetControllerAxisTypeNameFromEnum)(EVRControllerAxisType eAxisType); @@ -1375,6 +1515,10 @@ struct VR_IVRTrackedCamera_FnTable EVRTrackedCameraError (OPENVR_FNTABLE_CALLTYPE *AcquireVideoStreamingService)(TrackedDeviceIndex_t nDeviceIndex, TrackedCameraHandle_t * pHandle); EVRTrackedCameraError (OPENVR_FNTABLE_CALLTYPE *ReleaseVideoStreamingService)(TrackedCameraHandle_t hTrackedCamera); EVRTrackedCameraError (OPENVR_FNTABLE_CALLTYPE *GetVideoStreamFrameBuffer)(TrackedCameraHandle_t hTrackedCamera, EVRTrackedCameraFrameType eFrameType, void * pFrameBuffer, uint32_t nFrameBufferSize, CameraVideoStreamFrameHeader_t * pFrameHeader, uint32_t nFrameHeaderSize); + EVRTrackedCameraError (OPENVR_FNTABLE_CALLTYPE *GetVideoStreamTextureSize)(TrackedDeviceIndex_t nDeviceIndex, EVRTrackedCameraFrameType eFrameType, VRTextureBounds_t * pTextureBounds, uint32_t * pnWidth, uint32_t * pnHeight); + EVRTrackedCameraError (OPENVR_FNTABLE_CALLTYPE *GetVideoStreamTextureD3D11)(TrackedCameraHandle_t hTrackedCamera, EVRTrackedCameraFrameType eFrameType, void * pD3D11DeviceOrResource, void ** ppD3D11ShaderResourceView, CameraVideoStreamFrameHeader_t * pFrameHeader, uint32_t nFrameHeaderSize); + EVRTrackedCameraError (OPENVR_FNTABLE_CALLTYPE *GetVideoStreamTextureGL)(TrackedCameraHandle_t hTrackedCamera, EVRTrackedCameraFrameType eFrameType, glUInt_t * pglTextureId, CameraVideoStreamFrameHeader_t * pFrameHeader, uint32_t nFrameHeaderSize); + EVRTrackedCameraError (OPENVR_FNTABLE_CALLTYPE *ReleaseVideoStreamTextureGL)(TrackedCameraHandle_t hTrackedCamera, glUInt_t glTextureId); }; struct VR_IVRApplications_FnTable @@ -1387,6 +1531,7 @@ struct VR_IVRApplications_FnTable EVRApplicationError (OPENVR_FNTABLE_CALLTYPE *GetApplicationKeyByProcessId)(uint32_t unProcessId, char * pchAppKeyBuffer, uint32_t unAppKeyBufferLen); EVRApplicationError (OPENVR_FNTABLE_CALLTYPE *LaunchApplication)(char * pchAppKey); EVRApplicationError (OPENVR_FNTABLE_CALLTYPE *LaunchTemplateApplication)(char * pchTemplateAppKey, char * pchNewAppKey, struct AppOverrideKeys_t * pKeys, uint32_t unKeys); + EVRApplicationError (OPENVR_FNTABLE_CALLTYPE *LaunchApplicationFromMimeType)(char * pchMimeType, char * pchArgs); EVRApplicationError (OPENVR_FNTABLE_CALLTYPE *LaunchDashboardOverlay)(char * pchAppKey); bool (OPENVR_FNTABLE_CALLTYPE *CancelApplicationLaunch)(char * pchAppKey); EVRApplicationError (OPENVR_FNTABLE_CALLTYPE *IdentifyApplication)(uint32_t unProcessId, char * pchAppKey); @@ -1397,6 +1542,11 @@ struct VR_IVRApplications_FnTable uint64_t (OPENVR_FNTABLE_CALLTYPE *GetApplicationPropertyUint64)(char * pchAppKey, EVRApplicationProperty eProperty, EVRApplicationError * peError); EVRApplicationError (OPENVR_FNTABLE_CALLTYPE *SetApplicationAutoLaunch)(char * pchAppKey, bool bAutoLaunch); bool (OPENVR_FNTABLE_CALLTYPE *GetApplicationAutoLaunch)(char * pchAppKey); + EVRApplicationError (OPENVR_FNTABLE_CALLTYPE *SetDefaultApplicationForMimeType)(char * pchAppKey, char * pchMimeType); + bool (OPENVR_FNTABLE_CALLTYPE *GetDefaultApplicationForMimeType)(char * pchMimeType, char * pchAppKeyBuffer, uint32_t unAppKeyBufferLen); + bool (OPENVR_FNTABLE_CALLTYPE *GetApplicationSupportedMimeTypes)(char * pchAppKey, char * pchMimeTypesBuffer, uint32_t unMimeTypesBuffer); + uint32_t (OPENVR_FNTABLE_CALLTYPE *GetApplicationsThatSupportMimeType)(char * pchMimeType, char * pchAppKeysThatSupportBuffer, uint32_t unAppKeysThatSupportBuffer); + uint32_t (OPENVR_FNTABLE_CALLTYPE *GetApplicationLaunchArguments)(uint32_t unHandle, char * pchArgs, uint32_t unArgs); EVRApplicationError (OPENVR_FNTABLE_CALLTYPE *GetStartingApplication)(char * pchAppKeyBuffer, uint32_t unAppKeyBufferLen); EVRApplicationTransitionState (OPENVR_FNTABLE_CALLTYPE *GetTransitionState)(); EVRApplicationError (OPENVR_FNTABLE_CALLTYPE *PerformApplicationPrelaunchCheck)(char * pchAppKey); @@ -1452,10 +1602,13 @@ struct VR_IVRCompositor_FnTable void (OPENVR_FNTABLE_CALLTYPE *ClearLastSubmittedFrame)(); void (OPENVR_FNTABLE_CALLTYPE *PostPresentHandoff)(); bool (OPENVR_FNTABLE_CALLTYPE *GetFrameTiming)(struct Compositor_FrameTiming * pTiming, uint32_t unFramesAgo); + uint32_t (OPENVR_FNTABLE_CALLTYPE *GetFrameTimings)(struct Compositor_FrameTiming * pTiming, uint32_t nFrames); float (OPENVR_FNTABLE_CALLTYPE *GetFrameTimeRemaining)(); void (OPENVR_FNTABLE_CALLTYPE *GetCumulativeStats)(struct Compositor_CumulativeStats * pStats, uint32_t nStatsSizeInBytes); void (OPENVR_FNTABLE_CALLTYPE *FadeToColor)(float fSeconds, float fRed, float fGreen, float fBlue, float fAlpha, bool bBackground); + struct HmdColor_t (OPENVR_FNTABLE_CALLTYPE *GetCurrentFadeColor)(bool bBackground); void (OPENVR_FNTABLE_CALLTYPE *FadeGrid)(float fSeconds, bool bFadeIn); + float (OPENVR_FNTABLE_CALLTYPE *GetCurrentGridAlpha)(); EVRCompositorError (OPENVR_FNTABLE_CALLTYPE *SetSkyboxOverride)(struct Texture_t * pTextures, uint32_t unTextureCount); void (OPENVR_FNTABLE_CALLTYPE *ClearSkyboxOverride)(); void (OPENVR_FNTABLE_CALLTYPE *CompositorBringToFront)(); @@ -1473,8 +1626,6 @@ struct VR_IVRCompositor_FnTable void (OPENVR_FNTABLE_CALLTYPE *ForceInterleavedReprojectionOn)(bool bOverride); void (OPENVR_FNTABLE_CALLTYPE *ForceReconnectProcess)(); void (OPENVR_FNTABLE_CALLTYPE *SuspendRendering)(bool bSuspend); - EVRCompositorError (OPENVR_FNTABLE_CALLTYPE *RequestScreenshot)(EVRScreenshotType type, char * pchDestinationFileName, char * pchVRDestinationFileName); - EVRScreenshotType (OPENVR_FNTABLE_CALLTYPE *GetCurrentScreenshotType)(); EVRCompositorError (OPENVR_FNTABLE_CALLTYPE *GetMirrorTextureD3D11)(EVREye eEye, void * pD3D11DeviceOrResource, void ** ppD3D11ShaderResourceView); EVRCompositorError (OPENVR_FNTABLE_CALLTYPE *GetMirrorTextureGL)(EVREye eEye, glUInt_t * pglTextureId, glSharedTextureHandle_t * pglSharedTextureHandle); bool (OPENVR_FNTABLE_CALLTYPE *ReleaseSharedGLTexture)(glUInt_t glTextureId, glSharedTextureHandle_t glSharedTextureHandle); @@ -1501,6 +1652,10 @@ struct VR_IVROverlay_FnTable EVROverlayError (OPENVR_FNTABLE_CALLTYPE *GetOverlayColor)(VROverlayHandle_t ulOverlayHandle, float * pfRed, float * pfGreen, float * pfBlue); EVROverlayError (OPENVR_FNTABLE_CALLTYPE *SetOverlayAlpha)(VROverlayHandle_t ulOverlayHandle, float fAlpha); EVROverlayError (OPENVR_FNTABLE_CALLTYPE *GetOverlayAlpha)(VROverlayHandle_t ulOverlayHandle, float * pfAlpha); + EVROverlayError (OPENVR_FNTABLE_CALLTYPE *SetOverlayTexelAspect)(VROverlayHandle_t ulOverlayHandle, float fTexelAspect); + EVROverlayError (OPENVR_FNTABLE_CALLTYPE *GetOverlayTexelAspect)(VROverlayHandle_t ulOverlayHandle, float * pfTexelAspect); + EVROverlayError (OPENVR_FNTABLE_CALLTYPE *SetOverlaySortOrder)(VROverlayHandle_t ulOverlayHandle, uint32_t unSortOrder); + EVROverlayError (OPENVR_FNTABLE_CALLTYPE *GetOverlaySortOrder)(VROverlayHandle_t ulOverlayHandle, uint32_t * punSortOrder); EVROverlayError (OPENVR_FNTABLE_CALLTYPE *SetOverlayWidthInMeters)(VROverlayHandle_t ulOverlayHandle, float fWidthInMeters); EVROverlayError (OPENVR_FNTABLE_CALLTYPE *GetOverlayWidthInMeters)(VROverlayHandle_t ulOverlayHandle, float * pfWidthInMeters); EVROverlayError (OPENVR_FNTABLE_CALLTYPE *SetOverlayAutoCurveDistanceRangeInMeters)(VROverlayHandle_t ulOverlayHandle, float fMinDistanceInMeters, float fMaxDistanceInMeters); @@ -1552,6 +1707,7 @@ struct VR_IVROverlay_FnTable void (OPENVR_FNTABLE_CALLTYPE *HideKeyboard)(); void (OPENVR_FNTABLE_CALLTYPE *SetKeyboardTransformAbsolute)(ETrackingUniverseOrigin eTrackingOrigin, struct HmdMatrix34_t * pmatTrackingOriginToKeyboardTransform); void (OPENVR_FNTABLE_CALLTYPE *SetKeyboardPositionForOverlay)(VROverlayHandle_t ulOverlayHandle, struct HmdRect2_t avoidRect); + EVROverlayError (OPENVR_FNTABLE_CALLTYPE *SetOverlayIntersectionMask)(VROverlayHandle_t ulOverlayHandle, struct VROverlayIntersectionMaskPrimitive_t * pMaskPrimitives, uint32_t unNumMaskPrimitives, uint32_t unPrimitiveSize); }; struct VR_IVRRenderModels_FnTable @@ -1586,14 +1742,14 @@ struct VR_IVRSettings_FnTable { char * (OPENVR_FNTABLE_CALLTYPE *GetSettingsErrorNameFromEnum)(EVRSettingsError eError); bool (OPENVR_FNTABLE_CALLTYPE *Sync)(bool bForce, EVRSettingsError * peError); - bool (OPENVR_FNTABLE_CALLTYPE *GetBool)(char * pchSection, char * pchSettingsKey, bool bDefaultValue, EVRSettingsError * peError); void (OPENVR_FNTABLE_CALLTYPE *SetBool)(char * pchSection, char * pchSettingsKey, bool bValue, EVRSettingsError * peError); - int32_t (OPENVR_FNTABLE_CALLTYPE *GetInt32)(char * pchSection, char * pchSettingsKey, int32_t nDefaultValue, EVRSettingsError * peError); void (OPENVR_FNTABLE_CALLTYPE *SetInt32)(char * pchSection, char * pchSettingsKey, int32_t nValue, EVRSettingsError * peError); - float (OPENVR_FNTABLE_CALLTYPE *GetFloat)(char * pchSection, char * pchSettingsKey, float flDefaultValue, EVRSettingsError * peError); void (OPENVR_FNTABLE_CALLTYPE *SetFloat)(char * pchSection, char * pchSettingsKey, float flValue, EVRSettingsError * peError); - void (OPENVR_FNTABLE_CALLTYPE *GetString)(char * pchSection, char * pchSettingsKey, char * pchValue, uint32_t unValueLen, char * pchDefaultValue, EVRSettingsError * peError); void (OPENVR_FNTABLE_CALLTYPE *SetString)(char * pchSection, char * pchSettingsKey, char * pchValue, EVRSettingsError * peError); + bool (OPENVR_FNTABLE_CALLTYPE *GetBool)(char * pchSection, char * pchSettingsKey, EVRSettingsError * peError); + int32_t (OPENVR_FNTABLE_CALLTYPE *GetInt32)(char * pchSection, char * pchSettingsKey, EVRSettingsError * peError); + float (OPENVR_FNTABLE_CALLTYPE *GetFloat)(char * pchSection, char * pchSettingsKey, EVRSettingsError * peError); + void (OPENVR_FNTABLE_CALLTYPE *GetString)(char * pchSection, char * pchSettingsKey, char * pchValue, uint32_t unValueLen, EVRSettingsError * peError); void (OPENVR_FNTABLE_CALLTYPE *RemoveSection)(char * pchSection, EVRSettingsError * peError); void (OPENVR_FNTABLE_CALLTYPE *RemoveKeyInSection)(char * pchSection, char * pchSettingsKey, EVRSettingsError * peError); }; @@ -1609,6 +1765,12 @@ struct VR_IVRScreenshots_FnTable EVRScreenshotError (OPENVR_FNTABLE_CALLTYPE *SubmitScreenshot)(ScreenshotHandle_t screenshotHandle, EVRScreenshotType type, char * pchSourcePreviewFilename, char * pchSourceVRFilename); }; +struct VR_IVRResources_FnTable +{ + uint32_t (OPENVR_FNTABLE_CALLTYPE *LoadSharedResource)(char * pchResourceName, char * pchBuffer, uint32_t unBufferLen); + uint32_t (OPENVR_FNTABLE_CALLTYPE *GetResourceFullPath)(char * pchResourceName, char * pchResourceTypeDirectory, char * pchPathBuffer, uint32_t unBufferLen); +}; + #if 0 // Global entry points diff --git a/examples/ThirdPartyLibs/openvr/headers/openvr_driver.h b/examples/ThirdPartyLibs/openvr/headers/openvr_driver.h index 3f2a21df4..ae778b877 100644 --- a/examples/ThirdPartyLibs/openvr/headers/openvr_driver.h +++ b/examples/ThirdPartyLibs/openvr/headers/openvr_driver.h @@ -13,7 +13,13 @@ // vrtypes.h #ifndef _INCLUDE_VRTYPES_H -#define _INCLUDE_VRTYPES_H +#define _INCLUDE_VRTYPES_H + +// Forward declarations to avoid requiring vulkan.h +struct VkDevice_T; +struct VkPhysicalDevice_T; +struct VkInstance_T; +struct VkQueue_T; namespace vr { @@ -125,6 +131,10 @@ struct Texture_t EColorSpace eColorSpace; }; +// Handle to a shared texture (HANDLE on Windows obtained using OpenSharedResource). +typedef uint64_t SharedTextureHandle_t; +#define INVALID_SHARED_TEXTURE_HANDLE ((vr::SharedTextureHandle_t)0) + enum ETrackingResult { TrackingResult_Uninitialized = 1, @@ -136,7 +146,6 @@ enum ETrackingResult TrackingResult_Running_OutOfRange = 201, }; -static const uint32_t k_unTrackingStringSize = 32; static const uint32_t k_unMaxDriverDebugResponseSize = 32768; /** Used to pass device IDs to API calls */ @@ -154,6 +163,8 @@ enum ETrackedDeviceClass TrackedDeviceClass_Controller = 2, // Tracked controllers TrackedDeviceClass_TrackingReference = 4, // Camera and base stations that serve as tracking reference points + TrackedDeviceClass_Count, // This isn't a class that will ever be returned. It is used for allocating arrays and such + TrackedDeviceClass_Other = 1000, }; @@ -229,6 +240,7 @@ enum ETrackedDeviceProperty Prop_HasCamera_Bool = 1030, Prop_DriverVersion_String = 1031, Prop_Firmware_ForceUpdateRequired_Bool = 1032, + Prop_ViveSystemButtonFixRequired_Bool = 1033, // Properties that are unique to TrackedDeviceClass_HMD Prop_ReportsTimeSinceVSync_Bool = 2000, @@ -268,6 +280,7 @@ enum ETrackedDeviceProperty Prop_ScreenshotHorizontalFieldOfViewDegrees_Float = 2034, Prop_ScreenshotVerticalFieldOfViewDegrees_Float = 2035, Prop_DisplaySuppressed_Bool = 2036, + Prop_DisplayAllowNightMode_Bool = 2037, // Properties that are unique to TrackedDeviceClass_Controller Prop_AttachedDeviceId_String = 3000, @@ -277,6 +290,7 @@ enum ETrackedDeviceProperty Prop_Axis2Type_Int32 = 3004, // Return value is of type EVRControllerAxisType Prop_Axis3Type_Int32 = 3005, // Return value is of type EVRControllerAxisType Prop_Axis4Type_Int32 = 3006, // Return value is of type EVRControllerAxisType + Prop_ControllerRoleHint_Int32 = 3007, // Return value is of type ETrackedControllerRole // Properties that are unique to TrackedDeviceClass_TrackingReference Prop_FieldOfViewLeftDegrees_Float = 4000, @@ -287,6 +301,17 @@ enum ETrackedDeviceProperty Prop_TrackingRangeMaximumMeters_Float = 4005, Prop_ModeLabel_String = 4006, + // Properties that are used for user interface like icons names + Prop_IconPathName_String = 5000, // usually a directory named "icons" + Prop_NamedIconPathDeviceOff_String = 5001, // PNG for static icon, or GIF for animation, 50x32 for headsets and 32x32 for others + Prop_NamedIconPathDeviceSearching_String = 5002, // PNG for static icon, or GIF for animation, 50x32 for headsets and 32x32 for others + Prop_NamedIconPathDeviceSearchingAlert_String = 5003, // PNG for static icon, or GIF for animation, 50x32 for headsets and 32x32 for others + Prop_NamedIconPathDeviceReady_String = 5004, // PNG for static icon, or GIF for animation, 50x32 for headsets and 32x32 for others + Prop_NamedIconPathDeviceReadyAlert_String = 5005, // PNG for static icon, or GIF for animation, 50x32 for headsets and 32x32 for others + Prop_NamedIconPathDeviceNotReady_String = 5006, // PNG for static icon, or GIF for animation, 50x32 for headsets and 32x32 for others + Prop_NamedIconPathDeviceStandby_String = 5007, // PNG for static icon, or GIF for animation, 50x32 for headsets and 32x32 for others + Prop_NamedIconPathDeviceAlertLow_String = 5008, // PNG for static icon, or GIF for animation, 50x32 for headsets and 32x32 for others + // Vendors are free to expose private debug data in this reserved region Prop_VendorSpecific_Reserved_Start = 10000, Prop_VendorSpecific_Reserved_End = 10999, @@ -332,6 +357,22 @@ enum EVRSubmitFlags // If the texture pointer passed in is actually a renderbuffer (e.g. for MSAA in OpenGL) then set this flag. Submit_GlRenderBuffer = 0x02, + + // Handle is pointer to VulkanData_t + Submit_VulkanTexture = 0x04, +}; + +/** Data required for passing Vulkan textures to IVRCompositor::Submit. +* Be sure to call OpenVR_Shutdown before destroying these resources. */ +struct VulkanData_t +{ + uint64_t m_nImage; // VkImage + VkDevice_T *m_pDevice; + VkPhysicalDevice_T *m_pPhysicalDevice; + VkInstance_T *m_pInstance; + VkQueue_T *m_pQueue; + uint32_t m_nQueueFamilyIndex; + uint32_t m_nWidth, m_nHeight, m_nFormat, m_nSampleCount; }; @@ -346,6 +387,7 @@ enum EVRState VRState_Ready_Alert = 4, VRState_NotReady = 5, VRState_Standby = 6, + VRState_Ready_Alert_Low = 7, }; /** The types of events that could be posted (and what the parameters mean for each event type) */ @@ -362,6 +404,8 @@ enum EVREventType VREvent_EnterStandbyMode = 106, VREvent_LeaveStandbyMode = 107, VREvent_TrackedDeviceRoleChanged = 108, + VREvent_WatchdogWakeUpRequested = 109, + VREvent_LensDistortionChanged = 110, VREvent_ButtonPress = 200, // data is controller VREvent_ButtonUnpress = 201, // data is controller @@ -375,6 +419,7 @@ enum EVREventType VREvent_FocusLeave = 304, // data is overlay VREvent_Scroll = 305, // data is mouse VREvent_TouchPadMove = 306, // data is mouse + VREvent_OverlayFocusChanged = 307, // data is overlay, global event VREvent_InputFocusCaptured = 400, // data is process DEPRECATED VREvent_InputFocusReleased = 401, // data is process DEPRECATED @@ -406,12 +451,14 @@ enum EVREventType VREvent_DashboardGuideButtonUp = 515, VREvent_ScreenshotTriggered = 516, // Screenshot button combo was pressed, Dashboard should request a screenshot VREvent_ImageFailed = 517, // Sent to overlays when a SetOverlayRaw or SetOverlayfromFail fails to load + VREvent_DashboardOverlayCreated = 518, // Screenshot API VREvent_RequestScreenshot = 520, // Sent by vrclient application to compositor to take a screenshot VREvent_ScreenshotTaken = 521, // Sent by compositor to the application that the screenshot has been taken VREvent_ScreenshotFailed = 522, // Sent by compositor to the application that the screenshot failed to be taken VREvent_SubmitScreenshotToDashboard = 523, // Sent by compositor to the dashboard that a completed screenshot was submitted + VREvent_ScreenshotProgressToDashboard = 524, // Sent by compositor to the dashboard that a completed screenshot was submitted VREvent_Notification_Shown = 600, VREvent_Notification_Hidden = 601, @@ -437,6 +484,7 @@ enum EVREventType VREvent_ReprojectionSettingHasChanged = 852, VREvent_ModelSkinSettingsHaveChanged = 853, VREvent_EnvironmentSettingsHaveChanged = 854, + VREvent_PowerSettingsHaveChanged = 855, VREvent_StatusUpdate = 900, @@ -453,6 +501,7 @@ enum EVREventType VREvent_ApplicationTransitionAborted = 1301, VREvent_ApplicationTransitionNewAppStarted = 1302, VREvent_ApplicationListUpdated = 1303, + VREvent_ApplicationMimeTypeLoad = 1304, VREvent_Compositor_MirrorWindowShown = 1400, VREvent_Compositor_MirrorWindowHidden = 1401, @@ -463,6 +512,7 @@ enum EVREventType VREvent_TrackedCamera_StopVideoStream = 1501, VREvent_TrackedCamera_PauseVideoStream = 1502, VREvent_TrackedCamera_ResumeVideoStream = 1503, + VREvent_TrackedCamera_EditingSurface = 1550, VREvent_PerformanceTest_EnableCapture = 1600, VREvent_PerformanceTest_DisableCapture = 1601, @@ -496,6 +546,8 @@ enum EVRButtonId k_EButton_DPad_Right = 5, k_EButton_DPad_Down = 6, k_EButton_A = 7, + + k_EButton_ProximitySensor = 31, k_EButton_Axis0 = 32, k_EButton_Axis1 = 33, @@ -634,7 +686,24 @@ struct VREvent_Screenshot_t uint32_t type; }; -/** If you change this you must manually update openvr_interop.cs.py */ +struct VREvent_ScreenshotProgress_t +{ + float progress; +}; + +struct VREvent_ApplicationLaunch_t +{ + uint32_t pid; + uint32_t unArgsHandle; +}; + +struct VREvent_EditingCameraSurface_t +{ + uint64_t overlayHandle; + uint32_t nVisualMode; +}; + +/** NOTE!!! If you change this you MUST manually update openvr_interop.cs.py */ typedef union { VREvent_Reserved_t reserved; @@ -652,6 +721,9 @@ typedef union VREvent_TouchPadMove_t touchPadMove; VREvent_SeatedZeroPoseReset_t seatedZeroPoseReset; VREvent_Screenshot_t screenshot; + VREvent_ScreenshotProgress_t screenshotProgress; + VREvent_ApplicationLaunch_t applicationLaunch; + VREvent_EditingCameraSurface_t cameraSurface; } VREvent_Data_t; /** An event posted by the server to all running applications */ @@ -678,6 +750,14 @@ struct HiddenAreaMesh_t }; +enum EHiddenAreaMeshType +{ + k_eHiddenAreaMesh_Standard = 0, + k_eHiddenAreaMesh_Inverse = 1, + k_eHiddenAreaMesh_LineLoop = 2, +}; + + /** Identifies what kind of axis is on the controller at index n. Read this type * with pVRSystem->Get( nControllerDeviceIndex, Prop_Axis0Type_Int32 + n ); */ @@ -761,26 +841,28 @@ static const VROverlayHandle_t k_ulOverlayHandleInvalid = 0; /** Errors that can occur around VR overlays */ enum EVROverlayError { - VROverlayError_None = 0, + VROverlayError_None = 0, - VROverlayError_UnknownOverlay = 10, - VROverlayError_InvalidHandle = 11, - VROverlayError_PermissionDenied = 12, - VROverlayError_OverlayLimitExceeded = 13, // No more overlays could be created because the maximum number already exist - VROverlayError_WrongVisibilityType = 14, - VROverlayError_KeyTooLong = 15, - VROverlayError_NameTooLong = 16, - VROverlayError_KeyInUse = 17, - VROverlayError_WrongTransformType = 18, - VROverlayError_InvalidTrackedDevice = 19, - VROverlayError_InvalidParameter = 20, - VROverlayError_ThumbnailCantBeDestroyed = 21, - VROverlayError_ArrayTooSmall = 22, - VROverlayError_RequestFailed = 23, - VROverlayError_InvalidTexture = 24, - VROverlayError_UnableToLoadFile = 25, - VROVerlayError_KeyboardAlreadyInUse = 26, - VROverlayError_NoNeighbor = 27, + VROverlayError_UnknownOverlay = 10, + VROverlayError_InvalidHandle = 11, + VROverlayError_PermissionDenied = 12, + VROverlayError_OverlayLimitExceeded = 13, // No more overlays could be created because the maximum number already exist + VROverlayError_WrongVisibilityType = 14, + VROverlayError_KeyTooLong = 15, + VROverlayError_NameTooLong = 16, + VROverlayError_KeyInUse = 17, + VROverlayError_WrongTransformType = 18, + VROverlayError_InvalidTrackedDevice = 19, + VROverlayError_InvalidParameter = 20, + VROverlayError_ThumbnailCantBeDestroyed = 21, + VROverlayError_ArrayTooSmall = 22, + VROverlayError_RequestFailed = 23, + VROverlayError_InvalidTexture = 24, + VROverlayError_UnableToLoadFile = 25, + VROverlayError_KeyboardAlreadyInUse = 26, + VROverlayError_NoNeighbor = 27, + VROverlayError_TooManyMaskPrimitives = 29, + VROverlayError_BadMaskPrimitive = 30, }; /** enum values to pass in to VR_Init to identify whether the application will @@ -795,6 +877,9 @@ enum EVRApplicationType VRApplication_Utility = 4, // Init should not try to load any drivers. The application needs access to utility // interfaces (like IVRSettings and IVRApplications) but not hardware. VRApplication_VRMonitor = 5, // Reserved for vrmonitor + VRApplication_SteamWatchdog = 6,// Reserved for Steam + + VRApplication_Max }; @@ -851,6 +936,14 @@ enum EVRInitError VRInitError_Init_NotSupportedWithCompositor = 122, VRInitError_Init_NotAvailableToUtilityApps = 123, VRInitError_Init_Internal = 124, + VRInitError_Init_HmdDriverIdIsNone = 125, + VRInitError_Init_HmdNotFoundPresenceFailed = 126, + VRInitError_Init_VRMonitorNotFound = 127, + VRInitError_Init_VRMonitorStartupFailed = 128, + VRInitError_Init_LowPowerWatchdogNotSupported = 129, + VRInitError_Init_InvalidApplicationType = 130, + VRInitError_Init_NotAvailableToWatchdogApps = 131, + VRInitError_Init_WatchdogDisabledInSettings = 132, VRInitError_Driver_Failed = 200, VRInitError_Driver_Unknown = 201, @@ -861,13 +954,20 @@ enum EVRInitError VRInitError_Driver_NotCalibrated = 206, VRInitError_Driver_CalibrationInvalid = 207, VRInitError_Driver_HmdDisplayNotFound = 208, - + VRInitError_Driver_TrackedDeviceInterfaceUnknown = 209, + // VRInitError_Driver_HmdDisplayNotFoundAfterFix = 210, // not needed: here for historic reasons + VRInitError_Driver_HmdDriverIdOutOfBounds = 211, + VRInitError_Driver_HmdDisplayMirrored = 212, + VRInitError_IPC_ServerInitFailed = 300, VRInitError_IPC_ConnectFailed = 301, VRInitError_IPC_SharedStateInitFailed = 302, VRInitError_IPC_CompositorInitFailed = 303, VRInitError_IPC_MutexInitFailed = 304, VRInitError_IPC_Failed = 305, + VRInitError_IPC_CompositorConnectFailed = 306, + VRInitError_IPC_CompositorInvalidConnectResponse = 307, + VRInitError_IPC_ConnectFailedAfterMultipleAttempts = 308, VRInitError_Compositor_Failed = 400, VRInitError_Compositor_D3D11HardwareRequired = 401, @@ -971,7 +1071,7 @@ static const uint32_t k_unScreenshotHandleInvalid = 0; #define VR_INTERFACE extern "C" __declspec( dllimport ) #endif -#elif defined(GNUC) || defined(COMPILER_GCC) || defined(__APPLE__) +#elif defined(__GNUC__) || defined(COMPILER_GCC) || defined(__APPLE__) #ifdef VR_API_EXPORT #define VR_INTERFACE extern "C" __attribute__((visibility("default"))) @@ -995,6 +1095,25 @@ static const uint32_t k_unScreenshotHandleInvalid = 0; #endif // _INCLUDE_VRTYPES_H +// vrannotation.h +#ifdef API_GEN +# define VR_CLANG_ATTR(ATTR) __attribute__((annotate( ATTR ))) +#else +# define VR_CLANG_ATTR(ATTR) +#endif + +#define VR_METHOD_DESC(DESC) VR_CLANG_ATTR( "desc:" #DESC ";" ) +#define VR_IGNOREATTR() VR_CLANG_ATTR( "ignore" ) +#define VR_OUT_STRUCT() VR_CLANG_ATTR( "out_struct: ;" ) +#define VR_OUT_STRING() VR_CLANG_ATTR( "out_string: ;" ) +#define VR_OUT_ARRAY_CALL(COUNTER,FUNCTION,PARAMS) VR_CLANG_ATTR( "out_array_call:" #COUNTER "," #FUNCTION "," #PARAMS ";" ) +#define VR_OUT_ARRAY_COUNT(COUNTER) VR_CLANG_ATTR( "out_array_count:" #COUNTER ";" ) +#define VR_ARRAY_COUNT(COUNTER) VR_CLANG_ATTR( "array_count:" #COUNTER ";" ) +#define VR_ARRAY_COUNT_D(COUNTER, DESC) VR_CLANG_ATTR( "array_count:" #COUNTER ";desc:" #DESC ) +#define VR_BUFFER_COUNT(COUNTER) VR_CLANG_ATTR( "buffer_count:" #COUNTER ";" ) +#define VR_OUT_BUFFER_COUNT(COUNTER) VR_CLANG_ATTR( "out_buffer_count:" #COUNTER ";" ) +#define VR_OUT_STRING_COUNT(COUNTER) VR_CLANG_ATTR( "out_string_count:" #COUNTER ";" ) + // vrtrackedcameratypes.h #ifndef _VRTRACKEDCAMERATYPES_H #define _VRTRACKEDCAMERATYPES_H @@ -1102,6 +1221,8 @@ namespace vr VRSettingsError_IPCFailed = 1, VRSettingsError_WriteFailed = 2, VRSettingsError_ReadFailed = 3, + VRSettingsError_JsonParseFailed = 4, + VRSettingsError_UnsetSettingHasNoDefault = 5, // This will be returned if the setting does not appear in the appropriate default file and has not been set }; // The maximum length of a settings key @@ -1115,21 +1236,24 @@ namespace vr // Returns true if file sync occurred (force or settings dirty) virtual bool Sync( bool bForce = false, EVRSettingsError *peError = nullptr ) = 0; - virtual bool GetBool( const char *pchSection, const char *pchSettingsKey, bool bDefaultValue, EVRSettingsError *peError = nullptr ) = 0; virtual void SetBool( const char *pchSection, const char *pchSettingsKey, bool bValue, EVRSettingsError *peError = nullptr ) = 0; - virtual int32_t GetInt32( const char *pchSection, const char *pchSettingsKey, int32_t nDefaultValue, EVRSettingsError *peError = nullptr ) = 0; virtual void SetInt32( const char *pchSection, const char *pchSettingsKey, int32_t nValue, EVRSettingsError *peError = nullptr ) = 0; - virtual float GetFloat( const char *pchSection, const char *pchSettingsKey, float flDefaultValue, EVRSettingsError *peError = nullptr ) = 0; virtual void SetFloat( const char *pchSection, const char *pchSettingsKey, float flValue, EVRSettingsError *peError = nullptr ) = 0; - virtual void GetString( const char *pchSection, const char *pchSettingsKey, char *pchValue, uint32_t unValueLen, const char *pchDefaultValue, EVRSettingsError *peError = nullptr ) = 0; virtual void SetString( const char *pchSection, const char *pchSettingsKey, const char *pchValue, EVRSettingsError *peError = nullptr ) = 0; - + + // Users of the system need to provide a proper default in default.vrsettings in the resources/settings/ directory + // of either the runtime or the driver_xxx directory. Otherwise the default will be false, 0, 0.0 or "" + virtual bool GetBool( const char *pchSection, const char *pchSettingsKey, EVRSettingsError *peError = nullptr ) = 0; + virtual int32_t GetInt32( const char *pchSection, const char *pchSettingsKey, EVRSettingsError *peError = nullptr ) = 0; + virtual float GetFloat( const char *pchSection, const char *pchSettingsKey, EVRSettingsError *peError = nullptr ) = 0; + virtual void GetString( const char *pchSection, const char *pchSettingsKey, VR_OUT_STRING() char *pchValue, uint32_t unValueLen, EVRSettingsError *peError = nullptr ) = 0; + virtual void RemoveSection( const char *pchSection, EVRSettingsError *peError = nullptr ) = 0; virtual void RemoveKeyInSection( const char *pchSection, const char *pchSettingsKey, EVRSettingsError *peError = nullptr ) = 0; }; //----------------------------------------------------------------------------- - static const char * const IVRSettings_Version = "IVRSettings_001"; + static const char * const IVRSettings_Version = "IVRSettings_002"; //----------------------------------------------------------------------------- // steamvr keys @@ -1147,16 +1271,13 @@ namespace vr static const char * const k_pch_SteamVR_LogLevel_Int32 = "loglevel"; static const char * const k_pch_SteamVR_IPD_Float = "ipd"; static const char * const k_pch_SteamVR_Background_String = "background"; + static const char * const k_pch_SteamVR_BackgroundUseDomeProjection_Bool = "backgroundUseDomeProjection"; static const char * const k_pch_SteamVR_BackgroundCameraHeight_Float = "backgroundCameraHeight"; static const char * const k_pch_SteamVR_BackgroundDomeRadius_Float = "backgroundDomeRadius"; - static const char * const k_pch_SteamVR_Environment_String = "environment"; static const char * const k_pch_SteamVR_GridColor_String = "gridColor"; static const char * const k_pch_SteamVR_PlayAreaColor_String = "playAreaColor"; static const char * const k_pch_SteamVR_ShowStage_Bool = "showStage"; static const char * const k_pch_SteamVR_ActivateMultipleDrivers_Bool = "activateMultipleDrivers"; - static const char * const k_pch_SteamVR_PowerOffOnExit_Bool = "powerOffOnExit"; - static const char * const k_pch_SteamVR_StandbyAppRunningTimeout_Float = "standbyAppRunningTimeout"; - static const char * const k_pch_SteamVR_StandbyNoAppTimeout_Float = "standbyNoAppTimeout"; static const char * const k_pch_SteamVR_DirectMode_Bool = "directMode"; static const char * const k_pch_SteamVR_DirectModeEdidVid_Int32 = "directModeEdidVid"; static const char * const k_pch_SteamVR_DirectModeEdidPid_Int32 = "directModeEdidPid"; @@ -1165,11 +1286,20 @@ namespace vr static const char * const k_pch_SteamVR_BaseStationPowerManagement_Bool = "basestationPowerManagement"; static const char * const k_pch_SteamVR_NeverKillProcesses_Bool = "neverKillProcesses"; static const char * const k_pch_SteamVR_RenderTargetMultiplier_Float = "renderTargetMultiplier"; - static const char * const k_pch_SteamVR_AllowReprojection_Bool = "allowReprojection"; + static const char * const k_pch_SteamVR_AllowAsyncReprojection_Bool = "allowAsyncReprojection"; + static const char * const k_pch_SteamVR_AllowReprojection_Bool = "allowInterleavedReprojection"; static const char * const k_pch_SteamVR_ForceReprojection_Bool = "forceReprojection"; static const char * const k_pch_SteamVR_ForceFadeOnBadTracking_Bool = "forceFadeOnBadTracking"; static const char * const k_pch_SteamVR_DefaultMirrorView_Int32 = "defaultMirrorView"; static const char * const k_pch_SteamVR_ShowMirrorView_Bool = "showMirrorView"; + static const char * const k_pch_SteamVR_MirrorViewGeometry_String = "mirrorViewGeometry"; + static const char * const k_pch_SteamVR_StartMonitorFromAppLaunch = "startMonitorFromAppLaunch"; + static const char * const k_pch_SteamVR_EnableHomeApp = "enableHomeApp"; + static const char * const k_pch_SteamVR_SetInitialDefaultHomeApp = "setInitialDefaultHomeApp"; + static const char * const k_pch_SteamVR_CycleBackgroundImageTimeSec_Int32 = "CycleBackgroundImageTimeSec"; + static const char * const k_pch_SteamVR_RetailDemo_Bool = "retailDemo"; + static const char * const k_pch_SteamVR_IpdOffset_Float = "ipdOffset"; + //----------------------------------------------------------------------------- // lighthouse keys @@ -1180,9 +1310,6 @@ namespace vr static const char * const k_pch_Lighthouse_DisambiguationDebug_Int32 = "disambiguationdebug"; static const char * const k_pch_Lighthouse_PrimaryBasestation_Int32 = "primarybasestation"; - static const char * const k_pch_Lighthouse_LighthouseName_String = "lighthousename"; - static const char * const k_pch_Lighthouse_MaxIncidenceAngleDegrees_Float = "maxincidenceangledegrees"; - static const char * const k_pch_Lighthouse_UseLighthouseDirect_Bool = "uselighthousedirect"; static const char * const k_pch_Lighthouse_DBHistory_Bool = "dbhistory"; //----------------------------------------------------------------------------- @@ -1205,7 +1332,9 @@ namespace vr // user interface keys static const char * const k_pch_UserInterface_Section = "userinterface"; static const char * const k_pch_UserInterface_StatusAlwaysOnTop_Bool = "StatusAlwaysOnTop"; - static const char * const k_pch_UserInterface_EnableScreenshots_Bool = "EnableScreenshots"; + static const char * const k_pch_UserInterface_MinimizeToTray_Bool = "MinimizeToTray"; + static const char * const k_pch_UserInterface_Screenshots_Bool = "screenshots"; + static const char * const k_pch_UserInterface_ScreenshotType_Int = "screenshotType"; //----------------------------------------------------------------------------- // notification keys @@ -1257,6 +1386,7 @@ namespace vr static const char * const k_pch_Camera_BoundsColorGammaG_Int32 = "cameraBoundsColorGammaG"; static const char * const k_pch_Camera_BoundsColorGammaB_Int32 = "cameraBoundsColorGammaB"; static const char * const k_pch_Camera_BoundsColorGammaA_Int32 = "cameraBoundsColorGammaA"; + static const char * const k_pch_Camera_BoundsStrength_Int32 = "cameraBoundsStrength"; //----------------------------------------------------------------------------- // audio keys @@ -1268,6 +1398,21 @@ namespace vr static const char * const k_pch_audio_OffRecordDevice_String = "offRecordDevice"; static const char * const k_pch_audio_VIVEHDMIGain = "viveHDMIGain"; + //----------------------------------------------------------------------------- + // power management keys + static const char * const k_pch_Power_Section = "power"; + static const char * const k_pch_Power_PowerOffOnExit_Bool = "powerOffOnExit"; + static const char * const k_pch_Power_TurnOffScreensTimeout_Float = "turnOffScreensTimeout"; + static const char * const k_pch_Power_TurnOffControllersTimeout_Float = "turnOffControllersTimeout"; + static const char * const k_pch_Power_ReturnToWatchdogTimeout_Float = "returnToWatchdogTimeout"; + static const char * const k_pch_Power_AutoLaunchSteamVROnButtonPress = "autoLaunchSteamVROnButtonPress"; + + //----------------------------------------------------------------------------- + // dashboard keys + static const char * const k_pch_Dashboard_Section = "dashboard"; + static const char * const k_pch_Dashboard_EnableDashboard_Bool = "enableDashboard"; + static const char * const k_pch_Dashboard_ArcadeMode_Bool = "arcadeMode"; + //----------------------------------------------------------------------------- // model skin keys static const char * const k_pch_modelskin_Section = "modelskins"; @@ -1373,8 +1518,8 @@ public: * and thread use it can when it is deactivated */ virtual void Deactivate() = 0; - /** Handles a request from the system to power off this device */ - virtual void PowerOff() = 0; + /** Handles a request from the system to put this device into standby mode. What that means is defined per-device. */ + virtual void EnterStandby() = 0; /** Requests a component interface of the driver for device-specific functionality. The driver should return NULL * if the requested interface or version is not supported. */ @@ -1411,9 +1556,8 @@ public: /** Returns a string property. If the property is not available this function will return 0 and pError will be * set to an error. Otherwise it returns the length of the number of bytes necessary to hold this string including - * the trailing null. If the buffer is too small the error will be TrackedProp_BufferTooSmall. Strings will - * generally fit in buffers of k_unTrackingStringSize characters. Drivers may not return strings longer than - * k_unMaxPropertyStringSize. */ + * the trailing null. If the buffer is too small the error will be TrackedProp_BufferTooSmall. Drivers may not + * return strings longer than k_unMaxPropertyStringSize. */ virtual uint32_t GetStringTrackedDeviceProperty( ETrackedDeviceProperty prop, char *pchValue, uint32_t unBufferSize, ETrackedPropertyError *pError ) = 0; }; @@ -1487,27 +1631,27 @@ namespace vr // ----------------------------------- /** Specific to Oculus compositor support, textures supplied must be created using this method. */ - virtual void CreateSwapTextureSet( uint32_t unPid, uint32_t unFormat, uint32_t unWidth, uint32_t unHeight, void *(*pSharedTextureHandles)[3] ) {} + virtual void CreateSwapTextureSet( uint32_t unPid, uint32_t unFormat, uint32_t unWidth, uint32_t unHeight, vr::SharedTextureHandle_t( *pSharedTextureHandles )[ 3 ] ) {} /** Used to textures created using CreateSwapTextureSet. Only one of the set's handles needs to be used to destroy the entire set. */ - virtual void DestroySwapTextureSet( void *pSharedTextureHandle ) {} + virtual void DestroySwapTextureSet( vr::SharedTextureHandle_t sharedTextureHandle ) {} /** Used to purge all texture sets for a given process. */ virtual void DestroyAllSwapTextureSets( uint32_t unPid ) {} /** After Present returns, calls this to get the next index to use for rendering. */ - virtual void GetNextSwapTextureSetIndex( void *pSharedTextureHandles[ 2 ], uint32_t( *pIndices )[ 2 ] ) {} + virtual void GetNextSwapTextureSetIndex( vr::SharedTextureHandle_t sharedTextureHandles[ 2 ], uint32_t( *pIndices )[ 2 ] ) {} /** Call once per layer to draw for this frame. One shared texture handle per eye. Textures must be created * using CreateSwapTextureSet and should be alternated per frame. Call Present once all layers have been submitted. */ - virtual void SubmitLayer( void *pSharedTextureHandles[ 2 ], const vr::VRTextureBounds_t( &bounds )[ 2 ], const vr::HmdMatrix34_t *pPose ) {} + virtual void SubmitLayer( vr::SharedTextureHandle_t sharedTextureHandles[ 2 ], const vr::VRTextureBounds_t( &bounds )[ 2 ], const vr::HmdMatrix34_t *pPose ) {} /** Submits queued layers for display. */ - virtual void Present( void *hSyncTexture ) {} + virtual void Present( vr::SharedTextureHandle_t syncTexture ) {} }; - static const char *IVRDriverDirectModeComponent_Version = "IVRDriverDirectModeComponent_001"; + static const char *IVRDriverDirectModeComponent_Version = "IVRDriverDirectModeComponent_002"; } @@ -1543,7 +1687,6 @@ namespace vr // ivrcameracomponent.h namespace vr { - //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- class ICameraVideoSinkCallback @@ -1561,8 +1704,6 @@ namespace vr // ------------------------------------ // Camera Methods // ------------------------------------ - virtual bool HasCamera() = 0; - virtual bool GetCameraFirmwareDescription( char *pBuffer, uint32_t nBufferLen ) = 0; virtual bool GetCameraFrameDimensions( vr::ECameraVideoStreamFormat nVideoStreamFormat, uint32_t *pWidth, uint32_t *pHeight ) = 0; virtual bool GetCameraFrameBufferingRequirements( int *pDefaultFrameQueueSize, uint32_t *pFrameBufferDataSize ) = 0; virtual bool SetCameraFrameBuffering( int nFrameBufferCount, void **ppFrameBuffers, uint32_t nFrameBufferDataSize ) = 0; @@ -1570,19 +1711,14 @@ namespace vr virtual vr::ECameraVideoStreamFormat GetCameraVideoStreamFormat() = 0; virtual bool StartVideoStream() = 0; virtual void StopVideoStream() = 0; - virtual bool IsVideoStreamActive() = 0; - virtual float GetVideoStreamElapsedTime() = 0; + virtual bool IsVideoStreamActive( bool *pbPaused, float *pflElapsedTime ) = 0; virtual const vr::CameraVideoStreamFrame_t *GetVideoStreamFrame() = 0; virtual void ReleaseVideoStreamFrame( const vr::CameraVideoStreamFrame_t *pFrameImage ) = 0; virtual bool SetAutoExposure( bool bEnable ) = 0; virtual bool PauseVideoStream() = 0; virtual bool ResumeVideoStream() = 0; - virtual bool IsVideoStreamPaused() = 0; virtual bool GetCameraDistortion( float flInputU, float flInputV, float *pflOutputU, float *pflOutputV ) = 0; - virtual bool GetCameraProjection( float flWidthPixels, float flHeightPixels, float flZNear, float flZFar, vr::HmdMatrix44_t *pProjection ) = 0; - virtual bool GetRecommendedCameraUndistortion( uint32_t *pUndistortionWidthPixels, uint32_t *pUndistortionHeightPixels ) = 0; - virtual bool SetCameraUndistortion( uint32_t nUndistortionWidthPixels, uint32_t nUndistortionHeightPixels ) = 0; - virtual bool GetCameraFirmwareVersion( uint64_t *pFirmwareVersion ) = 0; + virtual bool GetCameraProjection( vr::EVRTrackedCameraFrameType eFrameType, float flZNear, float flZFar, vr::HmdMatrix44_t *pProjection ) = 0; virtual bool SetFrameRate( int nISPFrameRate, int nSensorFrameRate ) = 0; virtual bool SetCameraVideoSinkCallback( vr::ICameraVideoSinkCallback *pCameraVideoSinkCallback ) = 0; virtual bool GetCameraCompatibilityMode( vr::ECameraCompatibilityMode *pCameraCompatibilityMode ) = 0; @@ -1591,7 +1727,7 @@ namespace vr virtual bool GetCameraIntrinsics( vr::EVRTrackedCameraFrameType eFrameType, HmdVector2_t *pFocalLength, HmdVector2_t *pCenter ) = 0; }; - static const char *IVRCameraComponent_Version = "IVRCameraComponent_001"; + static const char *IVRCameraComponent_Version = "IVRCameraComponent_002"; } // itrackeddevicedriverprovider.h namespace vr @@ -1663,6 +1799,10 @@ public: /** Returns true if SteamVR is exiting */ virtual bool IsExiting() = 0; + + /** Returns true and fills the event with the next event on the queue if there is one. If there are no events + * this method returns false. uncbVREvent should be the size in bytes of the VREvent_t struct */ + virtual bool PollNextEvent( VREvent_t *pEvent, uint32_t uncbVREvent ) = 0; }; @@ -1753,10 +1893,21 @@ public: virtual uint32_t GetStringTrackedDeviceProperty( vr::TrackedDeviceIndex_t unDeviceIndex, ETrackedDeviceProperty prop, char *pchValue, uint32_t unBufferSize, ETrackedPropertyError *pError = 0L ) = 0; /** always returns a pointer to a valid interface pointer of IVRSettings */ - virtual IVRSettings *GetSettings( const char *pchInterfaceVersion ) = 0; + virtual void *GetGenericInterface( const char *pchInterfaceVersion ) = 0; + + /** Client drivers in watchdog mode should call this when they have received a signal from hardware that should + * cause SteamVR to start */ + virtual void WatchdogWakeUp() = 0; }; +/** Defines the mode that the client driver should start in. */ +enum EClientDriverMode +{ + ClientDriverMode_Normal = 0, + ClientDriverMode_Watchdog = 1, // client should return VRInitError_Init_LowPowerWatchdogNotSupported if it can't support this mode +}; + /** This interface must be implemented in each driver. It will be loaded in vrclient.dll */ class IClientTrackedDeviceProvider @@ -1772,7 +1923,7 @@ public: * config files. * pchDriverInstallDir - The absolute path of the root directory for the driver. */ - virtual EVRInitError Init( IDriverLog *pDriverLog, vr::IClientDriverHost *pDriverHost, const char *pchUserDriverConfigDir, const char *pchDriverInstallDir ) = 0; + virtual EVRInitError Init( EClientDriverMode eDriverMode, IDriverLog *pDriverLog, vr::IClientDriverHost *pDriverHost, const char *pchUserDriverConfigDir, const char *pchDriverInstallDir ) = 0; /** cleans up the driver right before it is unloaded */ virtual void Cleanup() = 0; @@ -1793,14 +1944,14 @@ public: * This will improve perf by letting the GPU early-reject pixels the user will never see before running the pixel shader. * NOTE: Render this mesh with backface culling disabled since the winding order of the vertices can be different per-HMD or per-eye. */ - virtual HiddenAreaMesh_t GetHiddenAreaMesh( EVREye eEye ) = 0; + virtual HiddenAreaMesh_t GetHiddenAreaMesh( EVREye eEye, EHiddenAreaMeshType type ) = 0; /** Get the MC image for the current HMD. * Returns the size in bytes of the buffer required to hold the specified resource. */ virtual uint32_t GetMCImage( uint32_t *pImgWidth, uint32_t *pImgHeight, uint32_t *pChannels, void *pDataBuffer, uint32_t unBufferLen ) = 0; }; -static const char *IClientTrackedDeviceProvider_Version = "IClientTrackedDeviceProvider_003"; +static const char *IClientTrackedDeviceProvider_Version = "IClientTrackedDeviceProvider_005"; } diff --git a/examples/ThirdPartyLibs/openvr/lib/linux32/libopenvr_api.so b/examples/ThirdPartyLibs/openvr/lib/linux32/libopenvr_api.so deleted file mode 100644 index 27da01cbe..000000000 Binary files a/examples/ThirdPartyLibs/openvr/lib/linux32/libopenvr_api.so and /dev/null differ diff --git a/examples/ThirdPartyLibs/openvr/lib/linux64/libopenvr_api.so b/examples/ThirdPartyLibs/openvr/lib/linux64/libopenvr_api.so index 52fd2271b..d3b8cc764 100644 Binary files a/examples/ThirdPartyLibs/openvr/lib/linux64/libopenvr_api.so and b/examples/ThirdPartyLibs/openvr/lib/linux64/libopenvr_api.so differ diff --git a/examples/ThirdPartyLibs/openvr/lib/win32/openvr_api.lib b/examples/ThirdPartyLibs/openvr/lib/win32/openvr_api.lib index 45a41aeb0..ca1946aaa 100644 Binary files a/examples/ThirdPartyLibs/openvr/lib/win32/openvr_api.lib and b/examples/ThirdPartyLibs/openvr/lib/win32/openvr_api.lib differ diff --git a/examples/ThirdPartyLibs/openvr/lib/win64/openvr_api.lib b/examples/ThirdPartyLibs/openvr/lib/win64/openvr_api.lib index 12344317a..89e078486 100644 Binary files a/examples/ThirdPartyLibs/openvr/lib/win64/openvr_api.lib and b/examples/ThirdPartyLibs/openvr/lib/win64/openvr_api.lib differ diff --git a/examples/TinyRenderer/TinyRenderer.cpp b/examples/TinyRenderer/TinyRenderer.cpp index 0a5b7c861..3b55d188b 100644 --- a/examples/TinyRenderer/TinyRenderer.cpp +++ b/examples/TinyRenderer/TinyRenderer.cpp @@ -13,81 +13,195 @@ #include "LinearMath/btAlignedObjectArray.h" #include "LinearMath/btVector3.h" - +struct DepthShader : public IShader { + + Model* m_model; + Matrix& m_modelMat; + Matrix m_invModelMat; + + Matrix& m_projectionMat; + Vec3f m_localScaling; + Matrix& m_lightModelView; + float m_lightDistance; + + mat<2,3,float> varying_uv; // triangle uv coordinates, written by the vertex shader, read by the fragment shader + mat<4,3,float> varying_tri; // triangle coordinates (clip coordinates), written by VS, read by FS + + mat<3,3,float> varying_nrm; // normal per vertex to be interpolated by FS + + DepthShader(Model* model, Matrix& lightModelView, Matrix& projectionMat, Matrix& modelMat, Vec3f localScaling, float lightDistance) + :m_model(model), + m_lightModelView(lightModelView), + m_projectionMat(projectionMat), + m_modelMat(modelMat), + m_localScaling(localScaling), + m_lightDistance(lightDistance) + { + m_invModelMat = m_modelMat.invert_transpose(); + } + virtual Vec4f vertex(int iface, int nthvert) { + Vec2f uv = m_model->uv(iface, nthvert); + varying_uv.set_col(nthvert, uv); + varying_nrm.set_col(nthvert, proj<3>(m_invModelMat*embed<4>(m_model->normal(iface, nthvert), 0.f))); + Vec3f unScaledVert = m_model->vert(iface, nthvert); + Vec3f scaledVert=Vec3f(unScaledVert[0]*m_localScaling[0], + unScaledVert[1]*m_localScaling[1], + unScaledVert[2]*m_localScaling[2]); + Vec4f gl_Vertex = m_projectionMat*m_lightModelView*embed<4>(scaledVert); + varying_tri.set_col(nthvert, gl_Vertex); + return gl_Vertex; + } + + virtual bool fragment(Vec3f bar, TGAColor &color) { + Vec4f p = varying_tri*bar; + color = TGAColor(255, 255, 255)*(p[2]/m_lightDistance); + return false; + } +}; struct Shader : public IShader { Model* m_model; Vec3f m_light_dir_local; + Vec3f m_light_color; Matrix& m_modelMat; - Matrix m_invModelMat; - + Matrix m_invModelMat; Matrix& m_modelView1; - Matrix& m_projectionMatrix; + Matrix& m_projectionMat; Vec3f m_localScaling; + Matrix& m_lightModelView; Vec4f m_colorRGBA; - + Matrix& m_viewportMat; + float m_ambient_coefficient; + float m_diffuse_coefficient; + float m_specular_coefficient; + + b3AlignedObjectArray* m_shadowBuffer; + + int m_width; + int m_height; + + int m_index; + mat<2,3,float> varying_uv; // triangle uv coordinates, written by the vertex shader, read by the fragment shader mat<4,3,float> varying_tri; // triangle coordinates (clip coordinates), written by VS, read by FS + mat<4,3,float> varying_tri_light_view; mat<3,3,float> varying_nrm; // normal per vertex to be interpolated by FS - //mat<3,3,float> ndc_tri; // triangle in normalized device coordinates - - Shader(Model* model, Vec3f light_dir_local, Matrix& modelView, Matrix& projectionMatrix, Matrix& modelMat, Vec3f localScaling, const Vec4f& colorRGBA) + + Shader(Model* model, Vec3f light_dir_local, Vec3f light_color, Matrix& modelView, Matrix& lightModelView, Matrix& projectionMat, Matrix& modelMat, Matrix& viewportMat, Vec3f localScaling, const Vec4f& colorRGBA, int width, int height, b3AlignedObjectArray* shadowBuffer, float ambient_coefficient=0.6, float diffuse_coefficient=0.35, float specular_coefficient=0.05) :m_model(model), m_light_dir_local(light_dir_local), + m_light_color(light_color), + m_ambient_coefficient(ambient_coefficient), + m_diffuse_coefficient(diffuse_coefficient), + m_specular_coefficient(specular_coefficient), m_modelView1(modelView), - m_projectionMatrix(projectionMatrix), + m_lightModelView(lightModelView), + m_projectionMat(projectionMat), m_modelMat(modelMat), - m_localScaling(localScaling), - m_colorRGBA(colorRGBA) + m_viewportMat(viewportMat), + m_localScaling(localScaling), + m_colorRGBA(colorRGBA), + m_width(width), + m_height(height), + m_shadowBuffer(shadowBuffer) { m_invModelMat = m_modelMat.invert_transpose(); } - virtual Vec4f vertex(int iface, int nthvert) { Vec2f uv = m_model->uv(iface, nthvert); varying_uv.set_col(nthvert, uv); - //varying_nrm.set_col(nthvert, proj<3>((m_projectionMatrix*m_modelView).invert_transpose()*embed<4>(m_model->normal(iface, nthvert), 0.f))); varying_nrm.set_col(nthvert, proj<3>(m_invModelMat*embed<4>(m_model->normal(iface, nthvert), 0.f))); - //m_localNormal = m_model->normal(iface, nthvert); - //varying_nrm.set_col(nthvert, m_model->normal(iface, nthvert)); Vec3f unScaledVert = m_model->vert(iface, nthvert); - Vec3f scaledVert=Vec3f(unScaledVert[0]*m_localScaling[0], unScaledVert[1]*m_localScaling[1], unScaledVert[2]*m_localScaling[2]); - - Vec4f gl_Vertex = m_projectionMatrix*m_modelView1*embed<4>(scaledVert); + Vec4f gl_Vertex = m_projectionMat*m_modelView1*embed<4>(scaledVert); varying_tri.set_col(nthvert, gl_Vertex); + Vec4f gl_VertexLightView = m_projectionMat*m_lightModelView*embed<4>(scaledVert); + varying_tri_light_view.set_col(nthvert, gl_VertexLightView); return gl_Vertex; } - + virtual bool fragment(Vec3f bar, TGAColor &color) { + Vec4f p = m_viewportMat*(varying_tri_light_view*bar); + float depth = p[2]; + p = p/p[3]; + + int index_x = b3Max(0, b3Min(m_width-1, int(p[0]))); + int index_y = b3Max(0, b3Min(m_height-1, int(p[1]))); + int idx = index_x + index_y*m_width; // index in the shadowbuffer array + float shadow = 0.8+0.2*(m_shadowBuffer->at(idx)<-depth+0.05); // magic coeff to avoid z-fighting + Vec3f bn = (varying_nrm*bar).normalize(); Vec2f uv = varying_uv*bar; - + Vec3f reflection_direction = (bn * (bn * m_light_dir_local * 2.f) - m_light_dir_local).normalize(); float specular = pow(b3Max(reflection_direction.z, 0.f), m_model->specular(uv)); float diffuse = b3Max(0.f, bn * m_light_dir_local); - - float ambient_coefficient = 0.6; - float diffuse_coefficient = 0.35; - float specular_coefficient = 0.05; - - float intensity = ambient_coefficient + b3Min(diffuse * diffuse_coefficient + specular * specular_coefficient, 1.0f - ambient_coefficient); - - color = m_model->diffuse(uv) * intensity; - - //warning: bgra color is swapped to rgba to upload texture - color.bgra[0] *= m_colorRGBA[0]; - color.bgra[1] *= m_colorRGBA[1]; - color.bgra[2] *= m_colorRGBA[2]; - color.bgra[3] *= m_colorRGBA[3]; - + + color = m_model->diffuse(uv); + color[0] *= m_colorRGBA[0]; + color[1] *= m_colorRGBA[1]; + color[2] *= m_colorRGBA[2]; + color[3] *= m_colorRGBA[3]; + + for (int i = 0; i < 3; ++i) + { + color[i] = b3Min(int(m_ambient_coefficient*color[i] + shadow*(m_diffuse_coefficient*diffuse+m_specular_coefficient*specular)*color[i]*m_light_color[i]), 255); + } + return false; + } }; +TinyRenderObjectData::TinyRenderObjectData(TGAImage& rgbColorBuffer,b3AlignedObjectArray&depthBuffer,b3AlignedObjectArray* shadowBuffer) +:m_rgbColorBuffer(rgbColorBuffer), +m_depthBuffer(depthBuffer), +m_shadowBuffer(shadowBuffer), +m_segmentationMaskBufferPtr(0), +m_model(0), +m_userData(0), +m_userIndex(-1), +m_objectIndex(-1) +{ + Vec3f eye(1,1,3); + Vec3f center(0,0,0); + Vec3f up(0,0,1); + m_lightDirWorld.setValue(0,0,0); + m_lightColor.setValue(1, 1, 1); + m_localScaling.setValue(1,1,1); + m_modelMatrix = Matrix::identity(); + m_lightAmbientCoeff = 0.6; + m_lightDiffuseCoeff = 0.35; + m_lightSpecularCoeff = 0.05; + +} + +TinyRenderObjectData::TinyRenderObjectData(TGAImage& rgbColorBuffer,b3AlignedObjectArray&depthBuffer, b3AlignedObjectArray* shadowBuffer, b3AlignedObjectArray* segmentationMaskBuffer, int objectIndex) +:m_rgbColorBuffer(rgbColorBuffer), +m_depthBuffer(depthBuffer), +m_shadowBuffer(shadowBuffer), +m_segmentationMaskBufferPtr(segmentationMaskBuffer), +m_model(0), +m_userData(0), +m_userIndex(-1), +m_objectIndex(objectIndex) +{ + Vec3f eye(1,1,3); + Vec3f center(0,0,0); + Vec3f up(0,0,1); + m_lightDirWorld.setValue(0,0,0); + m_lightColor.setValue(1, 1, 1); + m_localScaling.setValue(1,1,1); + m_modelMatrix = Matrix::identity(); + m_lightAmbientCoeff = 0.6; + m_lightDiffuseCoeff = 0.35; + m_lightSpecularCoeff = 0.05; + +} + TinyRenderObjectData::TinyRenderObjectData(TGAImage& rgbColorBuffer,b3AlignedObjectArray&depthBuffer) :m_rgbColorBuffer(rgbColorBuffer), m_depthBuffer(depthBuffer), @@ -101,13 +215,15 @@ m_objectIndex(-1) Vec3f center(0,0,0); Vec3f up(0,0,1); m_lightDirWorld.setValue(0,0,0); + m_lightColor.setValue(1, 1, 1); m_localScaling.setValue(1,1,1); m_modelMatrix = Matrix::identity(); + m_lightAmbientCoeff = 0.6; + m_lightDiffuseCoeff = 0.35; + m_lightSpecularCoeff = 0.05; } - - TinyRenderObjectData::TinyRenderObjectData(TGAImage& rgbColorBuffer,b3AlignedObjectArray&depthBuffer, b3AlignedObjectArray* segmentationMaskBuffer, int objectIndex) :m_rgbColorBuffer(rgbColorBuffer), m_depthBuffer(depthBuffer), @@ -121,8 +237,12 @@ m_objectIndex(objectIndex) Vec3f center(0,0,0); Vec3f up(0,0,1); m_lightDirWorld.setValue(0,0,0); + m_lightColor.setValue(1, 1, 1); m_localScaling.setValue(1,1,1); m_modelMatrix = Matrix::identity(); + m_lightAmbientCoeff = 0.6; + m_lightDiffuseCoeff = 0.35; + m_lightSpecularCoeff = 0.05; } @@ -254,42 +374,80 @@ TinyRenderObjectData::~TinyRenderObjectData() delete m_model; } -void TinyRenderer::renderObject(TinyRenderObjectData& renderData) +void TinyRenderer::renderObjectDepth(TinyRenderObjectData& renderData) { - int width = renderData.m_rgbColorBuffer.get_width(); - int height = renderData.m_rgbColorBuffer.get_height(); - - Vec3f light_dir_local = Vec3f(renderData.m_lightDirWorld[0],renderData.m_lightDirWorld[1],renderData.m_lightDirWorld[2]); + int width = renderData.m_rgbColorBuffer.get_width(); + int height = renderData.m_rgbColorBuffer.get_height(); + + Vec3f light_dir_local = Vec3f(renderData.m_lightDirWorld[0],renderData.m_lightDirWorld[1],renderData.m_lightDirWorld[2]); + float light_distance = renderData.m_lightDistance; Model* model = renderData.m_model; if (0==model) return; - + renderData.m_viewportMatrix = viewport(0,0,width, height); + + float* shadowBufferPtr = (renderData.m_shadowBuffer && renderData.m_shadowBuffer->size())?&renderData.m_shadowBuffer->at(0):0; + int* segmentationMaskBufferPtr = 0; + + TGAImage depthFrame(width, height, TGAImage::RGB); + + { + // light target is set to be the origin, and the up direction is set to be vertical up. + Matrix lightViewMatrix = lookat(light_dir_local*light_distance, Vec3f(0.0,0.0,0.0), Vec3f(0.0,0.0,1.0)); + Matrix lightModelViewMatrix = lightViewMatrix*renderData.m_modelMatrix; + Matrix lightViewProjectionMatrix = renderData.m_projectionMatrix; + Vec3f localScaling(renderData.m_localScaling[0],renderData.m_localScaling[1],renderData.m_localScaling[2]); + + DepthShader shader(model, lightModelViewMatrix, lightViewProjectionMatrix,renderData.m_modelMatrix, localScaling, light_distance); + + for (int i=0; infaces(); i++) + { + for (int j=0; j<3; j++) { + shader.vertex(i, j); + } + triangle(shader.varying_tri, shader, depthFrame, shadowBufferPtr, segmentationMaskBufferPtr, renderData.m_viewportMatrix, renderData.m_objectIndex); + } + } + +} - renderData.m_viewportMatrix = viewport(0,0,width, height); - +void TinyRenderer::renderObject(TinyRenderObjectData& renderData) +{ + int width = renderData.m_rgbColorBuffer.get_width(); + int height = renderData.m_rgbColorBuffer.get_height(); + + Vec3f light_dir_local = Vec3f(renderData.m_lightDirWorld[0],renderData.m_lightDirWorld[1],renderData.m_lightDirWorld[2]); + Vec3f light_color = Vec3f(renderData.m_lightColor[0],renderData.m_lightColor[1],renderData.m_lightColor[2]); + float light_distance = renderData.m_lightDistance; + Model* model = renderData.m_model; + if (0==model) + return; + + renderData.m_viewportMatrix = viewport(0,0,width, height); + b3AlignedObjectArray& zbuffer = renderData.m_depthBuffer; + b3AlignedObjectArray* shadowBufferPtr = renderData.m_shadowBuffer; int* segmentationMaskBufferPtr = (renderData.m_segmentationMaskBufferPtr && renderData.m_segmentationMaskBufferPtr->size())?&renderData.m_segmentationMaskBufferPtr->at(0):0; TGAImage& frame = renderData.m_rgbColorBuffer; - - - + { + // light target is set to be the origin, and the up direction is set to be vertical up. + Matrix lightViewMatrix = lookat(light_dir_local*light_distance, Vec3f(0.0,0.0,0.0), Vec3f(0.0,0.0,1.0)); + Matrix lightModelViewMatrix = lightViewMatrix*renderData.m_modelMatrix; Matrix modelViewMatrix = renderData.m_viewMatrix*renderData.m_modelMatrix; Vec3f localScaling(renderData.m_localScaling[0],renderData.m_localScaling[1],renderData.m_localScaling[2]); - Shader shader(model, light_dir_local, modelViewMatrix, renderData.m_projectionMatrix,renderData.m_modelMatrix, localScaling, model->getColorRGBA()); - - //printf("Render %d triangles.\n",model->nfaces()); - for (int i=0; infaces(); i++) - { - + + Shader shader(model, light_dir_local, light_color, modelViewMatrix, lightModelViewMatrix, renderData.m_projectionMatrix,renderData.m_modelMatrix, renderData.m_viewportMatrix, localScaling, model->getColorRGBA(), width, height, shadowBufferPtr, renderData.m_lightAmbientCoeff, renderData.m_lightDiffuseCoeff, renderData.m_lightSpecularCoeff); + + for (int i=0; infaces(); i++) + { for (int j=0; j<3; j++) { shader.vertex(i, j); } triangle(shader.varying_tri, shader, frame, &zbuffer[0], segmentationMaskBufferPtr, renderData.m_viewportMatrix, renderData.m_objectIndex); } - } - + } diff --git a/examples/TinyRenderer/TinyRenderer.h b/examples/TinyRenderer/TinyRenderer.h index 1819790a6..c4df3c3e7 100644 --- a/examples/TinyRenderer/TinyRenderer.h +++ b/examples/TinyRenderer/TinyRenderer.h @@ -18,6 +18,11 @@ struct TinyRenderObjectData Matrix m_viewportMatrix; btVector3 m_localScaling; btVector3 m_lightDirWorld; + btVector3 m_lightColor; + float m_lightDistance; + float m_lightAmbientCoeff; + float m_lightDiffuseCoeff; + float m_lightSpecularCoeff; //Model (vertices, indices, textures, shader) Matrix m_modelMatrix; @@ -28,10 +33,13 @@ struct TinyRenderObjectData TGAImage& m_rgbColorBuffer; b3AlignedObjectArray& m_depthBuffer;//required, hence a reference + b3AlignedObjectArray* m_shadowBuffer;//optional, hence a pointer b3AlignedObjectArray* m_segmentationMaskBufferPtr;//optional, hence a pointer - + TinyRenderObjectData(TGAImage& rgbColorBuffer,b3AlignedObjectArray&depthBuffer); - TinyRenderObjectData(TGAImage& rgbColorBuffer,b3AlignedObjectArray&depthBuffer, b3AlignedObjectArray* segmentationMaskBuffer,int objectIndex); + TinyRenderObjectData(TGAImage& rgbColorBuffer,b3AlignedObjectArray&depthBuffer,b3AlignedObjectArray* segmentationMaskBuffer,int objectIndex); + TinyRenderObjectData(TGAImage& rgbColorBuffer,b3AlignedObjectArray&depthBuffer,b3AlignedObjectArray* shadowBuffer); + TinyRenderObjectData(TGAImage& rgbColorBuffer,b3AlignedObjectArray&depthBuffer,b3AlignedObjectArray* shadowBuffer, b3AlignedObjectArray* segmentationMaskBuffer,int objectIndex); virtual ~TinyRenderObjectData(); void loadModel(const char* fileName); @@ -50,6 +58,7 @@ struct TinyRenderObjectData class TinyRenderer { public: + static void renderObjectDepth(TinyRenderObjectData& renderData); static void renderObject(TinyRenderObjectData& renderData); }; diff --git a/examples/TinyRenderer/our_gl.cpp b/examples/TinyRenderer/our_gl.cpp index eb5a05a78..04863503b 100644 --- a/examples/TinyRenderer/our_gl.cpp +++ b/examples/TinyRenderer/our_gl.cpp @@ -4,9 +4,6 @@ #include "our_gl.h" #include "Bullet3Common/b3MinMax.h" - - - IShader::~IShader() {} Matrix viewport(int x, int y, int w, int h) @@ -15,10 +12,10 @@ Matrix viewport(int x, int y, int w, int h) Viewport = Matrix::identity(); Viewport[0][3] = x+w/2.f; Viewport[1][3] = y+h/2.f; - Viewport[2][3] = 1.f; + Viewport[2][3] = .5f; Viewport[0][0] = w/2.f; Viewport[1][1] = h/2.f; - Viewport[2][2] = 0; + Viewport[2][2] = .5f; return Viewport; } @@ -30,19 +27,33 @@ Matrix projection(float coeff) { } Matrix lookat(Vec3f eye, Vec3f center, Vec3f up) { - Vec3f z = (eye-center).normalize(); - Vec3f x = cross(up,z).normalize(); - Vec3f y = cross(z,x).normalize(); - Matrix Minv = Matrix::identity(); - Matrix Tr = Matrix::identity(); - for (int i=0; i<3; i++) { - Minv[0][i] = x[i]; - Minv[1][i] = y[i]; - Minv[2][i] = z[i]; - Tr[i][3] = -center[i]; - } + Vec3f f = (center - eye).normalize(); + Vec3f u = up.normalize(); + Vec3f s = cross(f,u).normalize(); + u = cross(s,f); + Matrix ModelView; - ModelView = Minv*Tr; + ModelView[0][0] = s.x; + ModelView[0][1] = s.y; + ModelView[0][2] = s.z; + + ModelView[1][0] = u.x; + ModelView[1][1] = u.y; + ModelView[1][2] = u.z; + + ModelView[2][0] =-f.x; + ModelView[2][1] =-f.y; + ModelView[2][2] =-f.z; + + ModelView[3][0] = 0.f; + ModelView[3][1] = 0.f; + ModelView[3][2] = 0.f; + + ModelView[0][3] = -(s[0]*eye[0]+s[1]*eye[1]+s[2]*eye[2]); + ModelView[1][3] = -(u[0]*eye[0]+u[1]*eye[1]+u[2]*eye[2]); + ModelView[2][3] = f[0]*eye[0]+f[1]*eye[1]+f[2]*eye[2]; + ModelView[3][3] = 1.f; + return ModelView; } @@ -66,13 +77,11 @@ void triangle(mat<4,3,float> &clipc, IShader &shader, TGAImage &image, float *zb void triangle(mat<4,3,float> &clipc, IShader &shader, TGAImage &image, float *zbuffer, int* segmentationMaskBuffer, const Matrix& viewPortMatrix, int objectIndex) { mat<3,4,float> pts = (viewPortMatrix*clipc).transpose(); // transposed to ease access to each of the points - - + //we don't clip triangles that cross the near plane, just discard them instead of showing artifacts if (pts[0][3]<0 || pts[1][3] <0 || pts[2][3] <0) return; - mat<3,2,float> pts2; for (int i=0; i<3; i++) pts2[i] = proj<2>(pts[i]/pts[i][3]); @@ -87,19 +96,15 @@ void triangle(mat<4,3,float> &clipc, IShader &shader, TGAImage &image, float *zb } } - - Vec2i P; TGAColor color; for (P.x=bboxmin.x; P.x<=bboxmax.x; P.x++) { for (P.y=bboxmin.y; P.y<=bboxmax.y; P.y++) { Vec3f bc_screen = barycentric(pts2[0], pts2[1], pts2[2], P); - - Vec3f bc_clip = Vec3f(bc_screen.x/pts[0][3], bc_screen.y/pts[1][3], bc_screen.z/pts[2][3]); bc_clip = bc_clip/(bc_clip.x+bc_clip.y+bc_clip.z); float frag_depth = -1*(clipc[2]*bc_clip); - if (bc_screen.x<0 || bc_screen.y<0 || bc_screen.z<0 || + if (bc_screen.x<0 || bc_screen.y<0 || bc_screen.z<0 || zbuffer[P.x+P.y*image.get_width()]>frag_depth) continue; bool discard = shader.fragment(bc_clip, color); diff --git a/examples/pybullet/CMakeLists.txt b/examples/pybullet/CMakeLists.txt index dbac56750..85de30a69 100644 --- a/examples/pybullet/CMakeLists.txt +++ b/examples/pybullet/CMakeLists.txt @@ -3,6 +3,7 @@ INCLUDE_DIRECTORIES( ${BULLET_PHYSICS_SOURCE_DIR}/src ${BULLET_PHYSICS_SOURCE_DIR}/examples ${BULLET_PHYSICS_SOURCE_DIR}/examples/ThirdPartyLibs + ${BULLET_PHYSICS_SOURCE_DIR}/examples/ThirdPartyLibs/enet/include ${PYTHON_INCLUDE_DIRS} ) IF(BUILD_PYBULLET_NUMPY) @@ -16,7 +17,7 @@ SET(pybullet_SRCS ../../examples/SharedMemory/IKTrajectoryHelper.cpp ../../examples/SharedMemory/IKTrajectoryHelper.h ../../examples/ExampleBrowser/InProcessExampleBrowser.cpp - ../../examples/SharedMemory/TinyRendererVisualShapeConverter.cpp + ../../examples/SharedMemory/TinyRendererVisualShapeConverter.cpp ../../examples/SharedMemory/TinyRendererVisualShapeConverter.h ../../examples/OpenGLWindow/SimpleCamera.cpp ../../examples/OpenGLWindow/SimpleCamera.h @@ -42,6 +43,9 @@ SET(pybullet_SRCS ../../examples/SharedMemory/PhysicsServerCommandProcessor.h ../../examples/SharedMemory/PhysicsClientSharedMemory.cpp ../../examples/SharedMemory/PhysicsClientSharedMemory.h + ../../examples/SharedMemory/PhysicsClientSharedMemory_C_API.cpp + ../../examples/SharedMemory/PhysicsClientSharedMemory_C_API.h + ../../examples/SharedMemory/PhysicsClientC_API.cpp ../../examples/SharedMemory/PhysicsClientC_API.h ../../examples/SharedMemory/Win32SharedMemory.cpp @@ -69,19 +73,61 @@ SET(pybullet_SRCS ../../examples/MultiThreading/b3PosixThreadSupport.cpp ../../examples/MultiThreading/b3Win32ThreadSupport.cpp ../../examples/MultiThreading/b3ThreadSupportInterface.cpp + ) IF(WIN32) -LINK_LIBRARIES( + LINK_LIBRARIES( ${OPENGL_gl_LIBRARY} ${OPENGL_glu_LIBRARY} ) - + IF(BUILD_PYBULLET_ENET) + ADD_DEFINITIONS(-DWIN32 -DBT_ENABLE_ENET) + ENDIF(BUILD_PYBULLET_ENET) +ELSE(WIN32) + IF(BUILD_PYBULLET_ENET) + ADD_DEFINITIONS(-DHAS_SOCKLEN_T -DBT_ENABLE_ENET) + ENDIF(BUILD_PYBULLET_ENET) ENDIF(WIN32) -ADD_LIBRARY(pybullet SHARED ${pybullet_SRCS}) + +IF(BUILD_PYBULLET_ENET) + ADD_LIBRARY(pybullet SHARED ${pybullet_SRCS} + ../../examples/SharedMemory/PhysicsClientUDP.cpp + ../../examples/SharedMemory/PhysicsClientUDP_C_API.cpp + ../../examples/SharedMemory/PhysicsClientUDP.h + ../../examples/SharedMemory/PhysicsClientUDP_C_API.h + ../../examples/ThirdPartyLibs/enet/win32.c + ../../examples/ThirdPartyLibs/enet/unix.c + ../../examples/ThirdPartyLibs/enet/callbacks.c + ../../examples/ThirdPartyLibs/enet/compress.c + ../../examples/ThirdPartyLibs/enet/host.c + ../../examples/ThirdPartyLibs/enet/list.c + ../../examples/ThirdPartyLibs/enet/packet.c + ../../examples/ThirdPartyLibs/enet/peer.c + ../../examples/ThirdPartyLibs/enet/protocol.c + ) +ELSE(BUILD_PYBULLET_ENET) + ADD_LIBRARY(pybullet SHARED ${pybullet_SRCS}) +ENDIF(BUILD_PYBULLET_ENET) + +SET_TARGET_PROPERTIES(pybullet PROPERTIES PREFIX "") +SET_TARGET_PROPERTIES(pybullet PROPERTIES POSTFIX "") SET_TARGET_PROPERTIES(pybullet PROPERTIES VERSION ${BULLET_VERSION}) SET_TARGET_PROPERTIES(pybullet PROPERTIES SOVERSION ${BULLET_VERSION}) +SET_TARGET_PROPERTIES(pybullet PROPERTIES DEBUG_POSTFIX "_d") + + +IF(WIN32) + IF(BUILD_PYBULLET_ENET) + TARGET_LINK_LIBRARIES(pybullet ws2_32 ) + ENDIF(BUILD_PYBULLET_ENET) + + SET_TARGET_PROPERTIES(pybullet PROPERTIES SUFFIX ".pyd" ) +ENDIF(WIN32) + + + TARGET_LINK_LIBRARIES(pybullet BulletExampleBrowserLib BulletFileLoader BulletWorldImporter BulletSoftBody BulletDynamics BulletCollision BulletInverseDynamicsUtils BulletInverseDynamics LinearMath OpenGLWindow gwen BussIK Bullet3Common ${PYTHON_LIBRARIES}) diff --git a/examples/pybullet/premake4.lua b/examples/pybullet/premake4.lua index 6f684a331..86ed39611 100644 --- a/examples/pybullet/premake4.lua +++ b/examples/pybullet/premake4.lua @@ -33,12 +33,37 @@ project ("pybullet") } end +if not _OPTIONS["no-enet"] then + + includedirs {"../../examples/ThirdPartyLibs/enet/include"} + + if os.is("Windows") then + defines { "WIN32" } + links {"Ws2_32","Winmm"} + end + if os.is("Linux") then + end + if os.is("MacOSX") then + end + + links {"enet"} + + files { + "../../examples/SharedMemory/PhysicsClientUDP.cpp", + "../../examples/SharedMemory/PhysicsClientUDP.h", + "../../examples/SharedMemory/PhysicsClientUDP_C_API.cpp", + "../../examples/SharedMemory/PhysicsClientUDP_C_API.h", + } + defines {"BT_ENABLE_ENET"} + end + + files { "pybullet.c", "../../examples/SharedMemory/IKTrajectoryHelper.cpp", "../../examples/SharedMemory/IKTrajectoryHelper.h", "../../examples/ExampleBrowser/InProcessExampleBrowser.cpp", - "../../examples/SharedMemory/TinyRendererVisualShapeConverter.cpp", + "../../examples/SharedMemory/TinyRendererVisualShapeConverter.cpp", "../../examples/SharedMemory/TinyRendererVisualShapeConverter.h", "../../examples/OpenGLWindow/SimpleCamera.cpp", "../../examples/OpenGLWindow/SimpleCamera.h", @@ -64,6 +89,8 @@ project ("pybullet") "../../examples/SharedMemory/PhysicsServerCommandProcessor.h", "../../examples/SharedMemory/PhysicsClientSharedMemory.cpp", "../../examples/SharedMemory/PhysicsClientSharedMemory.h", + "../../examples/SharedMemory/PhysicsClientSharedMemory_C_API.cpp", + "../../examples/SharedMemory/PhysicsClientSharedMemory_C_API.h", "../../examples/SharedMemory/PhysicsClientC_API.cpp", "../../examples/SharedMemory/PhysicsClientC_API.h", "../../examples/SharedMemory/Win32SharedMemory.cpp", diff --git a/examples/pybullet/pybullet.c b/examples/pybullet/pybullet.c index 93499e82d..d130712d5 100644 --- a/examples/pybullet/pybullet.c +++ b/examples/pybullet/pybullet.c @@ -1,7 +1,9 @@ #include "../SharedMemory/PhysicsClientC_API.h" #include "../SharedMemory/PhysicsDirectC_API.h" #include "../SharedMemory/SharedMemoryInProcessPhysicsC_API.h" - +#ifdef BT_ENABLE_ENET +#include "../SharedMemory/PhysicsClientUDP_C_API.h" +#endif //BT_ENABLE_ENET #ifdef __APPLE__ #include @@ -22,11 +24,129 @@ enum eCONNECT_METHOD { eCONNECT_GUI = 1, eCONNECT_DIRECT = 2, eCONNECT_SHARED_MEMORY = 3, + eCONNECT_UDP = 4, }; static PyObject* SpamError; static b3PhysicsClientHandle sm = 0; + +static double pybullet_internalGetFloatFromSequence(PyObject* seq, int index) { + double v = 0.0; + PyObject* item; + + if (PyList_Check(seq)) { + item = PyList_GET_ITEM(seq, index); + v = PyFloat_AsDouble(item); + } + else { + item = PyTuple_GET_ITEM(seq, index); + v = PyFloat_AsDouble(item); + } + return v; +} + + +// internal function to set a float matrix[16] +// used to initialize camera position with +// a view and projection matrix in renderImage() +// +// // Args: +// matrix - float[16] which will be set by values from objMat +static int pybullet_internalSetMatrix(PyObject* objMat, float matrix[16]) { + int i, len; + PyObject* seq; + + seq = PySequence_Fast(objMat, "expected a sequence"); + if (seq) + { + len = PySequence_Size(objMat); + if (len == 16) { + for (i = 0; i < len; i++) { + matrix[i] = pybullet_internalGetFloatFromSequence(seq, i); + } + Py_DECREF(seq); + return 1; + } + Py_DECREF(seq); + } + return 0; +} + +// internal function to set a float vector[3] +// used to initialize camera position with +// a view and projection matrix in renderImage() +// +// // Args: +// vector - float[3] which will be set by values from objMat +static int pybullet_internalSetVector(PyObject* objVec, float vector[3]) { + int i, len; + PyObject* seq = 0; + if (objVec == NULL) + return 0; + + seq = PySequence_Fast(objVec, "expected a sequence"); + if (seq) + { + + len = PySequence_Size(objVec); + if (len == 3) { + for (i = 0; i < len; i++) { + vector[i] = pybullet_internalGetFloatFromSequence(seq, i); + } + Py_DECREF(seq); + return 1; + } + Py_DECREF(seq); + } + return 0; +} + +// vector - double[3] which will be set by values from obVec +static int pybullet_internalSetVectord(PyObject* obVec, double vector[3]) { + int i, len; + PyObject* seq; + if (obVec == NULL) + return 0; + + seq = PySequence_Fast(obVec, "expected a sequence"); + if (seq) + { + len = PySequence_Size(obVec); + if (len == 3) { + for (i = 0; i < len; i++) { + vector[i] = pybullet_internalGetFloatFromSequence(seq, i); + } + Py_DECREF(seq); + return 1; + } + Py_DECREF(seq); + } + return 0; +} + +// vector - double[3] which will be set by values from obVec +static int pybullet_internalSetVector4d(PyObject* obVec, double vector[4]) { + int i, len; + PyObject* seq; + if (obVec == NULL) + return 0; + + seq = PySequence_Fast(obVec, "expected a sequence"); + len = PySequence_Size(obVec); + if (len == 4) { + for (i = 0; i < len; i++) { + vector[i] = pybullet_internalGetFloatFromSequence(seq, i); + } + Py_DECREF(seq); + return 1; + } + Py_DECREF(seq); + return 0; +} + + + // Step through one timestep of the simulation static PyObject* pybullet_stepSimulation(PyObject* self, PyObject* args) { if (0 == sm) { @@ -58,12 +178,45 @@ static PyObject* pybullet_connectPhysicsServer(PyObject* self, PyObject* args) { { int method = eCONNECT_GUI; - if (!PyArg_ParseTuple(args, "i", &method)) { - PyErr_SetString(SpamError, - "connectPhysicsServer expected argument eCONNECT_GUI, " - "eCONNECT_DIRECT or eCONNECT_SHARED_MEMORY"); - return NULL; - } + int key = SHARED_MEMORY_KEY; + int port = 1234; + const char* hostName = "localhost"; + + int size = PySequence_Size(args); + if (size == 1) + { + if (!PyArg_ParseTuple(args, "i", &method)) { + PyErr_SetString(SpamError, + "connectPhysicsServer expected argument GUI, " + "DIRECT, SHARED_MEMORY or UDP"); + return NULL; + } + } + + if (size == 2) + { + if (!PyArg_ParseTuple(args, "ii", &method, &key)) + { + if (!PyArg_ParseTuple(args, "is", &method, &hostName)) + { + PyErr_SetString(SpamError, + "connectPhysicsServer cannot parse second argument (either integer or string)"); + return NULL; + + } + } + } + + if (size == 3) + { + if (!PyArg_ParseTuple(args, "isi", &method, &hostName, &port)) + { + PyErr_SetString(SpamError, + "connectPhysicsServer 3 arguments: method, hostname, port"); + return NULL; + } + } + switch (method) { case eCONNECT_GUI: { @@ -82,9 +235,21 @@ static PyObject* pybullet_connectPhysicsServer(PyObject* self, PyObject* args) { break; } case eCONNECT_SHARED_MEMORY: { - sm = b3ConnectSharedMemory(SHARED_MEMORY_KEY); + sm = b3ConnectSharedMemory(key); break; } + case eCONNECT_UDP: + { +#ifdef BT_ENABLE_ENET + + sm = b3ConnectPhysicsUDP(hostName, port); +#else + PyErr_SetString(SpamError, "UDP is not enabled in this pybullet build"); + return NULL; +#endif //BT_ENABLE_ENET + + break; + } default: { PyErr_SetString(SpamError, "connectPhysicsServer unexpected argument"); @@ -149,18 +314,187 @@ static PyObject* pybullet_saveWorld(PyObject* self, PyObject* args) { PyErr_SetString(SpamError, "Cannot execute saveWorld command."); return NULL; +} + +#define MAX_SDF_BODIES 512 +static PyObject* pybullet_loadBullet(PyObject* self, PyObject* args) +{ + int size = PySequence_Size(args); + const char* bulletFileName = ""; + b3SharedMemoryStatusHandle statusHandle; + int statusType; + b3SharedMemoryCommandHandle command; + int i,numBodies; + int bodyIndicesOut[MAX_SDF_BODIES]; + PyObject* pylist = 0; + if (0 == sm) { + PyErr_SetString(SpamError, "Not connected to physics server."); + return NULL; +} + if (size == 1) { + if (!PyArg_ParseTuple(args, "s", &bulletFileName)) return NULL; + } + + command = b3LoadBulletCommandInit(sm, bulletFileName); + statusHandle = b3SubmitClientCommandAndWaitStatus(sm, command); + statusType = b3GetStatusType(statusHandle); + if (statusType != CMD_BULLET_LOADING_COMPLETED) + { + PyErr_SetString(SpamError, "Couldn't load .bullet file."); + return NULL; + } + + numBodies = + b3GetStatusBodyIndices(statusHandle, bodyIndicesOut, MAX_SDF_BODIES); + if (numBodies > MAX_SDF_BODIES) { + PyErr_SetString(SpamError, "loadBullet exceeds body capacity"); return NULL; + } + + pylist = PyTuple_New(numBodies); + + if (numBodies > 0 && numBodies <= MAX_SDF_BODIES) { + for (i = 0; i < numBodies; i++) { + PyTuple_SetItem(pylist, i, PyInt_FromLong(bodyIndicesOut[i])); + } + } + return pylist; + + +} + +static PyObject* pybullet_saveBullet(PyObject* self, PyObject* args) +{ + int size = PySequence_Size(args); + const char* bulletFileName = ""; + b3SharedMemoryStatusHandle statusHandle; + int statusType; + b3SharedMemoryCommandHandle command; + + if (0 == sm) { + PyErr_SetString(SpamError, "Not connected to physics server."); + return NULL; + } + if (size == 1) { + if (!PyArg_ParseTuple(args, "s", &bulletFileName)) return NULL; + } + command = b3SaveBulletCommandInit(sm, bulletFileName); + statusHandle = b3SubmitClientCommandAndWaitStatus(sm, command); + statusType = b3GetStatusType(statusHandle); + if (statusType != CMD_BULLET_SAVING_COMPLETED) + { + PyErr_SetString(SpamError, "Couldn't save .bullet file."); + return NULL; + } + Py_INCREF(Py_None); + return Py_None; } -// Load a URDF file indicating the links and joints of an object +static PyObject* pybullet_loadMJCF(PyObject* self, PyObject* args) +{ + int size = PySequence_Size(args); + const char* mjcfjFileName = ""; + b3SharedMemoryStatusHandle statusHandle; + int statusType; + b3SharedMemoryCommandHandle command; + + if (0 == sm) { + PyErr_SetString(SpamError, "Not connected to physics server."); + return NULL; + } + if (size == 1) { + if (!PyArg_ParseTuple(args, "s", &mjcfjFileName)) return NULL; + } + command = b3LoadMJCFCommandInit(sm, mjcfjFileName); + statusHandle = b3SubmitClientCommandAndWaitStatus(sm, command); + statusType = b3GetStatusType(statusHandle); + if (statusType != CMD_MJCF_LOADING_COMPLETED) + { + PyErr_SetString(SpamError, "Couldn't load .mjcf file."); + return NULL; + } + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject* pybullet_setPhysicsEngineParameter(PyObject* self, PyObject* args, PyObject *keywds) +{ + double fixedTimeStep = -1; + int numSolverIterations = -1; + int useSplitImpulse = -1; + double splitImpulsePenetrationThreshold = -1; + int numSubSteps = -1; + + if (0 == sm) { + PyErr_SetString(SpamError, "Not connected to physics server."); + return NULL; + } + + static char *kwlist[] = { "fixedTimeStep", "numSolverIterations","useSplitImpulse","splitImpulsePenetrationThreshold", "numSubSteps", NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, keywds, "|diidi", kwlist,&fixedTimeStep,&numSolverIterations,&useSplitImpulse,&splitImpulsePenetrationThreshold,&numSubSteps)) + { + return NULL; + } + { + b3SharedMemoryCommandHandle command = b3InitPhysicsParamCommand(sm); + b3SharedMemoryStatusHandle statusHandle; + + if (numSolverIterations >= 0) + { + b3PhysicsParamSetNumSolverIterations(command, numSolverIterations); + } + if (numSubSteps >= 0) + { + b3PhysicsParamSetNumSubSteps(command, numSubSteps); + } + if (fixedTimeStep >= 0) + { + b3PhysicsParamSetTimeStep(command, fixedTimeStep); + } + if (useSplitImpulse >= 0) + { + b3PhysicsParamSetUseSplitImpulse(command,useSplitImpulse); + } + if (splitImpulsePenetrationThreshold >= 0) + { + b3PhysicsParamSetSplitImpulsePenetrationThreshold(command, splitImpulsePenetrationThreshold); + } + + //ret = b3PhysicsParamSetRealTimeSimulation(command, enableRealTimeSimulation); + + statusHandle = b3SubmitClientCommandAndWaitStatus(sm, command); + } +#if 0 + b3SharedMemoryCommandHandle b3InitPhysicsParamCommand(b3PhysicsClientHandle physClient); + int b3PhysicsParamSetGravity(b3SharedMemoryCommandHandle commandHandle, double gravx, double gravy, double gravz); + int b3PhysicsParamSetTimeStep(b3SharedMemoryCommandHandle commandHandle, double timeStep); + int b3PhysicsParamSetDefaultContactERP(b3SharedMemoryCommandHandle commandHandle, double defaultContactERP); + int b3PhysicsParamSetNumSubSteps(b3SharedMemoryCommandHandle commandHandle, int numSubSteps); + int b3PhysicsParamSetRealTimeSimulation(b3SharedMemoryCommandHandle commandHandle, int enableRealTimeSimulation); + int b3PhysicsParamSetNumSolverIterations(b3SharedMemoryCommandHandle commandHandle, int numSolverIterations); +#endif + + Py_INCREF(Py_None); + return Py_None; +} + + +// Load a robot from a URDF file (universal robot description format) // function can be called without arguments and will default // to position (0,0,1) with orientation(0,0,0,1) // els(x,y,z) or // loadURDF(pos_x, pos_y, pos_z, orn_x, orn_y, orn_z, orn_w) -static PyObject* pybullet_loadURDF(PyObject* self, PyObject* args) { +static PyObject* pybullet_loadURDF(PyObject* self, PyObject* args, PyObject *keywds) +{ int size = PySequence_Size(args); + static char *kwlist[] = { "fileName", "basePosition", "baseOrientation", "useMaximalCoordinates","useFixedBase", NULL }; + + static char *kwlistBackwardCompatible4[] = { "fileName", "startPosX", "startPosY", "startPosZ", NULL }; + static char *kwlistBackwardCompatible8[] = { "fileName", "startPosX", "startPosY", "startPosZ", "startOrnX", "startOrnY","startOrnZ","startOrnW", NULL }; + int bodyIndex = -1; const char* urdfFileName = ""; @@ -172,24 +506,79 @@ static PyObject* pybullet_loadURDF(PyObject* self, PyObject* args) { double startOrnY = 0.0; double startOrnZ = 0.0; double startOrnW = 1.0; + int useMaximalCoordinates = 0; + int useFixedBase = 0; + + int backwardsCompatibilityArgs = 0; if (0 == sm) { PyErr_SetString(SpamError, "Not connected to physics server."); return NULL; } - if (size == 1) { - if (!PyArg_ParseTuple(args, "s", &urdfFileName)) return NULL; + + if (PyArg_ParseTupleAndKeywords(args, keywds, "sddd", kwlistBackwardCompatible4, &urdfFileName, &startPosX, + &startPosY, &startPosZ)) + { + backwardsCompatibilityArgs = 1; } - if (size == 4) { - if (!PyArg_ParseTuple(args, "sddd", &urdfFileName, &startPosX, &startPosY, - &startPosZ)) - return NULL; + else + { + PyErr_Clear(); } - if (size == 8) { - if (!PyArg_ParseTuple(args, "sddddddd", &urdfFileName, &startPosX, - &startPosY, &startPosZ, &startOrnX, &startOrnY, - &startOrnZ, &startOrnW)) - return NULL; + + + if (PyArg_ParseTupleAndKeywords(args, keywds, "sddddddd", kwlistBackwardCompatible8,&urdfFileName, &startPosX, + &startPosY, &startPosZ, &startOrnX, &startOrnY,&startOrnZ, &startOrnW)) + { + backwardsCompatibilityArgs = 1; + } + else + { + PyErr_Clear(); + } + + + + if (!backwardsCompatibilityArgs) + { + PyObject* basePosObj = 0; + PyObject* baseOrnObj = 0; + double basePos[3]; + double baseOrn[4]; + + + if (!PyArg_ParseTupleAndKeywords(args, keywds, "s|OOii", kwlist, &urdfFileName, &basePosObj, &baseOrnObj, &useMaximalCoordinates,&useFixedBase)) + { + + return NULL; + } + else + { + if (basePosObj) + { + if (!pybullet_internalSetVectord(basePosObj, basePos)) + { + PyErr_SetString(SpamError, "Cannot convert basePosition."); + return NULL; + } + startPosX = basePos[0]; + startPosY = basePos[1]; + startPosZ = basePos[2]; + + } + if (baseOrnObj) + { + if (!pybullet_internalSetVector4d(baseOrnObj, baseOrn)) + { + PyErr_SetString(SpamError, "Cannot convert baseOrientation."); + return NULL; + } + startOrnX = baseOrn[0]; + startOrnY = baseOrn[1]; + startOrnZ = baseOrn[2]; + startOrnW = baseOrn[3]; + } + } } if (strlen(urdfFileName)) { @@ -206,6 +595,15 @@ static PyObject* pybullet_loadURDF(PyObject* self, PyObject* args) { b3LoadUrdfCommandSetStartPosition(command, startPosX, startPosY, startPosZ); b3LoadUrdfCommandSetStartOrientation(command, startOrnX, startOrnY, startOrnZ, startOrnW); + if (useMaximalCoordinates) + { + b3LoadUrdfCommandSetUseMultiBody(command, 0); + } + if (useFixedBase) + { + b3LoadUrdfCommandSetUseFixedBase(command, 1); + } + statusHandle = b3SubmitClientCommandAndWaitStatus(sm, command); statusType = b3GetStatusType(statusHandle); if (statusType != CMD_URDF_LOADING_COMPLETED) { @@ -221,21 +619,8 @@ static PyObject* pybullet_loadURDF(PyObject* self, PyObject* args) { return PyLong_FromLong(bodyIndex); } -static double pybullet_internalGetFloatFromSequence(PyObject* seq, int index) { - double v = 0.0; - PyObject* item; - if (PyList_Check(seq)) { - item = PyList_GET_ITEM(seq, index); - v = PyFloat_AsDouble(item); - } else { - item = PyTuple_GET_ITEM(seq, index); - v = PyFloat_AsDouble(item); - } - return v; -} -#define MAX_SDF_BODIES 512 static PyObject* pybullet_loadSDF(PyObject* self, PyObject* args) { const char* sdfFileName = ""; @@ -618,11 +1003,68 @@ pybullet_setDefaultContactERP(PyObject* self, PyObject* args) return Py_None; } +static int pybullet_internalGetBaseVelocity( + int bodyIndex, double baseLinearVelocity[3], double baseAngularVelocity[3]) { + baseLinearVelocity[0] = 0.; + baseLinearVelocity[1] = 0.; + baseLinearVelocity[2] = 0.; + + baseAngularVelocity[0] = 0.; + baseAngularVelocity[1] = 0.; + baseAngularVelocity[2] = 0.; + + if (0 == sm) { + PyErr_SetString(SpamError, "Not connected to physics server."); + return 0; + } + + { + { + b3SharedMemoryCommandHandle cmd_handle = + b3RequestActualStateCommandInit(sm, bodyIndex); + b3SharedMemoryStatusHandle status_handle = + b3SubmitClientCommandAndWaitStatus(sm, cmd_handle); + + const int status_type = b3GetStatusType(status_handle); + const double* actualStateQdot; + // const double* jointReactionForces[]; + + + if (status_type != CMD_ACTUAL_STATE_UPDATE_COMPLETED) { + PyErr_SetString(SpamError, "getBaseVelocity failed."); + return 0; + } + + b3GetStatusActualState( + status_handle, 0 /* body_unique_id */, + 0 /* num_degree_of_freedom_q */, 0 /* num_degree_of_freedom_u */, + 0 /*root_local_inertial_frame*/, 0, + &actualStateQdot, 0 /* joint_reaction_forces */); + + // printf("joint reaction forces="); + // for (i=0; i < (sizeof(jointReactionForces)/sizeof(double)); i++) { + // printf("%f ", jointReactionForces[i]); + // } + // now, position x,y,z = actualStateQ[0],actualStateQ[1],actualStateQ[2] + // and orientation x,y,z,w = + // actualStateQ[3],actualStateQ[4],actualStateQ[5],actualStateQ[6] + baseLinearVelocity[0] = actualStateQdot[0]; + baseLinearVelocity[1] = actualStateQdot[1]; + baseLinearVelocity[2] = actualStateQdot[2]; + + baseAngularVelocity[0] = actualStateQdot[3]; + baseAngularVelocity[1] = actualStateQdot[4]; + baseAngularVelocity[2] = actualStateQdot[5]; + + } + } + return 1; +} // Internal function used to get the base position and orientation // Orientation is returned in quaternions static int pybullet_internalGetBasePositionAndOrientation( - int bodyIndex, double basePosition[3], double baseOrientation[3]) { + int bodyIndex, double basePosition[3], double baseOrientation[4]) { basePosition[0] = 0.; basePosition[1] = 0.; basePosition[2] = 0.; @@ -632,6 +1074,11 @@ static int pybullet_internalGetBasePositionAndOrientation( baseOrientation[2] = 0.; baseOrientation[3] = 1.; + if (0 == sm) { + PyErr_SetString(SpamError, "Not connected to physics server."); + return 0; + } + { { b3SharedMemoryCommandHandle cmd_handle = @@ -700,8 +1147,7 @@ static PyObject* pybullet_getBasePositionAndOrientation(PyObject* self, if (0 == pybullet_internalGetBasePositionAndOrientation( bodyIndex, basePosition, baseOrientation)) { PyErr_SetString(SpamError, - "GetBasePositionAndOrientation failed (#joints/links " - "exceeds maximum?)."); + "GetBasePositionAndOrientation failed."); return NULL; } @@ -736,6 +1182,62 @@ static PyObject* pybullet_getBasePositionAndOrientation(PyObject* self, } } + +static PyObject* pybullet_getBaseVelocity(PyObject* self, + PyObject* args) { + int bodyIndex = -1; + double baseLinearVelocity[3]; + double baseAngularVelocity[3]; + PyObject* pylistLinVel=0; + PyObject* pylistAngVel=0; + + if (0 == sm) { + PyErr_SetString(SpamError, "Not connected to physics server."); + return NULL; + } + + if (!PyArg_ParseTuple(args, "i", &bodyIndex)) { + PyErr_SetString(SpamError, "Expected a body index (integer)."); + return NULL; + } + + if (0 == pybullet_internalGetBaseVelocity( + bodyIndex, baseLinearVelocity, baseAngularVelocity)) { + PyErr_SetString(SpamError, + "getBaseVelocity failed."); + return NULL; + } + + { + PyObject* item; + int i; + int num = 3; + pylistLinVel = PyTuple_New(num); + for (i = 0; i < num; i++) { + item = PyFloat_FromDouble(baseLinearVelocity[i]); + PyTuple_SetItem(pylistLinVel, i, item); + } + } + + { + PyObject* item; + int i; + int num = 3; + pylistAngVel = PyTuple_New(num); + for (i = 0; i < num; i++) { + item = PyFloat_FromDouble(baseAngularVelocity[i]); + PyTuple_SetItem(pylistAngVel, i, item); + } + } + + { + PyObject* pylist; + pylist = PyTuple_New(2); + PyTuple_SetItem(pylist, 0, pylistLinVel); + PyTuple_SetItem(pylist, 1, pylistAngVel); + return pylist; + } +} static PyObject* pybullet_getNumBodies(PyObject* self, PyObject* args) { if (0 == sm) { @@ -880,6 +1382,66 @@ static PyObject* pybullet_resetJointState(PyObject* self, PyObject* args) { return NULL; } + + + +static PyObject* pybullet_resetBaseVelocity(PyObject* self, PyObject* args, PyObject *keywds) +{ + static char *kwlist[] = { "objectUniqueId", "linearVelocity", "angularVelocity", NULL }; + + if (0 == sm) + { + PyErr_SetString(SpamError, "Not connected to physics server."); + return NULL; + } + + { + int bodyIndex=0; + PyObject* linVelObj=0; + PyObject* angVelObj=0; + double linVel[3] = { 0, 0, 0 }; + double angVel[3] = { 0, 0, 0 }; + + if (!PyArg_ParseTupleAndKeywords(args, keywds, "i|OO", kwlist, &bodyIndex, &linVelObj, &angVelObj)) + { + return NULL; + } + if (linVelObj || angVelObj) + { + + b3SharedMemoryCommandHandle commandHandle; + b3SharedMemoryStatusHandle statusHandle; + + commandHandle = b3CreatePoseCommandInit(sm, bodyIndex); + + if (linVelObj) + { + pybullet_internalSetVectord(linVelObj, linVel); + b3CreatePoseCommandSetBaseLinearVelocity(commandHandle, linVel); + } + + if (angVelObj) + { + pybullet_internalSetVectord(angVelObj, angVel); + b3CreatePoseCommandSetBaseAngularVelocity(commandHandle, angVel); + } + + statusHandle = b3SubmitClientCommandAndWaitStatus(sm, commandHandle); + Py_INCREF(Py_None); + return Py_None; + } + else + { + PyErr_SetString(SpamError, "expected at least linearVelocity and/or angularVelocity."); + return NULL; + } + } + PyErr_SetString(SpamError, "error in resetJointState."); + return NULL; +} + + + // Reset the position and orientation of the base/root link, position [x,y,z] // and orientation quaternion [x,y,z,w] static PyObject* pybullet_resetBasePositionAndOrientation(PyObject* self, @@ -1211,88 +1773,228 @@ static PyObject* pybullet_getLinkState(PyObject* self, PyObject* args) { return Py_None; } -// internal function to set a float matrix[16] -// used to initialize camera position with -// a view and projection matrix in renderImage() -// -// // Args: -// matrix - float[16] which will be set by values from objMat -static int pybullet_internalSetMatrix(PyObject* objMat, float matrix[16]) { - int i, len; - PyObject* seq; - seq = PySequence_Fast(objMat, "expected a sequence"); - len = PySequence_Size(objMat); - if (len == 16) { - for (i = 0; i < len; i++) { - matrix[i] = pybullet_internalGetFloatFromSequence(seq, i); - } - Py_DECREF(seq); - return 1; +static PyObject* pybullet_addUserDebugText(PyObject* self, PyObject* args, PyObject *keywds) +{ + int size = PySequence_Size(args); + + b3SharedMemoryCommandHandle commandHandle; + b3SharedMemoryStatusHandle statusHandle; + int statusType; + int res = 0; + + PyObject* pyResultList = 0; + char* text; + double posXYZ[3]; + double colorRGB[3]={1,1,1}; + + + PyObject* textPositionObj=0; + PyObject* textColorRGBObj=0; + double textSize = 1.f; + double lifeTime = 0.f; + + static char *kwlist[] = { "text", "textPosition", "textColorRGB", "textSize", "lifeTime", NULL }; + + if (0 == sm) { + PyErr_SetString(SpamError, "Not connected to physics server."); + return NULL; } - Py_DECREF(seq); - return 0; -} -// internal function to set a float vector[3] -// used to initialize camera position with -// a view and projection matrix in renderImage() -// -// // Args: -// vector - float[3] which will be set by values from objMat -static int pybullet_internalSetVector(PyObject* objMat, float vector[3]) { - int i, len; - PyObject* seq; - - seq = PySequence_Fast(objMat, "expected a sequence"); - len = PySequence_Size(objMat); - if (len == 3) { - for (i = 0; i < len; i++) { - vector[i] = pybullet_internalGetFloatFromSequence(seq, i); - } - Py_DECREF(seq); - return 1; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "sO|Odd", kwlist, &text, &textPositionObj, &textColorRGBObj,&textSize, &lifeTime)) + { + return NULL; } - Py_DECREF(seq); - return 0; + + res = pybullet_internalSetVectord(textPositionObj,posXYZ); + if (!res) + { + PyErr_SetString(SpamError, "Error converting textPositionObj[3]"); + return NULL; + } + + if (textColorRGBObj) + { + res = pybullet_internalSetVectord(textColorRGBObj,colorRGB); + if (!res) + { + PyErr_SetString(SpamError, "Error converting textColorRGBObj[3]"); + return NULL; + } + } + + + commandHandle = b3InitUserDebugDrawAddText3D(sm,text,posXYZ,colorRGB,textSize,lifeTime); + + statusHandle = b3SubmitClientCommandAndWaitStatus(sm, commandHandle); + statusType = b3GetStatusType(statusHandle); + if (statusType == CMD_USER_DEBUG_DRAW_COMPLETED) + { + int debugItemUniqueId = b3GetDebugItemUniqueId(statusHandle); + PyObject* item = PyInt_FromLong(debugItemUniqueId); + return item; + } + + PyErr_SetString(SpamError, "Error in addUserDebugText."); + return NULL; } -// vector - double[3] which will be set by values from obVec -static int pybullet_internalSetVectord(PyObject* obVec, double vector[3]) { - int i, len; - PyObject* seq; - - seq = PySequence_Fast(obVec, "expected a sequence"); - len = PySequence_Size(obVec); - if (len == 3) { - for (i = 0; i < len; i++) { - vector[i] = pybullet_internalGetFloatFromSequence(seq, i); - } - Py_DECREF(seq); - return 1; - } - Py_DECREF(seq); - return 0; + +static PyObject* pybullet_addUserDebugLine(PyObject* self, PyObject* args, PyObject *keywds) +{ + int size = PySequence_Size(args); + + b3SharedMemoryCommandHandle commandHandle; + b3SharedMemoryStatusHandle statusHandle; + int statusType; + int res = 0; + + PyObject* pyResultList = 0; + + double fromXYZ[3]; + double toXYZ[3]; + double colorRGB[3]={1,1,1}; + + PyObject* lineFromObj=0; + PyObject* lineToObj=0; + PyObject* lineColorRGBObj=0; + double lineWidth = 1.f; + double lifeTime = 0.f; + + static char *kwlist[] = { "lineFromXYZ", "lineToXYZ", "lineColorRGB", "lineWidth", "lifeTime", NULL }; + + if (0 == sm) { + PyErr_SetString(SpamError, "Not connected to physics server."); + return NULL; + } + + if (!PyArg_ParseTupleAndKeywords(args, keywds, "OO|Odd", kwlist, &lineFromObj, &lineToObj, &lineColorRGBObj,&lineWidth, &lifeTime)) + { + return NULL; + } + + res = pybullet_internalSetVectord(lineFromObj,fromXYZ); + if (!res) + { + PyErr_SetString(SpamError, "Error converting lineFrom[3]"); + return NULL; + } + + res = pybullet_internalSetVectord(lineToObj,toXYZ); + if (!res) + { + PyErr_SetString(SpamError, "Error converting lineTo[3]"); + return NULL; + } + if (lineColorRGBObj) + { + res = pybullet_internalSetVectord(lineColorRGBObj,colorRGB); + } + + commandHandle = b3InitUserDebugDrawAddLine3D(sm,fromXYZ,toXYZ,colorRGB,lineWidth,lifeTime); + + statusHandle = b3SubmitClientCommandAndWaitStatus(sm, commandHandle); + statusType = b3GetStatusType(statusHandle); + if (statusType == CMD_USER_DEBUG_DRAW_COMPLETED) + { + int debugItemUniqueId = b3GetDebugItemUniqueId(statusHandle); + PyObject* item = PyInt_FromLong(debugItemUniqueId); + return item; + } + + PyErr_SetString(SpamError, "Error in addUserDebugLine."); + return NULL; } -// vector - double[3] which will be set by values from obVec -static int pybullet_internalSetVector4(PyObject* obVec, double vector[4]) { - int i, len; - PyObject* seq; - - seq = PySequence_Fast(obVec, "expected a sequence"); - len = PySequence_Size(obVec); - if (len == 4) { - for (i = 0; i < len; i++) { - vector[i] = pybullet_internalGetFloatFromSequence(seq, i); - } - Py_DECREF(seq); - return 1; - } - Py_DECREF(seq); - return 0; + + + +static PyObject* pybullet_removeUserDebugItem(PyObject* self, PyObject* args, PyObject *keywds) +{ + b3SharedMemoryCommandHandle commandHandle; + b3SharedMemoryStatusHandle statusHandle; + int statusType; + int itemUniqueId; + + if (0 == sm) { + PyErr_SetString(SpamError, "Not connected to physics server."); + return NULL; + } + + if (!PyArg_ParseTuple(args, "i", &itemUniqueId)) { + PyErr_SetString(SpamError, "Error parsing user debug item unique id"); + return NULL; + } + + commandHandle = b3InitUserDebugDrawRemove(sm,itemUniqueId); + + statusHandle = b3SubmitClientCommandAndWaitStatus(sm, commandHandle); + statusType = b3GetStatusType(statusHandle); + + Py_INCREF(Py_None); + return Py_None; } +static PyObject* pybullet_removeAllUserDebugItems(PyObject* self, PyObject* args, PyObject *keywds) +{ + b3SharedMemoryCommandHandle commandHandle; + b3SharedMemoryStatusHandle statusHandle; + int statusType; + + if (0 == sm) { + PyErr_SetString(SpamError, "Not connected to physics server."); + return NULL; + } + + commandHandle = b3InitUserDebugDrawRemoveAll(sm); + + statusHandle = b3SubmitClientCommandAndWaitStatus(sm, commandHandle); + statusType = b3GetStatusType(statusHandle); + + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject* pybullet_setDebugObjectColor(PyObject* self, PyObject* args, PyObject *keywds) +{ + PyObject* objectColorRGBObj = 0; + double objectColorRGB[3]; + + int objectUniqueId = -1; + int linkIndex = -2; + + static char *kwlist[] = { "objectUniqueId", "linkIndex","objectDebugColorRGB", NULL }; + + if (0 == sm) { + PyErr_SetString(SpamError, "Not connected to physics server."); + return NULL; + } + + if (!PyArg_ParseTupleAndKeywords(args, keywds, "ii|O", kwlist, + &objectUniqueId, &linkIndex, &objectColorRGBObj)) + return NULL; + + if (objectColorRGBObj) + { + if (pybullet_internalSetVectord(objectColorRGBObj, objectColorRGB)) + { + b3SharedMemoryCommandHandle commandHandle = b3InitDebugDrawingCommand(sm); + b3SetDebugObjectColor(commandHandle, objectUniqueId, linkIndex, objectColorRGB); + b3SubmitClientCommandAndWaitStatus(sm, commandHandle); + } + } + else + { + b3SharedMemoryCommandHandle commandHandle = b3InitDebugDrawingCommand(sm); + b3RemoveDebugObjectColor(commandHandle, objectUniqueId, linkIndex); + b3SubmitClientCommandAndWaitStatus(sm, commandHandle); + } + Py_INCREF(Py_None); + return Py_None; +} + + static PyObject* pybullet_getVisualShapeData(PyObject* self, PyObject* args) { int size = PySequence_Size(args); @@ -1304,6 +2006,10 @@ static PyObject* pybullet_getVisualShapeData(PyObject* self, PyObject* args) int i; PyObject* pyResultList = 0; + if (0 == sm) { + PyErr_SetString(SpamError, "Not connected to physics server."); + return NULL; + } if (size == 1) { if (!PyArg_ParseTuple(args, "i", &objectUniqueId)) { @@ -1369,7 +2075,7 @@ static PyObject* pybullet_getVisualShapeData(PyObject* self, PyObject* args) PyTuple_SetItem(visualShapeObList, 6, vec); } - + visualShapeInfo.m_visualShapeData[0].m_rgbaColor[0]; PyTuple_SetItem(pyResultList, i, visualShapeObList); } @@ -1402,6 +2108,11 @@ static PyObject* pybullet_resetVisualShapeData(PyObject* self, PyObject* args) b3SharedMemoryStatusHandle statusHandle; int statusType; + if (0 == sm) { + PyErr_SetString(SpamError, "Not connected to physics server."); + return NULL; + } + if (size == 4) { if (!PyArg_ParseTuple(args, "iiii", &objectUniqueId, &jointIndex, &shapeIndex, &textureUniqueId)) { @@ -1434,11 +2145,16 @@ static PyObject* pybullet_resetVisualShapeData(PyObject* self, PyObject* args) static PyObject* pybullet_loadTexture(PyObject* self, PyObject* args) { int size = PySequence_Size(args); - const char* filename = -1; + const char* filename = 0; b3SharedMemoryCommandHandle commandHandle; b3SharedMemoryStatusHandle statusHandle; int statusType; + if (0 == sm) { + PyErr_SetString(SpamError, "Not connected to physics server."); + return NULL; + } + if (size == 1) { if (!PyArg_ParseTuple(args, "s", &filename)) { @@ -1468,121 +2184,715 @@ static PyObject* pybullet_loadTexture(PyObject* self, PyObject* args) return Py_None; } -static PyObject* pybullet_getContactPointData(PyObject* self, PyObject* args) { - int size = PySequence_Size(args); - int objectUniqueIdA = -1; - int objectUniqueIdB = -1; - b3SharedMemoryCommandHandle commandHandle; - struct b3ContactInformation contactPointData; - b3SharedMemoryStatusHandle statusHandle; - int statusType; - int i; - PyObject* pyResultList = 0; - if (size == 1) { - if (!PyArg_ParseTuple(args, "i", &objectUniqueIdA)) { - PyErr_SetString(SpamError, "Error parsing object unique id"); - return NULL; - } - } - if (size == 2) { - if (!PyArg_ParseTuple(args, "ii", &objectUniqueIdA, &objectUniqueIdB)) { - PyErr_SetString(SpamError, "Error parsing object unique id"); - return NULL; - } - } - - commandHandle = b3InitRequestContactPointInformation(sm); - b3SetContactFilterBodyA(commandHandle, objectUniqueIdA); - b3SetContactFilterBodyB(commandHandle, objectUniqueIdB); - - statusHandle = b3SubmitClientCommandAndWaitStatus(sm, commandHandle); - statusType = b3GetStatusType(statusHandle); - if (statusType == CMD_CONTACT_POINT_INFORMATION_COMPLETED) { - /* +static PyObject* MyConvertContactPoint( struct b3ContactInformation* contactPointPtr) +{ + /* 0 int m_contactFlags; 1 int m_bodyUniqueIdA; 2 int m_bodyUniqueIdB; 3 int m_linkIndexA; 4 int m_linkIndexB; - 5-6-7 double m_positionOnAInWS[3];//contact point location on object A, + 5 double m_positionOnAInWS[3];//contact point location on object A, in world space coordinates - 8-9-10 double m_positionOnBInWS[3];//contact point location on object + 6 double m_positionOnBInWS[3];//contact point location on object A, in world space coordinates - 11-12-13 double m_contactNormalOnBInWS[3];//the separating contact + 7 double m_contactNormalOnBInWS[3];//the separating contact normal, pointing from object B towards object A - 14 double m_contactDistance;//negative number is penetration, positive + 8 double m_contactDistance;//negative number is penetration, positive is distance. - - 15 double m_normalForce; + 9 double m_normalForce; */ - b3GetContactPointInformation(sm, &contactPointData); - pyResultList = PyTuple_New(contactPointData.m_numContactPoints); - for (i = 0; i < contactPointData.m_numContactPoints; i++) { - PyObject* contactObList = PyTuple_New(16); // see above 16 fields + int i; + + PyObject* pyResultList = PyTuple_New(contactPointPtr->m_numContactPoints); + for (i = 0; i < contactPointPtr->m_numContactPoints; i++) { + PyObject* contactObList = PyTuple_New(10); // see above 10 fields PyObject* item; item = - PyInt_FromLong(contactPointData.m_contactPointData[i].m_contactFlags); + PyInt_FromLong(contactPointPtr->m_contactPointData[i].m_contactFlags); PyTuple_SetItem(contactObList, 0, item); item = PyInt_FromLong( - contactPointData.m_contactPointData[i].m_bodyUniqueIdA); + contactPointPtr->m_contactPointData[i].m_bodyUniqueIdA); PyTuple_SetItem(contactObList, 1, item); item = PyInt_FromLong( - contactPointData.m_contactPointData[i].m_bodyUniqueIdB); + contactPointPtr->m_contactPointData[i].m_bodyUniqueIdB); PyTuple_SetItem(contactObList, 2, item); item = - PyInt_FromLong(contactPointData.m_contactPointData[i].m_linkIndexA); + PyInt_FromLong(contactPointPtr->m_contactPointData[i].m_linkIndexA); PyTuple_SetItem(contactObList, 3, item); item = - PyInt_FromLong(contactPointData.m_contactPointData[i].m_linkIndexB); + PyInt_FromLong(contactPointPtr->m_contactPointData[i].m_linkIndexB); PyTuple_SetItem(contactObList, 4, item); - item = PyFloat_FromDouble( - contactPointData.m_contactPointData[i].m_positionOnAInWS[0]); - PyTuple_SetItem(contactObList, 5, item); - item = PyFloat_FromDouble( - contactPointData.m_contactPointData[i].m_positionOnAInWS[1]); - PyTuple_SetItem(contactObList, 6, item); - item = PyFloat_FromDouble( - contactPointData.m_contactPointData[i].m_positionOnAInWS[2]); - PyTuple_SetItem(contactObList, 7, item); + + { + PyObject* posAObj = PyTuple_New(3); + + item = PyFloat_FromDouble( + contactPointPtr->m_contactPointData[i].m_positionOnAInWS[0]); + PyTuple_SetItem(posAObj, 0, item); + item = PyFloat_FromDouble( + contactPointPtr->m_contactPointData[i].m_positionOnAInWS[1]); + PyTuple_SetItem(posAObj, 1, item); + item = PyFloat_FromDouble( + contactPointPtr->m_contactPointData[i].m_positionOnAInWS[2]); + PyTuple_SetItem(posAObj, 2, item); + + PyTuple_SetItem(contactObList, 5, posAObj); + } + + { + PyObject* posBObj = PyTuple_New(3); + + + item = PyFloat_FromDouble( + contactPointPtr->m_contactPointData[i].m_positionOnBInWS[0]); + PyTuple_SetItem(posBObj, 0, item); + item = PyFloat_FromDouble( + contactPointPtr->m_contactPointData[i].m_positionOnBInWS[1]); + PyTuple_SetItem(posBObj, 1, item); + item = PyFloat_FromDouble( + contactPointPtr->m_contactPointData[i].m_positionOnBInWS[2]); + PyTuple_SetItem(posBObj, 2, item); + + PyTuple_SetItem(contactObList, 6, posBObj); + + } + + { + PyObject* normalOnB = PyTuple_New(3); + item = PyFloat_FromDouble( + contactPointPtr->m_contactPointData[i].m_contactNormalOnBInWS[0]); + PyTuple_SetItem(normalOnB, 0, item); + item = PyFloat_FromDouble( + contactPointPtr->m_contactPointData[i].m_contactNormalOnBInWS[1]); + PyTuple_SetItem(normalOnB, 1, item); + item = PyFloat_FromDouble( + contactPointPtr->m_contactPointData[i].m_contactNormalOnBInWS[2]); + PyTuple_SetItem(normalOnB, 2, item); + PyTuple_SetItem(contactObList, 7, normalOnB); + } item = PyFloat_FromDouble( - contactPointData.m_contactPointData[i].m_positionOnBInWS[0]); + contactPointPtr->m_contactPointData[i].m_contactDistance); PyTuple_SetItem(contactObList, 8, item); item = PyFloat_FromDouble( - contactPointData.m_contactPointData[i].m_positionOnBInWS[1]); + contactPointPtr->m_contactPointData[i].m_normalForce); PyTuple_SetItem(contactObList, 9, item); - item = PyFloat_FromDouble( - contactPointData.m_contactPointData[i].m_positionOnBInWS[2]); - PyTuple_SetItem(contactObList, 10, item); - - item = PyFloat_FromDouble( - contactPointData.m_contactPointData[i].m_contactNormalOnBInWS[0]); - PyTuple_SetItem(contactObList, 11, item); - item = PyFloat_FromDouble( - contactPointData.m_contactPointData[i].m_contactNormalOnBInWS[1]); - PyTuple_SetItem(contactObList, 12, item); - item = PyFloat_FromDouble( - contactPointData.m_contactPointData[i].m_contactNormalOnBInWS[2]); - PyTuple_SetItem(contactObList, 13, item); - - item = PyFloat_FromDouble( - contactPointData.m_contactPointData[i].m_contactDistance); - PyTuple_SetItem(contactObList, 14, item); - item = PyFloat_FromDouble( - contactPointData.m_contactPointData[i].m_normalForce); - PyTuple_SetItem(contactObList, 15, item); PyTuple_SetItem(pyResultList, i, contactObList); } return pyResultList; +} + +static PyObject* pybullet_getOverlappingObjects(PyObject* self, PyObject* args, PyObject *keywds) +{ + PyObject* aabbMinOb=0, *aabbMaxOb=0; + double aabbMin[3]; + double aabbMax[3]; + b3SharedMemoryCommandHandle commandHandle; + b3SharedMemoryStatusHandle statusHandle; + struct b3AABBOverlapData overlapData; + int i; + + static char *kwlist[] = { "aabbMin", "aabbMax", NULL }; + if (0 == sm) { + PyErr_SetString(SpamError, "Not connected to physics server."); + return NULL; + } + + if (!PyArg_ParseTupleAndKeywords(args, keywds, "OO", kwlist, + &aabbMinOb, &aabbMaxOb)) + return NULL; + + pybullet_internalSetVectord(aabbMinOb, aabbMin); + pybullet_internalSetVectord(aabbMaxOb, aabbMax); + + commandHandle = b3InitAABBOverlapQuery(sm, aabbMin, aabbMax); + statusHandle = b3SubmitClientCommandAndWaitStatus(sm, commandHandle); + b3GetAABBOverlapResults(sm, &overlapData); + + if (overlapData.m_numOverlappingObjects) + { + PyObject* pyResultList = PyTuple_New(overlapData.m_numOverlappingObjects); + //For huge amount of overlap, we could use numpy instead (see camera pixel data) + //What would Python do with huge amount of data? Pass it onto TensorFlow! + + for (i = 0; i < overlapData.m_numOverlappingObjects; i++) { + PyObject* overlap = PyTuple_New(2);//body unique id and link index + + PyObject* item; + item = + PyInt_FromLong(overlapData.m_overlappingObjects[i].m_objectUniqueId); + PyTuple_SetItem(overlap, 0, item); + item = + PyInt_FromLong(overlapData.m_overlappingObjects[i].m_linkIndex); + PyTuple_SetItem(overlap, 1, item); + PyTuple_SetItem(pyResultList, i, overlap); + } + + return pyResultList; + } + + Py_INCREF(Py_None); + return Py_None; +} + + +static PyObject* pybullet_getClosestPointData(PyObject* self, PyObject* args, PyObject *keywds) +{ + int size = PySequence_Size(args); + int bodyUniqueIdA = -1; + int bodyUniqueIdB = -1; + int linkIndexA = -2; + int linkIndexB = -2; + + double distanceThreshold = 0.f; + + b3SharedMemoryCommandHandle commandHandle; + struct b3ContactInformation contactPointData; + b3SharedMemoryStatusHandle statusHandle; + int statusType; + PyObject* pyResultList = 0; + + + static char *kwlist[] = { "bodyA", "bodyB", "distance", "linkIndexA","linkIndexB",NULL }; + + if (0 == sm) { + PyErr_SetString(SpamError, "Not connected to physics server."); + return NULL; + } + + if (!PyArg_ParseTupleAndKeywords(args, keywds, "iid|ii", kwlist, + &bodyUniqueIdA, &bodyUniqueIdB, &distanceThreshold, &linkIndexA, &linkIndexB)) + return NULL; + + + commandHandle = b3InitClosestDistanceQuery(sm); + b3SetClosestDistanceFilterBodyA(commandHandle, bodyUniqueIdA); + b3SetClosestDistanceFilterBodyB(commandHandle, bodyUniqueIdB); + b3SetClosestDistanceThreshold(commandHandle, distanceThreshold); + if (linkIndexA >= -1) + { + b3SetClosestDistanceFilterLinkA(commandHandle, linkIndexA); + } + if (linkIndexB >= -1) + { + b3SetClosestDistanceFilterLinkB(commandHandle, linkIndexB); + } + + statusHandle = b3SubmitClientCommandAndWaitStatus(sm, commandHandle); + statusType = b3GetStatusType(statusHandle); + if (statusType == CMD_CONTACT_POINT_INFORMATION_COMPLETED) { + + + b3GetContactPointInformation(sm, &contactPointData); + + return MyConvertContactPoint(&contactPointData); + } Py_INCREF(Py_None); return Py_None; } +static PyObject* pybullet_removeUserConstraint(PyObject* self, PyObject* args, PyObject *keywds) +{ + static char *kwlist[] = { "userConstraintUniqueId",NULL}; + int userConstraintUniqueId=-1; + b3SharedMemoryCommandHandle commandHandle; + b3SharedMemoryStatusHandle statusHandle; + int statusType; + + + if (0 == sm) + { + PyErr_SetString(SpamError, "Not connected to physics server."); + return NULL; + } + + + if (!PyArg_ParseTupleAndKeywords(args, keywds, "i", kwlist,&userConstraintUniqueId)) + { + return NULL; + } + + commandHandle = b3InitRemoveUserConstraintCommand(sm,userConstraintUniqueId); + statusHandle = b3SubmitClientCommandAndWaitStatus(sm, commandHandle); + statusType = b3GetStatusType(statusHandle); + Py_INCREF(Py_None); + return Py_None; +}; + + +/* +static PyObject* pybullet_updateUserConstraint(PyObject* self, PyObject* args, PyObject *keywds) +{ + return NULL; +} +*/ + +static PyObject* pybullet_createUserConstraint(PyObject* self, PyObject* args, PyObject *keywds) +{ + int size = PySequence_Size(args); + int bodyUniqueIdA = -1; + int bodyUniqueIdB = -1; + + b3SharedMemoryCommandHandle commandHandle; + int parentBodyUniqueId=-1; + int parentLinkIndex=-1; + int childBodyUniqueId=-1; + int childLinkIndex=-1; + int jointType=ePoint2PointType; + PyObject* jointAxisObj=0; + double jointAxis[3]={0,0,0}; + PyObject* parentFramePositionObj = 0; + double parentFramePosition[3]={0,0,0}; + PyObject* childFramePositionObj = 0; + double childFramePosition[3]={0,0,0}; + PyObject* parentFrameOrientationObj = 0; + double parentFrameOrientation[4]={0,0,0,1}; + PyObject* childFrameOrientationObj = 0; + double childFrameOrientation[4]={0,0,0,1}; + + struct b3JointInfo jointInfo; + b3SharedMemoryStatusHandle statusHandle; + int statusType; + PyObject* pyResultList = 0; + + + static char *kwlist[] = { "parentBodyUniqueId", "parentLinkIndex", + "childBodyUniqueId", "childLinkIndex", + "jointType", + "jointAxis", + "parentFramePosition", + "childFramePosition", + "parentFrameOrientation", + "childFrameOrientation", + NULL }; + + if (0 == sm) + { + PyErr_SetString(SpamError, "Not connected to physics server."); + return NULL; + } + + if (!PyArg_ParseTupleAndKeywords(args, keywds, "iiiiiOOO|OO", kwlist,&parentBodyUniqueId,&parentLinkIndex, + &childBodyUniqueId,&childLinkIndex, + &jointType,&jointAxisObj, + &parentFramePositionObj, + &childFramePositionObj, + &parentFrameOrientationObj, + &childFrameOrientationObj + )) + { + return NULL; + } + + pybullet_internalSetVectord(jointAxisObj,jointAxis); + pybullet_internalSetVectord(parentFramePositionObj,parentFramePosition); + pybullet_internalSetVectord(childFramePositionObj,childFramePosition); + pybullet_internalSetVector4d(parentFrameOrientationObj,parentFrameOrientation); + pybullet_internalSetVector4d(childFrameOrientationObj,childFrameOrientation); + + jointInfo.m_jointType = jointType; + jointInfo.m_parentFrame[0] = parentFramePosition[0]; + jointInfo.m_parentFrame[1] = parentFramePosition[1]; + jointInfo.m_parentFrame[2] = parentFramePosition[2]; + jointInfo.m_parentFrame[3] = parentFrameOrientation[0]; + jointInfo.m_parentFrame[4] = parentFrameOrientation[1]; + jointInfo.m_parentFrame[5] = parentFrameOrientation[2]; + jointInfo.m_parentFrame[6] = parentFrameOrientation[3]; + + jointInfo.m_childFrame[0] = childFramePosition[0]; + jointInfo.m_childFrame[1] = childFramePosition[1]; + jointInfo.m_childFrame[2] = childFramePosition[2]; + jointInfo.m_childFrame[3] = childFrameOrientation[0]; + jointInfo.m_childFrame[4] = childFrameOrientation[1]; + jointInfo.m_childFrame[5] = childFrameOrientation[2]; + jointInfo.m_childFrame[6] = childFrameOrientation[3]; + + jointInfo.m_jointAxis[0] = jointAxis[0]; + jointInfo.m_jointAxis[1] = jointAxis[1]; + jointInfo.m_jointAxis[2] = jointAxis[2]; + + commandHandle = b3InitCreateUserConstraintCommand(sm, parentBodyUniqueId, parentLinkIndex, childBodyUniqueId, childLinkIndex, &jointInfo); + statusHandle = b3SubmitClientCommandAndWaitStatus(sm, commandHandle); + statusType = b3GetStatusType(statusHandle); + if (statusType==CMD_USER_CONSTRAINT_COMPLETED) + { + int userConstraintUid = b3GetStatusUserConstraintUniqueId(statusHandle); + PyObject* ob = PyLong_FromLong(userConstraintUid); + return ob; + } else + { + PyErr_SetString(SpamError, "createConstraint failed."); + return NULL; + } + + Py_INCREF(Py_None); + return Py_None; + +} + +static PyObject* pybullet_getContactPointData(PyObject* self, PyObject* args, PyObject *keywds) { + int size = PySequence_Size(args); + int bodyUniqueIdA = -1; + int bodyUniqueIdB = -1; + + b3SharedMemoryCommandHandle commandHandle; + struct b3ContactInformation contactPointData; + b3SharedMemoryStatusHandle statusHandle; + int statusType; + PyObject* pyResultList = 0; + + + static char *kwlist[] = { "bodyA", "bodyB", NULL }; + + if (0 == sm) { + PyErr_SetString(SpamError, "Not connected to physics server."); + return NULL; + } + + if (!PyArg_ParseTupleAndKeywords(args, keywds, "|ii", kwlist, + &bodyUniqueIdA, &bodyUniqueIdB)) + return NULL; + + + commandHandle = b3InitRequestContactPointInformation(sm); + b3SetContactFilterBodyA(commandHandle, bodyUniqueIdA); + b3SetContactFilterBodyB(commandHandle, bodyUniqueIdB); + //b3SetContactQueryMode(commandHandle, mode); + + statusHandle = b3SubmitClientCommandAndWaitStatus(sm, commandHandle); + statusType = b3GetStatusType(statusHandle); + if (statusType == CMD_CONTACT_POINT_INFORMATION_COMPLETED) { + + b3GetContactPointInformation(sm, &contactPointData); + + return MyConvertContactPoint(&contactPointData); + + } + + Py_INCREF(Py_None); + return Py_None; +} + + + +/// Render an image from the current timestep of the simulation, width, height are required, other args are optional +// getCameraImage(w, h, view[16], projection[16], lightDir[3], lightColor[3], lightDist, hasShadow, lightAmbientCoeff, lightDiffuseCoeff, lightSpecularCoeff) +static PyObject* pybullet_getCameraImage(PyObject* self, PyObject* args, PyObject *keywds) +{ + /// request an image from a simulated camera, using a software renderer. + struct b3CameraImageData imageData; + PyObject* objViewMat = 0, *objProjMat = 0, *lightDirObj = 0, *lightColorObj = 0; + int width, height; + int size = PySequence_Size(args); + float viewMatrix[16]; + float projectionMatrix[16]; + float lightDir[3]; + float lightColor[3]; + float lightDist = 10.0; + int hasShadow = 0; + float lightAmbientCoeff = 0.6; + float lightDiffuseCoeff = 0.35; + float lightSpecularCoeff = 0.05; + // inialize cmd + b3SharedMemoryCommandHandle command; + + if (0 == sm) + { + PyErr_SetString(SpamError, "Not connected to physics server."); + return NULL; + } + + command = b3InitRequestCameraImage(sm); + + // set camera resolution, optionally view, projection matrix, light direction, light color, light distance, shadow + static char *kwlist[] = { "width", "height", "viewMatrix", "projectionMatrix", "lightDirection", "lightColor", "lightDistance", "shadow", "lightAmbientCoeff", "lightDiffuseCoeff", "lightSpecularCoeff", NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, keywds, "ii|OOOOfifff", kwlist, &width, &height, &objViewMat, &objProjMat, &lightDirObj, &lightColorObj, &lightDist, &hasShadow, &lightAmbientCoeff, &lightDiffuseCoeff, &lightSpecularCoeff)) + { + return NULL; + } + b3RequestCameraImageSetPixelResolution(command, width, height); + + // set camera matrices only if set matrix function succeeds + if (pybullet_internalSetMatrix(objViewMat, viewMatrix) && (pybullet_internalSetMatrix(objProjMat, projectionMatrix))) + { + b3RequestCameraImageSetCameraMatrices(command, viewMatrix, projectionMatrix); + } + //set light direction only if function succeeds + if (pybullet_internalSetVector(lightDirObj, lightDir)) + { + b3RequestCameraImageSetLightDirection(command, lightDir); + } + //set light color only if function succeeds + if (pybullet_internalSetVector(lightColorObj, lightColor)) + { + b3RequestCameraImageSetLightColor(command, lightColor); + } + + b3RequestCameraImageSetLightDistance(command, lightDist); + + b3RequestCameraImageSetShadow(command, hasShadow); + + b3RequestCameraImageSetLightAmbientCoeff(command, lightAmbientCoeff); + b3RequestCameraImageSetLightDiffuseCoeff(command, lightDiffuseCoeff); + b3RequestCameraImageSetLightSpecularCoeff(command, lightSpecularCoeff); + + if (b3CanSubmitCommand(sm)) + { + b3SharedMemoryStatusHandle statusHandle; + int statusType; + + // b3RequestCameraImageSelectRenderer(command,ER_BULLET_HARDWARE_OPENGL); + + statusHandle = b3SubmitClientCommandAndWaitStatus(sm, command); + statusType = b3GetStatusType(statusHandle); + if (statusType == CMD_CAMERA_IMAGE_COMPLETED) { + PyObject* item2; + PyObject* pyResultList; // store 4 elements in this result: width, + // height, rgbData, depth + +#ifdef PYBULLET_USE_NUMPY + PyObject* pyRGB; + PyObject* pyDep; + PyObject* pySeg; + + int i, j, p; + + b3GetCameraImageData(sm, &imageData); + // TODO(hellojas): error handling if image size is 0 + pyResultList = PyTuple_New(5); + PyTuple_SetItem(pyResultList, 0, PyInt_FromLong(imageData.m_pixelWidth)); + PyTuple_SetItem(pyResultList, 1, PyInt_FromLong(imageData.m_pixelHeight)); + + int bytesPerPixel = 4; // Red, Green, Blue, and Alpha each 8 bit values + + npy_intp rgb_dims[3] = { imageData.m_pixelHeight, imageData.m_pixelWidth, + bytesPerPixel }; + npy_intp dep_dims[2] = { imageData.m_pixelHeight, imageData.m_pixelWidth }; + npy_intp seg_dims[2] = { imageData.m_pixelHeight, imageData.m_pixelWidth }; + + pyRGB = PyArray_SimpleNew(3, rgb_dims, NPY_UINT8); + pyDep = PyArray_SimpleNew(2, dep_dims, NPY_FLOAT32); + pySeg = PyArray_SimpleNew(2, seg_dims, NPY_INT32); + + memcpy(PyArray_DATA(pyRGB), imageData.m_rgbColorData, + imageData.m_pixelHeight * imageData.m_pixelWidth * bytesPerPixel); + memcpy(PyArray_DATA(pyDep), imageData.m_depthValues, + imageData.m_pixelHeight * imageData.m_pixelWidth); + memcpy(PyArray_DATA(pySeg), imageData.m_segmentationMaskValues, + imageData.m_pixelHeight * imageData.m_pixelWidth); + + PyTuple_SetItem(pyResultList, 2, pyRGB); + PyTuple_SetItem(pyResultList, 3, pyDep); + PyTuple_SetItem(pyResultList, 4, pySeg); +#else//PYBULLET_USE_NUMPY + PyObject* pylistRGB; + PyObject* pylistDep; + PyObject* pylistSeg; + + int i, j, p; + + b3GetCameraImageData(sm, &imageData); + // TODO(hellojas): error handling if image size is 0 + pyResultList = PyTuple_New(5); + PyTuple_SetItem(pyResultList, 0, PyInt_FromLong(imageData.m_pixelWidth)); + PyTuple_SetItem(pyResultList, 1, PyInt_FromLong(imageData.m_pixelHeight)); + + { + PyObject* item; + int bytesPerPixel = 4; // Red, Green, Blue, and Alpha each 8 bit values + int num = + bytesPerPixel * imageData.m_pixelWidth * imageData.m_pixelHeight; + pylistRGB = PyTuple_New(num); + pylistDep = + PyTuple_New(imageData.m_pixelWidth * imageData.m_pixelHeight); + pylistSeg = + PyTuple_New(imageData.m_pixelWidth * imageData.m_pixelHeight); + for (i = 0; i < imageData.m_pixelWidth; i++) { + for (j = 0; j < imageData.m_pixelHeight; j++) { + // TODO(hellojas): validate depth values make sense + int depIndex = i + j * imageData.m_pixelWidth; + { + item = PyFloat_FromDouble(imageData.m_depthValues[depIndex]); + PyTuple_SetItem(pylistDep, depIndex, item); + } + { + item2 = + PyLong_FromLong(imageData.m_segmentationMaskValues[depIndex]); + PyTuple_SetItem(pylistSeg, depIndex, item2); + } + + for (p = 0; p < bytesPerPixel; p++) { + int pixelIndex = + bytesPerPixel * (i + j * imageData.m_pixelWidth) + p; + item = PyInt_FromLong(imageData.m_rgbColorData[pixelIndex]); + PyTuple_SetItem(pylistRGB, pixelIndex, item); + } + } + } + } + + PyTuple_SetItem(pyResultList, 2, pylistRGB); + PyTuple_SetItem(pyResultList, 3, pylistDep); + PyTuple_SetItem(pyResultList, 4, pylistSeg); + return pyResultList; +#endif//PYBULLET_USE_NUMPY + + return pyResultList; + } + } + + Py_INCREF(Py_None); + return Py_None; + +} + + + +static PyObject* pybullet_computeViewMatrix(PyObject* self, PyObject* args, PyObject *keywds) +{ + PyObject* camEyeObj = 0; + PyObject* camTargetPositionObj = 0; + PyObject* camUpVectorObj = 0; + float camEye[3]; + float camTargetPosition[3]; + float camUpVector[3]; + + // set camera resolution, optionally view, projection matrix, light position + static char *kwlist[] = { "cameraEyePosition", "cameraTargetPosition", "cameraUpVector",NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, keywds, "OOO", kwlist, &camEyeObj, &camTargetPositionObj, &camUpVectorObj)) + { + return NULL; + } + + if (pybullet_internalSetVector(camEyeObj, camEye) && + pybullet_internalSetVector(camTargetPositionObj, camTargetPosition) && + pybullet_internalSetVector(camUpVectorObj, camUpVector)) + { + float viewMatrix[16]; + PyObject* pyResultList=0; + int i; + b3ComputeViewMatrixFromPositions(camEye, camTargetPosition, camUpVector, viewMatrix); + + pyResultList = PyTuple_New(16); + for (i = 0; i < 16; i++) + { + PyObject* item = PyFloat_FromDouble(viewMatrix[i]); + PyTuple_SetItem(pyResultList, i, item); + } + return pyResultList; + } + + PyErr_SetString(SpamError, "Error in computeViewMatrix."); + return NULL; +} + +///compute a view matrix, helper function for b3RequestCameraImageSetCameraMatrices +static PyObject* pybullet_computeViewMatrixFromYawPitchRoll(PyObject* self, PyObject* args, PyObject *keywds) +{ + PyObject* cameraTargetPositionObj = 0; + float cameraTargetPosition[3]; + float distance, yaw, pitch, roll; + int upAxisIndex; + float viewMatrix[16]; + PyObject* pyResultList = 0; + int i; + + // set camera resolution, optionally view, projection matrix, light position + static char *kwlist[] = { "cameraTargetPosition", "distance", "yaw", "pitch", "roll", "upAxisIndex" ,NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, keywds, "Offffi", kwlist, &cameraTargetPositionObj, &distance,&yaw,&pitch,&roll, &upAxisIndex)) + { + return NULL; + } + + if (!pybullet_internalSetVector(cameraTargetPositionObj, cameraTargetPosition)) + { + PyErr_SetString(SpamError, "Cannot convert cameraTargetPosition."); + return NULL; + } + + b3ComputeViewMatrixFromYawPitchRoll(cameraTargetPosition, distance, yaw, pitch, roll, upAxisIndex, viewMatrix); + + pyResultList = PyTuple_New(16); + for (i = 0; i < 16; i++) + { + PyObject* item = PyFloat_FromDouble(viewMatrix[i]); + PyTuple_SetItem(pyResultList, i, item); + } + return pyResultList; + + +} + +///compute a projection matrix, helper function for b3RequestCameraImageSetCameraMatrices +static PyObject* pybullet_computeProjectionMatrix(PyObject* self, PyObject* args, PyObject *keywds) +{ + PyObject* pyResultList = 0; + float left; + float right; + float bottom; + float top; + float nearVal; + float farVal; + float projectionMatrix[16]; + int i; + + // set camera resolution, optionally view, projection matrix, light position + static char *kwlist[] = { "left", "right", "bottom", "top", "nearVal", "farVal" ,NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, keywds, "ffffff", kwlist, &left, &right, &bottom, &top, &nearVal, &farVal)) + { + return NULL; + } + + + b3ComputeProjectionMatrix(left, right, bottom, top, nearVal, farVal, projectionMatrix); + + pyResultList = PyTuple_New(16); + for (i = 0; i < 16; i++) + { + PyObject* item = PyFloat_FromDouble(projectionMatrix[i]); + PyTuple_SetItem(pyResultList, i, item); + } + return pyResultList; + +} + +static PyObject* pybullet_computeProjectionMatrixFOV(PyObject* self, PyObject* args, PyObject *keywds) +{ + float fov, aspect, nearVal, farVal; + PyObject* pyResultList = 0; + float projectionMatrix[16]; + int i; + + static char *kwlist[] = { "fov","aspect","nearVal","farVal",NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, keywds, "ffff", kwlist, &fov, &aspect, &nearVal, &farVal)) + { + return NULL; + } + + b3ComputeProjectionMatrixFOV(fov, aspect, nearVal, farVal, projectionMatrix); + + pyResultList = PyTuple_New(16); + for (i = 0; i < 16; i++) + { + PyObject* item = PyFloat_FromDouble(projectionMatrix[i]); + PyTuple_SetItem(pyResultList, i, item); + } + return pyResultList; + +} + + // Render an image from the current timestep of the simulation // // Examples: @@ -1606,7 +2916,7 @@ static PyObject* pybullet_getContactPointData(PyObject* self, PyObject* args) { // TODO(hellojas): fix image is cut off at head // TODO(hellojas): should we add check to give minimum image resolution // to see object based on camera position? -static PyObject* pybullet_renderImage(PyObject* self, PyObject* args) { +static PyObject* pybullet_renderImageObsolete(PyObject* self, PyObject* args) { /// request an image from a simulated camera, using a software renderer. struct b3CameraImageData imageData; PyObject* objViewMat, *objProjMat; @@ -1664,7 +2974,8 @@ static PyObject* pybullet_renderImage(PyObject* self, PyObject* args) { b3RequestCameraImageSetPixelResolution(command, width, height); if (pybullet_internalSetVector(objCameraPos, cameraPos) && pybullet_internalSetVector(objTargetPos, targetPos) && - pybullet_internalSetVector(objCameraUp, cameraUp)) { + pybullet_internalSetVector(objCameraUp, cameraUp)) + { b3RequestCameraImageSetViewMatrix(command, cameraPos, targetPos, cameraUp); } else { @@ -2094,8 +3405,8 @@ static PyObject* pybullet_getEulerFromQuaternion(PyObject* self, } -///Experimental Inverse Kinematics binding ,7-dof KUKA IIWA only -static PyObject* pybullet_calculateInverseKinematicsKuka(PyObject* self, +///Inverse Kinematics binding +static PyObject* pybullet_calculateInverseKinematics(PyObject* self, PyObject* args) { int size; if (0 == sm) { @@ -2117,7 +3428,7 @@ static PyObject* pybullet_calculateInverseKinematicsKuka(PyObject* self, double pos[3]; double ori[4]={0,1.0,0,0}; - if (pybullet_internalSetVectord(targetPosObj,pos) && pybullet_internalSetVector4(targetOrnObj,ori)) + if (pybullet_internalSetVectord(targetPosObj,pos) && pybullet_internalSetVector4d(targetOrnObj,ori)) { b3SharedMemoryStatusHandle statusHandle; int numPos=0; @@ -2311,9 +3622,6 @@ static PyMethodDef SpamMethods[] = { "is seconds, typically range is 0.01 or 0.001)"}, - {"setTimeStep", pybullet_setTimeStep, METH_VARARGS, - "Set the amount of time to proceed at each call to stepSimulation." - " (unit is seconds, typically range is 0.01 or 0.001)"}, {"setDefaultContactERP", pybullet_setDefaultContactERP, METH_VARARGS, "Set the amount of contact penetration Error Recovery Paramater " @@ -2325,17 +3633,37 @@ static PyMethodDef SpamMethods[] = { "Enable or disable real time simulation (using the real time clock," " RTC) in the physics server. Expects one integer argument, 0 or 1" }, + { "setPhysicsEngineParameter", (PyCFunction)pybullet_setPhysicsEngineParameter, METH_VARARGS | METH_KEYWORDS, + "Set some internal physics engine parameter, such as cfm or erp etc." }, + { "setInternalSimFlags", pybullet_setInternalSimFlags, METH_VARARGS, "This is for experimental purposes, use at own risk, magic may or not happen"}, - {"loadURDF", pybullet_loadURDF, METH_VARARGS, + {"loadURDF", (PyCFunction) pybullet_loadURDF, METH_VARARGS | METH_KEYWORDS, "Create a multibody by loading a URDF file."}, {"loadSDF", pybullet_loadSDF, METH_VARARGS, "Load multibodies from an SDF file."}, + { "loadBullet", pybullet_loadBullet, METH_VARARGS, + "Restore the full state of the world from a .bullet file." }, + + { "saveBullet", pybullet_saveBullet, METH_VARARGS, + "Save the full state of the world to a .bullet file." }, + + { "loadMJCF", pybullet_loadMJCF, METH_VARARGS, + "Load multibodies from an MJCF file." }, + + {"createConstraint", (PyCFunction)pybullet_createUserConstraint, METH_VARARGS | METH_KEYWORDS, + "Create a constraint between two bodies. Returns a (int) unique id, if successfull." + }, + + {"removeConstraint", (PyCFunction)pybullet_removeUserConstraint, METH_VARARGS | METH_KEYWORDS, + "Remove a constraint using its unique id." + }, + {"saveWorld", pybullet_saveWorld, METH_VARARGS, - "Save an approximate Python file to reproduce the current state of the world: saveWorld" + "Save a approximate Python file to reproduce the current state of the world: saveWorld" "(filename). (very preliminary and approximately)"}, {"getNumBodies", pybullet_getNumBodies, METH_VARARGS, @@ -2358,6 +3686,19 @@ static PyMethodDef SpamMethods[] = { "instantaneously, not through physics simulation. (x,y,z) position vector " "and (x,y,z,w) quaternion orientation."}, + { "getBaseVelocity", pybullet_getBaseVelocity, + METH_VARARGS, + "Get the linear and angular velocity of the base of the object " + " in world space coordinates. " + "(x,y,z) linear velocity vector and (x,y,z) angular velocity vector." }, + + { "resetBaseVelocity", (PyCFunction)pybullet_resetBaseVelocity, METH_VARARGS | METH_KEYWORDS, + "Reset the linear and/or angular velocity of the base of the object " + " in world space coordinates. " + "linearVelocity (x,y,z) and angularVelocity (x,y,z)." }, + + + {"getNumJoints", pybullet_getNumJoints, METH_VARARGS, "Get the number of joints for an object."}, @@ -2390,20 +3731,78 @@ static PyMethodDef SpamMethods[] = { "[x,y,z] in Cartesian coordinates, flag to select TORQUE_IN_LINK_FRAME or " "TORQUE_IN_WORLD_FRAME coordinates"}, - {"renderImage", pybullet_renderImage, METH_VARARGS, - "Render an image (given the pixel resolution width, height, camera view " - "matrix, projection matrix, near, and far values), and return the " - "8-8-8bit RGB pixel data and floating point depth values" -#ifdef PYBULLET_USE_NUMPY - " as NumPy arrays" -#endif + {"renderImage", pybullet_renderImageObsolete, METH_VARARGS, + "obsolete, please use getCameraImage and getViewProjectionMatrices instead" }, - {"getContactPointData", pybullet_getContactPointData, METH_VARARGS, - "Return the contact point information for all or some of pairwise " - "object-object collisions. Optional arguments one or two object unique " + { "getCameraImage",(PyCFunction)pybullet_getCameraImage, METH_VARARGS| METH_KEYWORDS, + "Render an image (given the pixel resolution width, height, camera viewMatrix " + ", projectionMatrix, lightDirection, lightColor, lightDistance, shadow, lightAmbientCoeff, lightDiffuseCoeff, and lightSpecularCoeff), and return the " + "8-8-8bit RGB pixel data and floating point depth values" +#ifdef PYBULLET_USE_NUMPY + " as NumPy arrays" +#endif + }, + + { "computeViewMatrix", (PyCFunction)pybullet_computeViewMatrix, METH_VARARGS | METH_KEYWORDS, + "Compute a camera viewmatrix from camera eye, target position and up vector " + }, + + { "computeViewMatrixFromYawPitchRoll",(PyCFunction)pybullet_computeViewMatrixFromYawPitchRoll, METH_VARARGS | METH_KEYWORDS, + "Compute a camera viewmatrix from camera eye, target position and up vector " + }, + + { "computeProjectionMatrix", (PyCFunction)pybullet_computeProjectionMatrix, METH_VARARGS | METH_KEYWORDS, + "Compute a camera projection matrix from screen left/right/bottom/top/near/far values" + }, + + { "computeProjectionMatrixFOV", (PyCFunction)pybullet_computeProjectionMatrixFOV, METH_VARARGS | METH_KEYWORDS, + "Compute a camera projection matrix from fov, aspect ratio, near, far values" + }, + + {"getContactPoints", (PyCFunction)pybullet_getContactPointData, METH_VARARGS | METH_KEYWORDS, + "Return existing contact points after the stepSimulation command. " + "Optional arguments one or two object unique " "ids, that need to be involved in the contact."}, + {"getClosestPoints", (PyCFunction)pybullet_getClosestPointData, METH_VARARGS | METH_KEYWORDS, + "Compute the closest points between two objects, if the distance is below a given threshold." + "Input is two objects unique ids and distance threshold." + }, + + { "getOverlappingObjects", (PyCFunction)pybullet_getOverlappingObjects, METH_VARARGS | METH_KEYWORDS, + "Return all the objects that have overlap with a given " + "axis-aligned bounding box volume (AABB)." + "Input are two vectors defining the AABB in world space [min_x,min_y,min_z],[max_x,max_y,max_z]." + }, + + + { "addUserDebugLine", (PyCFunction)pybullet_addUserDebugLine, METH_VARARGS | METH_KEYWORDS, + "Add a user debug draw line with lineFrom[3], lineTo[3], lineColorRGB[3], lineWidth, lifeTime. " + "A lifeTime of 0 means permanent until removed. Returns a unique id for the user debug item." + }, + + + { "addUserDebugText", (PyCFunction)pybullet_addUserDebugText, METH_VARARGS | METH_KEYWORDS, + "Add a user debug draw line with text, textPosition[3], textSize and lifeTime in seconds " + "A lifeTime of 0 means permanent until removed. Returns a unique id for the user debug item." + }, + + { "removeUserDebugItem", (PyCFunction)pybullet_removeUserDebugItem, METH_VARARGS | METH_KEYWORDS, + "remove a user debug draw item, giving its unique id" + }, + + + { "removeAllUserDebugItems", (PyCFunction)pybullet_removeAllUserDebugItems, METH_VARARGS | METH_KEYWORDS, + "remove all user debug draw items" + }, + + { "setDebugObjectColor", (PyCFunction)pybullet_setDebugObjectColor, METH_VARARGS | METH_KEYWORDS, + "Override the wireframe debug drawing color for a particular object unique id / link index." + "If you ommit the color, the custom color will be removed." + }, + + {"getVisualShapeData", pybullet_getVisualShapeData, METH_VARARGS, "Return the visual shape information for one object." }, @@ -2426,9 +3825,9 @@ static PyMethodDef SpamMethods[] = { "Given an object id, joint positions, joint velocities and joint " "accelerations, compute the joint forces using Inverse Dynamics"}, - {"calculateInverseKinematicsKuka", pybullet_calculateInverseKinematicsKuka, + {"calculateInverseKinematics", pybullet_calculateInverseKinematics, METH_VARARGS, - "Experimental, KUKA IIWA only: Given an object id, " + "Inverse Kinematics bindings: Given an object id, " "current joint positions and target position" " for the end effector," "compute the inverse kinematics and return the new joint state"}, @@ -2438,6 +3837,7 @@ static PyMethodDef SpamMethods[] = { // loadSnapshot // raycast info // object names + // collision query {NULL, NULL, 0, NULL} /* Sentinel */ }; @@ -2481,6 +3881,14 @@ initpybullet(void) eCONNECT_SHARED_MEMORY); // user read PyModule_AddIntConstant(m, "DIRECT", eCONNECT_DIRECT); // user read PyModule_AddIntConstant(m, "GUI", eCONNECT_GUI); // user read + PyModule_AddIntConstant(m, "UDP", eCONNECT_UDP); // user read + + PyModule_AddIntConstant(m, "JOINT_REVOLUTE", eRevoluteType); // user read + PyModule_AddIntConstant(m, "JOINT_PRISMATIC", ePrismaticType); // user read + PyModule_AddIntConstant(m, "JOINT_SPHERICAL", eSphericalType); // user read + PyModule_AddIntConstant(m, "JOINT_PLANAR", ePlanarType); // user read + PyModule_AddIntConstant(m, "JOINT_FIXED", eFixedType); // user read + PyModule_AddIntConstant(m, "JOINT_POINT2POINT", ePoint2PointType); // user read PyModule_AddIntConstant(m, "TORQUE_CONTROL", CONTROL_MODE_TORQUE); PyModule_AddIntConstant(m, "VELOCITY_CONTROL", @@ -2491,6 +3899,9 @@ initpybullet(void) PyModule_AddIntConstant(m, "LINK_FRAME", EF_LINK_FRAME); PyModule_AddIntConstant(m, "WORLD_FRAME", EF_WORLD_FRAME); + PyModule_AddIntConstant(m, "CONTACT_REPORT_EXISTING", CONTACT_QUERY_MODE_REPORT_EXISTING_CONTACT_POINTS); + PyModule_AddIntConstant(m, "CONTACT_RECOMPUTE_CLOSEST", CONTACT_QUERY_MODE_COMPUTE_CLOSEST_POINTS); + SpamError = PyErr_NewException("pybullet.error", NULL, NULL); Py_INCREF(SpamError); PyModule_AddObject(m, "error", SpamError); diff --git a/examples/pybullet/quadruped.py b/examples/pybullet/quadruped.py new file mode 100644 index 000000000..8431a59bd --- /dev/null +++ b/examples/pybullet/quadruped.py @@ -0,0 +1,130 @@ +import pybullet as p +import time +import math + +p.connect(p.SHARED_MEMORY) +p.loadURDF("plane.urdf") +p.setGravity(0,0,-1) +p.setRealTimeSimulation(0) +quadruped = p.loadURDF("quadruped/quadruped.urdf",10,-2,2) +#p.getNumJoints(1) +#right front leg +p.resetJointState(quadruped,0,1.57) +p.resetJointState(quadruped,2,-2.2) +p.resetJointState(quadruped,3,-1.57) +p.resetJointState(quadruped,5,2.2) +p.createConstraint(quadruped,2,quadruped,5,p.JOINT_POINT2POINT,[0,0,0],[0,0.01,0.2],[0,-0.015,0.2]) + +p.setJointMotorControl(quadruped,0,p.POSITION_CONTROL,1.57,1) +p.setJointMotorControl(quadruped,1,p.VELOCITY_CONTROL,0,0) +p.setJointMotorControl(quadruped,2,p.VELOCITY_CONTROL,0,0) +p.setJointMotorControl(quadruped,3,p.POSITION_CONTROL,-1.57,1) +p.setJointMotorControl(quadruped,4,p.VELOCITY_CONTROL,0,0) +p.setJointMotorControl(quadruped,5,p.VELOCITY_CONTROL,0,0) + +#left front leg +p.resetJointState(quadruped,6,1.57) +p.resetJointState(quadruped,8,-2.2) +p.resetJointState(quadruped,9,-1.57) +p.resetJointState(quadruped,11,2.2) +p.createConstraint(quadruped,8,quadruped,11,p.JOINT_POINT2POINT,[0,0,0],[0,-0.01,0.2],[0,0.015,0.2]) + +p.setJointMotorControl(quadruped,6,p.POSITION_CONTROL,1.57,1) +p.setJointMotorControl(quadruped,7,p.VELOCITY_CONTROL,0,0) +p.setJointMotorControl(quadruped,8,p.VELOCITY_CONTROL,0,0) +p.setJointMotorControl(quadruped,9,p.POSITION_CONTROL,-1.57,1) +p.setJointMotorControl(quadruped,10,p.VELOCITY_CONTROL,0,0) +p.setJointMotorControl(quadruped,11,p.VELOCITY_CONTROL,0,0) + + +#right back leg +p.resetJointState(quadruped,12,1.57) +p.resetJointState(quadruped,14,-2.2) +p.resetJointState(quadruped,15,-1.57) +p.resetJointState(quadruped,17,2.2) +p.createConstraint(quadruped,14,quadruped,17,p.JOINT_POINT2POINT,[0,0,0],[0,0.01,0.2],[0,-0.015,0.2]) + +p.setJointMotorControl(quadruped,12,p.POSITION_CONTROL,1.57,1) +p.setJointMotorControl(quadruped,13,p.VELOCITY_CONTROL,0,0) +p.setJointMotorControl(quadruped,14,p.VELOCITY_CONTROL,0,0) +p.setJointMotorControl(quadruped,15,p.POSITION_CONTROL,-1.57,1) +p.setJointMotorControl(quadruped,16,p.VELOCITY_CONTROL,0,0) +p.setJointMotorControl(quadruped,17,p.VELOCITY_CONTROL,0,0) + +#left back leg +p.resetJointState(quadruped,18,1.57) +p.resetJointState(quadruped,20,-2.2) +p.resetJointState(quadruped,21,-1.57) +p.resetJointState(quadruped,23,2.2) +p.createConstraint(quadruped,20,quadruped,23,p.JOINT_POINT2POINT,[0,0,0],[0,-0.01,0.2],[0,0.015,0.2]) + +p.setJointMotorControl(quadruped,18,p.POSITION_CONTROL,1.57,1) +p.setJointMotorControl(quadruped,19,p.VELOCITY_CONTROL,0,0) +p.setJointMotorControl(quadruped,20,p.VELOCITY_CONTROL,0,0) +p.setJointMotorControl(quadruped,21,p.POSITION_CONTROL,-1.57,1) +p.setJointMotorControl(quadruped,22,p.VELOCITY_CONTROL,0,0) +p.setJointMotorControl(quadruped,23,p.VELOCITY_CONTROL,0,0) + + + +p_gain = 2 +speed = 10 +amplitude = 1.3 + +#stand still +t_end = time.time() + 2 +while time.time() < t_end: + p.stepSimulation() +p.setGravity(0,0,-10) + +jump_amp = 0.5 + +#jump +t_end = time.time() + 10 +i=0 +while time.time() < t_end: + t = time.time() + p.setJointMotorControl(quadruped,0,p.POSITION_CONTROL,math.sin(t*speed)*jump_amp+1.57,p_gain) + p.setJointMotorControl(quadruped,3,p.POSITION_CONTROL,-math.sin(t*speed)*jump_amp-1.57,p_gain) + p.setJointMotorControl(quadruped,6,p.POSITION_CONTROL,math.sin(t*speed)*jump_amp+1.57,p_gain) + p.setJointMotorControl(quadruped,9,p.POSITION_CONTROL,-math.sin(t*speed)*jump_amp-1.57,p_gain) + p.setJointMotorControl(quadruped,12,p.POSITION_CONTROL,math.sin(t*speed)*jump_amp+1.57,p_gain) + p.setJointMotorControl(quadruped,15,p.POSITION_CONTROL,-math.sin(t*speed)*jump_amp-1.57,p_gain) + p.setJointMotorControl(quadruped,18,p.POSITION_CONTROL,math.sin(t*speed)*jump_amp+1.57,p_gain) + p.setJointMotorControl(quadruped,21,p.POSITION_CONTROL,-math.sin(t*speed)*jump_amp-1.57,p_gain) + + p.stepSimulation() + + +#hop forward +t_end = time.time() + 30 +i=0 +while time.time() < t_end: + t = time.time() + p.setJointMotorControl(quadruped,0,p.POSITION_CONTROL,math.sin(t*speed)*amplitude+1.57,p_gain) + p.setJointMotorControl(quadruped,3,p.POSITION_CONTROL,-1.57,p_gain) + p.setJointMotorControl(quadruped,6,p.POSITION_CONTROL,math.sin(t*speed)*amplitude+1.57,p_gain) + p.setJointMotorControl(quadruped,9,p.POSITION_CONTROL,-1.57,p_gain) + p.setJointMotorControl(quadruped,12,p.POSITION_CONTROL,math.sin(t*speed+3.14)*amplitude+1.57,p_gain) + p.setJointMotorControl(quadruped,15,p.POSITION_CONTROL,-1.57,p_gain) + p.setJointMotorControl(quadruped,18,p.POSITION_CONTROL,math.sin(t*speed+3.14)*amplitude+1.57,p_gain) + p.setJointMotorControl(quadruped,21,p.POSITION_CONTROL,-1.57,p_gain) + + p.stepSimulation() + +#walk +t_end = time.time() + 120 +i=0 +while time.time() < t_end: + t = time.time() + p.setJointMotorControl(quadruped,0,p.POSITION_CONTROL,math.sin(t*3)*.3+1.57,1) + p.setJointMotorControl(quadruped,3,p.POSITION_CONTROL,-1.57,1) + p.setJointMotorControl(quadruped,6,p.POSITION_CONTROL,math.sin(t*3+0.5*3.14)*.3+1.57,1) + p.setJointMotorControl(quadruped,9,p.POSITION_CONTROL,-1.57,1) + p.setJointMotorControl(quadruped,12,p.POSITION_CONTROL,math.sin(t*3+3.14)*.3+1.57,1) + p.setJointMotorControl(quadruped,15,p.POSITION_CONTROL,-1.57,1) + p.setJointMotorControl(quadruped,18,p.POSITION_CONTROL,math.sin(t*3+1.5*3.14)*.3+1.57,1) + p.setJointMotorControl(quadruped,21,p.POSITION_CONTROL,-1.57,1) + + p.stepSimulation() +p.setRealTimeSimulation(1) diff --git a/examples/pybullet/test.py b/examples/pybullet/test.py index 1a184985f..762026246 100644 --- a/examples/pybullet/test.py +++ b/examples/pybullet/test.py @@ -3,7 +3,7 @@ import time #choose connection method: GUI, DIRECT, SHARED_MEMORY pybullet.connect(pybullet.GUI) - +pybullet.loadURDF("plane.urdf",0,0,-1) #load URDF, given a relative or absolute file+path obj = pybullet.loadURDF("r2d2.urdf") diff --git a/examples/pybullet/testrender.py b/examples/pybullet/testrender.py index da96bbbc5..0d3475c84 100644 --- a/examples/pybullet/testrender.py +++ b/examples/pybullet/testrender.py @@ -5,7 +5,7 @@ import pybullet pybullet.connect(pybullet.GUI) pybullet.loadURDF("r2d2.urdf") -camTargetPos = [0,0,0] +camTargetPos = [0.,0.,0.] cameraUp = [0,0,1] cameraPos = [1,1,1] yaw = 40 @@ -18,29 +18,29 @@ pixelWidth = 320 pixelHeight = 240 nearPlane = 0.01 farPlane = 1000 - +lightDirection = [0,1,0] +lightColor = [1,1,1]#optional argument fov = 60 #img_arr = pybullet.renderImage(pixelWidth, pixelHeight) #renderImage(w, h, view[16], projection[16]) #img_arr = pybullet.renderImage(pixelWidth, pixelHeight, cameraPos, camTargetPos, cameraUp, nearPlane, farPlane) for pitch in range (0,360,10) : - img_arr = pybullet.renderImage(pixelWidth, pixelHeight, camTargetPos, camDistance, yaw, pitch, roll, upAxisIndex, nearPlane, farPlane, fov) - - w=img_arr[0] #width of the image, in pixels - h=img_arr[1] #height of the image, in pixels - rgb=img_arr[2] #color data RGB - dep=img_arr[3] #depth data - - #print 'width = %d height = %d' % (w,h) - - # reshape creates np array - np_img_arr = np.reshape(rgb, (h, w, 4)) - np_img_arr = np_img_arr*(1./255.) - - #show - plt.imshow(np_img_arr,interpolation='none') - #plt.show() - plt.pause(0.01) + viewMatrix = pybullet.computeViewMatrixFromYawPitchRoll(camTargetPos, camDistance, yaw, pitch, roll, upAxisIndex) + aspect = pixelWidth / pixelHeight; + projectionMatrix = pybullet.computeProjectionMatrixFOV(fov, aspect, nearPlane, farPlane); + img_arr = pybullet.getCameraImage(pixelWidth, pixelHeight, viewMatrix,projectionMatrix, lightDirection,lightColor) + w=img_arr[0] + h=img_arr[1] + rgb=img_arr[2] + dep=img_arr[3] + #print 'width = %d height = %d' % (w,h) + # reshape creates np array + np_img_arr = np.reshape(rgb, (h, w, 4)) + np_img_arr = np_img_arr*(1./255.) + #show + plt.imshow(np_img_arr,interpolation='none') + + plt.pause(0.01) pybullet.resetSimulation() diff --git a/examples/pybullet/testrender_np.py b/examples/pybullet/testrender_np.py index 56439dde6..b8fca10eb 100644 --- a/examples/pybullet/testrender_np.py +++ b/examples/pybullet/testrender_np.py @@ -1,3 +1,6 @@ + +#make sure to compile pybullet with PYBULLET_USE_NUMPY enabled, otherwise use testrender.py (slower but compatible without numpy) + import numpy as np import matplotlib.pyplot as plt import pybullet @@ -23,28 +26,30 @@ farPlane = 1000 fov = 60 main_start = time.time() -#img_arr = pybullet.renderImage(pixelWidth, pixelHeight) -#renderImage(w, h, view[16], projection[16]) -#img_arr = pybullet.renderImage(pixelWidth, pixelHeight, cameraPos, camTargetPos, cameraUp, nearPlane, farPlane) for pitch in range (0,360,10) : - start = time.time() - img_arr = pybullet.renderImage(pixelWidth, pixelHeight, camTargetPos, camDistance, yaw, pitch, roll, upAxisIndex, nearPlane, farPlane, fov) - stop = time.time() - print "renderImage %f" % (stop - start) + start = time.time() + viewMatrix = pybullet.computeViewMatrixFromYawPitchRoll(camTargetPos, camDistance, yaw, pitch, roll, upAxisIndex) + aspect = pixelWidth / pixelHeight; + projectionMatrix = pybullet.computeProjectionMatrixFOV(fov, aspect, nearPlane, farPlane); + img_arr = pybullet.getCameraImage(pixelWidth, pixelHeight, viewMatrix,projectionMatrix, [0,1,0]) + stop = time.time() + print ("renderImage %f" % (stop - start)) - w=img_arr[0] #width of the image, in pixels - h=img_arr[1] #height of the image, in pixels - rgb=img_arr[2] #color data RGB - dep=img_arr[3] #depth data + w=img_arr[0] #width of the image, in pixels + h=img_arr[1] #height of the image, in pixels + rgb=img_arr[2] #color data RGB + dep=img_arr[3] #depth data - #print 'width = %d height = %d' % (w,h) + print 'width = %d height = %d' % (w,h) - #show - plt.imshow(rgb,interpolation='none') - #plt.show() - plt.pause(0.01) + #note that sending the data to matplotlib is really slow + #show + plt.imshow(rgb,interpolation='none') + #plt.show() + plt.pause(0.01) main_stop = time.time() -print "Total time %f" % (main_stop - main_start) + +print ("Total time %f" % (main_stop - main_start)) pybullet.resetSimulation() diff --git a/src/Bullet3Collision/NarrowPhaseCollision/b3Config.h b/src/Bullet3Collision/NarrowPhaseCollision/b3Config.h index e23fe11a5..65d4a2161 100644 --- a/src/Bullet3Collision/NarrowPhaseCollision/b3Config.h +++ b/src/Bullet3Collision/NarrowPhaseCollision/b3Config.h @@ -20,7 +20,7 @@ struct b3Config int m_maxTriConvexPairCapacity; b3Config() - :m_maxConvexBodies(32*1024), + :m_maxConvexBodies(128*1024), m_maxVerticesPerFace(64), m_maxFacesPerShape(12), m_maxConvexVertices(8192), diff --git a/src/BulletCollision/BroadphaseCollision/btDbvt.h b/src/BulletCollision/BroadphaseCollision/btDbvt.h index bee17e5c8..1ca175723 100644 --- a/src/BulletCollision/BroadphaseCollision/btDbvt.h +++ b/src/BulletCollision/BroadphaseCollision/btDbvt.h @@ -267,7 +267,6 @@ struct btDbvt btAlignedObjectArray m_stkStack; - mutable btAlignedObjectArray m_rayTestStack; // Methods @@ -357,6 +356,7 @@ struct btDbvt btScalar lambda_max, const btVector3& aabbMin, const btVector3& aabbMax, + btAlignedObjectArray& stack, DBVT_IPOLICY) const; DBVT_PREFIX @@ -1006,7 +1006,8 @@ inline void btDbvt::rayTestInternal( const btDbvtNode* root, btScalar lambda_max, const btVector3& aabbMin, const btVector3& aabbMax, - DBVT_IPOLICY) const + btAlignedObjectArray& stack, + DBVT_IPOLICY ) const { (void) rayTo; DBVT_CHECKTYPE @@ -1016,7 +1017,6 @@ inline void btDbvt::rayTestInternal( const btDbvtNode* root, int depth=1; int treshold=DOUBLE_STACKSIZE-2; - btAlignedObjectArray& stack = m_rayTestStack; stack.resize(DOUBLE_STACKSIZE); stack[0]=root; btVector3 bounds[2]; diff --git a/src/BulletCollision/BroadphaseCollision/btDbvtBroadphase.cpp b/src/BulletCollision/BroadphaseCollision/btDbvtBroadphase.cpp index 75cfac643..4f33db500 100644 --- a/src/BulletCollision/BroadphaseCollision/btDbvtBroadphase.cpp +++ b/src/BulletCollision/BroadphaseCollision/btDbvtBroadphase.cpp @@ -16,6 +16,7 @@ subject to the following restrictions: ///btDbvtBroadphase implementation by Nathanael Presson #include "btDbvtBroadphase.h" +#include "LinearMath/btThreads.h" // // Profiling @@ -142,6 +143,11 @@ btDbvtBroadphase::btDbvtBroadphase(btOverlappingPairCache* paircache) { m_stageRoots[i]=0; } +#if BT_THREADSAFE + m_rayTestStacks.resize(BT_MAX_THREAD_COUNT); +#else + m_rayTestStacks.resize(1); +#endif #if DBVT_BP_PROFILE clear(m_profiling); #endif @@ -227,6 +233,23 @@ struct BroadphaseRayTester : btDbvt::ICollide void btDbvtBroadphase::rayTest(const btVector3& rayFrom,const btVector3& rayTo, btBroadphaseRayCallback& rayCallback,const btVector3& aabbMin,const btVector3& aabbMax) { BroadphaseRayTester callback(rayCallback); + btAlignedObjectArray* stack = &m_rayTestStacks[0]; +#if BT_THREADSAFE + // for this function to be threadsafe, each thread must have a separate copy + // of this stack. This could be thread-local static to avoid dynamic allocations, + // instead of just a local. + int threadIndex = btGetCurrentThreadIndex(); + btAlignedObjectArray localStack; + if (threadIndex < m_rayTestStacks.size()) + { + // use per-thread preallocated stack if possible to avoid dynamic allocations + stack = &m_rayTestStacks[threadIndex]; + } + else + { + stack = &localStack; + } +#endif m_sets[0].rayTestInternal( m_sets[0].m_root, rayFrom, @@ -236,6 +259,7 @@ void btDbvtBroadphase::rayTest(const btVector3& rayFrom,const btVector3& rayTo, rayCallback.m_lambda_max, aabbMin, aabbMax, + *stack, callback); m_sets[1].rayTestInternal( m_sets[1].m_root, @@ -246,6 +270,7 @@ void btDbvtBroadphase::rayTest(const btVector3& rayFrom,const btVector3& rayTo, rayCallback.m_lambda_max, aabbMin, aabbMax, + *stack, callback); } diff --git a/src/BulletCollision/BroadphaseCollision/btDbvtBroadphase.h b/src/BulletCollision/BroadphaseCollision/btDbvtBroadphase.h index 18b64ad0e..a61f00df0 100644 --- a/src/BulletCollision/BroadphaseCollision/btDbvtBroadphase.h +++ b/src/BulletCollision/BroadphaseCollision/btDbvtBroadphase.h @@ -87,6 +87,7 @@ struct btDbvtBroadphase : btBroadphaseInterface bool m_releasepaircache; // Release pair cache on delete bool m_deferedcollide; // Defere dynamic/static collision to collide call bool m_needcleanup; // Need to run cleanup? + btAlignedObjectArray< btAlignedObjectArray > m_rayTestStacks; #if DBVT_BP_PROFILE btClock m_clock; struct { diff --git a/src/BulletCollision/BroadphaseCollision/btDispatcher.h b/src/BulletCollision/BroadphaseCollision/btDispatcher.h index 89c307d14..7b0f9489a 100644 --- a/src/BulletCollision/BroadphaseCollision/btDispatcher.h +++ b/src/BulletCollision/BroadphaseCollision/btDispatcher.h @@ -64,6 +64,12 @@ struct btDispatcherInfo btScalar m_convexConservativeDistanceThreshold; }; +enum ebtDispatcherQueryType +{ + BT_CONTACT_POINT_ALGORITHMS = 1, + BT_CLOSEST_POINT_ALGORITHMS = 2 +}; + ///The btDispatcher interface class can be used in combination with broadphase to dispatch calculations for overlapping pairs. ///For example for pairwise collision detection, calculating contact points stored in btPersistentManifold or user callbacks (game logic). class btDispatcher @@ -73,7 +79,7 @@ class btDispatcher public: virtual ~btDispatcher() ; - virtual btCollisionAlgorithm* findAlgorithm(const btCollisionObjectWrapper* body0Wrap,const btCollisionObjectWrapper* body1Wrap,btPersistentManifold* sharedManifold=0) = 0; + virtual btCollisionAlgorithm* findAlgorithm(const btCollisionObjectWrapper* body0Wrap,const btCollisionObjectWrapper* body1Wrap,btPersistentManifold* sharedManifold, ebtDispatcherQueryType queryType) = 0; virtual btPersistentManifold* getNewManifold(const btCollisionObject* b0,const btCollisionObject* b1)=0; diff --git a/src/BulletCollision/CollisionDispatch/SphereTriangleDetector.cpp b/src/BulletCollision/CollisionDispatch/SphereTriangleDetector.cpp index 634017809..006cc65a2 100644 --- a/src/BulletCollision/CollisionDispatch/SphereTriangleDetector.cpp +++ b/src/BulletCollision/CollisionDispatch/SphereTriangleDetector.cpp @@ -100,7 +100,7 @@ bool SphereTriangleDetector::collide(const btVector3& sphereCenter,btVector3 &po btScalar radiusWithThreshold = radius + contactBreakingThreshold; btVector3 normal = (vertices[1]-vertices[0]).cross(vertices[2]-vertices[0]); - normal.normalize(); + normal.safeNormalize(); btVector3 p1ToCentre = sphereCenter - vertices[0]; btScalar distanceFromPlane = p1ToCentre.dot(normal); diff --git a/src/BulletCollision/CollisionDispatch/btCollisionConfiguration.h b/src/BulletCollision/CollisionDispatch/btCollisionConfiguration.h index 669498494..35f77d4e6 100644 --- a/src/BulletCollision/CollisionDispatch/btCollisionConfiguration.h +++ b/src/BulletCollision/CollisionDispatch/btCollisionConfiguration.h @@ -40,6 +40,9 @@ public: virtual btCollisionAlgorithmCreateFunc* getCollisionAlgorithmCreateFunc(int proxyType0,int proxyType1) =0; + virtual btCollisionAlgorithmCreateFunc* getClosestPointsAlgorithmCreateFunc(int proxyType0, int proxyType1) = 0; + + }; #endif //BT_COLLISION_CONFIGURATION diff --git a/src/BulletCollision/CollisionDispatch/btCollisionDispatcher.cpp b/src/BulletCollision/CollisionDispatch/btCollisionDispatcher.cpp index d41e98c32..737067ef9 100644 --- a/src/BulletCollision/CollisionDispatch/btCollisionDispatcher.cpp +++ b/src/BulletCollision/CollisionDispatch/btCollisionDispatcher.cpp @@ -50,8 +50,10 @@ m_dispatcherFlags(btCollisionDispatcher::CD_USE_RELATIVE_CONTACT_BREAKING_THRESH { for (int j=0;jgetCollisionAlgorithmCreateFunc(i,j); - btAssert(m_doubleDispatch[i][j]); + m_doubleDispatchContactPoints[i][j] = m_collisionConfiguration->getCollisionAlgorithmCreateFunc(i,j); + btAssert(m_doubleDispatchContactPoints[i][j]); + m_doubleDispatchClosestPoints[i][j] = m_collisionConfiguration->getClosestPointsAlgorithmCreateFunc(i, j); + } } @@ -61,7 +63,12 @@ m_dispatcherFlags(btCollisionDispatcher::CD_USE_RELATIVE_CONTACT_BREAKING_THRESH void btCollisionDispatcher::registerCollisionCreateFunc(int proxyType0, int proxyType1, btCollisionAlgorithmCreateFunc *createFunc) { - m_doubleDispatch[proxyType0][proxyType1] = createFunc; + m_doubleDispatchContactPoints[proxyType0][proxyType1] = createFunc; +} + +void btCollisionDispatcher::registerClosestPointsCreateFunc(int proxyType0, int proxyType1, btCollisionAlgorithmCreateFunc *createFunc) +{ + m_doubleDispatchClosestPoints[proxyType0][proxyType1] = createFunc; } btCollisionDispatcher::~btCollisionDispatcher() @@ -84,14 +91,10 @@ btPersistentManifold* btCollisionDispatcher::getNewManifold(const btCollisionObj btScalar contactProcessingThreshold = btMin(body0->getContactProcessingThreshold(),body1->getContactProcessingThreshold()); - void* mem = 0; - - if (m_persistentManifoldPoolAllocator->getFreeCount()) + void* mem = m_persistentManifoldPoolAllocator->allocate( sizeof( btPersistentManifold ) ); + if (NULL == mem) { - mem = m_persistentManifoldPoolAllocator->allocate(sizeof(btPersistentManifold)); - } else - { - //we got a pool memory overflow, by default we fallback to dynamically allocate memory. If we require a contiguous contact pool then assert. + //we got a pool memory overflow, by default we fallback to dynamically allocate memory. If we require a contiguous contact pool then assert. if ((m_dispatcherFlags&CD_DISABLE_CONTACTPOOL_DYNAMIC_ALLOCATION)==0) { mem = btAlignedAlloc(sizeof(btPersistentManifold),16); @@ -142,14 +145,23 @@ void btCollisionDispatcher::releaseManifold(btPersistentManifold* manifold) -btCollisionAlgorithm* btCollisionDispatcher::findAlgorithm(const btCollisionObjectWrapper* body0Wrap,const btCollisionObjectWrapper* body1Wrap,btPersistentManifold* sharedManifold) + +btCollisionAlgorithm* btCollisionDispatcher::findAlgorithm(const btCollisionObjectWrapper* body0Wrap,const btCollisionObjectWrapper* body1Wrap,btPersistentManifold* sharedManifold, ebtDispatcherQueryType algoType) { btCollisionAlgorithmConstructionInfo ci; ci.m_dispatcher1 = this; ci.m_manifold = sharedManifold; - btCollisionAlgorithm* algo = m_doubleDispatch[body0Wrap->getCollisionShape()->getShapeType()][body1Wrap->getCollisionShape()->getShapeType()]->CreateCollisionAlgorithm(ci,body0Wrap,body1Wrap); + btCollisionAlgorithm* algo = 0; + if (algoType == BT_CONTACT_POINT_ALGORITHMS) + { + algo = m_doubleDispatchContactPoints[body0Wrap->getCollisionShape()->getShapeType()][body1Wrap->getCollisionShape()->getShapeType()]->CreateCollisionAlgorithm(ci, body0Wrap, body1Wrap); + } + else + { + algo = m_doubleDispatchClosestPoints[body0Wrap->getCollisionShape()->getShapeType()][body1Wrap->getCollisionShape()->getShapeType()]->CreateCollisionAlgorithm(ci, body0Wrap, body1Wrap); + } return algo; } @@ -266,7 +278,7 @@ void btCollisionDispatcher::defaultNearCallback(btBroadphasePair& collisionPair, //dispatcher will keep algorithms persistent in the collision pair if (!collisionPair.m_algorithm) { - collisionPair.m_algorithm = dispatcher.findAlgorithm(&obj0Wrap,&obj1Wrap); + collisionPair.m_algorithm = dispatcher.findAlgorithm(&obj0Wrap,&obj1Wrap,0, BT_CONTACT_POINT_ALGORITHMS); } if (collisionPair.m_algorithm) @@ -294,13 +306,13 @@ void btCollisionDispatcher::defaultNearCallback(btBroadphasePair& collisionPair, void* btCollisionDispatcher::allocateCollisionAlgorithm(int size) { - if (m_collisionAlgorithmPoolAllocator->getFreeCount()) - { - return m_collisionAlgorithmPoolAllocator->allocate(size); - } - - //warn user for overflow? - return btAlignedAlloc(static_cast(size), 16); + void* mem = m_collisionAlgorithmPoolAllocator->allocate( size ); + if (NULL == mem) + { + //warn user for overflow? + return btAlignedAlloc(static_cast(size), 16); + } + return mem; } void btCollisionDispatcher::freeCollisionAlgorithm(void* ptr) diff --git a/src/BulletCollision/CollisionDispatch/btCollisionDispatcher.h b/src/BulletCollision/CollisionDispatch/btCollisionDispatcher.h index 92696ee54..b97ee3c1b 100644 --- a/src/BulletCollision/CollisionDispatch/btCollisionDispatcher.h +++ b/src/BulletCollision/CollisionDispatch/btCollisionDispatcher.h @@ -57,7 +57,9 @@ protected: btPoolAllocator* m_persistentManifoldPoolAllocator; - btCollisionAlgorithmCreateFunc* m_doubleDispatch[MAX_BROADPHASE_COLLISION_TYPES][MAX_BROADPHASE_COLLISION_TYPES]; + btCollisionAlgorithmCreateFunc* m_doubleDispatchContactPoints[MAX_BROADPHASE_COLLISION_TYPES][MAX_BROADPHASE_COLLISION_TYPES]; + + btCollisionAlgorithmCreateFunc* m_doubleDispatchClosestPoints[MAX_BROADPHASE_COLLISION_TYPES][MAX_BROADPHASE_COLLISION_TYPES]; btCollisionConfiguration* m_collisionConfiguration; @@ -84,6 +86,8 @@ public: ///registerCollisionCreateFunc allows registration of custom/alternative collision create functions void registerCollisionCreateFunc(int proxyType0,int proxyType1, btCollisionAlgorithmCreateFunc* createFunc); + void registerClosestPointsCreateFunc(int proxyType0, int proxyType1, btCollisionAlgorithmCreateFunc *createFunc); + int getNumManifolds() const { return int( m_manifoldsPtr.size()); @@ -115,7 +119,7 @@ public: virtual void clearManifold(btPersistentManifold* manifold); - btCollisionAlgorithm* findAlgorithm(const btCollisionObjectWrapper* body0Wrap,const btCollisionObjectWrapper* body1Wrap,btPersistentManifold* sharedManifold = 0); + btCollisionAlgorithm* findAlgorithm(const btCollisionObjectWrapper* body0Wrap,const btCollisionObjectWrapper* body1Wrap,btPersistentManifold* sharedManifold, ebtDispatcherQueryType queryType); virtual bool needsCollision(const btCollisionObject* body0,const btCollisionObject* body1); diff --git a/src/BulletCollision/CollisionDispatch/btCollisionObject.cpp b/src/BulletCollision/CollisionDispatch/btCollisionObject.cpp index 25cefb11f..fdecac162 100644 --- a/src/BulletCollision/CollisionDispatch/btCollisionObject.cpp +++ b/src/BulletCollision/CollisionDispatch/btCollisionObject.cpp @@ -28,6 +28,7 @@ btCollisionObject::btCollisionObject() m_collisionFlags(btCollisionObject::CF_STATIC_OBJECT), m_islandTag1(-1), m_companionId(-1), + m_worldArrayIndex(-1), m_activationState1(1), m_deactivationTime(btScalar(0.)), m_friction(btScalar(0.5)), diff --git a/src/BulletCollision/CollisionDispatch/btCollisionObject.h b/src/BulletCollision/CollisionDispatch/btCollisionObject.h index d042115e6..0cae21000 100644 --- a/src/BulletCollision/CollisionDispatch/btCollisionObject.h +++ b/src/BulletCollision/CollisionDispatch/btCollisionObject.h @@ -79,6 +79,7 @@ protected: int m_islandTag1; int m_companionId; + int m_worldArrayIndex; // index of object in world's collisionObjects array mutable int m_activationState1; mutable btScalar m_deactivationTime; @@ -121,6 +122,7 @@ protected: ///internal update revision number. It will be increased when the object changes. This allows some subsystems to perform lazy evaluation. int m_updateRevision; + btVector3 m_customDebugColorRGB; public: @@ -135,7 +137,8 @@ public: CF_CHARACTER_OBJECT = 16, CF_DISABLE_VISUALIZE_OBJECT = 32, //disable debug drawing CF_DISABLE_SPU_COLLISION_PROCESSING = 64,//disable parallel/SPU processing - CF_HAS_CONTACT_STIFFNESS_DAMPING = 128 + CF_HAS_CONTACT_STIFFNESS_DAMPING = 128, + CF_HAS_CUSTOM_DEBUG_RENDERING_COLOR = 256, }; enum CollisionObjectTypes @@ -455,7 +458,18 @@ public: m_companionId = id; } - SIMD_FORCE_INLINE btScalar getHitFraction() const + SIMD_FORCE_INLINE int getWorldArrayIndex() const + { + return m_worldArrayIndex; + } + + // only should be called by CollisionWorld + void setWorldArrayIndex(int ix) + { + m_worldArrayIndex = ix; + } + + SIMD_FORCE_INLINE btScalar getHitFraction() const { return m_hitFraction; } @@ -544,6 +558,26 @@ public: return m_updateRevision; } + void setCustomDebugColor(const btVector3& colorRGB) + { + m_customDebugColorRGB = colorRGB; + m_collisionFlags |= CF_HAS_CUSTOM_DEBUG_RENDERING_COLOR; + } + + void removeCustomDebugColor() + { + m_collisionFlags &= ~CF_HAS_CUSTOM_DEBUG_RENDERING_COLOR; + } + + bool getCustomDebugColor(btVector3& colorRGB) const + { + bool hasCustomColor = (0!=(m_collisionFlags&CF_HAS_CUSTOM_DEBUG_RENDERING_COLOR)); + if (hasCustomColor) + { + colorRGB = m_customDebugColorRGB; + } + return hasCustomColor; + } inline bool checkCollideWith(const btCollisionObject* co) const { diff --git a/src/BulletCollision/CollisionDispatch/btCollisionWorld.cpp b/src/BulletCollision/CollisionDispatch/btCollisionWorld.cpp index fa4cac660..3bbf7586e 100644 --- a/src/BulletCollision/CollisionDispatch/btCollisionWorld.cpp +++ b/src/BulletCollision/CollisionDispatch/btCollisionWorld.cpp @@ -115,7 +115,9 @@ void btCollisionWorld::addCollisionObject(btCollisionObject* collisionObject,sho //check that the object isn't already added btAssert( m_collisionObjects.findLinearSearch(collisionObject) == m_collisionObjects.size()); + btAssert(collisionObject->getWorldArrayIndex() == -1); // do not add the same object to more than one collision world + collisionObject->setWorldArrayIndex(m_collisionObjects.size()); m_collisionObjects.push_back(collisionObject); //calculate new AABB @@ -195,6 +197,7 @@ void btCollisionWorld::updateAabbs() for ( int i=0;igetWorldArrayIndex() == i); //only update aabb of active objects if (m_forceUpdateAllAabbs || colObj->isActive()) @@ -253,9 +256,25 @@ void btCollisionWorld::removeCollisionObject(btCollisionObject* collisionObject) } - //swapremove - m_collisionObjects.remove(collisionObject); - + int iObj = collisionObject->getWorldArrayIndex(); + btAssert(iObj >= 0 && iObj < m_collisionObjects.size()); // trying to remove an object that was never added or already removed previously? + if (iObj >= 0 && iObj < m_collisionObjects.size()) + { + btAssert(collisionObject == m_collisionObjects[iObj]); + m_collisionObjects.swap(iObj, m_collisionObjects.size()-1); + m_collisionObjects.pop_back(); + if (iObj < m_collisionObjects.size()) + { + m_collisionObjects[iObj]->setWorldArrayIndex(iObj); + } + } + else + { + // slow linear search + //swapremove + m_collisionObjects.remove(collisionObject); + } + collisionObject->setWorldArrayIndex(-1); } @@ -1212,7 +1231,7 @@ struct btSingleContactCallback : public btBroadphaseAabbCallback btCollisionObjectWrapper ob0(0,m_collisionObject->getCollisionShape(),m_collisionObject,m_collisionObject->getWorldTransform(),-1,-1); btCollisionObjectWrapper ob1(0,collisionObject->getCollisionShape(),collisionObject,collisionObject->getWorldTransform(),-1,-1); - btCollisionAlgorithm* algorithm = m_world->getDispatcher()->findAlgorithm(&ob0,&ob1); + btCollisionAlgorithm* algorithm = m_world->getDispatcher()->findAlgorithm(&ob0,&ob1,0, BT_CLOSEST_POINT_ALGORITHMS); if (algorithm) { btBridgedManifoldResult contactPointResult(&ob0,&ob1, m_resultCallback); @@ -1248,10 +1267,11 @@ void btCollisionWorld::contactPairTest(btCollisionObject* colObjA, btCollisionOb btCollisionObjectWrapper obA(0,colObjA->getCollisionShape(),colObjA,colObjA->getWorldTransform(),-1,-1); btCollisionObjectWrapper obB(0,colObjB->getCollisionShape(),colObjB,colObjB->getWorldTransform(),-1,-1); - btCollisionAlgorithm* algorithm = getDispatcher()->findAlgorithm(&obA,&obB); + btCollisionAlgorithm* algorithm = getDispatcher()->findAlgorithm(&obA,&obB, 0, BT_CLOSEST_POINT_ALGORITHMS); if (algorithm) { btBridgedManifoldResult contactPointResult(&obA,&obB, resultCallback); + contactPointResult.m_closestPointDistanceThreshold = resultCallback.m_closestDistanceThreshold; //discrete collision detection query algorithm->processCollision(&obA,&obB, getDispatchInfo(),&contactPointResult); @@ -1552,6 +1572,8 @@ void btCollisionWorld::debugDrawWorld() } }; + colObj->getCustomDebugColor(color); + debugDrawObject(colObj->getWorldTransform(),colObj->getCollisionShape(),color); } if (m_debugDrawer && (m_debugDrawer->getDebugMode() & btIDebugDraw::DBG_DrawAabb)) diff --git a/src/BulletCollision/CollisionDispatch/btCollisionWorld.h b/src/BulletCollision/CollisionDispatch/btCollisionWorld.h index be9eca61a..29d371116 100644 --- a/src/BulletCollision/CollisionDispatch/btCollisionWorld.h +++ b/src/BulletCollision/CollisionDispatch/btCollisionWorld.h @@ -412,10 +412,12 @@ public: { short int m_collisionFilterGroup; short int m_collisionFilterMask; - + btScalar m_closestDistanceThreshold; + ContactResultCallback() :m_collisionFilterGroup(btBroadphaseProxy::DefaultFilter), - m_collisionFilterMask(btBroadphaseProxy::AllFilter) + m_collisionFilterMask(btBroadphaseProxy::AllFilter), + m_closestDistanceThreshold(0) { } diff --git a/src/BulletCollision/CollisionDispatch/btCompoundCollisionAlgorithm.cpp b/src/BulletCollision/CollisionDispatch/btCompoundCollisionAlgorithm.cpp index 13cddc11a..7f4dea1c6 100644 --- a/src/BulletCollision/CollisionDispatch/btCompoundCollisionAlgorithm.cpp +++ b/src/BulletCollision/CollisionDispatch/btCompoundCollisionAlgorithm.cpp @@ -65,7 +65,13 @@ void btCompoundCollisionAlgorithm::preallocateChildAlgorithms(const btCollisionO const btCollisionShape* childShape = compoundShape->getChildShape(i); btCollisionObjectWrapper childWrap(colObjWrap,childShape,colObjWrap->getCollisionObject(),colObjWrap->getWorldTransform(),-1,i);//wrong child trans, but unused (hopefully) - m_childCollisionAlgorithms[i] = m_dispatcher->findAlgorithm(&childWrap,otherObjWrap,m_sharedManifold); + m_childCollisionAlgorithms[i] = m_dispatcher->findAlgorithm(&childWrap,otherObjWrap,m_sharedManifold, BT_CONTACT_POINT_ALGORITHMS); + + + btAlignedObjectArray m_childCollisionAlgorithmsContact; + btAlignedObjectArray m_childCollisionAlgorithmsClosestPoints; + + } } } @@ -128,8 +134,14 @@ public: btTransform newChildWorldTrans = orgTrans*childTrans ; //perform an AABB check first - btVector3 aabbMin0,aabbMax0,aabbMin1,aabbMax1; + btVector3 aabbMin0,aabbMax0; childShape->getAabb(newChildWorldTrans,aabbMin0,aabbMax0); + + btVector3 extendAabb(m_resultOut->m_closestPointDistanceThreshold, m_resultOut->m_closestPointDistanceThreshold, m_resultOut->m_closestPointDistanceThreshold); + aabbMin0 -= extendAabb; + aabbMax0 += extendAabb; + + btVector3 aabbMin1, aabbMax1; m_otherObjWrap->getCollisionShape()->getAabb(m_otherObjWrap->getWorldTransform(),aabbMin1,aabbMax1); if (gCompoundChildShapePairCallback) @@ -142,12 +154,22 @@ public: { btCollisionObjectWrapper compoundWrap(this->m_compoundColObjWrap,childShape,m_compoundColObjWrap->getCollisionObject(),newChildWorldTrans,-1,index); + + btCollisionAlgorithm* algo = 0; - - //the contactpoint is still projected back using the original inverted worldtrans - if (!m_childCollisionAlgorithms[index]) - m_childCollisionAlgorithms[index] = m_dispatcher->findAlgorithm(&compoundWrap,m_otherObjWrap,m_sharedManifold); - + if (m_resultOut->m_closestPointDistanceThreshold > 0) + { + algo = m_dispatcher->findAlgorithm(&compoundWrap, m_otherObjWrap, 0, BT_CLOSEST_POINT_ALGORITHMS); + } + else + { + //the contactpoint is still projected back using the original inverted worldtrans + if (!m_childCollisionAlgorithms[index]) + { + m_childCollisionAlgorithms[index] = m_dispatcher->findAlgorithm(&compoundWrap, m_otherObjWrap, m_sharedManifold, BT_CONTACT_POINT_ALGORITHMS); + } + algo = m_childCollisionAlgorithms[index]; + } const btCollisionObjectWrapper* tmpWrap = 0; @@ -164,8 +186,7 @@ public: m_resultOut->setShapeIdentifiersB(-1,index); } - - m_childCollisionAlgorithms[index]->processCollision(&compoundWrap,m_otherObjWrap,m_dispatchInfo,m_resultOut); + algo->processCollision(&compoundWrap,m_otherObjWrap,m_dispatchInfo,m_resultOut); #if 0 if (m_dispatchInfo.m_debugDraw && (m_dispatchInfo.m_debugDraw->getDebugMode() & btIDebugDraw::DBG_DrawAabb)) @@ -271,6 +292,9 @@ void btCompoundCollisionAlgorithm::processCollision (const btCollisionObjectWrap btTransform otherInCompoundSpace; otherInCompoundSpace = colObjWrap->getWorldTransform().inverse() * otherObjWrap->getWorldTransform(); otherObjWrap->getCollisionShape()->getAabb(otherInCompoundSpace,localAabbMin,localAabbMax); + btVector3 extraExtends(resultOut->m_closestPointDistanceThreshold, resultOut->m_closestPointDistanceThreshold, resultOut->m_closestPointDistanceThreshold); + localAabbMin -= extraExtends; + localAabbMax += extraExtends; const ATTRIBUTE_ALIGNED16(btDbvtVolume) bounds=btDbvtVolume::FromMM(localAabbMin,localAabbMax); //process all children, that overlap with the given AABB bounds diff --git a/src/BulletCollision/CollisionDispatch/btCompoundCompoundCollisionAlgorithm.cpp b/src/BulletCollision/CollisionDispatch/btCompoundCompoundCollisionAlgorithm.cpp index ab2632ee3..8dd7e4403 100644 --- a/src/BulletCollision/CollisionDispatch/btCompoundCompoundCollisionAlgorithm.cpp +++ b/src/BulletCollision/CollisionDispatch/btCompoundCompoundCollisionAlgorithm.cpp @@ -161,6 +161,11 @@ struct btCompoundCompoundLeafCallback : btDbvt::ICollide childShape0->getAabb(newChildWorldTrans0,aabbMin0,aabbMax0); childShape1->getAabb(newChildWorldTrans1,aabbMin1,aabbMax1); + btVector3 thresholdVec(m_resultOut->m_closestPointDistanceThreshold, m_resultOut->m_closestPointDistanceThreshold, m_resultOut->m_closestPointDistanceThreshold); + + aabbMin0 -= thresholdVec; + aabbMax0 += thresholdVec; + if (gCompoundCompoundChildShapePairCallback) { if (!gCompoundCompoundChildShapePairCallback(childShape0,childShape1)) @@ -176,17 +181,24 @@ struct btCompoundCompoundLeafCallback : btDbvt::ICollide btSimplePair* pair = m_childCollisionAlgorithmCache->findPair(childIndex0,childIndex1); btCollisionAlgorithm* colAlgo = 0; + if (m_resultOut->m_closestPointDistanceThreshold > 0) + { + colAlgo = m_dispatcher->findAlgorithm(&compoundWrap0, &compoundWrap1, 0, BT_CLOSEST_POINT_ALGORITHMS); + } + else + { + if (pair) + { + colAlgo = (btCollisionAlgorithm*)pair->m_userPointer; - if (pair) - { - colAlgo = (btCollisionAlgorithm*)pair->m_userPointer; - - } else - { - colAlgo = m_dispatcher->findAlgorithm(&compoundWrap0,&compoundWrap1,m_sharedManifold); - pair = m_childCollisionAlgorithmCache->addOverlappingPair(childIndex0,childIndex1); - btAssert(pair); - pair->m_userPointer = colAlgo; + } + else + { + colAlgo = m_dispatcher->findAlgorithm(&compoundWrap0, &compoundWrap1, m_sharedManifold, BT_CONTACT_POINT_ALGORITHMS); + pair = m_childCollisionAlgorithmCache->addOverlappingPair(childIndex0, childIndex1); + btAssert(pair); + pair->m_userPointer = colAlgo; + } } btAssert(colAlgo); @@ -217,10 +229,12 @@ struct btCompoundCompoundLeafCallback : btDbvt::ICollide static DBVT_INLINE bool MyIntersect( const btDbvtAabbMm& a, - const btDbvtAabbMm& b, const btTransform& xform) + const btDbvtAabbMm& b, const btTransform& xform, btScalar distanceThreshold) { btVector3 newmin,newmax; btTransformAabb(b.Mins(),b.Maxs(),0.f,xform,newmin,newmax); + newmin -= btVector3(distanceThreshold, distanceThreshold, distanceThreshold); + newmax += btVector3(distanceThreshold, distanceThreshold, distanceThreshold); btDbvtAabbMm newb = btDbvtAabbMm::FromMM(newmin,newmax); return Intersect(a,newb); } @@ -229,7 +243,7 @@ static DBVT_INLINE bool MyIntersect( const btDbvtAabbMm& a, static inline void MycollideTT( const btDbvtNode* root0, const btDbvtNode* root1, const btTransform& xform, - btCompoundCompoundLeafCallback* callback) + btCompoundCompoundLeafCallback* callback, btScalar distanceThreshold) { if(root0&&root1) @@ -241,7 +255,7 @@ static inline void MycollideTT( const btDbvtNode* root0, stkStack[0]=btDbvt::sStkNN(root0,root1); do { btDbvt::sStkNN p=stkStack[--depth]; - if(MyIntersect(p.a->volume,p.b->volume,xform)) + if(MyIntersect(p.a->volume,p.b->volume,xform, distanceThreshold)) { if(depth>treshold) { @@ -343,7 +357,7 @@ void btCompoundCompoundCollisionAlgorithm::processCollision (const btCollisionOb const btTransform xform=col0ObjWrap->getWorldTransform().inverse()*col1ObjWrap->getWorldTransform(); - MycollideTT(tree0->m_root,tree1->m_root,xform,&callback); + MycollideTT(tree0->m_root,tree1->m_root,xform,&callback, resultOut->m_closestPointDistanceThreshold); //printf("#compound-compound child/leaf overlap =%d \r",callback.m_numOverlapPairs); @@ -383,7 +397,9 @@ void btCompoundCompoundCollisionAlgorithm::processCollision (const btCollisionOb newChildWorldTrans0 = orgTrans0*childTrans0 ; childShape0->getAabb(newChildWorldTrans0,aabbMin0,aabbMax0); } - + btVector3 thresholdVec(resultOut->m_closestPointDistanceThreshold, resultOut->m_closestPointDistanceThreshold, resultOut->m_closestPointDistanceThreshold); + aabbMin0 -= thresholdVec; + aabbMax0 += thresholdVec; { btTransform orgInterpolationTrans1; const btCollisionShape* childShape1 = 0; @@ -398,7 +414,8 @@ void btCompoundCompoundCollisionAlgorithm::processCollision (const btCollisionOb childShape1->getAabb(newChildWorldTrans1,aabbMin1,aabbMax1); } - + aabbMin1 -= thresholdVec; + aabbMax1 += thresholdVec; if (!TestAabbAgainstAabb2(aabbMin0,aabbMax0,aabbMin1,aabbMax1)) { diff --git a/src/BulletCollision/CollisionDispatch/btConvexConcaveCollisionAlgorithm.cpp b/src/BulletCollision/CollisionDispatch/btConvexConcaveCollisionAlgorithm.cpp index 322b1288d..c774383dc 100644 --- a/src/BulletCollision/CollisionDispatch/btConvexConcaveCollisionAlgorithm.cpp +++ b/src/BulletCollision/CollisionDispatch/btConvexConcaveCollisionAlgorithm.cpp @@ -118,8 +118,16 @@ partId, int triangleIndex) btCollisionObjectWrapper triObWrap(m_triBodyWrap,&tm,m_triBodyWrap->getCollisionObject(),m_triBodyWrap->getWorldTransform(),partId,triangleIndex);//correct transform? - btCollisionAlgorithm* colAlgo = ci.m_dispatcher1->findAlgorithm(m_convexBodyWrap,&triObWrap,m_manifoldPtr); - + btCollisionAlgorithm* colAlgo = 0; + + if (m_resultOut->m_closestPointDistanceThreshold > 0) + { + colAlgo = ci.m_dispatcher1->findAlgorithm(m_convexBodyWrap, &triObWrap, 0, BT_CLOSEST_POINT_ALGORITHMS); + } + else + { + colAlgo = ci.m_dispatcher1->findAlgorithm(m_convexBodyWrap, &triObWrap, m_manifoldPtr, BT_CONTACT_POINT_ALGORITHMS); + } const btCollisionObjectWrapper* tmpWrap = 0; if (m_resultOut->getBody0Internal() == m_triBodyWrap->getCollisionObject()) @@ -170,7 +178,8 @@ void btConvexTriangleCallback::setTimeStepAndCounters(btScalar collisionMarginTr const btCollisionShape* convexShape = static_cast(m_convexBodyWrap->getCollisionShape()); //CollisionShape* triangleShape = static_cast(triBody->m_collisionShape); convexShape->getAabb(convexInTriangleSpace,m_aabbMin,m_aabbMax); - btScalar extraMargin = collisionMarginTriangle; + btScalar extraMargin = collisionMarginTriangle+ resultOut->m_closestPointDistanceThreshold; + btVector3 extra(extraMargin,extraMargin,extraMargin); m_aabbMax += extra; diff --git a/src/BulletCollision/CollisionDispatch/btConvexConvexAlgorithm.cpp b/src/BulletCollision/CollisionDispatch/btConvexConvexAlgorithm.cpp index b9cc04186..bc23fdb98 100644 --- a/src/BulletCollision/CollisionDispatch/btConvexConvexAlgorithm.cpp +++ b/src/BulletCollision/CollisionDispatch/btConvexConvexAlgorithm.cpp @@ -179,11 +179,10 @@ static SIMD_FORCE_INLINE btScalar capsuleCapsuleDistance( -btConvexConvexAlgorithm::CreateFunc::CreateFunc(btSimplexSolverInterface* simplexSolver, btConvexPenetrationDepthSolver* pdSolver) +btConvexConvexAlgorithm::CreateFunc::CreateFunc(btConvexPenetrationDepthSolver* pdSolver) { m_numPerturbationIterations = 0; m_minimumPointsPerturbationThreshold = 3; - m_simplexSolver = simplexSolver; m_pdSolver = pdSolver; } @@ -191,9 +190,8 @@ btConvexConvexAlgorithm::CreateFunc::~CreateFunc() { } -btConvexConvexAlgorithm::btConvexConvexAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,const btCollisionObjectWrapper* body0Wrap,const btCollisionObjectWrapper* body1Wrap,btSimplexSolverInterface* simplexSolver, btConvexPenetrationDepthSolver* pdSolver,int numPerturbationIterations, int minimumPointsPerturbationThreshold) +btConvexConvexAlgorithm::btConvexConvexAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,const btCollisionObjectWrapper* body0Wrap,const btCollisionObjectWrapper* body1Wrap,btConvexPenetrationDepthSolver* pdSolver,int numPerturbationIterations, int minimumPointsPerturbationThreshold) : btActivatingCollisionAlgorithm(ci,body0Wrap,body1Wrap), -m_simplexSolver(simplexSolver), m_pdSolver(pdSolver), m_ownManifold (false), m_manifoldPtr(mf), @@ -349,8 +347,8 @@ void btConvexConvexAlgorithm ::processCollision (const btCollisionObjectWrapper* btGjkPairDetector::ClosestPointInput input; - - btGjkPairDetector gjkPairDetector(min0,min1,m_simplexSolver,m_pdSolver); + btVoronoiSimplexSolver simplexSolver; + btGjkPairDetector gjkPairDetector( min0, min1, &simplexSolver, m_pdSolver ); //TODO: if (dispatchInfo.m_useContinuous) gjkPairDetector.setMinkowskiA(min0); gjkPairDetector.setMinkowskiB(min1); @@ -367,7 +365,7 @@ void btConvexConvexAlgorithm ::processCollision (const btCollisionObjectWrapper* // input.m_maximumDistanceSquared = min0->getMargin() + min1->getMargin() + m_manifoldPtr->getContactProcessingThreshold(); //} else //{ - input.m_maximumDistanceSquared = min0->getMargin() + min1->getMargin() + m_manifoldPtr->getContactBreakingThreshold(); + input.m_maximumDistanceSquared = min0->getMargin() + min1->getMargin() + m_manifoldPtr->getContactBreakingThreshold()+resultOut->m_closestPointDistanceThreshold; // } input.m_maximumDistanceSquared*= input.m_maximumDistanceSquared; diff --git a/src/BulletCollision/CollisionDispatch/btConvexConvexAlgorithm.h b/src/BulletCollision/CollisionDispatch/btConvexConvexAlgorithm.h index d0ff3b3c1..cd75ba12d 100644 --- a/src/BulletCollision/CollisionDispatch/btConvexConvexAlgorithm.h +++ b/src/BulletCollision/CollisionDispatch/btConvexConvexAlgorithm.h @@ -43,7 +43,6 @@ class btConvexConvexAlgorithm : public btActivatingCollisionAlgorithm #ifdef USE_SEPDISTANCE_UTIL2 btConvexSeparatingDistanceUtil m_sepDistance; #endif - btSimplexSolverInterface* m_simplexSolver; btConvexPenetrationDepthSolver* m_pdSolver; btVertexArray worldVertsB1; @@ -62,7 +61,7 @@ class btConvexConvexAlgorithm : public btActivatingCollisionAlgorithm public: - btConvexConvexAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,const btCollisionObjectWrapper* body0Wrap,const btCollisionObjectWrapper* body1Wrap, btSimplexSolverInterface* simplexSolver, btConvexPenetrationDepthSolver* pdSolver, int numPerturbationIterations, int minimumPointsPerturbationThreshold); + btConvexConvexAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,const btCollisionObjectWrapper* body0Wrap,const btCollisionObjectWrapper* body1Wrap, btConvexPenetrationDepthSolver* pdSolver, int numPerturbationIterations, int minimumPointsPerturbationThreshold); virtual ~btConvexConvexAlgorithm(); @@ -90,18 +89,17 @@ public: { btConvexPenetrationDepthSolver* m_pdSolver; - btSimplexSolverInterface* m_simplexSolver; int m_numPerturbationIterations; int m_minimumPointsPerturbationThreshold; - CreateFunc(btSimplexSolverInterface* simplexSolver, btConvexPenetrationDepthSolver* pdSolver); + CreateFunc(btConvexPenetrationDepthSolver* pdSolver); virtual ~CreateFunc(); virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& ci, const btCollisionObjectWrapper* body0Wrap,const btCollisionObjectWrapper* body1Wrap) { void* mem = ci.m_dispatcher1->allocateCollisionAlgorithm(sizeof(btConvexConvexAlgorithm)); - return new(mem) btConvexConvexAlgorithm(ci.m_manifold,ci,body0Wrap,body1Wrap,m_simplexSolver,m_pdSolver,m_numPerturbationIterations,m_minimumPointsPerturbationThreshold); + return new(mem) btConvexConvexAlgorithm(ci.m_manifold,ci,body0Wrap,body1Wrap,m_pdSolver,m_numPerturbationIterations,m_minimumPointsPerturbationThreshold); } }; diff --git a/src/BulletCollision/CollisionDispatch/btDefaultCollisionConfiguration.cpp b/src/BulletCollision/CollisionDispatch/btDefaultCollisionConfiguration.cpp index 9a2e3394d..f6e4e57b0 100644 --- a/src/BulletCollision/CollisionDispatch/btDefaultCollisionConfiguration.cpp +++ b/src/BulletCollision/CollisionDispatch/btDefaultCollisionConfiguration.cpp @@ -44,9 +44,7 @@ btDefaultCollisionConfiguration::btDefaultCollisionConfiguration(const btDefault //btDefaultCollisionConfiguration::btDefaultCollisionConfiguration(btStackAlloc* stackAlloc,btPoolAllocator* persistentManifoldPool,btPoolAllocator* collisionAlgorithmPool) { - void* mem = btAlignedAlloc(sizeof(btVoronoiSimplexSolver),16); - m_simplexSolver = new (mem)btVoronoiSimplexSolver(); - + void* mem = NULL; if (constructionInfo.m_useEpaPenetrationAlgorithm) { mem = btAlignedAlloc(sizeof(btGjkEpaPenetrationDepthSolver),16); @@ -59,7 +57,7 @@ btDefaultCollisionConfiguration::btDefaultCollisionConfiguration(const btDefault //default CreationFunctions, filling the m_doubleDispatch table mem = btAlignedAlloc(sizeof(btConvexConvexAlgorithm::CreateFunc),16); - m_convexConvexCreateFunc = new(mem) btConvexConvexAlgorithm::CreateFunc(m_simplexSolver,m_pdSolver); + m_convexConvexCreateFunc = new(mem) btConvexConvexAlgorithm::CreateFunc(m_pdSolver); mem = btAlignedAlloc(sizeof(btConvexConcaveCollisionAlgorithm::CreateFunc),16); m_convexConcaveCreateFunc = new (mem)btConvexConcaveCollisionAlgorithm::CreateFunc; mem = btAlignedAlloc(sizeof(btConvexConcaveCollisionAlgorithm::CreateFunc),16); @@ -193,9 +191,6 @@ btDefaultCollisionConfiguration::~btDefaultCollisionConfiguration() m_planeConvexCF->~btCollisionAlgorithmCreateFunc(); btAlignedFree( m_planeConvexCF); - m_simplexSolver->~btVoronoiSimplexSolver(); - btAlignedFree(m_simplexSolver); - m_pdSolver->~btConvexPenetrationDepthSolver(); btAlignedFree(m_pdSolver); @@ -203,6 +198,86 @@ btDefaultCollisionConfiguration::~btDefaultCollisionConfiguration() } +btCollisionAlgorithmCreateFunc* btDefaultCollisionConfiguration::getClosestPointsAlgorithmCreateFunc(int proxyType0, int proxyType1) +{ + + + if ((proxyType0 == SPHERE_SHAPE_PROXYTYPE) && (proxyType1 == SPHERE_SHAPE_PROXYTYPE)) + { + return m_sphereSphereCF; + } +#ifdef USE_BUGGY_SPHERE_BOX_ALGORITHM + if ((proxyType0 == SPHERE_SHAPE_PROXYTYPE) && (proxyType1 == BOX_SHAPE_PROXYTYPE)) + { + return m_sphereBoxCF; + } + + if ((proxyType0 == BOX_SHAPE_PROXYTYPE) && (proxyType1 == SPHERE_SHAPE_PROXYTYPE)) + { + return m_boxSphereCF; + } +#endif //USE_BUGGY_SPHERE_BOX_ALGORITHM + + + if ((proxyType0 == SPHERE_SHAPE_PROXYTYPE) && (proxyType1 == TRIANGLE_SHAPE_PROXYTYPE)) + { + return m_sphereTriangleCF; + } + + if ((proxyType0 == TRIANGLE_SHAPE_PROXYTYPE) && (proxyType1 == SPHERE_SHAPE_PROXYTYPE)) + { + return m_triangleSphereCF; + } + + if (btBroadphaseProxy::isConvex(proxyType0) && (proxyType1 == STATIC_PLANE_PROXYTYPE)) + { + return m_convexPlaneCF; + } + + if (btBroadphaseProxy::isConvex(proxyType1) && (proxyType0 == STATIC_PLANE_PROXYTYPE)) + { + return m_planeConvexCF; + } + + + + if (btBroadphaseProxy::isConvex(proxyType0) && btBroadphaseProxy::isConvex(proxyType1)) + { + return m_convexConvexCreateFunc; + } + + if (btBroadphaseProxy::isConvex(proxyType0) && btBroadphaseProxy::isConcave(proxyType1)) + { + return m_convexConcaveCreateFunc; + } + + if (btBroadphaseProxy::isConvex(proxyType1) && btBroadphaseProxy::isConcave(proxyType0)) + { + return m_swappedConvexConcaveCreateFunc; + } + + + if (btBroadphaseProxy::isCompound(proxyType0) && btBroadphaseProxy::isCompound(proxyType1)) + { + return m_compoundCompoundCreateFunc; + } + + if (btBroadphaseProxy::isCompound(proxyType0)) + { + return m_compoundCreateFunc; + } + else + { + if (btBroadphaseProxy::isCompound(proxyType1)) + { + return m_swappedCompoundCreateFunc; + } + } + + //failed to find an algorithm + return m_emptyCreateFunc; + +} btCollisionAlgorithmCreateFunc* btDefaultCollisionConfiguration::getCollisionAlgorithmCreateFunc(int proxyType0,int proxyType1) { diff --git a/src/BulletCollision/CollisionDispatch/btDefaultCollisionConfiguration.h b/src/BulletCollision/CollisionDispatch/btDefaultCollisionConfiguration.h index 2078420e1..17c7596cf 100644 --- a/src/BulletCollision/CollisionDispatch/btDefaultCollisionConfiguration.h +++ b/src/BulletCollision/CollisionDispatch/btDefaultCollisionConfiguration.h @@ -60,8 +60,7 @@ protected: btPoolAllocator* m_collisionAlgorithmPool; bool m_ownsCollisionAlgorithmPool; - //default simplex/penetration depth solvers - btVoronoiSimplexSolver* m_simplexSolver; + //default penetration depth solver btConvexPenetrationDepthSolver* m_pdSolver; //default CreationFunctions, filling the m_doubleDispatch table @@ -102,14 +101,10 @@ public: } - virtual btVoronoiSimplexSolver* getSimplexSolver() - { - return m_simplexSolver; - } - - virtual btCollisionAlgorithmCreateFunc* getCollisionAlgorithmCreateFunc(int proxyType0,int proxyType1); + virtual btCollisionAlgorithmCreateFunc* getClosestPointsAlgorithmCreateFunc(int proxyType0, int proxyType1); + ///Use this method to allow to generate multiple contact points between at once, between two objects using the generic convex-convex algorithm. ///By default, this feature is disabled for best performance. ///@param numPerturbationIterations controls the number of collision queries. Set it to zero to disable the feature. diff --git a/src/BulletCollision/CollisionDispatch/btManifoldResult.cpp b/src/BulletCollision/CollisionDispatch/btManifoldResult.cpp index 96c1eb5d5..be8e51d52 100644 --- a/src/BulletCollision/CollisionDispatch/btManifoldResult.cpp +++ b/src/BulletCollision/CollisionDispatch/btManifoldResult.cpp @@ -96,6 +96,7 @@ btManifoldResult::btManifoldResult(const btCollisionObjectWrapper* body0Wrap,con m_index0(-1), m_index1(-1) #endif //DEBUG_PART_INDEX + , m_closestPointDistanceThreshold(0) { } diff --git a/src/BulletCollision/CollisionDispatch/btManifoldResult.h b/src/BulletCollision/CollisionDispatch/btManifoldResult.h index 55b6380a5..86bbc3f72 100644 --- a/src/BulletCollision/CollisionDispatch/btManifoldResult.h +++ b/src/BulletCollision/CollisionDispatch/btManifoldResult.h @@ -49,17 +49,19 @@ protected: int m_index0; int m_index1; - + public: btManifoldResult() -#ifdef DEBUG_PART_INDEX : +#ifdef DEBUG_PART_INDEX + m_partId0(-1), m_partId1(-1), m_index0(-1), m_index1(-1) #endif //DEBUG_PART_INDEX + m_closestPointDistanceThreshold(0) { } @@ -142,6 +144,8 @@ public: return m_body1Wrap->getCollisionObject(); } + btScalar m_closestPointDistanceThreshold; + /// in the future we can let the user override the methods to combine restitution and friction static btScalar calculateCombinedRestitution(const btCollisionObject* body0,const btCollisionObject* body1); static btScalar calculateCombinedFriction(const btCollisionObject* body0,const btCollisionObject* body1); diff --git a/src/BulletCollision/CollisionDispatch/btSphereSphereCollisionAlgorithm.cpp b/src/BulletCollision/CollisionDispatch/btSphereSphereCollisionAlgorithm.cpp index 36ba21f5b..27eaec305 100644 --- a/src/BulletCollision/CollisionDispatch/btSphereSphereCollisionAlgorithm.cpp +++ b/src/BulletCollision/CollisionDispatch/btSphereSphereCollisionAlgorithm.cpp @@ -12,6 +12,7 @@ subject to the following restrictions: 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ +#define CLEAR_MANIFOLD 1 #include "btSphereSphereCollisionAlgorithm.h" #include "BulletCollision/CollisionDispatch/btCollisionDispatcher.h" @@ -62,7 +63,7 @@ void btSphereSphereCollisionAlgorithm::processCollision (const btCollisionObject #endif ///iff distance positive, don't generate a new contact - if ( len > (radius0+radius1)) + if ( len > (radius0+radius1+resultOut->m_closestPointDistanceThreshold)) { #ifndef CLEAR_MANIFOLD resultOut->refreshContactPoints(); diff --git a/src/BulletCollision/CollisionDispatch/btSphereTriangleCollisionAlgorithm.cpp b/src/BulletCollision/CollisionDispatch/btSphereTriangleCollisionAlgorithm.cpp index 280a4d355..86d4e7440 100644 --- a/src/BulletCollision/CollisionDispatch/btSphereTriangleCollisionAlgorithm.cpp +++ b/src/BulletCollision/CollisionDispatch/btSphereTriangleCollisionAlgorithm.cpp @@ -56,7 +56,7 @@ void btSphereTriangleCollisionAlgorithm::processCollision (const btCollisionObje /// report a contact. internally this will be kept persistent, and contact reduction is done resultOut->setPersistentManifold(m_manifoldPtr); - SphereTriangleDetector detector(sphere,triangle, m_manifoldPtr->getContactBreakingThreshold()); + SphereTriangleDetector detector(sphere,triangle, m_manifoldPtr->getContactBreakingThreshold()+ resultOut->m_closestPointDistanceThreshold); btDiscreteCollisionDetectorInterface::ClosestPointInput input; input.m_maximumDistanceSquared = btScalar(BT_LARGE_FLOAT);///@todo: tighter bounds diff --git a/src/BulletCollision/CollisionShapes/btCollisionShape.h b/src/BulletCollision/CollisionShapes/btCollisionShape.h index 5e8656800..6c4916fbd 100644 --- a/src/BulletCollision/CollisionShapes/btCollisionShape.h +++ b/src/BulletCollision/CollisionShapes/btCollisionShape.h @@ -48,7 +48,7 @@ public: virtual void getBoundingSphere(btVector3& center,btScalar& radius) const; - ///getAngularMotionDisc returns the maximus radius needed for Conservative Advancement to handle time-of-impact with rotations. + ///getAngularMotionDisc returns the maximum radius needed for Conservative Advancement to handle time-of-impact with rotations. virtual btScalar getAngularMotionDisc() const; virtual btScalar getContactBreakingThreshold(btScalar defaultContactThresholdFactor) const; diff --git a/src/BulletCollision/Gimpact/btGImpactCollisionAlgorithm.h b/src/BulletCollision/Gimpact/btGImpactCollisionAlgorithm.h index f85a94cb4..3e5675f72 100644 --- a/src/BulletCollision/Gimpact/btGImpactCollisionAlgorithm.h +++ b/src/BulletCollision/Gimpact/btGImpactCollisionAlgorithm.h @@ -122,7 +122,7 @@ protected: checkManifold(body0Wrap,body1Wrap); btCollisionAlgorithm * convex_algorithm = m_dispatcher->findAlgorithm( - body0Wrap,body1Wrap,getLastManifold()); + body0Wrap,body1Wrap,getLastManifold(), BT_CONTACT_POINT_ALGORITHMS); return convex_algorithm ; } diff --git a/src/BulletCollision/Gimpact/btGImpactShape.cpp b/src/BulletCollision/Gimpact/btGImpactShape.cpp index ac8efdf38..30c85e3ff 100644 --- a/src/BulletCollision/Gimpact/btGImpactShape.cpp +++ b/src/BulletCollision/Gimpact/btGImpactShape.cpp @@ -23,6 +23,59 @@ subject to the following restrictions: #include "btGImpactMassUtil.h" +btGImpactMeshShapePart::btGImpactMeshShapePart( btStridingMeshInterface * meshInterface, int part ) +{ + // moved from .h to .cpp because of conditional compilation + // (The setting of BT_THREADSAFE may differ between various cpp files, so it is best to + // avoid using it in h files) + m_primitive_manager.m_meshInterface = meshInterface; + m_primitive_manager.m_part = part; + m_box_set.setPrimitiveManager( &m_primitive_manager ); +#if BT_THREADSAFE + // If threadsafe is requested, this object uses a different lock/unlock + // model with the btStridingMeshInterface -- lock once when the object is constructed + // and unlock once in the destructor. + // The other way of locking and unlocking for each collision check in the narrowphase + // is not threadsafe. Note these are not thread-locks, they are calls to the meshInterface's + // getLockedReadOnlyVertexIndexBase virtual function, which by default just returns a couple of + // pointers. In theory a client could override the lock function to do all sorts of + // things like reading data from GPU memory, or decompressing data on the fly, but such things + // do not seem all that likely or useful, given the performance cost. + m_primitive_manager.lock(); +#endif +} + +btGImpactMeshShapePart::~btGImpactMeshShapePart() +{ + // moved from .h to .cpp because of conditional compilation +#if BT_THREADSAFE + m_primitive_manager.unlock(); +#endif +} + +void btGImpactMeshShapePart::lockChildShapes() const +{ + // moved from .h to .cpp because of conditional compilation +#if ! BT_THREADSAFE + // called in the narrowphase -- not threadsafe! + void * dummy = (void*) ( m_box_set.getPrimitiveManager() ); + TrimeshPrimitiveManager * dummymanager = static_cast( dummy ); + dummymanager->lock(); +#endif +} + +void btGImpactMeshShapePart::unlockChildShapes() const +{ + // moved from .h to .cpp because of conditional compilation +#if ! BT_THREADSAFE + // called in the narrowphase -- not threadsafe! + void * dummy = (void*) ( m_box_set.getPrimitiveManager() ); + TrimeshPrimitiveManager * dummymanager = static_cast( dummy ); + dummymanager->unlock(); +#endif +} + + #define CALC_EXACT_INERTIA 1 diff --git a/src/BulletCollision/Gimpact/btGImpactShape.h b/src/BulletCollision/Gimpact/btGImpactShape.h index 3d1f48d47..9d7e40562 100644 --- a/src/BulletCollision/Gimpact/btGImpactShape.h +++ b/src/BulletCollision/Gimpact/btGImpactShape.h @@ -722,17 +722,8 @@ public: m_box_set.setPrimitiveManager(&m_primitive_manager); } - - btGImpactMeshShapePart(btStridingMeshInterface * meshInterface, int part) - { - m_primitive_manager.m_meshInterface = meshInterface; - m_primitive_manager.m_part = part; - m_box_set.setPrimitiveManager(&m_primitive_manager); - } - - virtual ~btGImpactMeshShapePart() - { - } + btGImpactMeshShapePart( btStridingMeshInterface * meshInterface, int part ); + virtual ~btGImpactMeshShapePart(); //! if true, then its children must get transforms. virtual bool childrenHasTransform() const @@ -742,19 +733,8 @@ public: //! call when reading child shapes - virtual void lockChildShapes() const - { - void * dummy = (void*)(m_box_set.getPrimitiveManager()); - TrimeshPrimitiveManager * dummymanager = static_cast(dummy); - dummymanager->lock(); - } - - virtual void unlockChildShapes() const - { - void * dummy = (void*)(m_box_set.getPrimitiveManager()); - TrimeshPrimitiveManager * dummymanager = static_cast(dummy); - dummymanager->unlock(); - } + virtual void lockChildShapes() const; + virtual void unlockChildShapes() const; //! Gets the number of children virtual int getNumChildShapes() const diff --git a/src/BulletCollision/NarrowPhaseCollision/btGjkPairDetector.cpp b/src/BulletCollision/NarrowPhaseCollision/btGjkPairDetector.cpp index a23ee3d88..257b026d9 100644 --- a/src/BulletCollision/NarrowPhaseCollision/btGjkPairDetector.cpp +++ b/src/BulletCollision/NarrowPhaseCollision/btGjkPairDetector.cpp @@ -32,14 +32,16 @@ subject to the following restrictions: //must be above the machine epsilon #ifdef BT_USE_DOUBLE_PRECISION #define REL_ERROR2 btScalar(1.0e-12) + btScalar gGjkEpaPenetrationTolerance = 1e-7; #else #define REL_ERROR2 btScalar(1.0e-6) + btScalar gGjkEpaPenetrationTolerance = 0.001; #endif //temp globals, to improve GJK/EPA/penetration calculations int gNumDeepPenetrationChecks = 0; int gNumGjkChecks = 0; -btScalar gGjkEpaPenetrationTolerance = 0.001; + btGjkPairDetector::btGjkPairDetector(const btConvexShape* objectA,const btConvexShape* objectB,btSimplexSolverInterface* simplexSolver,btConvexPenetrationDepthSolver* penetrationDepthSolver) :m_cachedSeparatingAxis(btScalar(0.),btScalar(1.),btScalar(0.)), @@ -279,7 +281,7 @@ void btGjkPairDetector::getClosestPointsNonVirtual(const ClosestPointInput& inpu btScalar lenSqr =m_cachedSeparatingAxis.length2(); //valid normal - if (lenSqr < 0.0001) + if (lenSqr < REL_ERROR2) { m_degenerateSimplex = 5; } @@ -351,46 +353,7 @@ void btGjkPairDetector::getClosestPointsNonVirtual(const ClosestPointInput& inpu pointOnA = tmpPointOnA; pointOnB = tmpPointOnB; normalInB = tmpNormalInB; - ///todo: need to track down this EPA penetration solver degeneracy - ///the penetration solver reports penetration but the contact normal - ///connecting the contact points is pointing in the opposite direction - ///until then, detect the issue and revert the normal - { - btScalar d1=0; - { - btVector3 seperatingAxisInA = (normalInB)* input.m_transformA.getBasis(); - btVector3 seperatingAxisInB = -normalInB* input.m_transformB.getBasis(); - - - btVector3 pInA = m_minkowskiA->localGetSupportVertexWithoutMarginNonVirtual(seperatingAxisInA); - btVector3 qInB = m_minkowskiB->localGetSupportVertexWithoutMarginNonVirtual(seperatingAxisInB); - - btVector3 pWorld = localTransA(pInA); - btVector3 qWorld = localTransB(qInB); - btVector3 w = pWorld - qWorld; - d1 = (-normalInB).dot(w); - } - btScalar d0 = 0.f; - { - btVector3 seperatingAxisInA = (-normalInB)* input.m_transformA.getBasis(); - btVector3 seperatingAxisInB = normalInB* input.m_transformB.getBasis(); - - - btVector3 pInA = m_minkowskiA->localGetSupportVertexWithoutMarginNonVirtual(seperatingAxisInA); - btVector3 qInB = m_minkowskiB->localGetSupportVertexWithoutMarginNonVirtual(seperatingAxisInB); - - btVector3 pWorld = localTransA(pInA); - btVector3 qWorld = localTransB(qInB); - btVector3 w = pWorld - qWorld; - d0 = normalInB.dot(w); - } - if (d1>d0) - { - m_lastUsedMethod = 10; - normalInB*=-1; - } - - } + isValid = true; } else @@ -447,6 +410,47 @@ void btGjkPairDetector::getClosestPointsNonVirtual(const ClosestPointInput& inpu m_cachedSeparatingAxis = normalInB; m_cachedSeparatingDistance = distance; + { + ///todo: need to track down this EPA penetration solver degeneracy + ///the penetration solver reports penetration but the contact normal + ///connecting the contact points is pointing in the opposite direction + ///until then, detect the issue and revert the normal + + btScalar d1=0; + { + btVector3 seperatingAxisInA = (normalInB)* input.m_transformA.getBasis(); + btVector3 seperatingAxisInB = -normalInB* input.m_transformB.getBasis(); + + + btVector3 pInA = m_minkowskiA->localGetSupportVertexWithoutMarginNonVirtual(seperatingAxisInA); + btVector3 qInB = m_minkowskiB->localGetSupportVertexWithoutMarginNonVirtual(seperatingAxisInB); + + btVector3 pWorld = localTransA(pInA); + btVector3 qWorld = localTransB(qInB); + btVector3 w = pWorld - qWorld; + d1 = (-normalInB).dot(w); + } + btScalar d0 = 0.f; + { + btVector3 seperatingAxisInA = (-normalInB)* input.m_transformA.getBasis(); + btVector3 seperatingAxisInB = normalInB* input.m_transformB.getBasis(); + + + btVector3 pInA = m_minkowskiA->localGetSupportVertexWithoutMarginNonVirtual(seperatingAxisInA); + btVector3 qInB = m_minkowskiB->localGetSupportVertexWithoutMarginNonVirtual(seperatingAxisInB); + + btVector3 pWorld = localTransA(pInA); + btVector3 qWorld = localTransB(qInB); + btVector3 w = pWorld - qWorld; + d0 = normalInB.dot(w); + } + if (d1>d0) + { + m_lastUsedMethod = 10; + normalInB*=-1; + } + + } output.addContactPoint( normalInB, pointOnB+positionOffset, diff --git a/src/BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.h b/src/BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.h index 2f389e27e..80fd490f4 100644 --- a/src/BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.h +++ b/src/BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.h @@ -26,8 +26,12 @@ subject to the following restrictions: ///disable next define, or use defaultCollisionConfiguration->getSimplexSolver()->setEqualVertexThreshold(0.f) to disable/configure #define BT_USE_EQUAL_VERTEX_THRESHOLD -#define VORONOI_DEFAULT_EQUAL_VERTEX_THRESHOLD 0.0001f +#ifdef BT_USE_DOUBLE_PRECISION +#define VORONOI_DEFAULT_EQUAL_VERTEX_THRESHOLD 1e-12f +#else +#define VORONOI_DEFAULT_EQUAL_VERTEX_THRESHOLD 0.0001f +#endif//BT_USE_DOUBLE_PRECISION struct btUsageBitfield{ btUsageBitfield() diff --git a/src/BulletDynamics/CMakeLists.txt b/src/BulletDynamics/CMakeLists.txt index 656fc8433..4023d721e 100644 --- a/src/BulletDynamics/CMakeLists.txt +++ b/src/BulletDynamics/CMakeLists.txt @@ -21,6 +21,8 @@ SET(BulletDynamics_SRCS ConstraintSolver/btTypedConstraint.cpp ConstraintSolver/btUniversalConstraint.cpp Dynamics/btDiscreteDynamicsWorld.cpp + Dynamics/btDiscreteDynamicsWorldMt.cpp + Dynamics/btSimulationIslandManagerMt.cpp Dynamics/btRigidBody.cpp Dynamics/btSimpleDynamicsWorld.cpp # Dynamics/Bullet-C-API.cpp @@ -70,6 +72,8 @@ SET(ConstraintSolver_HDRS SET(Dynamics_HDRS Dynamics/btActionInterface.h Dynamics/btDiscreteDynamicsWorld.h + Dynamics/btDiscreteDynamicsWorldMt.h + Dynamics/btSimulationIslandManagerMt.h Dynamics/btDynamicsWorld.h Dynamics/btSimpleDynamicsWorld.h Dynamics/btRigidBody.h diff --git a/src/BulletDynamics/ConstraintSolver/btContactSolverInfo.h b/src/BulletDynamics/ConstraintSolver/btContactSolverInfo.h index cf310da76..739b066fe 100644 --- a/src/BulletDynamics/ConstraintSolver/btContactSolverInfo.h +++ b/src/BulletDynamics/ConstraintSolver/btContactSolverInfo.h @@ -58,7 +58,7 @@ struct btContactSolverInfoData int m_minimumSolverBatchSize; btScalar m_maxGyroscopicForce; btScalar m_singleAxisRollingFrictionThreshold; - + btScalar m_leastSquaresResidualThreshold; }; @@ -91,6 +91,7 @@ struct btContactSolverInfo : public btContactSolverInfoData m_minimumSolverBatchSize = 128; //try to combine islands until the amount of constraints reaches this limit m_maxGyroscopicForce = 100.f; ///it is only used for 'explicit' version of gyroscopic force m_singleAxisRollingFrictionThreshold = 1e30f;///if the velocity is above this threshold, it will use a single constraint row (axis), otherwise 3 rows. + m_leastSquaresResidualThreshold = 0.f; } }; diff --git a/src/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.cpp b/src/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.cpp index aced8fae1..c14999112 100644 --- a/src/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.cpp +++ b/src/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.cpp @@ -39,7 +39,7 @@ int gNumSplitImpulseRecoveries = 0; #include "BulletDynamics/Dynamics/btRigidBody.h" - +//#define VERBOSE_RESIDUAL_PRINTF 1 ///This is the scalar reference implementation of solving a single constraint row, the innerloop of the Projected Gauss Seidel/Sequential Impulse constraint solver ///Below are optional SSE2 and SSE4/FMA3 versions. We assume most hardware has SSE2. For SSE4/FMA3 we perform a CPU feature check. static btSimdScalar gResolveSingleConstraintRowGeneric_scalar_reference(btSolverBody& body1, btSolverBody& body2, const btSolverConstraint& c) @@ -298,15 +298,17 @@ btSimdScalar btSequentialImpulseConstraintSolver::resolveSingleConstraintRowLowe } -void btSequentialImpulseConstraintSolver::resolveSplitPenetrationImpulseCacheFriendly( +btScalar btSequentialImpulseConstraintSolver::resolveSplitPenetrationImpulseCacheFriendly( btSolverBody& body1, btSolverBody& body2, const btSolverConstraint& c) { + btScalar deltaImpulse = 0.f; + if (c.m_rhsPenetration) { gNumSplitImpulseRecoveries++; - btScalar deltaImpulse = c.m_rhsPenetration-btScalar(c.m_appliedPushImpulse)*c.m_cfm; + deltaImpulse = c.m_rhsPenetration-btScalar(c.m_appliedPushImpulse)*c.m_cfm; const btScalar deltaVel1Dotn = c.m_contactNormal1.dot(body1.internalGetPushVelocity()) + c.m_relpos1CrossNormal.dot(body1.internalGetTurnVelocity()); const btScalar deltaVel2Dotn = c.m_contactNormal2.dot(body2.internalGetPushVelocity()) + c.m_relpos2CrossNormal.dot(body2.internalGetTurnVelocity()); @@ -325,13 +327,14 @@ void btSequentialImpulseConstraintSolver::resolveSplitPenetrationImpulseCacheFri body1.internalApplyPushImpulse(c.m_contactNormal1*body1.internalGetInvMass(),c.m_angularComponentA,deltaImpulse); body2.internalApplyPushImpulse(c.m_contactNormal2*body2.internalGetInvMass(),c.m_angularComponentB,deltaImpulse); } + return deltaImpulse; } - void btSequentialImpulseConstraintSolver::resolveSplitPenetrationSIMD(btSolverBody& body1,btSolverBody& body2,const btSolverConstraint& c) +btSimdScalar btSequentialImpulseConstraintSolver::resolveSplitPenetrationSIMD(btSolverBody& body1,btSolverBody& body2,const btSolverConstraint& c) { #ifdef USE_SIMD if (!c.m_rhsPenetration) - return; + return 0.f; gNumSplitImpulseRecoveries++; @@ -357,8 +360,9 @@ void btSequentialImpulseConstraintSolver::resolveSplitPenetrationImpulseCacheFri body1.internalGetTurnVelocity().mVec128 = _mm_add_ps(body1.internalGetTurnVelocity().mVec128 ,_mm_mul_ps(c.m_angularComponentA.mVec128,impulseMagnitude)); body2.internalGetPushVelocity().mVec128 = _mm_add_ps(body2.internalGetPushVelocity().mVec128,_mm_mul_ps(linearComponentB,impulseMagnitude)); body2.internalGetTurnVelocity().mVec128 = _mm_add_ps(body2.internalGetTurnVelocity().mVec128 ,_mm_mul_ps(c.m_angularComponentB.mVec128,impulseMagnitude)); + return deltaImpulse; #else - resolveSplitPenetrationImpulseCacheFriendly(body1,body2,c); + return resolveSplitPenetrationImpulseCacheFriendly(body1,body2,c); #endif } @@ -716,8 +720,67 @@ btSolverConstraint& btSequentialImpulseConstraintSolver::addTorsionalFrictionCon int btSequentialImpulseConstraintSolver::getOrInitSolverBody(btCollisionObject& body,btScalar timeStep) { +#if BT_THREADSAFE + int solverBodyId = -1; + if ( !body.isStaticOrKinematicObject() ) + { + // dynamic body + // Dynamic bodies can only be in one island, so it's safe to write to the companionId + solverBodyId = body.getCompanionId(); + if ( solverBodyId < 0 ) + { + if ( btRigidBody* rb = btRigidBody::upcast( &body ) ) + { + solverBodyId = m_tmpSolverBodyPool.size(); + btSolverBody& solverBody = m_tmpSolverBodyPool.expand(); + initSolverBody( &solverBody, &body, timeStep ); + body.setCompanionId( solverBodyId ); + } + } + } + else if (body.isKinematicObject()) + { + // + // NOTE: must test for kinematic before static because some kinematic objects also + // identify as "static" + // + // Kinematic bodies can be in multiple islands at once, so it is a + // race condition to write to them, so we use an alternate method + // to record the solverBodyId + int uniqueId = body.getWorldArrayIndex(); + const int INVALID_SOLVER_BODY_ID = -1; + if (uniqueId >= m_kinematicBodyUniqueIdToSolverBodyTable.size()) + { + m_kinematicBodyUniqueIdToSolverBodyTable.resize(uniqueId + 1, INVALID_SOLVER_BODY_ID); + } + solverBodyId = m_kinematicBodyUniqueIdToSolverBodyTable[ uniqueId ]; + // if no table entry yet, + if ( solverBodyId == INVALID_SOLVER_BODY_ID ) + { + // create a table entry for this body + btRigidBody* rb = btRigidBody::upcast( &body ); + solverBodyId = m_tmpSolverBodyPool.size(); + btSolverBody& solverBody = m_tmpSolverBodyPool.expand(); + initSolverBody( &solverBody, &body, timeStep ); + m_kinematicBodyUniqueIdToSolverBodyTable[ uniqueId ] = solverBodyId; + } + } + else + { + // all fixed bodies (inf mass) get mapped to a single solver id + if ( m_fixedBodyId < 0 ) + { + m_fixedBodyId = m_tmpSolverBodyPool.size(); + btSolverBody& fixedBody = m_tmpSolverBodyPool.expand(); + initSolverBody( &fixedBody, 0, timeStep ); + } + solverBodyId = m_fixedBodyId; + } + btAssert( solverBodyId < m_tmpSolverBodyPool.size() ); + return solverBodyId; +#else // BT_THREADSAFE - int solverBodyIdA = -1; + int solverBodyIdA = -1; if (body.getCompanionId() >= 0) { @@ -749,6 +812,7 @@ int btSequentialImpulseConstraintSolver::getOrInitSolverBody(btCollisionObject& } return solverBodyIdA; +#endif // BT_THREADSAFE } #include @@ -1263,7 +1327,9 @@ btScalar btSequentialImpulseConstraintSolver::solveGroupCacheFriendlySetup(btCol { bodies[i]->setCompanionId(-1); } - +#if BT_THREADSAFE + m_kinematicBodyUniqueIdToSolverBodyTable.resize( 0 ); +#endif // BT_THREADSAFE m_tmpSolverBodyPool.reserve(numBodies+1); m_tmpSolverBodyPool.resize(0); @@ -1542,6 +1608,7 @@ btScalar btSequentialImpulseConstraintSolver::solveGroupCacheFriendlySetup(btCol btScalar btSequentialImpulseConstraintSolver::solveSingleIteration(int iteration, btCollisionObject** /*bodies */,int /*numBodies*/,btPersistentManifold** /*manifoldPtr*/, int /*numManifolds*/,btTypedConstraint** constraints,int numConstraints,const btContactSolverInfo& infoGlobal,btIDebugDraw* /*debugDrawer*/) { + btScalar leastSquaresResidual = 0.f; int numNonContactPool = m_tmpSolverNonContactConstraintPool.size(); int numConstraintPool = m_tmpSolverContactConstraintPool.size(); @@ -1586,7 +1653,10 @@ btScalar btSequentialImpulseConstraintSolver::solveSingleIteration(int iteration { btSolverConstraint& constraint = m_tmpSolverNonContactConstraintPool[m_orderNonContactConstraintPool[j]]; if (iteration < constraint.m_overrideNumSolverIterations) - resolveSingleConstraintRowGenericSIMD(m_tmpSolverBodyPool[constraint.m_solverBodyIdA],m_tmpSolverBodyPool[constraint.m_solverBodyIdB],constraint); + { + btScalar residual = resolveSingleConstraintRowGenericSIMD(m_tmpSolverBodyPool[constraint.m_solverBodyIdA],m_tmpSolverBodyPool[constraint.m_solverBodyIdB],constraint); + leastSquaresResidual += residual*residual; + } } if (iteration< infoGlobal.m_numIterations) @@ -1615,7 +1685,9 @@ btScalar btSequentialImpulseConstraintSolver::solveSingleIteration(int iteration { const btSolverConstraint& solveManifold = m_tmpSolverContactConstraintPool[m_orderTmpConstraintPool[c]]; - resolveSingleConstraintRowLowerLimitSIMD(m_tmpSolverBodyPool[solveManifold.m_solverBodyIdA],m_tmpSolverBodyPool[solveManifold.m_solverBodyIdB],solveManifold); + btScalar residual = resolveSingleConstraintRowLowerLimitSIMD(m_tmpSolverBodyPool[solveManifold.m_solverBodyIdA],m_tmpSolverBodyPool[solveManifold.m_solverBodyIdB],solveManifold); + leastSquaresResidual += residual*residual; + totalImpulse = solveManifold.m_appliedImpulse; } bool applyFriction = true; @@ -1630,7 +1702,8 @@ btScalar btSequentialImpulseConstraintSolver::solveSingleIteration(int iteration solveManifold.m_lowerLimit = -(solveManifold.m_friction*totalImpulse); solveManifold.m_upperLimit = solveManifold.m_friction*totalImpulse; - resolveSingleConstraintRowGenericSIMD(m_tmpSolverBodyPool[solveManifold.m_solverBodyIdA],m_tmpSolverBodyPool[solveManifold.m_solverBodyIdB],solveManifold); + btScalar residual = resolveSingleConstraintRowGenericSIMD(m_tmpSolverBodyPool[solveManifold.m_solverBodyIdA],m_tmpSolverBodyPool[solveManifold.m_solverBodyIdB],solveManifold); + leastSquaresResidual += residual*residual; } } @@ -1644,7 +1717,8 @@ btScalar btSequentialImpulseConstraintSolver::solveSingleIteration(int iteration solveManifold.m_lowerLimit = -(solveManifold.m_friction*totalImpulse); solveManifold.m_upperLimit = solveManifold.m_friction*totalImpulse; - resolveSingleConstraintRowGenericSIMD(m_tmpSolverBodyPool[solveManifold.m_solverBodyIdA],m_tmpSolverBodyPool[solveManifold.m_solverBodyIdB],solveManifold); + btScalar residual = resolveSingleConstraintRowGenericSIMD(m_tmpSolverBodyPool[solveManifold.m_solverBodyIdA],m_tmpSolverBodyPool[solveManifold.m_solverBodyIdB],solveManifold); + leastSquaresResidual += residual*residual; } } } @@ -1660,8 +1734,8 @@ btScalar btSequentialImpulseConstraintSolver::solveSingleIteration(int iteration for (j=0;j=(infoGlobal.m_numIterations-1)) + { +#ifdef VERBOSE_RESIDUAL_PRINTF + printf("residual = %f at iteration #%d\n",leastSquaresResidual,iteration); +#endif + break; + } } } else { for ( iteration = 0;iteration=(infoGlobal.m_numIterations-1)) + { +#ifdef VERBOSE_RESIDUAL_PRINTF + printf("residual = %f at iteration #%d\n",leastSquaresResidual,iteration); +#endif + break; } } } @@ -1829,7 +1929,15 @@ btScalar btSequentialImpulseConstraintSolver::solveGroupCacheFriendlyIterations( for ( int iteration = 0 ; iteration< maxIterations ; iteration++) //for ( int iteration = maxIterations-1 ; iteration >= 0;iteration--) { - solveSingleIteration(iteration, bodies ,numBodies,manifoldPtr, numManifolds,constraints,numConstraints,infoGlobal,debugDrawer); + m_leastSquaresResidual = solveSingleIteration(iteration, bodies ,numBodies,manifoldPtr, numManifolds,constraints,numConstraints,infoGlobal,debugDrawer); + + if (m_leastSquaresResidual <= infoGlobal.m_leastSquaresResidualThreshold || (iteration>= (maxIterations-1))) + { +#ifdef VERBOSE_RESIDUAL_PRINTF + printf("residual = %f at iteration #%d\n",m_leastSquaresResidual,iteration); +#endif + break; + } } } diff --git a/src/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.h b/src/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.h index 7eafa3a68..0dd31d142 100644 --- a/src/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.h +++ b/src/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.h @@ -45,10 +45,20 @@ protected: btAlignedObjectArray m_tmpConstraintSizesPool; int m_maxOverrideNumSolverIterations; int m_fixedBodyId; + // When running solvers on multiple threads, a race condition exists for Kinematic objects that + // participate in more than one solver. + // The getOrInitSolverBody() function writes the companionId of each body (storing the index of the solver body + // for the current solver). For normal dynamic bodies it isn't an issue because they can only be in one island + // (and therefore one thread) at a time. But kinematic bodies can be in multiple islands at once. + // To avoid this race condition, this solver does not write the companionId, instead it stores the solver body + // index in this solver-local table, indexed by the uniqueId of the body. + btAlignedObjectArray m_kinematicBodyUniqueIdToSolverBodyTable; // only used for multithreading btSingleConstraintRowSolver m_resolveSingleConstraintRowGeneric; btSingleConstraintRowSolver m_resolveSingleConstraintRowLowerLimit; + btScalar m_leastSquaresResidual; + void setupFrictionConstraint( btSolverConstraint& solverConstraint, const btVector3& normalAxis,int solverBodyIdA,int solverBodyIdB, btManifoldPoint& cp,const btVector3& rel_pos1,const btVector3& rel_pos2, btCollisionObject* colObj0,btCollisionObject* colObj1, btScalar relaxation, @@ -82,11 +92,11 @@ protected: void convertContact(btPersistentManifold* manifold,const btContactSolverInfo& infoGlobal); - void resolveSplitPenetrationSIMD( + btSimdScalar resolveSplitPenetrationSIMD( btSolverBody& bodyA,btSolverBody& bodyB, const btSolverConstraint& contactConstraint); - void resolveSplitPenetrationImpulseCacheFriendly( + btScalar resolveSplitPenetrationImpulseCacheFriendly( btSolverBody& bodyA,btSolverBody& bodyB, const btSolverConstraint& contactConstraint); diff --git a/src/BulletDynamics/Dynamics/btDiscreteDynamicsWorld.cpp b/src/BulletDynamics/Dynamics/btDiscreteDynamicsWorld.cpp index 361a054ec..808f2720c 100644 --- a/src/BulletDynamics/Dynamics/btDiscreteDynamicsWorld.cpp +++ b/src/BulletDynamics/Dynamics/btDiscreteDynamicsWorld.cpp @@ -878,25 +878,12 @@ public: int gNumClampedCcdMotions=0; -void btDiscreteDynamicsWorld::createPredictiveContacts(btScalar timeStep) +void btDiscreteDynamicsWorld::createPredictiveContactsInternal( btRigidBody** bodies, int numBodies, btScalar timeStep) { - BT_PROFILE("createPredictiveContacts"); - - { - BT_PROFILE("release predictive contact manifolds"); - - for (int i=0;im_dispatcher1->releaseManifold(manifold); - } - m_predictiveManifolds.clear(); - } - btTransform predictedTrans; - for ( int i=0;isetHitFraction(1.f); if (body->isActive() && (!body->isStaticOrKinematicObject())) @@ -953,7 +940,9 @@ void btDiscreteDynamicsWorld::createPredictiveContacts(btScalar timeStep) btPersistentManifold* manifold = m_dispatcher1->getNewManifold(body,sweepResults.m_hitCollisionObject); + btMutexLock( &m_predictiveManifoldsMutex ); m_predictiveManifolds.push_back(manifold); + btMutexUnlock( &m_predictiveManifoldsMutex ); btVector3 worldPointB = body->getWorldTransform().getOrigin()+distVec; btVector3 localPointB = sweepResults.m_hitCollisionObject->getWorldTransform().inverse()*worldPointB; @@ -974,13 +963,35 @@ void btDiscreteDynamicsWorld::createPredictiveContacts(btScalar timeStep) } } } -void btDiscreteDynamicsWorld::integrateTransforms(btScalar timeStep) + +void btDiscreteDynamicsWorld::releasePredictiveContacts() +{ + BT_PROFILE( "release predictive contact manifolds" ); + + for ( int i = 0; i < m_predictiveManifolds.size(); i++ ) + { + btPersistentManifold* manifold = m_predictiveManifolds[ i ]; + this->m_dispatcher1->releaseManifold( manifold ); + } + m_predictiveManifolds.clear(); +} + +void btDiscreteDynamicsWorld::createPredictiveContacts(btScalar timeStep) +{ + BT_PROFILE("createPredictiveContacts"); + releasePredictiveContacts(); + if (m_nonStaticRigidBodies.size() > 0) + { + createPredictiveContactsInternal( &m_nonStaticRigidBodies[ 0 ], m_nonStaticRigidBodies.size(), timeStep ); + } +} + +void btDiscreteDynamicsWorld::integrateTransformsInternal( btRigidBody** bodies, int numBodies, btScalar timeStep ) { - BT_PROFILE("integrateTransforms"); btTransform predictedTrans; - for ( int i=0;isetHitFraction(1.f); if (body->isActive() && (!body->isStaticOrKinematicObject())) @@ -1080,7 +1091,17 @@ void btDiscreteDynamicsWorld::integrateTransforms(btScalar timeStep) } - ///this should probably be switched on by default, but it is not well tested yet +} + +void btDiscreteDynamicsWorld::integrateTransforms(btScalar timeStep) +{ + BT_PROFILE("integrateTransforms"); + if (m_nonStaticRigidBodies.size() > 0) + { + integrateTransformsInternal(&m_nonStaticRigidBodies[0], m_nonStaticRigidBodies.size(), timeStep); + } + + ///this should probably be switched on by default, but it is not well tested yet if (m_applySpeculativeContactRestitution) { BT_PROFILE("apply speculative contact restitution"); @@ -1114,14 +1135,12 @@ void btDiscreteDynamicsWorld::integrateTransforms(btScalar timeStep) } } } - } - void btDiscreteDynamicsWorld::predictUnconstraintMotion(btScalar timeStep) { BT_PROFILE("predictUnconstraintMotion"); diff --git a/src/BulletDynamics/Dynamics/btDiscreteDynamicsWorld.h b/src/BulletDynamics/Dynamics/btDiscreteDynamicsWorld.h index dd3d1c366..d2789cc6b 100644 --- a/src/BulletDynamics/Dynamics/btDiscreteDynamicsWorld.h +++ b/src/BulletDynamics/Dynamics/btDiscreteDynamicsWorld.h @@ -30,6 +30,7 @@ class btIDebugDraw; struct InplaceSolverIslandCallback; #include "LinearMath/btAlignedObjectArray.h" +#include "LinearMath/btThreads.h" ///btDiscreteDynamicsWorld provides discrete rigid body simulation @@ -68,9 +69,11 @@ protected: bool m_latencyMotionStateInterpolation; btAlignedObjectArray m_predictiveManifolds; + btSpinMutex m_predictiveManifoldsMutex; // used to synchronize threads creating predictive contacts virtual void predictUnconstraintMotion(btScalar timeStep); + void integrateTransformsInternal( btRigidBody** bodies, int numBodies, btScalar timeStep ); // can be called in parallel virtual void integrateTransforms(btScalar timeStep); virtual void calculateSimulationIslands(); @@ -85,7 +88,9 @@ protected: virtual void internalSingleStepSimulation( btScalar timeStep); - void createPredictiveContacts(btScalar timeStep); + void releasePredictiveContacts(); + void createPredictiveContactsInternal( btRigidBody** bodies, int numBodies, btScalar timeStep ); // can be called in parallel + virtual void createPredictiveContacts(btScalar timeStep); virtual void saveKinematicState(btScalar timeStep); diff --git a/src/BulletDynamics/Dynamics/btDiscreteDynamicsWorldMt.cpp b/src/BulletDynamics/Dynamics/btDiscreteDynamicsWorldMt.cpp new file mode 100644 index 000000000..5e51a994c --- /dev/null +++ b/src/BulletDynamics/Dynamics/btDiscreteDynamicsWorldMt.cpp @@ -0,0 +1,162 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + + +#include "btDiscreteDynamicsWorldMt.h" + +//collision detection +#include "BulletCollision/CollisionDispatch/btCollisionDispatcher.h" +#include "BulletCollision/BroadphaseCollision/btSimpleBroadphase.h" +#include "BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h" +#include "BulletCollision/CollisionShapes/btCollisionShape.h" +#include "btSimulationIslandManagerMt.h" +#include "LinearMath/btTransformUtil.h" +#include "LinearMath/btQuickprof.h" + +//rigidbody & constraints +#include "BulletDynamics/Dynamics/btRigidBody.h" +#include "BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.h" +#include "BulletDynamics/ConstraintSolver/btContactSolverInfo.h" +#include "BulletDynamics/ConstraintSolver/btTypedConstraint.h" +#include "BulletDynamics/ConstraintSolver/btPoint2PointConstraint.h" +#include "BulletDynamics/ConstraintSolver/btHingeConstraint.h" +#include "BulletDynamics/ConstraintSolver/btConeTwistConstraint.h" +#include "BulletDynamics/ConstraintSolver/btGeneric6DofConstraint.h" +#include "BulletDynamics/ConstraintSolver/btGeneric6DofSpring2Constraint.h" +#include "BulletDynamics/ConstraintSolver/btSliderConstraint.h" +#include "BulletDynamics/ConstraintSolver/btContactConstraint.h" + + +#include "LinearMath/btIDebugDraw.h" +#include "BulletCollision/CollisionShapes/btSphereShape.h" + + +#include "BulletDynamics/Dynamics/btActionInterface.h" +#include "LinearMath/btQuickprof.h" +#include "LinearMath/btMotionState.h" + +#include "LinearMath/btSerializer.h" + + +struct InplaceSolverIslandCallbackMt : public btSimulationIslandManagerMt::IslandCallback +{ + btContactSolverInfo* m_solverInfo; + btConstraintSolver* m_solver; + btIDebugDraw* m_debugDrawer; + btDispatcher* m_dispatcher; + + InplaceSolverIslandCallbackMt( + btConstraintSolver* solver, + btStackAlloc* stackAlloc, + btDispatcher* dispatcher) + :m_solverInfo(NULL), + m_solver(solver), + m_debugDrawer(NULL), + m_dispatcher(dispatcher) + { + + } + + InplaceSolverIslandCallbackMt& operator=(InplaceSolverIslandCallbackMt& other) + { + btAssert(0); + (void)other; + return *this; + } + + SIMD_FORCE_INLINE void setup ( btContactSolverInfo* solverInfo, btIDebugDraw* debugDrawer) + { + btAssert(solverInfo); + m_solverInfo = solverInfo; + m_debugDrawer = debugDrawer; + } + + + virtual void processIsland( btCollisionObject** bodies, + int numBodies, + btPersistentManifold** manifolds, + int numManifolds, + btTypedConstraint** constraints, + int numConstraints, + int islandId + ) + { + m_solver->solveGroup( bodies, + numBodies, + manifolds, + numManifolds, + constraints, + numConstraints, + *m_solverInfo, + m_debugDrawer, + m_dispatcher + ); + } + +}; + + + +btDiscreteDynamicsWorldMt::btDiscreteDynamicsWorldMt(btDispatcher* dispatcher,btBroadphaseInterface* pairCache,btConstraintSolver* constraintSolver, btCollisionConfiguration* collisionConfiguration) +: btDiscreteDynamicsWorld(dispatcher,pairCache,constraintSolver,collisionConfiguration) +{ + if (m_ownsIslandManager) + { + m_islandManager->~btSimulationIslandManager(); + btAlignedFree( m_islandManager); + } + { + void* mem = btAlignedAlloc(sizeof(InplaceSolverIslandCallbackMt),16); + m_solverIslandCallbackMt = new (mem) InplaceSolverIslandCallbackMt (m_constraintSolver, 0, dispatcher); + } + { + void* mem = btAlignedAlloc(sizeof(btSimulationIslandManagerMt),16); + btSimulationIslandManagerMt* im = new (mem) btSimulationIslandManagerMt(); + m_islandManager = im; + im->setMinimumSolverBatchSize( m_solverInfo.m_minimumSolverBatchSize ); + } +} + + +btDiscreteDynamicsWorldMt::~btDiscreteDynamicsWorldMt() +{ + if (m_solverIslandCallbackMt) + { + m_solverIslandCallbackMt->~InplaceSolverIslandCallbackMt(); + btAlignedFree(m_solverIslandCallbackMt); + } + if (m_ownsConstraintSolver) + { + m_constraintSolver->~btConstraintSolver(); + btAlignedFree(m_constraintSolver); + } +} + + +void btDiscreteDynamicsWorldMt::solveConstraints(btContactSolverInfo& solverInfo) +{ + BT_PROFILE("solveConstraints"); + + m_solverIslandCallbackMt->setup(&solverInfo, getDebugDrawer()); + m_constraintSolver->prepareSolve(getCollisionWorld()->getNumCollisionObjects(), getCollisionWorld()->getDispatcher()->getNumManifolds()); + + /// solve all the constraints for this island + btSimulationIslandManagerMt* im = static_cast(m_islandManager); + im->buildAndProcessIslands( getCollisionWorld()->getDispatcher(), getCollisionWorld(), m_constraints, m_solverIslandCallbackMt ); + + m_constraintSolver->allSolved(solverInfo, m_debugDrawer); +} + + diff --git a/src/BulletDynamics/Dynamics/btDiscreteDynamicsWorldMt.h b/src/BulletDynamics/Dynamics/btDiscreteDynamicsWorldMt.h new file mode 100644 index 000000000..b28371b51 --- /dev/null +++ b/src/BulletDynamics/Dynamics/btDiscreteDynamicsWorldMt.h @@ -0,0 +1,42 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + + +#ifndef BT_DISCRETE_DYNAMICS_WORLD_MT_H +#define BT_DISCRETE_DYNAMICS_WORLD_MT_H + +#include "btDiscreteDynamicsWorld.h" + +struct InplaceSolverIslandCallbackMt; + +/// +/// btDiscreteDynamicsWorldMt -- a version of DiscreteDynamicsWorld with some minor changes to support +/// solving simulation islands on multiple threads. +/// +ATTRIBUTE_ALIGNED16(class) btDiscreteDynamicsWorldMt : public btDiscreteDynamicsWorld +{ +protected: + InplaceSolverIslandCallbackMt* m_solverIslandCallbackMt; + + virtual void solveConstraints(btContactSolverInfo& solverInfo); + +public: + BT_DECLARE_ALIGNED_ALLOCATOR(); + + btDiscreteDynamicsWorldMt(btDispatcher* dispatcher,btBroadphaseInterface* pairCache,btConstraintSolver* constraintSolver,btCollisionConfiguration* collisionConfiguration); + virtual ~btDiscreteDynamicsWorldMt(); +}; + +#endif //BT_DISCRETE_DYNAMICS_WORLD_H diff --git a/src/BulletDynamics/Dynamics/btSimulationIslandManagerMt.cpp b/src/BulletDynamics/Dynamics/btSimulationIslandManagerMt.cpp new file mode 100644 index 000000000..ad63b6ee0 --- /dev/null +++ b/src/BulletDynamics/Dynamics/btSimulationIslandManagerMt.cpp @@ -0,0 +1,641 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + + +#include "LinearMath/btScalar.h" +#include "btSimulationIslandManagerMt.h" +#include "BulletCollision/BroadphaseCollision/btDispatcher.h" +#include "BulletCollision/NarrowPhaseCollision/btPersistentManifold.h" +#include "BulletCollision/CollisionDispatch/btCollisionObject.h" +#include "BulletCollision/CollisionDispatch/btCollisionWorld.h" +#include "BulletDynamics/ConstraintSolver/btTypedConstraint.h" + +//#include +#include "LinearMath/btQuickprof.h" + + +SIMD_FORCE_INLINE int calcBatchCost( int bodies, int manifolds, int constraints ) +{ + // rough estimate of the cost of a batch, used for merging + int batchCost = bodies + 8 * manifolds + 4 * constraints; + return batchCost; +} + + +SIMD_FORCE_INLINE int calcBatchCost( const btSimulationIslandManagerMt::Island* island ) +{ + return calcBatchCost( island->bodyArray.size(), island->manifoldArray.size(), island->constraintArray.size() ); +} + + +btSimulationIslandManagerMt::btSimulationIslandManagerMt() +{ + m_minimumSolverBatchSize = calcBatchCost(0, 128, 0); + m_batchIslandMinBodyCount = 32; + m_islandDispatch = defaultIslandDispatch; + m_batchIsland = NULL; +} + + +btSimulationIslandManagerMt::~btSimulationIslandManagerMt() +{ + for ( int i = 0; i < m_allocatedIslands.size(); ++i ) + { + delete m_allocatedIslands[ i ]; + } + m_allocatedIslands.resize( 0 ); + m_activeIslands.resize( 0 ); + m_freeIslands.resize( 0 ); +} + + +inline int getIslandId(const btPersistentManifold* lhs) +{ + const btCollisionObject* rcolObj0 = static_cast(lhs->getBody0()); + const btCollisionObject* rcolObj1 = static_cast(lhs->getBody1()); + int islandId = rcolObj0->getIslandTag() >= 0 ? rcolObj0->getIslandTag() : rcolObj1->getIslandTag(); + return islandId; +} + + +SIMD_FORCE_INLINE int btGetConstraintIslandId( const btTypedConstraint* lhs ) +{ + const btCollisionObject& rcolObj0 = lhs->getRigidBodyA(); + const btCollisionObject& rcolObj1 = lhs->getRigidBodyB(); + int islandId = rcolObj0.getIslandTag() >= 0 ? rcolObj0.getIslandTag() : rcolObj1.getIslandTag(); + return islandId; +} + +/// function object that routes calls to operator< +class IslandBatchSizeSortPredicate +{ +public: + bool operator() ( const btSimulationIslandManagerMt::Island* lhs, const btSimulationIslandManagerMt::Island* rhs ) const + { + int lCost = calcBatchCost( lhs ); + int rCost = calcBatchCost( rhs ); + return lCost > rCost; + } +}; + + +class IslandBodyCapacitySortPredicate +{ +public: + bool operator() ( const btSimulationIslandManagerMt::Island* lhs, const btSimulationIslandManagerMt::Island* rhs ) const + { + return lhs->bodyArray.capacity() > rhs->bodyArray.capacity(); + } +}; + + +void btSimulationIslandManagerMt::Island::append( const Island& other ) +{ + // append bodies + for ( int i = 0; i < other.bodyArray.size(); ++i ) + { + bodyArray.push_back( other.bodyArray[ i ] ); + } + // append manifolds + for ( int i = 0; i < other.manifoldArray.size(); ++i ) + { + manifoldArray.push_back( other.manifoldArray[ i ] ); + } + // append constraints + for ( int i = 0; i < other.constraintArray.size(); ++i ) + { + constraintArray.push_back( other.constraintArray[ i ] ); + } +} + + +bool btIsBodyInIsland( const btSimulationIslandManagerMt::Island& island, const btCollisionObject* obj ) +{ + for ( int i = 0; i < island.bodyArray.size(); ++i ) + { + if ( island.bodyArray[ i ] == obj ) + { + return true; + } + } + return false; +} + + +void btSimulationIslandManagerMt::initIslandPools() +{ + // reset island pools + int numElem = getUnionFind().getNumElements(); + m_lookupIslandFromId.resize( numElem ); + for ( int i = 0; i < m_lookupIslandFromId.size(); ++i ) + { + m_lookupIslandFromId[ i ] = NULL; + } + m_activeIslands.resize( 0 ); + m_freeIslands.resize( 0 ); + // check whether allocated islands are sorted by body capacity (largest to smallest) + int lastCapacity = 0; + bool isSorted = true; + for ( int i = 0; i < m_allocatedIslands.size(); ++i ) + { + Island* island = m_allocatedIslands[ i ]; + int cap = island->bodyArray.capacity(); + if ( cap > lastCapacity ) + { + isSorted = false; + break; + } + lastCapacity = cap; + } + if ( !isSorted ) + { + m_allocatedIslands.quickSort( IslandBodyCapacitySortPredicate() ); + } + + m_batchIsland = NULL; + // mark all islands free (but avoid deallocation) + for ( int i = 0; i < m_allocatedIslands.size(); ++i ) + { + Island* island = m_allocatedIslands[ i ]; + island->bodyArray.resize( 0 ); + island->manifoldArray.resize( 0 ); + island->constraintArray.resize( 0 ); + island->id = -1; + island->isSleeping = true; + m_freeIslands.push_back( island ); + } +} + + +btSimulationIslandManagerMt::Island* btSimulationIslandManagerMt::getIsland( int id ) +{ + Island* island = m_lookupIslandFromId[ id ]; + if ( island == NULL ) + { + // search for existing island + for ( int i = 0; i < m_activeIslands.size(); ++i ) + { + if ( m_activeIslands[ i ]->id == id ) + { + island = m_activeIslands[ i ]; + break; + } + } + m_lookupIslandFromId[ id ] = island; + } + return island; +} + + +btSimulationIslandManagerMt::Island* btSimulationIslandManagerMt::allocateIsland( int id, int numBodies ) +{ + Island* island = NULL; + int allocSize = numBodies; + if ( numBodies < m_batchIslandMinBodyCount ) + { + if ( m_batchIsland ) + { + island = m_batchIsland; + m_lookupIslandFromId[ id ] = island; + // if we've made a large enough batch, + if ( island->bodyArray.size() + numBodies >= m_batchIslandMinBodyCount ) + { + // next time start a new batch + m_batchIsland = NULL; + } + return island; + } + else + { + // need to allocate a batch island + allocSize = m_batchIslandMinBodyCount * 2; + } + } + btAlignedObjectArray& freeIslands = m_freeIslands; + + // search for free island + if ( freeIslands.size() > 0 ) + { + // try to reuse a previously allocated island + int iFound = freeIslands.size(); + // linear search for smallest island that can hold our bodies + for ( int i = freeIslands.size() - 1; i >= 0; --i ) + { + if ( freeIslands[ i ]->bodyArray.capacity() >= allocSize ) + { + iFound = i; + island = freeIslands[ i ]; + island->id = id; + break; + } + } + // if found, shrink array while maintaining ordering + if ( island ) + { + int iDest = iFound; + int iSrc = iDest + 1; + while ( iSrc < freeIslands.size() ) + { + freeIslands[ iDest++ ] = freeIslands[ iSrc++ ]; + } + freeIslands.pop_back(); + } + } + if ( island == NULL ) + { + // no free island found, allocate + island = new Island(); // TODO: change this to use the pool allocator + island->id = id; + island->bodyArray.reserve( allocSize ); + m_allocatedIslands.push_back( island ); + } + m_lookupIslandFromId[ id ] = island; + if ( numBodies < m_batchIslandMinBodyCount ) + { + m_batchIsland = island; + } + m_activeIslands.push_back( island ); + return island; +} + + +void btSimulationIslandManagerMt::buildIslands( btDispatcher* dispatcher, btCollisionWorld* collisionWorld ) +{ + + BT_PROFILE("islandUnionFindAndQuickSort"); + + btCollisionObjectArray& collisionObjects = collisionWorld->getCollisionObjectArray(); + + //we are going to sort the unionfind array, and store the element id in the size + //afterwards, we clean unionfind, to make sure no-one uses it anymore + + getUnionFind().sortIslands(); + int numElem = getUnionFind().getNumElements(); + + int endIslandIndex=1; + int startIslandIndex; + + //update the sleeping state for bodies, if all are sleeping + for ( startIslandIndex=0;startIslandIndexgetIslandTag() != islandId) && (colObj0->getIslandTag() != -1)) + { +// printf("error in island management\n"); + } + + btAssert((colObj0->getIslandTag() == islandId) || (colObj0->getIslandTag() == -1)); + if (colObj0->getIslandTag() == islandId) + { + if (colObj0->getActivationState()== ACTIVE_TAG) + { + allSleeping = false; + } + if (colObj0->getActivationState()== DISABLE_DEACTIVATION) + { + allSleeping = false; + } + } + } + + if (allSleeping) + { + int idx; + for (idx=startIslandIndex;idxgetIslandTag() != islandId) && (colObj0->getIslandTag() != -1)) + { +// printf("error in island management\n"); + } + + btAssert((colObj0->getIslandTag() == islandId) || (colObj0->getIslandTag() == -1)); + + if (colObj0->getIslandTag() == islandId) + { + colObj0->setActivationState( ISLAND_SLEEPING ); + } + } + } else + { + + int idx; + for (idx=startIslandIndex;idxgetIslandTag() != islandId) && (colObj0->getIslandTag() != -1)) + { +// printf("error in island management\n"); + } + + btAssert((colObj0->getIslandTag() == islandId) || (colObj0->getIslandTag() == -1)); + + if (colObj0->getIslandTag() == islandId) + { + if ( colObj0->getActivationState() == ISLAND_SLEEPING) + { + colObj0->setActivationState( WANTS_DEACTIVATION); + colObj0->setDeactivationTime(0.f); + } + } + } + } + } +} + + +void btSimulationIslandManagerMt::addBodiesToIslands( btCollisionWorld* collisionWorld ) +{ + btCollisionObjectArray& collisionObjects = collisionWorld->getCollisionObjectArray(); + int endIslandIndex = 1; + int startIslandIndex; + int numElem = getUnionFind().getNumElements(); + + // create explicit islands and add bodies to each + for ( startIslandIndex = 0; startIslandIndex < numElem; startIslandIndex = endIslandIndex ) + { + int islandId = getUnionFind().getElement( startIslandIndex ).m_id; + + // find end index + for ( endIslandIndex = startIslandIndex; ( endIslandIndex < numElem ) && ( getUnionFind().getElement( endIslandIndex ).m_id == islandId ); endIslandIndex++ ) + { + } + // check if island is sleeping + bool islandSleeping = true; + for ( int iElem = startIslandIndex; iElem < endIslandIndex; iElem++ ) + { + int i = getUnionFind().getElement( iElem ).m_sz; + btCollisionObject* colObj = collisionObjects[ i ]; + if ( colObj->isActive() ) + { + islandSleeping = false; + } + } + if ( !islandSleeping ) + { + // want to count the number of bodies before allocating the island to optimize memory usage of the Island structures + int numBodies = endIslandIndex - startIslandIndex; + Island* island = allocateIsland( islandId, numBodies ); + island->isSleeping = false; + + // add bodies to island + for ( int iElem = startIslandIndex; iElem < endIslandIndex; iElem++ ) + { + int i = getUnionFind().getElement( iElem ).m_sz; + btCollisionObject* colObj = collisionObjects[ i ]; + island->bodyArray.push_back( colObj ); + } + } + } + +} + + +void btSimulationIslandManagerMt::addManifoldsToIslands( btDispatcher* dispatcher ) +{ + // walk all the manifolds, activating bodies touched by kinematic objects, and add each manifold to its Island + int maxNumManifolds = dispatcher->getNumManifolds(); + for ( int i = 0; i < maxNumManifolds; i++ ) + { + btPersistentManifold* manifold = dispatcher->getManifoldByIndexInternal( i ); + + const btCollisionObject* colObj0 = static_cast( manifold->getBody0() ); + const btCollisionObject* colObj1 = static_cast( manifold->getBody1() ); + + ///@todo: check sleeping conditions! + if ( ( ( colObj0 ) && colObj0->getActivationState() != ISLAND_SLEEPING ) || + ( ( colObj1 ) && colObj1->getActivationState() != ISLAND_SLEEPING ) ) + { + + //kinematic objects don't merge islands, but wake up all connected objects + if ( colObj0->isKinematicObject() && colObj0->getActivationState() != ISLAND_SLEEPING ) + { + if ( colObj0->hasContactResponse() ) + colObj1->activate(); + } + if ( colObj1->isKinematicObject() && colObj1->getActivationState() != ISLAND_SLEEPING ) + { + if ( colObj1->hasContactResponse() ) + colObj0->activate(); + } + //filtering for response + if ( dispatcher->needsResponse( colObj0, colObj1 ) ) + { + // scatter manifolds into various islands + int islandId = getIslandId( manifold ); + // if island not sleeping, + if ( Island* island = getIsland( islandId ) ) + { + island->manifoldArray.push_back( manifold ); + } + } + } + } +} + + +void btSimulationIslandManagerMt::addConstraintsToIslands( btAlignedObjectArray& constraints ) +{ + // walk constraints + for ( int i = 0; i < constraints.size(); i++ ) + { + // scatter constraints into various islands + btTypedConstraint* constraint = constraints[ i ]; + if ( constraint->isEnabled() ) + { + int islandId = btGetConstraintIslandId( constraint ); + // if island is not sleeping, + if ( Island* island = getIsland( islandId ) ) + { + island->constraintArray.push_back( constraint ); + } + } + } +} + + +void btSimulationIslandManagerMt::mergeIslands() +{ + // sort islands in order of decreasing batch size + m_activeIslands.quickSort( IslandBatchSizeSortPredicate() ); + + // merge small islands to satisfy minimum batch size + // find first small batch island + int destIslandIndex = m_activeIslands.size(); + for ( int i = 0; i < m_activeIslands.size(); ++i ) + { + Island* island = m_activeIslands[ i ]; + int batchSize = calcBatchCost( island ); + if ( batchSize < m_minimumSolverBatchSize ) + { + destIslandIndex = i; + break; + } + } + int lastIndex = m_activeIslands.size() - 1; + while ( destIslandIndex < lastIndex ) + { + // merge islands from the back of the list + Island* island = m_activeIslands[ destIslandIndex ]; + int numBodies = island->bodyArray.size(); + int numManifolds = island->manifoldArray.size(); + int numConstraints = island->constraintArray.size(); + int firstIndex = lastIndex; + // figure out how many islands we want to merge and find out how many bodies, manifolds and constraints we will have + while ( true ) + { + Island* src = m_activeIslands[ firstIndex ]; + numBodies += src->bodyArray.size(); + numManifolds += src->manifoldArray.size(); + numConstraints += src->constraintArray.size(); + int batchCost = calcBatchCost( numBodies, numManifolds, numConstraints ); + if ( batchCost >= m_minimumSolverBatchSize ) + { + break; + } + if ( firstIndex - 1 == destIslandIndex ) + { + break; + } + firstIndex--; + } + // reserve space for these pointers to minimize reallocation + island->bodyArray.reserve( numBodies ); + island->manifoldArray.reserve( numManifolds ); + island->constraintArray.reserve( numConstraints ); + // merge islands + for ( int i = firstIndex; i <= lastIndex; ++i ) + { + island->append( *m_activeIslands[ i ] ); + } + // shrink array to exclude the islands that were merged from + m_activeIslands.resize( firstIndex ); + lastIndex = firstIndex - 1; + destIslandIndex++; + } +} + + +void btSimulationIslandManagerMt::defaultIslandDispatch( btAlignedObjectArray* islandsPtr, IslandCallback* callback ) +{ + // serial dispatch + btAlignedObjectArray& islands = *islandsPtr; + for ( int i = 0; i < islands.size(); ++i ) + { + Island* island = islands[ i ]; + btPersistentManifold** manifolds = island->manifoldArray.size() ? &island->manifoldArray[ 0 ] : NULL; + btTypedConstraint** constraintsPtr = island->constraintArray.size() ? &island->constraintArray[ 0 ] : NULL; + callback->processIsland( &island->bodyArray[ 0 ], + island->bodyArray.size(), + manifolds, + island->manifoldArray.size(), + constraintsPtr, + island->constraintArray.size(), + island->id + ); + } +} + +///@todo: this is random access, it can be walked 'cache friendly'! +void btSimulationIslandManagerMt::buildAndProcessIslands( btDispatcher* dispatcher, + btCollisionWorld* collisionWorld, + btAlignedObjectArray& constraints, + IslandCallback* callback + ) +{ + btCollisionObjectArray& collisionObjects = collisionWorld->getCollisionObjectArray(); + + buildIslands(dispatcher,collisionWorld); + + BT_PROFILE("processIslands"); + + if(!getSplitIslands()) + { + btPersistentManifold** manifolds = dispatcher->getInternalManifoldPointer(); + int maxNumManifolds = dispatcher->getNumManifolds(); + + for ( int i = 0; i < maxNumManifolds; i++ ) + { + btPersistentManifold* manifold = manifolds[ i ]; + + const btCollisionObject* colObj0 = static_cast( manifold->getBody0() ); + const btCollisionObject* colObj1 = static_cast( manifold->getBody1() ); + + ///@todo: check sleeping conditions! + if ( ( ( colObj0 ) && colObj0->getActivationState() != ISLAND_SLEEPING ) || + ( ( colObj1 ) && colObj1->getActivationState() != ISLAND_SLEEPING ) ) + { + + //kinematic objects don't merge islands, but wake up all connected objects + if ( colObj0->isKinematicObject() && colObj0->getActivationState() != ISLAND_SLEEPING ) + { + if ( colObj0->hasContactResponse() ) + colObj1->activate(); + } + if ( colObj1->isKinematicObject() && colObj1->getActivationState() != ISLAND_SLEEPING ) + { + if ( colObj1->hasContactResponse() ) + colObj0->activate(); + } + } + } + btTypedConstraint** constraintsPtr = constraints.size() ? &constraints[ 0 ] : NULL; + callback->processIsland(&collisionObjects[0], + collisionObjects.size(), + manifolds, + maxNumManifolds, + constraintsPtr, + constraints.size(), + -1 + ); + } + else + { + initIslandPools(); + + //traverse the simulation islands, and call the solver, unless all objects are sleeping/deactivated + addBodiesToIslands( collisionWorld ); + addManifoldsToIslands( dispatcher ); + addConstraintsToIslands( constraints ); + + // m_activeIslands array should now contain all non-sleeping Islands, and each Island should + // have all the necessary bodies, manifolds and constraints. + + // if we want to merge islands with small batch counts, + if ( m_minimumSolverBatchSize > 1 ) + { + mergeIslands(); + } + // dispatch islands to solver + m_islandDispatch( &m_activeIslands, callback ); + } +} diff --git a/src/BulletDynamics/Dynamics/btSimulationIslandManagerMt.h b/src/BulletDynamics/Dynamics/btSimulationIslandManagerMt.h new file mode 100644 index 000000000..117061623 --- /dev/null +++ b/src/BulletDynamics/Dynamics/btSimulationIslandManagerMt.h @@ -0,0 +1,109 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef BT_SIMULATION_ISLAND_MANAGER_MT_H +#define BT_SIMULATION_ISLAND_MANAGER_MT_H + +#include "BulletCollision/CollisionDispatch/btSimulationIslandManager.h" + +class btTypedConstraint; + + +/// +/// SimulationIslandManagerMt -- Multithread capable version of SimulationIslandManager +/// Splits the world up into islands which can be solved in parallel. +/// In order to solve islands in parallel, an IslandDispatch function +/// must be provided which will dispatch calls to multiple threads. +/// The amount of parallelism that can be achieved depends on the number +/// of islands. If only a single island exists, then no parallelism is +/// possible. +/// +class btSimulationIslandManagerMt : public btSimulationIslandManager +{ +public: + struct Island + { + // a simulation island consisting of bodies, manifolds and constraints, + // to be passed into a constraint solver. + btAlignedObjectArray bodyArray; + btAlignedObjectArray manifoldArray; + btAlignedObjectArray constraintArray; + int id; // island id + bool isSleeping; + + void append( const Island& other ); // add bodies, manifolds, constraints to my own + }; + struct IslandCallback + { + virtual ~IslandCallback() {}; + + virtual void processIsland( btCollisionObject** bodies, + int numBodies, + btPersistentManifold** manifolds, + int numManifolds, + btTypedConstraint** constraints, + int numConstraints, + int islandId + ) = 0; + }; + typedef void( *IslandDispatchFunc ) ( btAlignedObjectArray* islands, IslandCallback* callback ); + static void defaultIslandDispatch( btAlignedObjectArray* islands, IslandCallback* callback ); +protected: + btAlignedObjectArray m_allocatedIslands; // owner of all Islands + btAlignedObjectArray m_activeIslands; // islands actively in use + btAlignedObjectArray m_freeIslands; // islands ready to be reused + btAlignedObjectArray m_lookupIslandFromId; // big lookup table to map islandId to Island pointer + Island* m_batchIsland; + int m_minimumSolverBatchSize; + int m_batchIslandMinBodyCount; + IslandDispatchFunc m_islandDispatch; + + Island* getIsland( int id ); + virtual Island* allocateIsland( int id, int numBodies ); + virtual void initIslandPools(); + virtual void addBodiesToIslands( btCollisionWorld* collisionWorld ); + virtual void addManifoldsToIslands( btDispatcher* dispatcher ); + virtual void addConstraintsToIslands( btAlignedObjectArray& constraints ); + virtual void mergeIslands(); + +public: + btSimulationIslandManagerMt(); + virtual ~btSimulationIslandManagerMt(); + + virtual void buildAndProcessIslands( btDispatcher* dispatcher, btCollisionWorld* collisionWorld, btAlignedObjectArray& constraints, IslandCallback* callback ); + + virtual void buildIslands(btDispatcher* dispatcher,btCollisionWorld* colWorld); + + int getMinimumSolverBatchSize() const + { + return m_minimumSolverBatchSize; + } + void setMinimumSolverBatchSize( int sz ) + { + m_minimumSolverBatchSize = sz; + } + IslandDispatchFunc getIslandDispatchFunction() const + { + return m_islandDispatch; + } + // allow users to set their own dispatch function for multithreaded dispatch + void setIslandDispatchFunction( IslandDispatchFunc func ) + { + m_islandDispatch = func; + } +}; + +#endif //BT_SIMULATION_ISLAND_MANAGER_H + diff --git a/src/BulletDynamics/Featherstone/btMultiBody.cpp b/src/BulletDynamics/Featherstone/btMultiBody.cpp index b85656875..3c6b6154c 100644 --- a/src/BulletDynamics/Featherstone/btMultiBody.cpp +++ b/src/BulletDynamics/Featherstone/btMultiBody.cpp @@ -570,7 +570,7 @@ void btMultiBody::clearForcesAndTorques() void btMultiBody::clearVelocities() { - for (int i = 0; i < 6 + getNumLinks(); ++i) + for (int i = 0; i < 6 + getNumDofs(); ++i) { m_realBuf[i] = 0.f; } diff --git a/src/BulletDynamics/Featherstone/btMultiBodyConstraint.cpp b/src/BulletDynamics/Featherstone/btMultiBodyConstraint.cpp index 01a59890c..d52852dd8 100644 --- a/src/BulletDynamics/Featherstone/btMultiBodyConstraint.cpp +++ b/src/BulletDynamics/Featherstone/btMultiBodyConstraint.cpp @@ -378,7 +378,9 @@ btScalar btMultiBodyConstraint::fillMultiBodyConstraint( btMultiBodySolverConstr btScalar erp = infoGlobal.m_erp2; - if (!infoGlobal.m_splitImpulse || (penetration > infoGlobal.m_splitImpulsePenetrationThreshold)) + + //split impulse is not implemented yet for btMultiBody* + //if (!infoGlobal.m_splitImpulse || (penetration > infoGlobal.m_splitImpulsePenetrationThreshold)) { erp = infoGlobal.m_erp; } @@ -388,19 +390,23 @@ btScalar btMultiBodyConstraint::fillMultiBodyConstraint( btMultiBodySolverConstr btScalar penetrationImpulse = positionalError*solverConstraint.m_jacDiagABInv; btScalar velocityImpulse = velocityError *solverConstraint.m_jacDiagABInv; - if (!infoGlobal.m_splitImpulse || (penetration > infoGlobal.m_splitImpulsePenetrationThreshold)) + //split impulse is not implemented yet for btMultiBody* + + // if (!infoGlobal.m_splitImpulse || (penetration > infoGlobal.m_splitImpulsePenetrationThreshold)) { //combine position and velocity into rhs solverConstraint.m_rhs = penetrationImpulse+velocityImpulse; solverConstraint.m_rhsPenetration = 0.f; - } else + } + /*else { //split position and velocity into rhs and m_rhsPenetration solverConstraint.m_rhs = velocityImpulse; solverConstraint.m_rhsPenetration = penetrationImpulse; } - + */ + solverConstraint.m_cfm = 0.f; solverConstraint.m_lowerLimit = lowerLimit; solverConstraint.m_upperLimit = upperLimit; diff --git a/src/BulletDynamics/Featherstone/btMultiBodyConstraintSolver.cpp b/src/BulletDynamics/Featherstone/btMultiBodyConstraintSolver.cpp index 29f8e469c..70e6c9922 100644 --- a/src/BulletDynamics/Featherstone/btMultiBodyConstraintSolver.cpp +++ b/src/BulletDynamics/Featherstone/btMultiBodyConstraintSolver.cpp @@ -26,7 +26,7 @@ subject to the following restrictions: btScalar btMultiBodyConstraintSolver::solveSingleIteration(int iteration, btCollisionObject** bodies ,int numBodies,btPersistentManifold** manifoldPtr, int numManifolds,btTypedConstraint** constraints,int numConstraints,const btContactSolverInfo& infoGlobal,btIDebugDraw* debugDrawer) { - btScalar val = btSequentialImpulseConstraintSolver::solveSingleIteration(iteration, bodies ,numBodies,manifoldPtr, numManifolds,constraints,numConstraints,infoGlobal,debugDrawer); + btScalar leastSquaredResidual = btSequentialImpulseConstraintSolver::solveSingleIteration(iteration, bodies ,numBodies,manifoldPtr, numManifolds,constraints,numConstraints,infoGlobal,debugDrawer); //solve featherstone non-contact constraints @@ -38,7 +38,9 @@ btScalar btMultiBodyConstraintSolver::solveSingleIteration(int iteration, btColl btMultiBodySolverConstraint& constraint = m_multiBodyNonContactConstraints[index]; - resolveSingleConstraintRowGeneric(constraint); + btScalar residual = resolveSingleConstraintRowGeneric(constraint); + leastSquaredResidual += residual*residual; + if(constraint.m_multiBodyA) constraint.m_multiBodyA->setPosUpdated(false); if(constraint.m_multiBodyB) @@ -49,9 +51,15 @@ btScalar btMultiBodyConstraintSolver::solveSingleIteration(int iteration, btColl for (int j=0;jsetPosUpdated(false); if(constraint.m_multiBodyB) @@ -71,7 +79,8 @@ btScalar btMultiBodyConstraintSolver::solveSingleIteration(int iteration, btColl { frictionConstraint.m_lowerLimit = -(frictionConstraint.m_friction*totalImpulse); frictionConstraint.m_upperLimit = frictionConstraint.m_friction*totalImpulse; - resolveSingleConstraintRowGeneric(frictionConstraint); + btScalar residual = resolveSingleConstraintRowGeneric(frictionConstraint); + leastSquaredResidual += residual*residual; if(frictionConstraint.m_multiBodyA) frictionConstraint.m_multiBodyA->setPosUpdated(false); @@ -80,7 +89,7 @@ btScalar btMultiBodyConstraintSolver::solveSingleIteration(int iteration, btColl } } } - return val; + return leastSquaredResidual; } btScalar btMultiBodyConstraintSolver::solveGroupCacheFriendlySetup(btCollisionObject** bodies,int numBodies,btPersistentManifold** manifoldPtr, int numManifolds,btTypedConstraint** constraints,int numConstraints,const btContactSolverInfo& infoGlobal,btIDebugDraw* debugDrawer) @@ -112,7 +121,7 @@ void btMultiBodyConstraintSolver::applyDeltaVee(btScalar* delta_vee, btScalar im m_data.m_deltaVelocities[velocityIndex+i] += delta_vee[i] * impulse; } -void btMultiBodyConstraintSolver::resolveSingleConstraintRowGeneric(const btMultiBodySolverConstraint& c) +btScalar btMultiBodyConstraintSolver::resolveSingleConstraintRowGeneric(const btMultiBodySolverConstraint& c) { btScalar deltaImpulse = c.m_rhs-btScalar(c.m_appliedImpulse)*c.m_cfm; @@ -190,7 +199,7 @@ void btMultiBodyConstraintSolver::resolveSingleConstraintRowGeneric(const btMult { bodyB->internalApplyImpulse(c.m_contactNormal2*bodyB->internalGetInvMass(),c.m_angularComponentB,deltaImpulse); } - + return deltaImpulse; } @@ -528,19 +537,20 @@ void btMultiBodyConstraintSolver::setupMultiBodyContactConstraint(btMultiBodySol if(!isFriction) { - if (!infoGlobal.m_splitImpulse || (penetration > infoGlobal.m_splitImpulsePenetrationThreshold)) + // if (!infoGlobal.m_splitImpulse || (penetration > infoGlobal.m_splitImpulsePenetrationThreshold)) { //combine position and velocity into rhs solverConstraint.m_rhs = penetrationImpulse+velocityImpulse; solverConstraint.m_rhsPenetration = 0.f; - } else + } + /*else { //split position and velocity into rhs and m_rhsPenetration solverConstraint.m_rhs = velocityImpulse; solverConstraint.m_rhsPenetration = penetrationImpulse; } - + */ solverConstraint.m_lowerLimit = 0; solverConstraint.m_upperLimit = 1e10f; } diff --git a/src/BulletDynamics/Featherstone/btMultiBodyConstraintSolver.h b/src/BulletDynamics/Featherstone/btMultiBodyConstraintSolver.h index 3a89c6373..489347d87 100644 --- a/src/BulletDynamics/Featherstone/btMultiBodyConstraintSolver.h +++ b/src/BulletDynamics/Featherstone/btMultiBodyConstraintSolver.h @@ -43,7 +43,7 @@ protected: btMultiBodyConstraint** m_tmpMultiBodyConstraints; int m_tmpNumMultiBodyConstraints; - void resolveSingleConstraintRowGeneric(const btMultiBodySolverConstraint& c); + btScalar resolveSingleConstraintRowGeneric(const btMultiBodySolverConstraint& c); void convertContacts(btPersistentManifold** manifoldPtr,int numManifolds, const btContactSolverInfo& infoGlobal); diff --git a/src/BulletDynamics/Featherstone/btMultiBodyDynamicsWorld.cpp b/src/BulletDynamics/Featherstone/btMultiBodyDynamicsWorld.cpp index d94d1d4ea..4b33cf69d 100644 --- a/src/BulletDynamics/Featherstone/btMultiBodyDynamicsWorld.cpp +++ b/src/BulletDynamics/Featherstone/btMultiBodyDynamicsWorld.cpp @@ -384,7 +384,7 @@ btMultiBodyDynamicsWorld::btMultiBodyDynamicsWorld(btDispatcher* dispatcher,btBr m_multiBodyConstraintSolver(constraintSolver) { //split impulse is not yet supported for Featherstone hierarchies - getSolverInfo().m_splitImpulse = false; +// getSolverInfo().m_splitImpulse = false; getSolverInfo().m_solverMode |=SOLVER_USE_2_FRICTION_DIRECTIONS; m_solverMultiBodyIslandCallback = new MultiBodyInplaceSolverIslandCallback(constraintSolver,dispatcher); } diff --git a/src/BulletDynamics/MLCPSolvers/btMLCPSolver.cpp b/src/BulletDynamics/MLCPSolvers/btMLCPSolver.cpp index e73f4acc4..8f54c5262 100644 --- a/src/BulletDynamics/MLCPSolvers/btMLCPSolver.cpp +++ b/src/BulletDynamics/MLCPSolvers/btMLCPSolver.cpp @@ -215,12 +215,12 @@ void btMLCPSolver::createMLCPFast(const btContactSolverInfo& infoGlobal) jointNodeArray.reserve(2*m_allConstraintPtrArray.size()); } - static btMatrixXu J3; + btMatrixXu& J3 = m_scratchJ3; { BT_PROFILE("J3.resize"); J3.resize(2*m,8); } - static btMatrixXu JinvM3; + btMatrixXu& JinvM3 = m_scratchJInvM3; { BT_PROFILE("JinvM3.resize/setZero"); @@ -230,7 +230,7 @@ void btMLCPSolver::createMLCPFast(const btContactSolverInfo& infoGlobal) } int cur=0; int rowOffset = 0; - static btAlignedObjectArray ofs; + btAlignedObjectArray& ofs = m_scratchOfs; { BT_PROFILE("ofs resize"); ofs.resize(0); @@ -489,7 +489,7 @@ void btMLCPSolver::createMLCP(const btContactSolverInfo& infoGlobal) } } - static btMatrixXu Minv; + btMatrixXu& Minv = m_scratchMInv; Minv.resize(6*numBodies,6*numBodies); Minv.setZero(); for (int i=0;igetInvInertiaTensorWorld()[r][c] : 0); } - static btMatrixXu J; + btMatrixXu& J = m_scratchJ; J.resize(numConstraintRows,6*numBodies); J.setZero(); @@ -541,10 +541,10 @@ void btMLCPSolver::createMLCP(const btContactSolverInfo& infoGlobal) } } - static btMatrixXu J_transpose; + btMatrixXu& J_transpose = m_scratchJTranspose; J_transpose= J.transpose(); - static btMatrixXu tmp; + btMatrixXu& tmp = m_scratchTmp; { { diff --git a/src/BulletDynamics/MLCPSolvers/btMLCPSolver.h b/src/BulletDynamics/MLCPSolvers/btMLCPSolver.h index 88d587c03..26b482ddc 100644 --- a/src/BulletDynamics/MLCPSolvers/btMLCPSolver.h +++ b/src/BulletDynamics/MLCPSolvers/btMLCPSolver.h @@ -43,6 +43,17 @@ protected: btMLCPSolverInterface* m_solver; int m_fallback; + /// The following scratch variables are not stateful -- contents are cleared prior to each use. + /// They are only cached here to avoid extra memory allocations and deallocations and to ensure + /// that multiple instances of the solver can be run in parallel. + btMatrixXu m_scratchJ3; + btMatrixXu m_scratchJInvM3; + btAlignedObjectArray m_scratchOfs; + btMatrixXu m_scratchMInv; + btMatrixXu m_scratchJ; + btMatrixXu m_scratchJTranspose; + btMatrixXu m_scratchTmp; + virtual btScalar solveGroupCacheFriendlySetup(btCollisionObject** bodies, int numBodies, btPersistentManifold** manifoldPtr, int numManifolds,btTypedConstraint** constraints,int numConstraints,const btContactSolverInfo& infoGlobal,btIDebugDraw* debugDrawer); virtual btScalar solveGroupCacheFriendlyIterations(btCollisionObject** bodies ,int numBodies,btPersistentManifold** manifoldPtr, int numManifolds,btTypedConstraint** constraints,int numConstraints,const btContactSolverInfo& infoGlobal,btIDebugDraw* debugDrawer); diff --git a/src/BulletDynamics/MLCPSolvers/btSolveProjectedGaussSeidel.h b/src/BulletDynamics/MLCPSolvers/btSolveProjectedGaussSeidel.h index 77cc57c6e..c0b40ffd9 100644 --- a/src/BulletDynamics/MLCPSolvers/btSolveProjectedGaussSeidel.h +++ b/src/BulletDynamics/MLCPSolvers/btSolveProjectedGaussSeidel.h @@ -23,7 +23,18 @@ subject to the following restrictions: ///This solver is mainly for debug/learning purposes: it is functionally equivalent to the btSequentialImpulseConstraintSolver solver, but much slower (it builds the full LCP matrix) class btSolveProjectedGaussSeidel : public btMLCPSolverInterface { + public: + + btScalar m_leastSquaresResidualThreshold; + btScalar m_leastSquaresResidual; + + btSolveProjectedGaussSeidel() + :m_leastSquaresResidualThreshold(0), + m_leastSquaresResidual(0) + { + } + virtual bool solveMLCP(const btMatrixXu & A, const btVectorXu & b, btVectorXu& x, const btVectorXu & lo,const btVectorXu & hi,const btAlignedObjectArray& limitDependency, int numIterations, bool useSparsity = true) { if (!A.rows()) @@ -36,10 +47,11 @@ public: int i, j, numRows = A.rows(); - float delta; + btScalar delta; for (int k = 0; k =0) { @@ -76,6 +89,17 @@ public: x[i]=lo[i]*s; if (x[i]>hi[i]*s) x[i]=hi[i]*s; + btScalar diff = x[i] - xOld; + m_leastSquaresResidual += diff*diff; + } + + btScalar eps = m_leastSquaresResidualThreshold; + if ((m_leastSquaresResidual < eps) || (k >=(numIterations-1))) + { +#ifdef VERBOSE_PRINTF_RESIDUAL + printf("totalLenSqr = %f at iteration #%d\n", m_leastSquaresResidual,k); +#endif + break; } } return true; diff --git a/src/BulletSoftBody/btSoftBody.cpp b/src/BulletSoftBody/btSoftBody.cpp index 51f4b33d0..d5de7c1b4 100644 --- a/src/BulletSoftBody/btSoftBody.cpp +++ b/src/BulletSoftBody/btSoftBody.cpp @@ -18,6 +18,8 @@ subject to the following restrictions: #include "BulletSoftBody/btSoftBodySolvers.h" #include "btSoftBodyData.h" #include "LinearMath/btSerializer.h" +#include "BulletDynamics/Featherstone/btMultiBodyLinkCollider.h" +#include "BulletDynamics/Featherstone/btMultiBodyConstraint.h" // @@ -3018,6 +3020,7 @@ void btSoftBody::PSolve_Anchors(btSoftBody* psb,btScalar kst,btScalar ti) } } + // void btSoftBody::PSolve_RContacts(btSoftBody* psb, btScalar kst, btScalar ti) { @@ -3029,9 +3032,39 @@ void btSoftBody::PSolve_RContacts(btSoftBody* psb, btScalar kst, btScalar ti) const sCti& cti = c.m_cti; if (cti.m_colObj->hasContactResponse()) { - btRigidBody* tmpRigid = (btRigidBody*)btRigidBody::upcast(cti.m_colObj); - const btVector3 va = tmpRigid ? tmpRigid->getVelocityInLocalPoint(c.m_c1)*dt : btVector3(0,0,0); - const btVector3 vb = c.m_node->m_x-c.m_node->m_q; + btVector3 va(0,0,0); + btRigidBody* rigidCol; + btMultiBodyLinkCollider* multibodyLinkCol; + btScalar* deltaV; + btMultiBodyJacobianData jacobianData; + if (cti.m_colObj->getInternalType() == btCollisionObject::CO_RIGID_BODY) + { + rigidCol = (btRigidBody*)btRigidBody::upcast(cti.m_colObj); + va = rigidCol ? rigidCol->getVelocityInLocalPoint(c.m_c1)*dt : btVector3(0,0,0); + } + else if (cti.m_colObj->getInternalType() == btCollisionObject::CO_FEATHERSTONE_LINK) + { + multibodyLinkCol = (btMultiBodyLinkCollider*)btMultiBodyLinkCollider::upcast(cti.m_colObj); + if (multibodyLinkCol) + { + const int ndof = multibodyLinkCol->m_multiBody->getNumDofs() + 6; + jacobianData.m_jacobians.resize(ndof); + jacobianData.m_deltaVelocitiesUnitImpulse.resize(ndof); + btScalar* jac=&jacobianData.m_jacobians[0]; + + multibodyLinkCol->m_multiBody->fillContactJacobianMultiDof(multibodyLinkCol->m_link, c.m_node->m_x, cti.m_normal, jac, jacobianData.scratch_r, jacobianData.scratch_v, jacobianData.scratch_m); + deltaV = &jacobianData.m_deltaVelocitiesUnitImpulse[0]; + multibodyLinkCol->m_multiBody->calcAccelerationDeltasMultiDof(&jacobianData.m_jacobians[0],deltaV,jacobianData.scratch_r, jacobianData.scratch_v); + + btScalar vel = 0.0; + for (int j = 0; j < ndof ; ++j) { + vel += multibodyLinkCol->m_multiBody->getVelocityVector()[j] * jac[j]; + } + va = cti.m_normal*vel*dt; + } + } + + const btVector3 vb = c.m_node->m_x-c.m_node->m_q; const btVector3 vr = vb-va; const btScalar dn = btDot(vr, cti.m_normal); if(dn<=SIMD_EPSILON) @@ -3041,8 +3074,20 @@ void btSoftBody::PSolve_RContacts(btSoftBody* psb, btScalar kst, btScalar ti) // c0 is the impulse matrix, c3 is 1 - the friction coefficient or 0, c4 is the contact hardness coefficient const btVector3 impulse = c.m_c0 * ( (vr - (fv * c.m_c3) + (cti.m_normal * (dp * c.m_c4))) * kst ); c.m_node->m_x -= impulse * c.m_c2; - if (tmpRigid) - tmpRigid->applyImpulse(impulse,c.m_c1); + + if (cti.m_colObj->getInternalType() == btCollisionObject::CO_RIGID_BODY) + { + if (rigidCol) + rigidCol->applyImpulse(impulse,c.m_c1); + } + else if (cti.m_colObj->getInternalType() == btCollisionObject::CO_FEATHERSTONE_LINK) + { + if (multibodyLinkCol) + { + double multiplier = 0.5; + multibodyLinkCol->m_multiBody->applyDeltaVeeMultiDof(deltaV,-impulse.length()*multiplier); + } + } } } } diff --git a/src/BulletSoftBody/btSoftBodyConcaveCollisionAlgorithm.cpp b/src/BulletSoftBody/btSoftBodyConcaveCollisionAlgorithm.cpp index 9f0d44526..ab84bddf2 100644 --- a/src/BulletSoftBody/btSoftBodyConcaveCollisionAlgorithm.cpp +++ b/src/BulletSoftBody/btSoftBodyConcaveCollisionAlgorithm.cpp @@ -120,8 +120,8 @@ void btSoftBodyTriangleCallback::processTriangle(btVector3* triangle,int partId, btCollisionObjectWrapper softBody(0,m_softBody->getCollisionShape(),m_softBody,m_softBody->getWorldTransform(),-1,-1); //btCollisionObjectWrapper triBody(0,tm, ob, btTransform::getIdentity());//ob->getWorldTransform());//?? btCollisionObjectWrapper triBody(0,tm, m_triBody, m_triBody->getWorldTransform(),partId, triangleIndex); - - btCollisionAlgorithm* colAlgo = ci.m_dispatcher1->findAlgorithm(&softBody,&triBody,0);//m_manifoldPtr); + ebtDispatcherQueryType algoType = m_resultOut->m_closestPointDistanceThreshold > 0 ? BT_CLOSEST_POINT_ALGORITHMS : BT_CONTACT_POINT_ALGORITHMS; + btCollisionAlgorithm* colAlgo = ci.m_dispatcher1->findAlgorithm(&softBody,&triBody,0, algoType);//m_manifoldPtr); colAlgo->processCollision(&softBody,&triBody,*m_dispatchInfoPtr,m_resultOut); colAlgo->~btCollisionAlgorithm(); @@ -164,7 +164,8 @@ void btSoftBodyTriangleCallback::processTriangle(btVector3* triangle,int partId, btCollisionObjectWrapper softBody(0,m_softBody->getCollisionShape(),m_softBody,m_softBody->getWorldTransform(),-1,-1); btCollisionObjectWrapper triBody(0,tm, m_triBody, m_triBody->getWorldTransform(),partId, triangleIndex);//btTransform::getIdentity());//?? - btCollisionAlgorithm* colAlgo = ci.m_dispatcher1->findAlgorithm(&softBody,&triBody,0);//m_manifoldPtr); + ebtDispatcherQueryType algoType = m_resultOut->m_closestPointDistanceThreshold > 0 ? BT_CLOSEST_POINT_ALGORITHMS : BT_CONTACT_POINT_ALGORITHMS; + btCollisionAlgorithm* colAlgo = ci.m_dispatcher1->findAlgorithm(&softBody,&triBody,0, algoType);//m_manifoldPtr); colAlgo->processCollision(&softBody,&triBody,*m_dispatchInfoPtr,m_resultOut); colAlgo->~btCollisionAlgorithm(); diff --git a/src/LinearMath/CMakeLists.txt b/src/LinearMath/CMakeLists.txt index 3846fb71d..9c1980442 100644 --- a/src/LinearMath/CMakeLists.txt +++ b/src/LinearMath/CMakeLists.txt @@ -11,6 +11,7 @@ SET(LinearMath_SRCS btPolarDecomposition.cpp btQuickprof.cpp btSerializer.cpp + btThreads.cpp btVector3.cpp ) @@ -38,6 +39,7 @@ SET(LinearMath_HDRS btScalar.h btSerializer.h btStackAlloc.h + btThreads.h btTransform.h btTransformUtil.h btVector3.h diff --git a/src/LinearMath/btAlignedObjectArray.h b/src/LinearMath/btAlignedObjectArray.h index 6193ef7f4..146ae72e8 100644 --- a/src/LinearMath/btAlignedObjectArray.h +++ b/src/LinearMath/btAlignedObjectArray.h @@ -322,7 +322,7 @@ protected: { public: - bool operator() ( const T& a, const T& b ) + bool operator() ( const T& a, const T& b ) const { return ( a < b ); } diff --git a/src/LinearMath/btConvexHull.cpp b/src/LinearMath/btConvexHull.cpp index 2ae855dbc..f8b79a1ab 100644 --- a/src/LinearMath/btConvexHull.cpp +++ b/src/LinearMath/btConvexHull.cpp @@ -87,7 +87,7 @@ btVector3 NormalOf(const btVector3 *vert, const int n); btVector3 PlaneLineIntersection(const btPlane &plane, const btVector3 &p0, const btVector3 &p1) { // returns the point where the line p0-p1 intersects the plane n&d - static btVector3 dif; + btVector3 dif; dif = p1-p0; btScalar dn= btDot(plane.normal,dif); btScalar t = -(plane.dist+btDot(plane.normal,p0) )/dn; @@ -112,7 +112,7 @@ btVector3 TriNormal(const btVector3 &v0, const btVector3 &v1, const btVector3 &v btScalar DistanceBetweenLines(const btVector3 &ustart, const btVector3 &udir, const btVector3 &vstart, const btVector3 &vdir, btVector3 *upoint, btVector3 *vpoint) { - static btVector3 cp; + btVector3 cp; cp = btCross(udir,vdir).normalized(); btScalar distu = -btDot(cp,ustart); diff --git a/src/LinearMath/btPoolAllocator.h b/src/LinearMath/btPoolAllocator.h index ef2084537..efdeda8ff 100644 --- a/src/LinearMath/btPoolAllocator.h +++ b/src/LinearMath/btPoolAllocator.h @@ -18,6 +18,7 @@ subject to the following restrictions: #include "btScalar.h" #include "btAlignedAllocator.h" +#include "btThreads.h" ///The btPoolAllocator class allows to efficiently allocate a large pool of objects, instead of dynamically allocating them separately. class btPoolAllocator @@ -27,6 +28,7 @@ class btPoolAllocator int m_freeCount; void* m_firstFree; unsigned char* m_pool; + btSpinMutex m_mutex; // only used if BT_THREADSAFE public: @@ -71,11 +73,16 @@ public: { // release mode fix (void)size; + btMutexLock(&m_mutex); btAssert(!size || size<=m_elemSize); - btAssert(m_freeCount>0); + //btAssert(m_freeCount>0); // should return null if all full void* result = m_firstFree; - m_firstFree = *(void**)m_firstFree; - --m_freeCount; + if (NULL != m_firstFree) + { + m_firstFree = *(void**)m_firstFree; + --m_freeCount; + } + btMutexUnlock(&m_mutex); return result; } @@ -95,9 +102,11 @@ public: if (ptr) { btAssert((unsigned char*)ptr >= m_pool && (unsigned char*)ptr < m_pool + m_maxElements * m_elemSize); + btMutexLock(&m_mutex); *(void**)ptr = m_firstFree; m_firstFree = ptr; ++m_freeCount; + btMutexUnlock(&m_mutex); } } diff --git a/src/LinearMath/btQuickprof.cpp b/src/LinearMath/btQuickprof.cpp index cfbda3628..f587770e8 100644 --- a/src/LinearMath/btQuickprof.cpp +++ b/src/LinearMath/btQuickprof.cpp @@ -16,6 +16,9 @@ #include "btQuickprof.h" +#if BT_THREADSAFE +#include "btThreads.h" +#endif //#if BT_THREADSAFE #ifdef __CELLOS_LV2__ @@ -455,6 +458,14 @@ unsigned long int CProfileManager::ResetTime = 0; *=============================================================================================*/ void CProfileManager::Start_Profile( const char * name ) { +#if BT_THREADSAFE + // profile system is not designed for profiling multiple threads + // disable collection on all but the main thread + if ( !btIsMainThread() ) + { + return; + } +#endif //#if BT_THREADSAFE if (name != CurrentNode->Get_Name()) { CurrentNode = CurrentNode->Get_Sub_Node( name ); } @@ -468,6 +479,14 @@ void CProfileManager::Start_Profile( const char * name ) *=============================================================================================*/ void CProfileManager::Stop_Profile( void ) { +#if BT_THREADSAFE + // profile system is not designed for profiling multiple threads + // disable collection on all but the main thread + if ( !btIsMainThread() ) + { + return; + } +#endif //#if BT_THREADSAFE // Return will indicate whether we should back up to our parent (we may // be profiling a recursive function) if (CurrentNode->Return()) { diff --git a/src/LinearMath/btSerializer.cpp b/src/LinearMath/btSerializer.cpp index 9838e6c09..2b5740b40 100644 --- a/src/LinearMath/btSerializer.cpp +++ b/src/LinearMath/btSerializer.cpp @@ -1,5 +1,5 @@ char sBulletDNAstr[]= { -char(83),char(68),char(78),char(65),char(78),char(65),char(77),char(69),char(126),char(1),char(0),char(0),char(109),char(95),char(115),char(105),char(122),char(101),char(0),char(109), +char(83),char(68),char(78),char(65),char(78),char(65),char(77),char(69),char(-128),char(1),char(0),char(0),char(109),char(95),char(115),char(105),char(122),char(101),char(0),char(109), char(95),char(99),char(97),char(112),char(97),char(99),char(105),char(116),char(121),char(0),char(42),char(109),char(95),char(100),char(97),char(116),char(97),char(0),char(109),char(95), char(99),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(83),char(104),char(97),char(112),char(101),char(115),char(0),char(109),char(95),char(99),char(111), char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(79),char(98),char(106),char(101),char(99),char(116),char(115),char(0),char(109),char(95),char(99),char(111),char(110), @@ -90,508 +90,511 @@ char(97),char(110),char(105),char(115),char(111),char(116),char(114),char(111),c char(109),char(95),char(99),char(111),char(110),char(116),char(97),char(99),char(116),char(80),char(114),char(111),char(99),char(101),char(115),char(115),char(105),char(110),char(103),char(84), char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109),char(95),char(100),char(101),char(97),char(99),char(116),char(105),char(118),char(97),char(116), char(105),char(111),char(110),char(84),char(105),char(109),char(101),char(0),char(109),char(95),char(102),char(114),char(105),char(99),char(116),char(105),char(111),char(110),char(0),char(109), -char(95),char(114),char(111),char(108),char(108),char(105),char(110),char(103),char(70),char(114),char(105),char(99),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(114), -char(101),char(115),char(116),char(105),char(116),char(117),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(104),char(105),char(116),char(70),char(114),char(97),char(99), -char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(99),char(99),char(100),char(83),char(119),char(101),char(112),char(116),char(83),char(112),char(104),char(101),char(114), -char(101),char(82),char(97),char(100),char(105),char(117),char(115),char(0),char(109),char(95),char(99),char(99),char(100),char(77),char(111),char(116),char(105),char(111),char(110),char(84), -char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109),char(95),char(104),char(97),char(115),char(65),char(110),char(105),char(115),char(111),char(116), -char(114),char(111),char(112),char(105),char(99),char(70),char(114),char(105),char(99),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(99),char(111),char(108),char(108), -char(105),char(115),char(105),char(111),char(110),char(70),char(108),char(97),char(103),char(115),char(0),char(109),char(95),char(105),char(115),char(108),char(97),char(110),char(100),char(84), -char(97),char(103),char(49),char(0),char(109),char(95),char(99),char(111),char(109),char(112),char(97),char(110),char(105),char(111),char(110),char(73),char(100),char(0),char(109),char(95), -char(97),char(99),char(116),char(105),char(118),char(97),char(116),char(105),char(111),char(110),char(83),char(116),char(97),char(116),char(101),char(49),char(0),char(109),char(95),char(105), -char(110),char(116),char(101),char(114),char(110),char(97),char(108),char(84),char(121),char(112),char(101),char(0),char(109),char(95),char(99),char(104),char(101),char(99),char(107),char(67), -char(111),char(108),char(108),char(105),char(100),char(101),char(87),char(105),char(116),char(104),char(0),char(109),char(95),char(116),char(97),char(117),char(0),char(109),char(95),char(100), -char(97),char(109),char(112),char(105),char(110),char(103),char(0),char(109),char(95),char(116),char(105),char(109),char(101),char(83),char(116),char(101),char(112),char(0),char(109),char(95), -char(109),char(97),char(120),char(69),char(114),char(114),char(111),char(114),char(82),char(101),char(100),char(117),char(99),char(116),char(105),char(111),char(110),char(0),char(109),char(95), -char(115),char(111),char(114),char(0),char(109),char(95),char(101),char(114),char(112),char(0),char(109),char(95),char(101),char(114),char(112),char(50),char(0),char(109),char(95),char(103), -char(108),char(111),char(98),char(97),char(108),char(67),char(102),char(109),char(0),char(109),char(95),char(115),char(112),char(108),char(105),char(116),char(73),char(109),char(112),char(117), -char(108),char(115),char(101),char(80),char(101),char(110),char(101),char(116),char(114),char(97),char(116),char(105),char(111),char(110),char(84),char(104),char(114),char(101),char(115),char(104), -char(111),char(108),char(100),char(0),char(109),char(95),char(115),char(112),char(108),char(105),char(116),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(84),char(117), -char(114),char(110),char(69),char(114),char(112),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83),char(108),char(111),char(112),char(0),char(109), -char(95),char(119),char(97),char(114),char(109),char(115),char(116),char(97),char(114),char(116),char(105),char(110),char(103),char(70),char(97),char(99),char(116),char(111),char(114),char(0), -char(109),char(95),char(109),char(97),char(120),char(71),char(121),char(114),char(111),char(115),char(99),char(111),char(112),char(105),char(99),char(70),char(111),char(114),char(99),char(101), -char(0),char(109),char(95),char(115),char(105),char(110),char(103),char(108),char(101),char(65),char(120),char(105),char(115),char(82),char(111),char(108),char(108),char(105),char(110),char(103), -char(70),char(114),char(105),char(99),char(116),char(105),char(111),char(110),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109),char(95), -char(110),char(117),char(109),char(73),char(116),char(101),char(114),char(97),char(116),char(105),char(111),char(110),char(115),char(0),char(109),char(95),char(115),char(111),char(108),char(118), -char(101),char(114),char(77),char(111),char(100),char(101),char(0),char(109),char(95),char(114),char(101),char(115),char(116),char(105),char(110),char(103),char(67),char(111),char(110),char(116), -char(97),char(99),char(116),char(82),char(101),char(115),char(116),char(105),char(116),char(117),char(116),char(105),char(111),char(110),char(84),char(104),char(114),char(101),char(115),char(104), -char(111),char(108),char(100),char(0),char(109),char(95),char(109),char(105),char(110),char(105),char(109),char(117),char(109),char(83),char(111),char(108),char(118),char(101),char(114),char(66), -char(97),char(116),char(99),char(104),char(83),char(105),char(122),char(101),char(0),char(109),char(95),char(115),char(112),char(108),char(105),char(116),char(73),char(109),char(112),char(117), -char(108),char(115),char(101),char(0),char(109),char(95),char(115),char(111),char(108),char(118),char(101),char(114),char(73),char(110),char(102),char(111),char(0),char(109),char(95),char(103), -char(114),char(97),char(118),char(105),char(116),char(121),char(0),char(109),char(95),char(99),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(79),char(98), -char(106),char(101),char(99),char(116),char(68),char(97),char(116),char(97),char(0),char(109),char(95),char(105),char(110),char(118),char(73),char(110),char(101),char(114),char(116),char(105), -char(97),char(84),char(101),char(110),char(115),char(111),char(114),char(87),char(111),char(114),char(108),char(100),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97), -char(114),char(86),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(86), -char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(70),char(97),char(99), -char(116),char(111),char(114),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(70),char(97),char(99),char(116),char(111),char(114),char(0),char(109), -char(95),char(103),char(114),char(97),char(118),char(105),char(116),char(121),char(95),char(97),char(99),char(99),char(101),char(108),char(101),char(114),char(97),char(116),char(105),char(111), -char(110),char(0),char(109),char(95),char(105),char(110),char(118),char(73),char(110),char(101),char(114),char(116),char(105),char(97),char(76),char(111),char(99),char(97),char(108),char(0), -char(109),char(95),char(116),char(111),char(116),char(97),char(108),char(70),char(111),char(114),char(99),char(101),char(0),char(109),char(95),char(116),char(111),char(116),char(97),char(108), -char(84),char(111),char(114),char(113),char(117),char(101),char(0),char(109),char(95),char(105),char(110),char(118),char(101),char(114),char(115),char(101),char(77),char(97),char(115),char(115), -char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(0),char(109),char(95),char(97), -char(110),char(103),char(117),char(108),char(97),char(114),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(0),char(109),char(95),char(97),char(100),char(100),char(105), -char(116),char(105),char(111),char(110),char(97),char(108),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(70),char(97),char(99),char(116),char(111),char(114),char(0), -char(109),char(95),char(97),char(100),char(100),char(105),char(116),char(105),char(111),char(110),char(97),char(108),char(76),char(105),char(110),char(101),char(97),char(114),char(68),char(97), -char(109),char(112),char(105),char(110),char(103),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(83),char(113),char(114),char(0),char(109),char(95), -char(97),char(100),char(100),char(105),char(116),char(105),char(111),char(110),char(97),char(108),char(65),char(110),char(103),char(117),char(108),char(97),char(114),char(68),char(97),char(109), -char(112),char(105),char(110),char(103),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(83),char(113),char(114),char(0),char(109),char(95),char(97), -char(100),char(100),char(105),char(116),char(105),char(111),char(110),char(97),char(108),char(65),char(110),char(103),char(117),char(108),char(97),char(114),char(68),char(97),char(109),char(112), -char(105),char(110),char(103),char(70),char(97),char(99),char(116),char(111),char(114),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83),char(108), -char(101),char(101),char(112),char(105),char(110),char(103),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109),char(95),char(97),char(110), -char(103),char(117),char(108),char(97),char(114),char(83),char(108),char(101),char(101),char(112),char(105),char(110),char(103),char(84),char(104),char(114),char(101),char(115),char(104),char(111), -char(108),char(100),char(0),char(109),char(95),char(97),char(100),char(100),char(105),char(116),char(105),char(111),char(110),char(97),char(108),char(68),char(97),char(109),char(112),char(105), -char(110),char(103),char(0),char(109),char(95),char(110),char(117),char(109),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(82),char(111), -char(119),char(115),char(0),char(110),char(117),char(98),char(0),char(42),char(109),char(95),char(114),char(98),char(65),char(0),char(42),char(109),char(95),char(114),char(98),char(66), -char(0),char(109),char(95),char(111),char(98),char(106),char(101),char(99),char(116),char(84),char(121),char(112),char(101),char(0),char(109),char(95),char(117),char(115),char(101),char(114), -char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(84),char(121),char(112),char(101),char(0),char(109),char(95),char(117),char(115),char(101), -char(114),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(73),char(100),char(0),char(109),char(95),char(110),char(101),char(101),char(100), -char(115),char(70),char(101),char(101),char(100),char(98),char(97),char(99),char(107),char(0),char(109),char(95),char(97),char(112),char(112),char(108),char(105),char(101),char(100),char(73), -char(109),char(112),char(117),char(108),char(115),char(101),char(0),char(109),char(95),char(100),char(98),char(103),char(68),char(114),char(97),char(119),char(83),char(105),char(122),char(101), -char(0),char(109),char(95),char(100),char(105),char(115),char(97),char(98),char(108),char(101),char(67),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(115), -char(66),char(101),char(116),char(119),char(101),char(101),char(110),char(76),char(105),char(110),char(107),char(101),char(100),char(66),char(111),char(100),char(105),char(101),char(115),char(0), -char(109),char(95),char(111),char(118),char(101),char(114),char(114),char(105),char(100),char(101),char(78),char(117),char(109),char(83),char(111),char(108),char(118),char(101),char(114),char(73), -char(116),char(101),char(114),char(97),char(116),char(105),char(111),char(110),char(115),char(0),char(109),char(95),char(98),char(114),char(101),char(97),char(107),char(105),char(110),char(103), -char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109),char(95),char(105), -char(115),char(69),char(110),char(97),char(98),char(108),char(101),char(100),char(0),char(112),char(97),char(100),char(100),char(105),char(110),char(103),char(91),char(52),char(93),char(0), -char(109),char(95),char(116),char(121),char(112),char(101),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(97),char(116),char(97), -char(0),char(109),char(95),char(112),char(105),char(118),char(111),char(116),char(73),char(110),char(65),char(0),char(109),char(95),char(112),char(105),char(118),char(111),char(116),char(73), -char(110),char(66),char(0),char(109),char(95),char(114),char(98),char(65),char(70),char(114),char(97),char(109),char(101),char(0),char(109),char(95),char(114),char(98),char(66),char(70), -char(114),char(97),char(109),char(101),char(0),char(109),char(95),char(117),char(115),char(101),char(82),char(101),char(102),char(101),char(114),char(101),char(110),char(99),char(101),char(70), -char(114),char(97),char(109),char(101),char(65),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(79),char(110),char(108),char(121),char(0), -char(109),char(95),char(101),char(110),char(97),char(98),char(108),char(101),char(65),char(110),char(103),char(117),char(108),char(97),char(114),char(77),char(111),char(116),char(111),char(114), -char(0),char(109),char(95),char(109),char(111),char(116),char(111),char(114),char(84),char(97),char(114),char(103),char(101),char(116),char(86),char(101),char(108),char(111),char(99),char(105), -char(116),char(121),char(0),char(109),char(95),char(109),char(97),char(120),char(77),char(111),char(116),char(111),char(114),char(73),char(109),char(112),char(117),char(108),char(115),char(101), -char(0),char(109),char(95),char(108),char(111),char(119),char(101),char(114),char(76),char(105),char(109),char(105),char(116),char(0),char(109),char(95),char(117),char(112),char(112),char(101), -char(114),char(76),char(105),char(109),char(105),char(116),char(0),char(109),char(95),char(108),char(105),char(109),char(105),char(116),char(83),char(111),char(102),char(116),char(110),char(101), -char(115),char(115),char(0),char(109),char(95),char(98),char(105),char(97),char(115),char(70),char(97),char(99),char(116),char(111),char(114),char(0),char(109),char(95),char(114),char(101), -char(108),char(97),char(120),char(97),char(116),char(105),char(111),char(110),char(70),char(97),char(99),char(116),char(111),char(114),char(0),char(109),char(95),char(112),char(97),char(100), -char(100),char(105),char(110),char(103),char(49),char(91),char(52),char(93),char(0),char(109),char(95),char(115),char(119),char(105),char(110),char(103),char(83),char(112),char(97),char(110), -char(49),char(0),char(109),char(95),char(115),char(119),char(105),char(110),char(103),char(83),char(112),char(97),char(110),char(50),char(0),char(109),char(95),char(116),char(119),char(105), -char(115),char(116),char(83),char(112),char(97),char(110),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(85),char(112),char(112),char(101),char(114), -char(76),char(105),char(109),char(105),char(116),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(76),char(111),char(119),char(101),char(114),char(76), -char(105),char(109),char(105),char(116),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(85),char(112),char(112),char(101),char(114),char(76), -char(105),char(109),char(105),char(116),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(76),char(111),char(119),char(101),char(114),char(76), -char(105),char(109),char(105),char(116),char(0),char(109),char(95),char(117),char(115),char(101),char(76),char(105),char(110),char(101),char(97),char(114),char(82),char(101),char(102),char(101), -char(114),char(101),char(110),char(99),char(101),char(70),char(114),char(97),char(109),char(101),char(65),char(0),char(109),char(95),char(117),char(115),char(101),char(79),char(102),char(102), -char(115),char(101),char(116),char(70),char(111),char(114),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(70),char(114),char(97),char(109), -char(101),char(0),char(109),char(95),char(54),char(100),char(111),char(102),char(68),char(97),char(116),char(97),char(0),char(109),char(95),char(115),char(112),char(114),char(105),char(110), -char(103),char(69),char(110),char(97),char(98),char(108),char(101),char(100),char(91),char(54),char(93),char(0),char(109),char(95),char(101),char(113),char(117),char(105),char(108),char(105), -char(98),char(114),char(105),char(117),char(109),char(80),char(111),char(105),char(110),char(116),char(91),char(54),char(93),char(0),char(109),char(95),char(115),char(112),char(114),char(105), -char(110),char(103),char(83),char(116),char(105),char(102),char(102),char(110),char(101),char(115),char(115),char(91),char(54),char(93),char(0),char(109),char(95),char(115),char(112),char(114), -char(105),char(110),char(103),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(91),char(54),char(93),char(0),char(109),char(95),char(108),char(105),char(110),char(101), -char(97),char(114),char(66),char(111),char(117),char(110),char(99),char(101),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83),char(116),char(111), -char(112),char(69),char(82),char(80),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83),char(116),char(111),char(112),char(67),char(70),char(77), -char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(77),char(111),char(116),char(111),char(114),char(69),char(82),char(80),char(0),char(109),char(95), -char(108),char(105),char(110),char(101),char(97),char(114),char(77),char(111),char(116),char(111),char(114),char(67),char(70),char(77),char(0),char(109),char(95),char(108),char(105),char(110), -char(101),char(97),char(114),char(84),char(97),char(114),char(103),char(101),char(116),char(86),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(0),char(109),char(95), -char(108),char(105),char(110),char(101),char(97),char(114),char(77),char(97),char(120),char(77),char(111),char(116),char(111),char(114),char(70),char(111),char(114),char(99),char(101),char(0), -char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83),char(101),char(114),char(118),char(111),char(84),char(97),char(114),char(103),char(101),char(116),char(0), -char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83),char(112),char(114),char(105),char(110),char(103),char(83),char(116),char(105),char(102),char(102),char(110), -char(101),char(115),char(115),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83),char(112),char(114),char(105),char(110),char(103),char(68),char(97), -char(109),char(112),char(105),char(110),char(103),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(69),char(113),char(117),char(105),char(108),char(105), -char(98),char(114),char(105),char(117),char(109),char(80),char(111),char(105),char(110),char(116),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(69), -char(110),char(97),char(98),char(108),char(101),char(77),char(111),char(116),char(111),char(114),char(91),char(52),char(93),char(0),char(109),char(95),char(108),char(105),char(110),char(101), -char(97),char(114),char(83),char(101),char(114),char(118),char(111),char(77),char(111),char(116),char(111),char(114),char(91),char(52),char(93),char(0),char(109),char(95),char(108),char(105), -char(110),char(101),char(97),char(114),char(69),char(110),char(97),char(98),char(108),char(101),char(83),char(112),char(114),char(105),char(110),char(103),char(91),char(52),char(93),char(0), -char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83),char(112),char(114),char(105),char(110),char(103),char(83),char(116),char(105),char(102),char(102),char(110), -char(101),char(115),char(115),char(76),char(105),char(109),char(105),char(116),char(101),char(100),char(91),char(52),char(93),char(0),char(109),char(95),char(108),char(105),char(110),char(101), -char(97),char(114),char(83),char(112),char(114),char(105),char(110),char(103),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(76),char(105),char(109),char(105),char(116), -char(101),char(100),char(91),char(52),char(93),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(66),char(111),char(117),char(110),char(99), -char(101),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(83),char(116),char(111),char(112),char(69),char(82),char(80),char(0),char(109), -char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(83),char(116),char(111),char(112),char(67),char(70),char(77),char(0),char(109),char(95),char(97),char(110), -char(103),char(117),char(108),char(97),char(114),char(77),char(111),char(116),char(111),char(114),char(69),char(82),char(80),char(0),char(109),char(95),char(97),char(110),char(103),char(117), -char(108),char(97),char(114),char(77),char(111),char(116),char(111),char(114),char(67),char(70),char(77),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97), -char(114),char(84),char(97),char(114),char(103),char(101),char(116),char(86),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(0),char(109),char(95),char(97),char(110), -char(103),char(117),char(108),char(97),char(114),char(77),char(97),char(120),char(77),char(111),char(116),char(111),char(114),char(70),char(111),char(114),char(99),char(101),char(0),char(109), -char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(83),char(101),char(114),char(118),char(111),char(84),char(97),char(114),char(103),char(101),char(116),char(0), -char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(83),char(112),char(114),char(105),char(110),char(103),char(83),char(116),char(105),char(102),char(102), -char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(83),char(112),char(114),char(105),char(110),char(103), -char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(69),char(113),char(117), -char(105),char(108),char(105),char(98),char(114),char(105),char(117),char(109),char(80),char(111),char(105),char(110),char(116),char(0),char(109),char(95),char(97),char(110),char(103),char(117), -char(108),char(97),char(114),char(69),char(110),char(97),char(98),char(108),char(101),char(77),char(111),char(116),char(111),char(114),char(91),char(52),char(93),char(0),char(109),char(95), -char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(83),char(101),char(114),char(118),char(111),char(77),char(111),char(116),char(111),char(114),char(91),char(52),char(93), -char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(69),char(110),char(97),char(98),char(108),char(101),char(83),char(112),char(114),char(105), -char(110),char(103),char(91),char(52),char(93),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(83),char(112),char(114),char(105),char(110), -char(103),char(83),char(116),char(105),char(102),char(102),char(110),char(101),char(115),char(115),char(76),char(105),char(109),char(105),char(116),char(101),char(100),char(91),char(52),char(93), +char(95),char(114),char(111),char(108),char(108),char(105),char(110),char(103),char(70),char(114),char(105),char(99),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(99), +char(111),char(110),char(116),char(97),char(99),char(116),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(0),char(109),char(95),char(99),char(111),char(110),char(116), +char(97),char(99),char(116),char(83),char(116),char(105),char(102),char(102),char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(114),char(101),char(115),char(116),char(105), +char(116),char(117),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(104),char(105),char(116),char(70),char(114),char(97),char(99),char(116),char(105),char(111),char(110), +char(0),char(109),char(95),char(99),char(99),char(100),char(83),char(119),char(101),char(112),char(116),char(83),char(112),char(104),char(101),char(114),char(101),char(82),char(97),char(100), +char(105),char(117),char(115),char(0),char(109),char(95),char(99),char(99),char(100),char(77),char(111),char(116),char(105),char(111),char(110),char(84),char(104),char(114),char(101),char(115), +char(104),char(111),char(108),char(100),char(0),char(109),char(95),char(104),char(97),char(115),char(65),char(110),char(105),char(115),char(111),char(116),char(114),char(111),char(112),char(105), +char(99),char(70),char(114),char(105),char(99),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(99),char(111),char(108),char(108),char(105),char(115),char(105),char(111), +char(110),char(70),char(108),char(97),char(103),char(115),char(0),char(109),char(95),char(105),char(115),char(108),char(97),char(110),char(100),char(84),char(97),char(103),char(49),char(0), +char(109),char(95),char(99),char(111),char(109),char(112),char(97),char(110),char(105),char(111),char(110),char(73),char(100),char(0),char(109),char(95),char(97),char(99),char(116),char(105), +char(118),char(97),char(116),char(105),char(111),char(110),char(83),char(116),char(97),char(116),char(101),char(49),char(0),char(109),char(95),char(105),char(110),char(116),char(101),char(114), +char(110),char(97),char(108),char(84),char(121),char(112),char(101),char(0),char(109),char(95),char(99),char(104),char(101),char(99),char(107),char(67),char(111),char(108),char(108),char(105), +char(100),char(101),char(87),char(105),char(116),char(104),char(0),char(109),char(95),char(116),char(97),char(117),char(0),char(109),char(95),char(100),char(97),char(109),char(112),char(105), +char(110),char(103),char(0),char(109),char(95),char(116),char(105),char(109),char(101),char(83),char(116),char(101),char(112),char(0),char(109),char(95),char(109),char(97),char(120),char(69), +char(114),char(114),char(111),char(114),char(82),char(101),char(100),char(117),char(99),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(115),char(111),char(114),char(0), +char(109),char(95),char(101),char(114),char(112),char(0),char(109),char(95),char(101),char(114),char(112),char(50),char(0),char(109),char(95),char(103),char(108),char(111),char(98),char(97), +char(108),char(67),char(102),char(109),char(0),char(109),char(95),char(115),char(112),char(108),char(105),char(116),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(80), +char(101),char(110),char(101),char(116),char(114),char(97),char(116),char(105),char(111),char(110),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0), +char(109),char(95),char(115),char(112),char(108),char(105),char(116),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(84),char(117),char(114),char(110),char(69),char(114), +char(112),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83),char(108),char(111),char(112),char(0),char(109),char(95),char(119),char(97),char(114), +char(109),char(115),char(116),char(97),char(114),char(116),char(105),char(110),char(103),char(70),char(97),char(99),char(116),char(111),char(114),char(0),char(109),char(95),char(109),char(97), +char(120),char(71),char(121),char(114),char(111),char(115),char(99),char(111),char(112),char(105),char(99),char(70),char(111),char(114),char(99),char(101),char(0),char(109),char(95),char(115), +char(105),char(110),char(103),char(108),char(101),char(65),char(120),char(105),char(115),char(82),char(111),char(108),char(108),char(105),char(110),char(103),char(70),char(114),char(105),char(99), +char(116),char(105),char(111),char(110),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109),char(95),char(110),char(117),char(109),char(73), +char(116),char(101),char(114),char(97),char(116),char(105),char(111),char(110),char(115),char(0),char(109),char(95),char(115),char(111),char(108),char(118),char(101),char(114),char(77),char(111), +char(100),char(101),char(0),char(109),char(95),char(114),char(101),char(115),char(116),char(105),char(110),char(103),char(67),char(111),char(110),char(116),char(97),char(99),char(116),char(82), +char(101),char(115),char(116),char(105),char(116),char(117),char(116),char(105),char(111),char(110),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0), +char(109),char(95),char(109),char(105),char(110),char(105),char(109),char(117),char(109),char(83),char(111),char(108),char(118),char(101),char(114),char(66),char(97),char(116),char(99),char(104), +char(83),char(105),char(122),char(101),char(0),char(109),char(95),char(115),char(112),char(108),char(105),char(116),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(0), +char(109),char(95),char(115),char(111),char(108),char(118),char(101),char(114),char(73),char(110),char(102),char(111),char(0),char(109),char(95),char(103),char(114),char(97),char(118),char(105), +char(116),char(121),char(0),char(109),char(95),char(99),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(79),char(98),char(106),char(101),char(99),char(116), +char(68),char(97),char(116),char(97),char(0),char(109),char(95),char(105),char(110),char(118),char(73),char(110),char(101),char(114),char(116),char(105),char(97),char(84),char(101),char(110), +char(115),char(111),char(114),char(87),char(111),char(114),char(108),char(100),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(86),char(101),char(108), +char(111),char(99),char(105),char(116),char(121),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(86),char(101),char(108),char(111),char(99), +char(105),char(116),char(121),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(70),char(97),char(99),char(116),char(111),char(114),char(0), +char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(70),char(97),char(99),char(116),char(111),char(114),char(0),char(109),char(95),char(103),char(114),char(97), +char(118),char(105),char(116),char(121),char(95),char(97),char(99),char(99),char(101),char(108),char(101),char(114),char(97),char(116),char(105),char(111),char(110),char(0),char(109),char(95), +char(105),char(110),char(118),char(73),char(110),char(101),char(114),char(116),char(105),char(97),char(76),char(111),char(99),char(97),char(108),char(0),char(109),char(95),char(116),char(111), +char(116),char(97),char(108),char(70),char(111),char(114),char(99),char(101),char(0),char(109),char(95),char(116),char(111),char(116),char(97),char(108),char(84),char(111),char(114),char(113), +char(117),char(101),char(0),char(109),char(95),char(105),char(110),char(118),char(101),char(114),char(115),char(101),char(77),char(97),char(115),char(115),char(0),char(109),char(95),char(108), +char(105),char(110),char(101),char(97),char(114),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108), +char(97),char(114),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(0),char(109),char(95),char(97),char(100),char(100),char(105),char(116),char(105),char(111),char(110), +char(97),char(108),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(70),char(97),char(99),char(116),char(111),char(114),char(0),char(109),char(95),char(97),char(100), +char(100),char(105),char(116),char(105),char(111),char(110),char(97),char(108),char(76),char(105),char(110),char(101),char(97),char(114),char(68),char(97),char(109),char(112),char(105),char(110), +char(103),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(83),char(113),char(114),char(0),char(109),char(95),char(97),char(100),char(100),char(105), +char(116),char(105),char(111),char(110),char(97),char(108),char(65),char(110),char(103),char(117),char(108),char(97),char(114),char(68),char(97),char(109),char(112),char(105),char(110),char(103), +char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(83),char(113),char(114),char(0),char(109),char(95),char(97),char(100),char(100),char(105),char(116), +char(105),char(111),char(110),char(97),char(108),char(65),char(110),char(103),char(117),char(108),char(97),char(114),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(70), +char(97),char(99),char(116),char(111),char(114),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83),char(108),char(101),char(101),char(112),char(105), +char(110),char(103),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97), +char(114),char(83),char(108),char(101),char(101),char(112),char(105),char(110),char(103),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109), +char(95),char(97),char(100),char(100),char(105),char(116),char(105),char(111),char(110),char(97),char(108),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(0),char(109), +char(95),char(110),char(117),char(109),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(82),char(111),char(119),char(115),char(0),char(110), +char(117),char(98),char(0),char(42),char(109),char(95),char(114),char(98),char(65),char(0),char(42),char(109),char(95),char(114),char(98),char(66),char(0),char(109),char(95),char(111), +char(98),char(106),char(101),char(99),char(116),char(84),char(121),char(112),char(101),char(0),char(109),char(95),char(117),char(115),char(101),char(114),char(67),char(111),char(110),char(115), +char(116),char(114),char(97),char(105),char(110),char(116),char(84),char(121),char(112),char(101),char(0),char(109),char(95),char(117),char(115),char(101),char(114),char(67),char(111),char(110), +char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(73),char(100),char(0),char(109),char(95),char(110),char(101),char(101),char(100),char(115),char(70),char(101),char(101), +char(100),char(98),char(97),char(99),char(107),char(0),char(109),char(95),char(97),char(112),char(112),char(108),char(105),char(101),char(100),char(73),char(109),char(112),char(117),char(108), +char(115),char(101),char(0),char(109),char(95),char(100),char(98),char(103),char(68),char(114),char(97),char(119),char(83),char(105),char(122),char(101),char(0),char(109),char(95),char(100), +char(105),char(115),char(97),char(98),char(108),char(101),char(67),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(115),char(66),char(101),char(116),char(119), +char(101),char(101),char(110),char(76),char(105),char(110),char(107),char(101),char(100),char(66),char(111),char(100),char(105),char(101),char(115),char(0),char(109),char(95),char(111),char(118), +char(101),char(114),char(114),char(105),char(100),char(101),char(78),char(117),char(109),char(83),char(111),char(108),char(118),char(101),char(114),char(73),char(116),char(101),char(114),char(97), +char(116),char(105),char(111),char(110),char(115),char(0),char(109),char(95),char(98),char(114),char(101),char(97),char(107),char(105),char(110),char(103),char(73),char(109),char(112),char(117), +char(108),char(115),char(101),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109),char(95),char(105),char(115),char(69),char(110),char(97), +char(98),char(108),char(101),char(100),char(0),char(112),char(97),char(100),char(100),char(105),char(110),char(103),char(91),char(52),char(93),char(0),char(109),char(95),char(116),char(121), +char(112),char(101),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(97),char(116),char(97),char(0),char(109),char(95),char(112), +char(105),char(118),char(111),char(116),char(73),char(110),char(65),char(0),char(109),char(95),char(112),char(105),char(118),char(111),char(116),char(73),char(110),char(66),char(0),char(109), +char(95),char(114),char(98),char(65),char(70),char(114),char(97),char(109),char(101),char(0),char(109),char(95),char(114),char(98),char(66),char(70),char(114),char(97),char(109),char(101), +char(0),char(109),char(95),char(117),char(115),char(101),char(82),char(101),char(102),char(101),char(114),char(101),char(110),char(99),char(101),char(70),char(114),char(97),char(109),char(101), +char(65),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(79),char(110),char(108),char(121),char(0),char(109),char(95),char(101),char(110), +char(97),char(98),char(108),char(101),char(65),char(110),char(103),char(117),char(108),char(97),char(114),char(77),char(111),char(116),char(111),char(114),char(0),char(109),char(95),char(109), +char(111),char(116),char(111),char(114),char(84),char(97),char(114),char(103),char(101),char(116),char(86),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(0),char(109), +char(95),char(109),char(97),char(120),char(77),char(111),char(116),char(111),char(114),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(0),char(109),char(95),char(108), +char(111),char(119),char(101),char(114),char(76),char(105),char(109),char(105),char(116),char(0),char(109),char(95),char(117),char(112),char(112),char(101),char(114),char(76),char(105),char(109), +char(105),char(116),char(0),char(109),char(95),char(108),char(105),char(109),char(105),char(116),char(83),char(111),char(102),char(116),char(110),char(101),char(115),char(115),char(0),char(109), +char(95),char(98),char(105),char(97),char(115),char(70),char(97),char(99),char(116),char(111),char(114),char(0),char(109),char(95),char(114),char(101),char(108),char(97),char(120),char(97), +char(116),char(105),char(111),char(110),char(70),char(97),char(99),char(116),char(111),char(114),char(0),char(109),char(95),char(112),char(97),char(100),char(100),char(105),char(110),char(103), +char(49),char(91),char(52),char(93),char(0),char(109),char(95),char(115),char(119),char(105),char(110),char(103),char(83),char(112),char(97),char(110),char(49),char(0),char(109),char(95), +char(115),char(119),char(105),char(110),char(103),char(83),char(112),char(97),char(110),char(50),char(0),char(109),char(95),char(116),char(119),char(105),char(115),char(116),char(83),char(112), +char(97),char(110),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(85),char(112),char(112),char(101),char(114),char(76),char(105),char(109),char(105), +char(116),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(76),char(111),char(119),char(101),char(114),char(76),char(105),char(109),char(105),char(116), +char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(85),char(112),char(112),char(101),char(114),char(76),char(105),char(109),char(105),char(116), +char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(76),char(111),char(119),char(101),char(114),char(76),char(105),char(109),char(105),char(116), +char(0),char(109),char(95),char(117),char(115),char(101),char(76),char(105),char(110),char(101),char(97),char(114),char(82),char(101),char(102),char(101),char(114),char(101),char(110),char(99), +char(101),char(70),char(114),char(97),char(109),char(101),char(65),char(0),char(109),char(95),char(117),char(115),char(101),char(79),char(102),char(102),char(115),char(101),char(116),char(70), +char(111),char(114),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(70),char(114),char(97),char(109),char(101),char(0),char(109),char(95), +char(54),char(100),char(111),char(102),char(68),char(97),char(116),char(97),char(0),char(109),char(95),char(115),char(112),char(114),char(105),char(110),char(103),char(69),char(110),char(97), +char(98),char(108),char(101),char(100),char(91),char(54),char(93),char(0),char(109),char(95),char(101),char(113),char(117),char(105),char(108),char(105),char(98),char(114),char(105),char(117), +char(109),char(80),char(111),char(105),char(110),char(116),char(91),char(54),char(93),char(0),char(109),char(95),char(115),char(112),char(114),char(105),char(110),char(103),char(83),char(116), +char(105),char(102),char(102),char(110),char(101),char(115),char(115),char(91),char(54),char(93),char(0),char(109),char(95),char(115),char(112),char(114),char(105),char(110),char(103),char(68), +char(97),char(109),char(112),char(105),char(110),char(103),char(91),char(54),char(93),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(66),char(111), +char(117),char(110),char(99),char(101),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83),char(116),char(111),char(112),char(69),char(82),char(80), +char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83),char(116),char(111),char(112),char(67),char(70),char(77),char(0),char(109),char(95),char(108), +char(105),char(110),char(101),char(97),char(114),char(77),char(111),char(116),char(111),char(114),char(69),char(82),char(80),char(0),char(109),char(95),char(108),char(105),char(110),char(101), +char(97),char(114),char(77),char(111),char(116),char(111),char(114),char(67),char(70),char(77),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(84), +char(97),char(114),char(103),char(101),char(116),char(86),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(0),char(109),char(95),char(108),char(105),char(110),char(101), +char(97),char(114),char(77),char(97),char(120),char(77),char(111),char(116),char(111),char(114),char(70),char(111),char(114),char(99),char(101),char(0),char(109),char(95),char(108),char(105), +char(110),char(101),char(97),char(114),char(83),char(101),char(114),char(118),char(111),char(84),char(97),char(114),char(103),char(101),char(116),char(0),char(109),char(95),char(108),char(105), +char(110),char(101),char(97),char(114),char(83),char(112),char(114),char(105),char(110),char(103),char(83),char(116),char(105),char(102),char(102),char(110),char(101),char(115),char(115),char(0), +char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83),char(112),char(114),char(105),char(110),char(103),char(68),char(97),char(109),char(112),char(105),char(110), +char(103),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(69),char(113),char(117),char(105),char(108),char(105),char(98),char(114),char(105),char(117), +char(109),char(80),char(111),char(105),char(110),char(116),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(69),char(110),char(97),char(98),char(108), +char(101),char(77),char(111),char(116),char(111),char(114),char(91),char(52),char(93),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83),char(101), +char(114),char(118),char(111),char(77),char(111),char(116),char(111),char(114),char(91),char(52),char(93),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114), +char(69),char(110),char(97),char(98),char(108),char(101),char(83),char(112),char(114),char(105),char(110),char(103),char(91),char(52),char(93),char(0),char(109),char(95),char(108),char(105), +char(110),char(101),char(97),char(114),char(83),char(112),char(114),char(105),char(110),char(103),char(83),char(116),char(105),char(102),char(102),char(110),char(101),char(115),char(115),char(76), +char(105),char(109),char(105),char(116),char(101),char(100),char(91),char(52),char(93),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83),char(112), +char(114),char(105),char(110),char(103),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(76),char(105),char(109),char(105),char(116),char(101),char(100),char(91),char(52), +char(93),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(66),char(111),char(117),char(110),char(99),char(101),char(0),char(109),char(95), +char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(83),char(116),char(111),char(112),char(69),char(82),char(80),char(0),char(109),char(95),char(97),char(110),char(103), +char(117),char(108),char(97),char(114),char(83),char(116),char(111),char(112),char(67),char(70),char(77),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97), +char(114),char(77),char(111),char(116),char(111),char(114),char(69),char(82),char(80),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(77), +char(111),char(116),char(111),char(114),char(67),char(70),char(77),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(84),char(97),char(114), +char(103),char(101),char(116),char(86),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97), +char(114),char(77),char(97),char(120),char(77),char(111),char(116),char(111),char(114),char(70),char(111),char(114),char(99),char(101),char(0),char(109),char(95),char(97),char(110),char(103), +char(117),char(108),char(97),char(114),char(83),char(101),char(114),char(118),char(111),char(84),char(97),char(114),char(103),char(101),char(116),char(0),char(109),char(95),char(97),char(110), +char(103),char(117),char(108),char(97),char(114),char(83),char(112),char(114),char(105),char(110),char(103),char(83),char(116),char(105),char(102),char(102),char(110),char(101),char(115),char(115), char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(83),char(112),char(114),char(105),char(110),char(103),char(68),char(97),char(109),char(112), -char(105),char(110),char(103),char(76),char(105),char(109),char(105),char(116),char(101),char(100),char(91),char(52),char(93),char(0),char(109),char(95),char(114),char(111),char(116),char(97), -char(116),char(101),char(79),char(114),char(100),char(101),char(114),char(0),char(109),char(95),char(97),char(120),char(105),char(115),char(73),char(110),char(65),char(0),char(109),char(95), -char(97),char(120),char(105),char(115),char(73),char(110),char(66),char(0),char(109),char(95),char(114),char(97),char(116),char(105),char(111),char(0),char(109),char(95),char(108),char(105), -char(110),char(101),char(97),char(114),char(83),char(116),char(105),char(102),char(102),char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(97),char(110),char(103),char(117), -char(108),char(97),char(114),char(83),char(116),char(105),char(102),char(102),char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(118),char(111),char(108),char(117),char(109), -char(101),char(83),char(116),char(105),char(102),char(102),char(110),char(101),char(115),char(115),char(0),char(42),char(109),char(95),char(109),char(97),char(116),char(101),char(114),char(105), -char(97),char(108),char(0),char(109),char(95),char(112),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(112),char(114),char(101),char(118), -char(105),char(111),char(117),char(115),char(80),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(118),char(101),char(108),char(111),char(99), -char(105),char(116),char(121),char(0),char(109),char(95),char(97),char(99),char(99),char(117),char(109),char(117),char(108),char(97),char(116),char(101),char(100),char(70),char(111),char(114), -char(99),char(101),char(0),char(109),char(95),char(110),char(111),char(114),char(109),char(97),char(108),char(0),char(109),char(95),char(97),char(114),char(101),char(97),char(0),char(109), -char(95),char(97),char(116),char(116),char(97),char(99),char(104),char(0),char(109),char(95),char(110),char(111),char(100),char(101),char(73),char(110),char(100),char(105),char(99),char(101), -char(115),char(91),char(50),char(93),char(0),char(109),char(95),char(114),char(101),char(115),char(116),char(76),char(101),char(110),char(103),char(116),char(104),char(0),char(109),char(95), -char(98),char(98),char(101),char(110),char(100),char(105),char(110),char(103),char(0),char(109),char(95),char(110),char(111),char(100),char(101),char(73),char(110),char(100),char(105),char(99), -char(101),char(115),char(91),char(51),char(93),char(0),char(109),char(95),char(114),char(101),char(115),char(116),char(65),char(114),char(101),char(97),char(0),char(109),char(95),char(99), -char(48),char(91),char(52),char(93),char(0),char(109),char(95),char(110),char(111),char(100),char(101),char(73),char(110),char(100),char(105),char(99),char(101),char(115),char(91),char(52), -char(93),char(0),char(109),char(95),char(114),char(101),char(115),char(116),char(86),char(111),char(108),char(117),char(109),char(101),char(0),char(109),char(95),char(99),char(49),char(0), -char(109),char(95),char(99),char(50),char(0),char(109),char(95),char(99),char(48),char(0),char(109),char(95),char(108),char(111),char(99),char(97),char(108),char(70),char(114),char(97), -char(109),char(101),char(0),char(42),char(109),char(95),char(114),char(105),char(103),char(105),char(100),char(66),char(111),char(100),char(121),char(0),char(109),char(95),char(110),char(111), -char(100),char(101),char(73),char(110),char(100),char(101),char(120),char(0),char(109),char(95),char(97),char(101),char(114),char(111),char(77),char(111),char(100),char(101),char(108),char(0), -char(109),char(95),char(98),char(97),char(117),char(109),char(103),char(97),char(114),char(116),char(101),char(0),char(109),char(95),char(100),char(114),char(97),char(103),char(0),char(109), -char(95),char(108),char(105),char(102),char(116),char(0),char(109),char(95),char(112),char(114),char(101),char(115),char(115),char(117),char(114),char(101),char(0),char(109),char(95),char(118), -char(111),char(108),char(117),char(109),char(101),char(0),char(109),char(95),char(100),char(121),char(110),char(97),char(109),char(105),char(99),char(70),char(114),char(105),char(99),char(116), -char(105),char(111),char(110),char(0),char(109),char(95),char(112),char(111),char(115),char(101),char(77),char(97),char(116),char(99),char(104),char(0),char(109),char(95),char(114),char(105), -char(103),char(105),char(100),char(67),char(111),char(110),char(116),char(97),char(99),char(116),char(72),char(97),char(114),char(100),char(110),char(101),char(115),char(115),char(0),char(109), -char(95),char(107),char(105),char(110),char(101),char(116),char(105),char(99),char(67),char(111),char(110),char(116),char(97),char(99),char(116),char(72),char(97),char(114),char(100),char(110), -char(101),char(115),char(115),char(0),char(109),char(95),char(115),char(111),char(102),char(116),char(67),char(111),char(110),char(116),char(97),char(99),char(116),char(72),char(97),char(114), -char(100),char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(97),char(110),char(99),char(104),char(111),char(114),char(72),char(97),char(114),char(100),char(110),char(101), -char(115),char(115),char(0),char(109),char(95),char(115),char(111),char(102),char(116),char(82),char(105),char(103),char(105),char(100),char(67),char(108),char(117),char(115),char(116),char(101), -char(114),char(72),char(97),char(114),char(100),char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(115),char(111),char(102),char(116),char(75),char(105),char(110),char(101), -char(116),char(105),char(99),char(67),char(108),char(117),char(115),char(116),char(101),char(114),char(72),char(97),char(114),char(100),char(110),char(101),char(115),char(115),char(0),char(109), -char(95),char(115),char(111),char(102),char(116),char(83),char(111),char(102),char(116),char(67),char(108),char(117),char(115),char(116),char(101),char(114),char(72),char(97),char(114),char(100), -char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(115),char(111),char(102),char(116),char(82),char(105),char(103),char(105),char(100),char(67),char(108),char(117),char(115), -char(116),char(101),char(114),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(83),char(112),char(108),char(105),char(116),char(0),char(109),char(95),char(115),char(111), -char(102),char(116),char(75),char(105),char(110),char(101),char(116),char(105),char(99),char(67),char(108),char(117),char(115),char(116),char(101),char(114),char(73),char(109),char(112),char(117), -char(108),char(115),char(101),char(83),char(112),char(108),char(105),char(116),char(0),char(109),char(95),char(115),char(111),char(102),char(116),char(83),char(111),char(102),char(116),char(67), -char(108),char(117),char(115),char(116),char(101),char(114),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(83),char(112),char(108),char(105),char(116),char(0),char(109), -char(95),char(109),char(97),char(120),char(86),char(111),char(108),char(117),char(109),char(101),char(0),char(109),char(95),char(116),char(105),char(109),char(101),char(83),char(99),char(97), -char(108),char(101),char(0),char(109),char(95),char(118),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(73),char(116),char(101),char(114),char(97),char(116),char(105), -char(111),char(110),char(115),char(0),char(109),char(95),char(112),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(73),char(116),char(101),char(114),char(97),char(116), -char(105),char(111),char(110),char(115),char(0),char(109),char(95),char(100),char(114),char(105),char(102),char(116),char(73),char(116),char(101),char(114),char(97),char(116),char(105),char(111), -char(110),char(115),char(0),char(109),char(95),char(99),char(108),char(117),char(115),char(116),char(101),char(114),char(73),char(116),char(101),char(114),char(97),char(116),char(105),char(111), -char(110),char(115),char(0),char(109),char(95),char(114),char(111),char(116),char(0),char(109),char(95),char(115),char(99),char(97),char(108),char(101),char(0),char(109),char(95),char(97), -char(113),char(113),char(0),char(109),char(95),char(99),char(111),char(109),char(0),char(42),char(109),char(95),char(112),char(111),char(115),char(105),char(116),char(105),char(111),char(110), -char(115),char(0),char(42),char(109),char(95),char(119),char(101),char(105),char(103),char(104),char(116),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(80),char(111), -char(115),char(105),char(116),char(105),char(111),char(110),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(87),char(101),char(105),char(103),char(116),char(115),char(0), -char(109),char(95),char(98),char(118),char(111),char(108),char(117),char(109),char(101),char(0),char(109),char(95),char(98),char(102),char(114),char(97),char(109),char(101),char(0),char(109), -char(95),char(102),char(114),char(97),char(109),char(101),char(120),char(102),char(111),char(114),char(109),char(0),char(109),char(95),char(108),char(111),char(99),char(105),char(105),char(0), -char(109),char(95),char(105),char(110),char(118),char(119),char(105),char(0),char(109),char(95),char(118),char(105),char(109),char(112),char(117),char(108),char(115),char(101),char(115),char(91), -char(50),char(93),char(0),char(109),char(95),char(100),char(105),char(109),char(112),char(117),char(108),char(115),char(101),char(115),char(91),char(50),char(93),char(0),char(109),char(95), -char(108),char(118),char(0),char(109),char(95),char(97),char(118),char(0),char(42),char(109),char(95),char(102),char(114),char(97),char(109),char(101),char(114),char(101),char(102),char(115), -char(0),char(42),char(109),char(95),char(110),char(111),char(100),char(101),char(73),char(110),char(100),char(105),char(99),char(101),char(115),char(0),char(42),char(109),char(95),char(109), -char(97),char(115),char(115),char(101),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(70),char(114),char(97),char(109),char(101),char(82),char(101),char(102),char(115), -char(0),char(109),char(95),char(110),char(117),char(109),char(78),char(111),char(100),char(101),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(77),char(97),char(115), -char(115),char(101),char(115),char(0),char(109),char(95),char(105),char(100),char(109),char(97),char(115),char(115),char(0),char(109),char(95),char(105),char(109),char(97),char(115),char(115), -char(0),char(109),char(95),char(110),char(118),char(105),char(109),char(112),char(117),char(108),char(115),char(101),char(115),char(0),char(109),char(95),char(110),char(100),char(105),char(109), -char(112),char(117),char(108),char(115),char(101),char(115),char(0),char(109),char(95),char(110),char(100),char(97),char(109),char(112),char(105),char(110),char(103),char(0),char(109),char(95), -char(108),char(100),char(97),char(109),char(112),char(105),char(110),char(103),char(0),char(109),char(95),char(97),char(100),char(97),char(109),char(112),char(105),char(110),char(103),char(0), -char(109),char(95),char(109),char(97),char(116),char(99),char(104),char(105),char(110),char(103),char(0),char(109),char(95),char(109),char(97),char(120),char(83),char(101),char(108),char(102), -char(67),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(0),char(109),char(95),char(115), -char(101),char(108),char(102),char(67),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(70), -char(97),char(99),char(116),char(111),char(114),char(0),char(109),char(95),char(99),char(111),char(110),char(116),char(97),char(105),char(110),char(115),char(65),char(110),char(99),char(104), -char(111),char(114),char(0),char(109),char(95),char(99),char(111),char(108),char(108),char(105),char(100),char(101),char(0),char(109),char(95),char(99),char(108),char(117),char(115),char(116), -char(101),char(114),char(73),char(110),char(100),char(101),char(120),char(0),char(42),char(109),char(95),char(98),char(111),char(100),char(121),char(65),char(0),char(42),char(109),char(95), -char(98),char(111),char(100),char(121),char(66),char(0),char(109),char(95),char(114),char(101),char(102),char(115),char(91),char(50),char(93),char(0),char(109),char(95),char(99),char(102), -char(109),char(0),char(109),char(95),char(115),char(112),char(108),char(105),char(116),char(0),char(109),char(95),char(100),char(101),char(108),char(101),char(116),char(101),char(0),char(109), -char(95),char(114),char(101),char(108),char(80),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(91),char(50),char(93),char(0),char(109),char(95),char(98),char(111), -char(100),char(121),char(65),char(116),char(121),char(112),char(101),char(0),char(109),char(95),char(98),char(111),char(100),char(121),char(66),char(116),char(121),char(112),char(101),char(0), -char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(84),char(121),char(112),char(101),char(0),char(42),char(109),char(95),char(112),char(111),char(115),char(101),char(0), -char(42),char(42),char(109),char(95),char(109),char(97),char(116),char(101),char(114),char(105),char(97),char(108),char(115),char(0),char(42),char(109),char(95),char(110),char(111),char(100), -char(101),char(115),char(0),char(42),char(109),char(95),char(108),char(105),char(110),char(107),char(115),char(0),char(42),char(109),char(95),char(102),char(97),char(99),char(101),char(115), -char(0),char(42),char(109),char(95),char(116),char(101),char(116),char(114),char(97),char(104),char(101),char(100),char(114),char(97),char(0),char(42),char(109),char(95),char(97),char(110), -char(99),char(104),char(111),char(114),char(115),char(0),char(42),char(109),char(95),char(99),char(108),char(117),char(115),char(116),char(101),char(114),char(115),char(0),char(42),char(109), -char(95),char(106),char(111),char(105),char(110),char(116),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(77),char(97),char(116),char(101),char(114),char(105),char(97), -char(108),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(76),char(105),char(110),char(107),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(70), -char(97),char(99),char(101),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(84),char(101),char(116),char(114),char(97),char(104),char(101),char(100),char(114),char(97), -char(0),char(109),char(95),char(110),char(117),char(109),char(65),char(110),char(99),char(104),char(111),char(114),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(67), -char(108),char(117),char(115),char(116),char(101),char(114),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(74),char(111),char(105),char(110),char(116),char(115),char(0), -char(109),char(95),char(99),char(111),char(110),char(102),char(105),char(103),char(0),char(109),char(95),char(122),char(101),char(114),char(111),char(82),char(111),char(116),char(80),char(97), -char(114),char(101),char(110),char(116),char(84),char(111),char(84),char(104),char(105),char(115),char(0),char(109),char(95),char(112),char(97),char(114),char(101),char(110),char(116),char(67), -char(111),char(109),char(84),char(111),char(84),char(104),char(105),char(115),char(67),char(111),char(109),char(79),char(102),char(102),char(115),char(101),char(116),char(0),char(109),char(95), -char(116),char(104),char(105),char(115),char(80),char(105),char(118),char(111),char(116),char(84),char(111),char(84),char(104),char(105),char(115),char(67),char(111),char(109),char(79),char(102), -char(102),char(115),char(101),char(116),char(0),char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(65),char(120),char(105),char(115),char(84),char(111),char(112),char(91), -char(54),char(93),char(0),char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(65),char(120),char(105),char(115),char(66),char(111),char(116),char(116),char(111),char(109), -char(91),char(54),char(93),char(0),char(109),char(95),char(108),char(105),char(110),char(107),char(73),char(110),char(101),char(114),char(116),char(105),char(97),char(0),char(109),char(95), -char(108),char(105),char(110),char(107),char(77),char(97),char(115),char(115),char(0),char(109),char(95),char(112),char(97),char(114),char(101),char(110),char(116),char(73),char(110),char(100), -char(101),char(120),char(0),char(109),char(95),char(100),char(111),char(102),char(67),char(111),char(117),char(110),char(116),char(0),char(109),char(95),char(112),char(111),char(115),char(86), -char(97),char(114),char(67),char(111),char(117),char(110),char(116),char(0),char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(80),char(111),char(115),char(91),char(55), -char(93),char(0),char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(86),char(101),char(108),char(91),char(54),char(93),char(0),char(109),char(95),char(106),char(111), -char(105),char(110),char(116),char(84),char(111),char(114),char(113),char(117),char(101),char(91),char(54),char(93),char(0),char(109),char(95),char(106),char(111),char(105),char(110),char(116), -char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(0),char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(70),char(114),char(105),char(99),char(116), -char(105),char(111),char(110),char(0),char(42),char(109),char(95),char(108),char(105),char(110),char(107),char(78),char(97),char(109),char(101),char(0),char(42),char(109),char(95),char(106), -char(111),char(105),char(110),char(116),char(78),char(97),char(109),char(101),char(0),char(42),char(109),char(95),char(108),char(105),char(110),char(107),char(67),char(111),char(108),char(108), -char(105),char(100),char(101),char(114),char(0),char(42),char(109),char(95),char(112),char(97),char(100),char(100),char(105),char(110),char(103),char(80),char(116),char(114),char(0),char(109), -char(95),char(98),char(97),char(115),char(101),char(87),char(111),char(114),char(108),char(100),char(84),char(114),char(97),char(110),char(115),char(102),char(111),char(114),char(109),char(0), -char(109),char(95),char(98),char(97),char(115),char(101),char(73),char(110),char(101),char(114),char(116),char(105),char(97),char(0),char(109),char(95),char(98),char(97),char(115),char(101), -char(77),char(97),char(115),char(115),char(0),char(42),char(109),char(95),char(98),char(97),char(115),char(101),char(78),char(97),char(109),char(101),char(0),char(42),char(109),char(95), -char(98),char(97),char(115),char(101),char(67),char(111),char(108),char(108),char(105),char(100),char(101),char(114),char(0),char(0),char(0),char(0),char(84),char(89),char(80),char(69), -char(95),char(0),char(0),char(0),char(99),char(104),char(97),char(114),char(0),char(117),char(99),char(104),char(97),char(114),char(0),char(115),char(104),char(111),char(114),char(116), -char(0),char(117),char(115),char(104),char(111),char(114),char(116),char(0),char(105),char(110),char(116),char(0),char(108),char(111),char(110),char(103),char(0),char(117),char(108),char(111), -char(110),char(103),char(0),char(102),char(108),char(111),char(97),char(116),char(0),char(100),char(111),char(117),char(98),char(108),char(101),char(0),char(118),char(111),char(105),char(100), -char(0),char(80),char(111),char(105),char(110),char(116),char(101),char(114),char(65),char(114),char(114),char(97),char(121),char(0),char(98),char(116),char(80),char(104),char(121),char(115), -char(105),char(99),char(115),char(83),char(121),char(115),char(116),char(101),char(109),char(0),char(76),char(105),char(115),char(116),char(66),char(97),char(115),char(101),char(0),char(98), -char(116),char(86),char(101),char(99),char(116),char(111),char(114),char(51),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116), -char(86),char(101),char(99),char(116),char(111),char(114),char(51),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116), -char(81),char(117),char(97),char(116),char(101),char(114),char(110),char(105),char(111),char(110),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0), -char(98),char(116),char(81),char(117),char(97),char(116),char(101),char(114),char(110),char(105),char(111),char(110),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97), -char(116),char(97),char(0),char(98),char(116),char(77),char(97),char(116),char(114),char(105),char(120),char(51),char(120),char(51),char(70),char(108),char(111),char(97),char(116),char(68), -char(97),char(116),char(97),char(0),char(98),char(116),char(77),char(97),char(116),char(114),char(105),char(120),char(51),char(120),char(51),char(68),char(111),char(117),char(98),char(108), -char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(84),char(114),char(97),char(110),char(115),char(102),char(111),char(114),char(109),char(70),char(108),char(111), -char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(84),char(114),char(97),char(110),char(115),char(102),char(111),char(114),char(109),char(68),char(111), -char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(66),char(118),char(104),char(83),char(117),char(98),char(116),char(114),char(101), -char(101),char(73),char(110),char(102),char(111),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(79),char(112),char(116),char(105),char(109),char(105),char(122),char(101), -char(100),char(66),char(118),char(104),char(78),char(111),char(100),char(101),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116), -char(79),char(112),char(116),char(105),char(109),char(105),char(122),char(101),char(100),char(66),char(118),char(104),char(78),char(111),char(100),char(101),char(68),char(111),char(117),char(98), -char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(81),char(117),char(97),char(110),char(116),char(105),char(122),char(101),char(100),char(66),char(118), -char(104),char(78),char(111),char(100),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(81),char(117),char(97),char(110),char(116),char(105),char(122),char(101), -char(100),char(66),char(118),char(104),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(81),char(117),char(97),char(110), -char(116),char(105),char(122),char(101),char(100),char(66),char(118),char(104),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98), -char(116),char(67),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0), -char(98),char(116),char(83),char(116),char(97),char(116),char(105),char(99),char(80),char(108),char(97),char(110),char(101),char(83),char(104),char(97),char(112),char(101),char(68),char(97), -char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(110),char(118),char(101),char(120),char(73),char(110),char(116),char(101),char(114),char(110),char(97),char(108),char(83), -char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(80),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(65), -char(110),char(100),char(82),char(97),char(100),char(105),char(117),char(115),char(0),char(98),char(116),char(77),char(117),char(108),char(116),char(105),char(83),char(112),char(104),char(101), -char(114),char(101),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(73),char(110),char(116),char(73),char(110),char(100), -char(101),char(120),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(83),char(104),char(111),char(114),char(116),char(73),char(110),char(116),char(73),char(110),char(100), -char(101),char(120),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(83),char(104),char(111),char(114),char(116),char(73),char(110),char(116),char(73),char(110),char(100), -char(101),char(120),char(84),char(114),char(105),char(112),char(108),char(101),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(104),char(97),char(114), -char(73),char(110),char(100),char(101),char(120),char(84),char(114),char(105),char(112),char(108),char(101),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(77), -char(101),char(115),char(104),char(80),char(97),char(114),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(83),char(116),char(114),char(105),char(100),char(105), -char(110),char(103),char(77),char(101),char(115),char(104),char(73),char(110),char(116),char(101),char(114),char(102),char(97),char(99),char(101),char(68),char(97),char(116),char(97),char(0), -char(98),char(116),char(84),char(114),char(105),char(97),char(110),char(103),char(108),char(101),char(77),char(101),char(115),char(104),char(83),char(104),char(97),char(112),char(101),char(68), -char(97),char(116),char(97),char(0),char(98),char(116),char(84),char(114),char(105),char(97),char(110),char(103),char(108),char(101),char(73),char(110),char(102),char(111),char(77),char(97), -char(112),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(83),char(99),char(97),char(108),char(101),char(100),char(84),char(114),char(105),char(97),char(110),char(103), -char(108),char(101),char(77),char(101),char(115),char(104),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111), -char(109),char(112),char(111),char(117),char(110),char(100),char(83),char(104),char(97),char(112),char(101),char(67),char(104),char(105),char(108),char(100),char(68),char(97),char(116),char(97), -char(0),char(98),char(116),char(67),char(111),char(109),char(112),char(111),char(117),char(110),char(100),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97), -char(0),char(98),char(116),char(67),char(121),char(108),char(105),char(110),char(100),char(101),char(114),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97), -char(0),char(98),char(116),char(67),char(111),char(110),char(101),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67), -char(97),char(112),char(115),char(117),char(108),char(101),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(84),char(114), -char(105),char(97),char(110),char(103),char(108),char(101),char(73),char(110),char(102),char(111),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(71),char(73),char(109), -char(112),char(97),char(99),char(116),char(77),char(101),char(115),char(104),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116), -char(67),char(111),char(110),char(118),char(101),char(120),char(72),char(117),char(108),char(108),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0), -char(98),char(116),char(67),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(79),char(98),char(106),char(101),char(99),char(116),char(68),char(111),char(117), -char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(79), -char(98),char(106),char(101),char(99),char(116),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(110), -char(116),char(97),char(99),char(116),char(83),char(111),char(108),char(118),char(101),char(114),char(73),char(110),char(102),char(111),char(68),char(111),char(117),char(98),char(108),char(101), -char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(110),char(116),char(97),char(99),char(116),char(83),char(111),char(108),char(118),char(101),char(114), -char(73),char(110),char(102),char(111),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(68),char(121),char(110),char(97), -char(109),char(105),char(99),char(115),char(87),char(111),char(114),char(108),char(100),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0), -char(98),char(116),char(68),char(121),char(110),char(97),char(109),char(105),char(99),char(115),char(87),char(111),char(114),char(108),char(100),char(70),char(108),char(111),char(97),char(116), -char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(82),char(105),char(103),char(105),char(100),char(66),char(111),char(100),char(121),char(70),char(108),char(111),char(97), -char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(82),char(105),char(103),char(105),char(100),char(66),char(111),char(100),char(121),char(68),char(111),char(117), -char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116), -char(73),char(110),char(102),char(111),char(49),char(0),char(98),char(116),char(84),char(121),char(112),char(101),char(100),char(67),char(111),char(110),char(115),char(116),char(114),char(97), -char(105),char(110),char(116),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(84),char(121),char(112),char(101),char(100), -char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(82),char(105),char(103), -char(105),char(100),char(66),char(111),char(100),char(121),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(84),char(121),char(112),char(101),char(100),char(67),char(111), -char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98), -char(116),char(80),char(111),char(105),char(110),char(116),char(50),char(80),char(111),char(105),char(110),char(116),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105), -char(110),char(116),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(80),char(111),char(105),char(110),char(116),char(50), -char(80),char(111),char(105),char(110),char(116),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108), -char(101),char(68),char(97),char(116),char(97),char(50),char(0),char(98),char(116),char(80),char(111),char(105),char(110),char(116),char(50),char(80),char(111),char(105),char(110),char(116), -char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97), -char(0),char(98),char(116),char(72),char(105),char(110),char(103),char(101),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111), -char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(72),char(105),char(110),char(103),char(101),char(67),char(111),char(110),char(115), -char(116),char(114),char(97),char(105),char(110),char(116),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(72),char(105), -char(110),char(103),char(101),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68), -char(97),char(116),char(97),char(50),char(0),char(98),char(116),char(67),char(111),char(110),char(101),char(84),char(119),char(105),char(115),char(116),char(67),char(111),char(110),char(115), -char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67), -char(111),char(110),char(101),char(84),char(119),char(105),char(115),char(116),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(97), -char(116),char(97),char(0),char(98),char(116),char(71),char(101),char(110),char(101),char(114),char(105),char(99),char(54),char(68),char(111),char(102),char(67),char(111),char(110),char(115), -char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(71),char(101),char(110),char(101),char(114),char(105),char(99), -char(54),char(68),char(111),char(102),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101), -char(68),char(97),char(116),char(97),char(50),char(0),char(98),char(116),char(71),char(101),char(110),char(101),char(114),char(105),char(99),char(54),char(68),char(111),char(102),char(83), -char(112),char(114),char(105),char(110),char(103),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(97),char(116),char(97),char(0), -char(98),char(116),char(71),char(101),char(110),char(101),char(114),char(105),char(99),char(54),char(68),char(111),char(102),char(83),char(112),char(114),char(105),char(110),char(103),char(67), +char(105),char(110),char(103),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(69),char(113),char(117),char(105),char(108),char(105),char(98), +char(114),char(105),char(117),char(109),char(80),char(111),char(105),char(110),char(116),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(69), +char(110),char(97),char(98),char(108),char(101),char(77),char(111),char(116),char(111),char(114),char(91),char(52),char(93),char(0),char(109),char(95),char(97),char(110),char(103),char(117), +char(108),char(97),char(114),char(83),char(101),char(114),char(118),char(111),char(77),char(111),char(116),char(111),char(114),char(91),char(52),char(93),char(0),char(109),char(95),char(97), +char(110),char(103),char(117),char(108),char(97),char(114),char(69),char(110),char(97),char(98),char(108),char(101),char(83),char(112),char(114),char(105),char(110),char(103),char(91),char(52), +char(93),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(83),char(112),char(114),char(105),char(110),char(103),char(83),char(116),char(105), +char(102),char(102),char(110),char(101),char(115),char(115),char(76),char(105),char(109),char(105),char(116),char(101),char(100),char(91),char(52),char(93),char(0),char(109),char(95),char(97), +char(110),char(103),char(117),char(108),char(97),char(114),char(83),char(112),char(114),char(105),char(110),char(103),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(76), +char(105),char(109),char(105),char(116),char(101),char(100),char(91),char(52),char(93),char(0),char(109),char(95),char(114),char(111),char(116),char(97),char(116),char(101),char(79),char(114), +char(100),char(101),char(114),char(0),char(109),char(95),char(97),char(120),char(105),char(115),char(73),char(110),char(65),char(0),char(109),char(95),char(97),char(120),char(105),char(115), +char(73),char(110),char(66),char(0),char(109),char(95),char(114),char(97),char(116),char(105),char(111),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114), +char(83),char(116),char(105),char(102),char(102),char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(83), +char(116),char(105),char(102),char(102),char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(118),char(111),char(108),char(117),char(109),char(101),char(83),char(116),char(105), +char(102),char(102),char(110),char(101),char(115),char(115),char(0),char(42),char(109),char(95),char(109),char(97),char(116),char(101),char(114),char(105),char(97),char(108),char(0),char(109), +char(95),char(112),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(112),char(114),char(101),char(118),char(105),char(111),char(117),char(115), +char(80),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(118),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(0), +char(109),char(95),char(97),char(99),char(99),char(117),char(109),char(117),char(108),char(97),char(116),char(101),char(100),char(70),char(111),char(114),char(99),char(101),char(0),char(109), +char(95),char(110),char(111),char(114),char(109),char(97),char(108),char(0),char(109),char(95),char(97),char(114),char(101),char(97),char(0),char(109),char(95),char(97),char(116),char(116), +char(97),char(99),char(104),char(0),char(109),char(95),char(110),char(111),char(100),char(101),char(73),char(110),char(100),char(105),char(99),char(101),char(115),char(91),char(50),char(93), +char(0),char(109),char(95),char(114),char(101),char(115),char(116),char(76),char(101),char(110),char(103),char(116),char(104),char(0),char(109),char(95),char(98),char(98),char(101),char(110), +char(100),char(105),char(110),char(103),char(0),char(109),char(95),char(110),char(111),char(100),char(101),char(73),char(110),char(100),char(105),char(99),char(101),char(115),char(91),char(51), +char(93),char(0),char(109),char(95),char(114),char(101),char(115),char(116),char(65),char(114),char(101),char(97),char(0),char(109),char(95),char(99),char(48),char(91),char(52),char(93), +char(0),char(109),char(95),char(110),char(111),char(100),char(101),char(73),char(110),char(100),char(105),char(99),char(101),char(115),char(91),char(52),char(93),char(0),char(109),char(95), +char(114),char(101),char(115),char(116),char(86),char(111),char(108),char(117),char(109),char(101),char(0),char(109),char(95),char(99),char(49),char(0),char(109),char(95),char(99),char(50), +char(0),char(109),char(95),char(99),char(48),char(0),char(109),char(95),char(108),char(111),char(99),char(97),char(108),char(70),char(114),char(97),char(109),char(101),char(0),char(42), +char(109),char(95),char(114),char(105),char(103),char(105),char(100),char(66),char(111),char(100),char(121),char(0),char(109),char(95),char(110),char(111),char(100),char(101),char(73),char(110), +char(100),char(101),char(120),char(0),char(109),char(95),char(97),char(101),char(114),char(111),char(77),char(111),char(100),char(101),char(108),char(0),char(109),char(95),char(98),char(97), +char(117),char(109),char(103),char(97),char(114),char(116),char(101),char(0),char(109),char(95),char(100),char(114),char(97),char(103),char(0),char(109),char(95),char(108),char(105),char(102), +char(116),char(0),char(109),char(95),char(112),char(114),char(101),char(115),char(115),char(117),char(114),char(101),char(0),char(109),char(95),char(118),char(111),char(108),char(117),char(109), +char(101),char(0),char(109),char(95),char(100),char(121),char(110),char(97),char(109),char(105),char(99),char(70),char(114),char(105),char(99),char(116),char(105),char(111),char(110),char(0), +char(109),char(95),char(112),char(111),char(115),char(101),char(77),char(97),char(116),char(99),char(104),char(0),char(109),char(95),char(114),char(105),char(103),char(105),char(100),char(67), +char(111),char(110),char(116),char(97),char(99),char(116),char(72),char(97),char(114),char(100),char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(107),char(105),char(110), +char(101),char(116),char(105),char(99),char(67),char(111),char(110),char(116),char(97),char(99),char(116),char(72),char(97),char(114),char(100),char(110),char(101),char(115),char(115),char(0), +char(109),char(95),char(115),char(111),char(102),char(116),char(67),char(111),char(110),char(116),char(97),char(99),char(116),char(72),char(97),char(114),char(100),char(110),char(101),char(115), +char(115),char(0),char(109),char(95),char(97),char(110),char(99),char(104),char(111),char(114),char(72),char(97),char(114),char(100),char(110),char(101),char(115),char(115),char(0),char(109), +char(95),char(115),char(111),char(102),char(116),char(82),char(105),char(103),char(105),char(100),char(67),char(108),char(117),char(115),char(116),char(101),char(114),char(72),char(97),char(114), +char(100),char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(115),char(111),char(102),char(116),char(75),char(105),char(110),char(101),char(116),char(105),char(99),char(67), +char(108),char(117),char(115),char(116),char(101),char(114),char(72),char(97),char(114),char(100),char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(115),char(111),char(102), +char(116),char(83),char(111),char(102),char(116),char(67),char(108),char(117),char(115),char(116),char(101),char(114),char(72),char(97),char(114),char(100),char(110),char(101),char(115),char(115), +char(0),char(109),char(95),char(115),char(111),char(102),char(116),char(82),char(105),char(103),char(105),char(100),char(67),char(108),char(117),char(115),char(116),char(101),char(114),char(73), +char(109),char(112),char(117),char(108),char(115),char(101),char(83),char(112),char(108),char(105),char(116),char(0),char(109),char(95),char(115),char(111),char(102),char(116),char(75),char(105), +char(110),char(101),char(116),char(105),char(99),char(67),char(108),char(117),char(115),char(116),char(101),char(114),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(83), +char(112),char(108),char(105),char(116),char(0),char(109),char(95),char(115),char(111),char(102),char(116),char(83),char(111),char(102),char(116),char(67),char(108),char(117),char(115),char(116), +char(101),char(114),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(83),char(112),char(108),char(105),char(116),char(0),char(109),char(95),char(109),char(97),char(120), +char(86),char(111),char(108),char(117),char(109),char(101),char(0),char(109),char(95),char(116),char(105),char(109),char(101),char(83),char(99),char(97),char(108),char(101),char(0),char(109), +char(95),char(118),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(73),char(116),char(101),char(114),char(97),char(116),char(105),char(111),char(110),char(115),char(0), +char(109),char(95),char(112),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(73),char(116),char(101),char(114),char(97),char(116),char(105),char(111),char(110),char(115), +char(0),char(109),char(95),char(100),char(114),char(105),char(102),char(116),char(73),char(116),char(101),char(114),char(97),char(116),char(105),char(111),char(110),char(115),char(0),char(109), +char(95),char(99),char(108),char(117),char(115),char(116),char(101),char(114),char(73),char(116),char(101),char(114),char(97),char(116),char(105),char(111),char(110),char(115),char(0),char(109), +char(95),char(114),char(111),char(116),char(0),char(109),char(95),char(115),char(99),char(97),char(108),char(101),char(0),char(109),char(95),char(97),char(113),char(113),char(0),char(109), +char(95),char(99),char(111),char(109),char(0),char(42),char(109),char(95),char(112),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(115),char(0),char(42),char(109), +char(95),char(119),char(101),char(105),char(103),char(104),char(116),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(80),char(111),char(115),char(105),char(116),char(105), +char(111),char(110),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(87),char(101),char(105),char(103),char(116),char(115),char(0),char(109),char(95),char(98),char(118), +char(111),char(108),char(117),char(109),char(101),char(0),char(109),char(95),char(98),char(102),char(114),char(97),char(109),char(101),char(0),char(109),char(95),char(102),char(114),char(97), +char(109),char(101),char(120),char(102),char(111),char(114),char(109),char(0),char(109),char(95),char(108),char(111),char(99),char(105),char(105),char(0),char(109),char(95),char(105),char(110), +char(118),char(119),char(105),char(0),char(109),char(95),char(118),char(105),char(109),char(112),char(117),char(108),char(115),char(101),char(115),char(91),char(50),char(93),char(0),char(109), +char(95),char(100),char(105),char(109),char(112),char(117),char(108),char(115),char(101),char(115),char(91),char(50),char(93),char(0),char(109),char(95),char(108),char(118),char(0),char(109), +char(95),char(97),char(118),char(0),char(42),char(109),char(95),char(102),char(114),char(97),char(109),char(101),char(114),char(101),char(102),char(115),char(0),char(42),char(109),char(95), +char(110),char(111),char(100),char(101),char(73),char(110),char(100),char(105),char(99),char(101),char(115),char(0),char(42),char(109),char(95),char(109),char(97),char(115),char(115),char(101), +char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(70),char(114),char(97),char(109),char(101),char(82),char(101),char(102),char(115),char(0),char(109),char(95),char(110), +char(117),char(109),char(78),char(111),char(100),char(101),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(77),char(97),char(115),char(115),char(101),char(115),char(0), +char(109),char(95),char(105),char(100),char(109),char(97),char(115),char(115),char(0),char(109),char(95),char(105),char(109),char(97),char(115),char(115),char(0),char(109),char(95),char(110), +char(118),char(105),char(109),char(112),char(117),char(108),char(115),char(101),char(115),char(0),char(109),char(95),char(110),char(100),char(105),char(109),char(112),char(117),char(108),char(115), +char(101),char(115),char(0),char(109),char(95),char(110),char(100),char(97),char(109),char(112),char(105),char(110),char(103),char(0),char(109),char(95),char(108),char(100),char(97),char(109), +char(112),char(105),char(110),char(103),char(0),char(109),char(95),char(97),char(100),char(97),char(109),char(112),char(105),char(110),char(103),char(0),char(109),char(95),char(109),char(97), +char(116),char(99),char(104),char(105),char(110),char(103),char(0),char(109),char(95),char(109),char(97),char(120),char(83),char(101),char(108),char(102),char(67),char(111),char(108),char(108), +char(105),char(115),char(105),char(111),char(110),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(0),char(109),char(95),char(115),char(101),char(108),char(102),char(67), +char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(70),char(97),char(99),char(116),char(111), +char(114),char(0),char(109),char(95),char(99),char(111),char(110),char(116),char(97),char(105),char(110),char(115),char(65),char(110),char(99),char(104),char(111),char(114),char(0),char(109), +char(95),char(99),char(111),char(108),char(108),char(105),char(100),char(101),char(0),char(109),char(95),char(99),char(108),char(117),char(115),char(116),char(101),char(114),char(73),char(110), +char(100),char(101),char(120),char(0),char(42),char(109),char(95),char(98),char(111),char(100),char(121),char(65),char(0),char(42),char(109),char(95),char(98),char(111),char(100),char(121), +char(66),char(0),char(109),char(95),char(114),char(101),char(102),char(115),char(91),char(50),char(93),char(0),char(109),char(95),char(99),char(102),char(109),char(0),char(109),char(95), +char(115),char(112),char(108),char(105),char(116),char(0),char(109),char(95),char(100),char(101),char(108),char(101),char(116),char(101),char(0),char(109),char(95),char(114),char(101),char(108), +char(80),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(91),char(50),char(93),char(0),char(109),char(95),char(98),char(111),char(100),char(121),char(65),char(116), +char(121),char(112),char(101),char(0),char(109),char(95),char(98),char(111),char(100),char(121),char(66),char(116),char(121),char(112),char(101),char(0),char(109),char(95),char(106),char(111), +char(105),char(110),char(116),char(84),char(121),char(112),char(101),char(0),char(42),char(109),char(95),char(112),char(111),char(115),char(101),char(0),char(42),char(42),char(109),char(95), +char(109),char(97),char(116),char(101),char(114),char(105),char(97),char(108),char(115),char(0),char(42),char(109),char(95),char(110),char(111),char(100),char(101),char(115),char(0),char(42), +char(109),char(95),char(108),char(105),char(110),char(107),char(115),char(0),char(42),char(109),char(95),char(102),char(97),char(99),char(101),char(115),char(0),char(42),char(109),char(95), +char(116),char(101),char(116),char(114),char(97),char(104),char(101),char(100),char(114),char(97),char(0),char(42),char(109),char(95),char(97),char(110),char(99),char(104),char(111),char(114), +char(115),char(0),char(42),char(109),char(95),char(99),char(108),char(117),char(115),char(116),char(101),char(114),char(115),char(0),char(42),char(109),char(95),char(106),char(111),char(105), +char(110),char(116),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(77),char(97),char(116),char(101),char(114),char(105),char(97),char(108),char(115),char(0),char(109), +char(95),char(110),char(117),char(109),char(76),char(105),char(110),char(107),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(70),char(97),char(99),char(101),char(115), +char(0),char(109),char(95),char(110),char(117),char(109),char(84),char(101),char(116),char(114),char(97),char(104),char(101),char(100),char(114),char(97),char(0),char(109),char(95),char(110), +char(117),char(109),char(65),char(110),char(99),char(104),char(111),char(114),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(67),char(108),char(117),char(115),char(116), +char(101),char(114),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(74),char(111),char(105),char(110),char(116),char(115),char(0),char(109),char(95),char(99),char(111), +char(110),char(102),char(105),char(103),char(0),char(109),char(95),char(122),char(101),char(114),char(111),char(82),char(111),char(116),char(80),char(97),char(114),char(101),char(110),char(116), +char(84),char(111),char(84),char(104),char(105),char(115),char(0),char(109),char(95),char(112),char(97),char(114),char(101),char(110),char(116),char(67),char(111),char(109),char(84),char(111), +char(84),char(104),char(105),char(115),char(67),char(111),char(109),char(79),char(102),char(102),char(115),char(101),char(116),char(0),char(109),char(95),char(116),char(104),char(105),char(115), +char(80),char(105),char(118),char(111),char(116),char(84),char(111),char(84),char(104),char(105),char(115),char(67),char(111),char(109),char(79),char(102),char(102),char(115),char(101),char(116), +char(0),char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(65),char(120),char(105),char(115),char(84),char(111),char(112),char(91),char(54),char(93),char(0),char(109), +char(95),char(106),char(111),char(105),char(110),char(116),char(65),char(120),char(105),char(115),char(66),char(111),char(116),char(116),char(111),char(109),char(91),char(54),char(93),char(0), +char(109),char(95),char(108),char(105),char(110),char(107),char(73),char(110),char(101),char(114),char(116),char(105),char(97),char(0),char(109),char(95),char(108),char(105),char(110),char(107), +char(77),char(97),char(115),char(115),char(0),char(109),char(95),char(112),char(97),char(114),char(101),char(110),char(116),char(73),char(110),char(100),char(101),char(120),char(0),char(109), +char(95),char(100),char(111),char(102),char(67),char(111),char(117),char(110),char(116),char(0),char(109),char(95),char(112),char(111),char(115),char(86),char(97),char(114),char(67),char(111), +char(117),char(110),char(116),char(0),char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(80),char(111),char(115),char(91),char(55),char(93),char(0),char(109),char(95), +char(106),char(111),char(105),char(110),char(116),char(86),char(101),char(108),char(91),char(54),char(93),char(0),char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(84), +char(111),char(114),char(113),char(117),char(101),char(91),char(54),char(93),char(0),char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(68),char(97),char(109),char(112), +char(105),char(110),char(103),char(0),char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(70),char(114),char(105),char(99),char(116),char(105),char(111),char(110),char(0), +char(42),char(109),char(95),char(108),char(105),char(110),char(107),char(78),char(97),char(109),char(101),char(0),char(42),char(109),char(95),char(106),char(111),char(105),char(110),char(116), +char(78),char(97),char(109),char(101),char(0),char(42),char(109),char(95),char(108),char(105),char(110),char(107),char(67),char(111),char(108),char(108),char(105),char(100),char(101),char(114), +char(0),char(42),char(109),char(95),char(112),char(97),char(100),char(100),char(105),char(110),char(103),char(80),char(116),char(114),char(0),char(109),char(95),char(98),char(97),char(115), +char(101),char(87),char(111),char(114),char(108),char(100),char(84),char(114),char(97),char(110),char(115),char(102),char(111),char(114),char(109),char(0),char(109),char(95),char(98),char(97), +char(115),char(101),char(73),char(110),char(101),char(114),char(116),char(105),char(97),char(0),char(109),char(95),char(98),char(97),char(115),char(101),char(77),char(97),char(115),char(115), +char(0),char(42),char(109),char(95),char(98),char(97),char(115),char(101),char(78),char(97),char(109),char(101),char(0),char(42),char(109),char(95),char(98),char(97),char(115),char(101), +char(67),char(111),char(108),char(108),char(105),char(100),char(101),char(114),char(0),char(0),char(0),char(0),char(84),char(89),char(80),char(69),char(95),char(0),char(0),char(0), +char(99),char(104),char(97),char(114),char(0),char(117),char(99),char(104),char(97),char(114),char(0),char(115),char(104),char(111),char(114),char(116),char(0),char(117),char(115),char(104), +char(111),char(114),char(116),char(0),char(105),char(110),char(116),char(0),char(108),char(111),char(110),char(103),char(0),char(117),char(108),char(111),char(110),char(103),char(0),char(102), +char(108),char(111),char(97),char(116),char(0),char(100),char(111),char(117),char(98),char(108),char(101),char(0),char(118),char(111),char(105),char(100),char(0),char(80),char(111),char(105), +char(110),char(116),char(101),char(114),char(65),char(114),char(114),char(97),char(121),char(0),char(98),char(116),char(80),char(104),char(121),char(115),char(105),char(99),char(115),char(83), +char(121),char(115),char(116),char(101),char(109),char(0),char(76),char(105),char(115),char(116),char(66),char(97),char(115),char(101),char(0),char(98),char(116),char(86),char(101),char(99), +char(116),char(111),char(114),char(51),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(86),char(101),char(99),char(116), +char(111),char(114),char(51),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(81),char(117),char(97),char(116), +char(101),char(114),char(110),char(105),char(111),char(110),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(81),char(117), +char(97),char(116),char(101),char(114),char(110),char(105),char(111),char(110),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98), +char(116),char(77),char(97),char(116),char(114),char(105),char(120),char(51),char(120),char(51),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0), +char(98),char(116),char(77),char(97),char(116),char(114),char(105),char(120),char(51),char(120),char(51),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116), +char(97),char(0),char(98),char(116),char(84),char(114),char(97),char(110),char(115),char(102),char(111),char(114),char(109),char(70),char(108),char(111),char(97),char(116),char(68),char(97), +char(116),char(97),char(0),char(98),char(116),char(84),char(114),char(97),char(110),char(115),char(102),char(111),char(114),char(109),char(68),char(111),char(117),char(98),char(108),char(101), +char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(66),char(118),char(104),char(83),char(117),char(98),char(116),char(114),char(101),char(101),char(73),char(110),char(102), +char(111),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(79),char(112),char(116),char(105),char(109),char(105),char(122),char(101),char(100),char(66),char(118),char(104), +char(78),char(111),char(100),char(101),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(79),char(112),char(116),char(105), +char(109),char(105),char(122),char(101),char(100),char(66),char(118),char(104),char(78),char(111),char(100),char(101),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97), +char(116),char(97),char(0),char(98),char(116),char(81),char(117),char(97),char(110),char(116),char(105),char(122),char(101),char(100),char(66),char(118),char(104),char(78),char(111),char(100), +char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(81),char(117),char(97),char(110),char(116),char(105),char(122),char(101),char(100),char(66),char(118),char(104), +char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(81),char(117),char(97),char(110),char(116),char(105),char(122),char(101), +char(100),char(66),char(118),char(104),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(108), +char(108),char(105),char(115),char(105),char(111),char(110),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(83),char(116), +char(97),char(116),char(105),char(99),char(80),char(108),char(97),char(110),char(101),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98), +char(116),char(67),char(111),char(110),char(118),char(101),char(120),char(73),char(110),char(116),char(101),char(114),char(110),char(97),char(108),char(83),char(104),char(97),char(112),char(101), +char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(80),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(65),char(110),char(100),char(82),char(97), +char(100),char(105),char(117),char(115),char(0),char(98),char(116),char(77),char(117),char(108),char(116),char(105),char(83),char(112),char(104),char(101),char(114),char(101),char(83),char(104), +char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(73),char(110),char(116),char(73),char(110),char(100),char(101),char(120),char(68),char(97), +char(116),char(97),char(0),char(98),char(116),char(83),char(104),char(111),char(114),char(116),char(73),char(110),char(116),char(73),char(110),char(100),char(101),char(120),char(68),char(97), +char(116),char(97),char(0),char(98),char(116),char(83),char(104),char(111),char(114),char(116),char(73),char(110),char(116),char(73),char(110),char(100),char(101),char(120),char(84),char(114), +char(105),char(112),char(108),char(101),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(104),char(97),char(114),char(73),char(110),char(100),char(101), +char(120),char(84),char(114),char(105),char(112),char(108),char(101),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(77),char(101),char(115),char(104),char(80), +char(97),char(114),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(83),char(116),char(114),char(105),char(100),char(105),char(110),char(103),char(77),char(101), +char(115),char(104),char(73),char(110),char(116),char(101),char(114),char(102),char(97),char(99),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(84),char(114), +char(105),char(97),char(110),char(103),char(108),char(101),char(77),char(101),char(115),char(104),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0), +char(98),char(116),char(84),char(114),char(105),char(97),char(110),char(103),char(108),char(101),char(73),char(110),char(102),char(111),char(77),char(97),char(112),char(68),char(97),char(116), +char(97),char(0),char(98),char(116),char(83),char(99),char(97),char(108),char(101),char(100),char(84),char(114),char(105),char(97),char(110),char(103),char(108),char(101),char(77),char(101), +char(115),char(104),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(109),char(112),char(111),char(117), +char(110),char(100),char(83),char(104),char(97),char(112),char(101),char(67),char(104),char(105),char(108),char(100),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67), +char(111),char(109),char(112),char(111),char(117),char(110),char(100),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67), +char(121),char(108),char(105),char(110),char(100),char(101),char(114),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67), +char(111),char(110),char(101),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(97),char(112),char(115),char(117), +char(108),char(101),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(84),char(114),char(105),char(97),char(110),char(103), +char(108),char(101),char(73),char(110),char(102),char(111),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(71),char(73),char(109),char(112),char(97),char(99),char(116), +char(77),char(101),char(115),char(104),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(110),char(118), +char(101),char(120),char(72),char(117),char(108),char(108),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111), +char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(79),char(98),char(106),char(101),char(99),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68), +char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(79),char(98),char(106),char(101),char(99), +char(116),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(110),char(116),char(97),char(99),char(116), +char(83),char(111),char(108),char(118),char(101),char(114),char(73),char(110),char(102),char(111),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97), +char(0),char(98),char(116),char(67),char(111),char(110),char(116),char(97),char(99),char(116),char(83),char(111),char(108),char(118),char(101),char(114),char(73),char(110),char(102),char(111), +char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(68),char(121),char(110),char(97),char(109),char(105),char(99),char(115), +char(87),char(111),char(114),char(108),char(100),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(68),char(121), +char(110),char(97),char(109),char(105),char(99),char(115),char(87),char(111),char(114),char(108),char(100),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97), +char(0),char(98),char(116),char(82),char(105),char(103),char(105),char(100),char(66),char(111),char(100),char(121),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116), +char(97),char(0),char(98),char(116),char(82),char(105),char(103),char(105),char(100),char(66),char(111),char(100),char(121),char(68),char(111),char(117),char(98),char(108),char(101),char(68), +char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(73),char(110),char(102),char(111), +char(49),char(0),char(98),char(116),char(84),char(121),char(112),char(101),char(100),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(70), +char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(84),char(121),char(112),char(101),char(100),char(67),char(111),char(110),char(115), +char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(82),char(105),char(103),char(105),char(100),char(66),char(111), +char(100),char(121),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(84),char(121),char(112),char(101),char(100),char(67),char(111),char(110),char(115),char(116),char(114), +char(97),char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(80),char(111),char(105), +char(110),char(116),char(50),char(80),char(111),char(105),char(110),char(116),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(70),char(108), +char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(80),char(111),char(105),char(110),char(116),char(50),char(80),char(111),char(105),char(110), +char(116),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116), +char(97),char(50),char(0),char(98),char(116),char(80),char(111),char(105),char(110),char(116),char(50),char(80),char(111),char(105),char(110),char(116),char(67),char(111),char(110),char(115), +char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(72), +char(105),char(110),char(103),char(101),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101), +char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(72),char(105),char(110),char(103),char(101),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105), +char(110),char(116),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(72),char(105),char(110),char(103),char(101),char(67), char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(50), -char(0),char(98),char(116),char(71),char(101),char(110),char(101),char(114),char(105),char(99),char(54),char(68),char(111),char(102),char(83),char(112),char(114),char(105),char(110),char(103), -char(50),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(71),char(101), -char(110),char(101),char(114),char(105),char(99),char(54),char(68),char(111),char(102),char(83),char(112),char(114),char(105),char(110),char(103),char(50),char(67),char(111),char(110),char(115), -char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(50),char(0),char(98),char(116), -char(83),char(108),char(105),char(100),char(101),char(114),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(97),char(116),char(97), -char(0),char(98),char(116),char(83),char(108),char(105),char(100),char(101),char(114),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68), -char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(71),char(101),char(97),char(114),char(67),char(111),char(110),char(115), -char(116),char(114),char(97),char(105),char(110),char(116),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(71),char(101), -char(97),char(114),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97), -char(116),char(97),char(0),char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(77),char(97),char(116),char(101),char(114),char(105),char(97),char(108),char(68), -char(97),char(116),char(97),char(0),char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(78),char(111),char(100),char(101),char(68),char(97),char(116),char(97), -char(0),char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(76),char(105),char(110),char(107),char(68),char(97),char(116),char(97),char(0),char(83),char(111), -char(102),char(116),char(66),char(111),char(100),char(121),char(70),char(97),char(99),char(101),char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102),char(116),char(66), -char(111),char(100),char(121),char(84),char(101),char(116),char(114),char(97),char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102),char(116),char(82),char(105),char(103), -char(105),char(100),char(65),char(110),char(99),char(104),char(111),char(114),char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102),char(116),char(66),char(111),char(100), -char(121),char(67),char(111),char(110),char(102),char(105),char(103),char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121), -char(80),char(111),char(115),char(101),char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(67),char(108),char(117), -char(115),char(116),char(101),char(114),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(74), -char(111),char(105),char(110),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(70), -char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(77),char(117),char(108),char(116),char(105),char(66),char(111),char(100),char(121), -char(76),char(105),char(110),char(107),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(77),char(117),char(108), -char(116),char(105),char(66),char(111),char(100),char(121),char(76),char(105),char(110),char(107),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0), -char(98),char(116),char(77),char(117),char(108),char(116),char(105),char(66),char(111),char(100),char(121),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116), -char(97),char(0),char(98),char(116),char(77),char(117),char(108),char(116),char(105),char(66),char(111),char(100),char(121),char(70),char(108),char(111),char(97),char(116),char(68),char(97), -char(116),char(97),char(0),char(0),char(84),char(76),char(69),char(78),char(1),char(0),char(1),char(0),char(2),char(0),char(2),char(0),char(4),char(0),char(4),char(0), -char(4),char(0),char(4),char(0),char(8),char(0),char(0),char(0),char(12),char(0),char(36),char(0),char(8),char(0),char(16),char(0),char(32),char(0),char(16),char(0), -char(32),char(0),char(48),char(0),char(96),char(0),char(64),char(0),char(-128),char(0),char(20),char(0),char(48),char(0),char(80),char(0),char(16),char(0),char(84),char(0), -char(-124),char(0),char(12),char(0),char(52),char(0),char(52),char(0),char(20),char(0),char(64),char(0),char(4),char(0),char(4),char(0),char(8),char(0),char(4),char(0), -char(32),char(0),char(28),char(0),char(60),char(0),char(56),char(0),char(76),char(0),char(76),char(0),char(24),char(0),char(60),char(0),char(60),char(0),char(60),char(0), -char(16),char(0),char(64),char(0),char(68),char(0),char(-48),char(1),char(0),char(1),char(-104),char(0),char(88),char(0),char(-72),char(0),char(104),char(0),char(-24),char(1), -char(-96),char(3),char(8),char(0),char(52),char(0),char(52),char(0),char(0),char(0),char(68),char(0),char(84),char(0),char(-124),char(0),char(116),char(0),char(92),char(1), -char(-36),char(0),char(-116),char(1),char(124),char(1),char(-44),char(0),char(-4),char(0),char(-52),char(1),char(92),char(1),char(116),char(2),char(-124),char(2),char(-76),char(4), -char(-52),char(0),char(108),char(1),char(92),char(0),char(-116),char(0),char(16),char(0),char(100),char(0),char(20),char(0),char(36),char(0),char(100),char(0),char(92),char(0), -char(104),char(0),char(-64),char(0),char(92),char(1),char(104),char(0),char(-84),char(1),char(-48),char(2),char(120),char(1),char(-64),char(0),char(100),char(0),char(0),char(0), -char(83),char(84),char(82),char(67),char(84),char(0),char(0),char(0),char(10),char(0),char(3),char(0),char(4),char(0),char(0),char(0),char(4),char(0),char(1),char(0), -char(9),char(0),char(2),char(0),char(11),char(0),char(3),char(0),char(10),char(0),char(3),char(0),char(10),char(0),char(4),char(0),char(10),char(0),char(5),char(0), -char(12),char(0),char(2),char(0),char(9),char(0),char(6),char(0),char(9),char(0),char(7),char(0),char(13),char(0),char(1),char(0),char(7),char(0),char(8),char(0), -char(14),char(0),char(1),char(0),char(8),char(0),char(8),char(0),char(15),char(0),char(1),char(0),char(7),char(0),char(8),char(0),char(16),char(0),char(1),char(0), -char(8),char(0),char(8),char(0),char(17),char(0),char(1),char(0),char(13),char(0),char(9),char(0),char(18),char(0),char(1),char(0),char(14),char(0),char(9),char(0), -char(19),char(0),char(2),char(0),char(17),char(0),char(10),char(0),char(13),char(0),char(11),char(0),char(20),char(0),char(2),char(0),char(18),char(0),char(10),char(0), -char(14),char(0),char(11),char(0),char(21),char(0),char(4),char(0),char(4),char(0),char(12),char(0),char(4),char(0),char(13),char(0),char(2),char(0),char(14),char(0), -char(2),char(0),char(15),char(0),char(22),char(0),char(6),char(0),char(13),char(0),char(16),char(0),char(13),char(0),char(17),char(0),char(4),char(0),char(18),char(0), -char(4),char(0),char(19),char(0),char(4),char(0),char(20),char(0),char(0),char(0),char(21),char(0),char(23),char(0),char(6),char(0),char(14),char(0),char(16),char(0), -char(14),char(0),char(17),char(0),char(4),char(0),char(18),char(0),char(4),char(0),char(19),char(0),char(4),char(0),char(20),char(0),char(0),char(0),char(21),char(0), -char(24),char(0),char(3),char(0),char(2),char(0),char(14),char(0),char(2),char(0),char(15),char(0),char(4),char(0),char(22),char(0),char(25),char(0),char(12),char(0), -char(13),char(0),char(23),char(0),char(13),char(0),char(24),char(0),char(13),char(0),char(25),char(0),char(4),char(0),char(26),char(0),char(4),char(0),char(27),char(0), -char(4),char(0),char(28),char(0),char(4),char(0),char(29),char(0),char(22),char(0),char(30),char(0),char(24),char(0),char(31),char(0),char(21),char(0),char(32),char(0), -char(4),char(0),char(33),char(0),char(4),char(0),char(34),char(0),char(26),char(0),char(12),char(0),char(14),char(0),char(23),char(0),char(14),char(0),char(24),char(0), -char(14),char(0),char(25),char(0),char(4),char(0),char(26),char(0),char(4),char(0),char(27),char(0),char(4),char(0),char(28),char(0),char(4),char(0),char(29),char(0), -char(23),char(0),char(30),char(0),char(24),char(0),char(31),char(0),char(4),char(0),char(33),char(0),char(4),char(0),char(34),char(0),char(21),char(0),char(32),char(0), -char(27),char(0),char(3),char(0),char(0),char(0),char(35),char(0),char(4),char(0),char(36),char(0),char(0),char(0),char(37),char(0),char(28),char(0),char(5),char(0), -char(27),char(0),char(38),char(0),char(13),char(0),char(39),char(0),char(13),char(0),char(40),char(0),char(7),char(0),char(41),char(0),char(0),char(0),char(21),char(0), -char(29),char(0),char(5),char(0),char(27),char(0),char(38),char(0),char(13),char(0),char(39),char(0),char(13),char(0),char(42),char(0),char(7),char(0),char(43),char(0), -char(4),char(0),char(44),char(0),char(30),char(0),char(2),char(0),char(13),char(0),char(45),char(0),char(7),char(0),char(46),char(0),char(31),char(0),char(4),char(0), -char(29),char(0),char(47),char(0),char(30),char(0),char(48),char(0),char(4),char(0),char(49),char(0),char(0),char(0),char(37),char(0),char(32),char(0),char(1),char(0), -char(4),char(0),char(50),char(0),char(33),char(0),char(2),char(0),char(2),char(0),char(50),char(0),char(0),char(0),char(51),char(0),char(34),char(0),char(2),char(0), -char(2),char(0),char(52),char(0),char(0),char(0),char(51),char(0),char(35),char(0),char(2),char(0),char(0),char(0),char(52),char(0),char(0),char(0),char(53),char(0), -char(36),char(0),char(8),char(0),char(13),char(0),char(54),char(0),char(14),char(0),char(55),char(0),char(32),char(0),char(56),char(0),char(34),char(0),char(57),char(0), -char(35),char(0),char(58),char(0),char(33),char(0),char(59),char(0),char(4),char(0),char(60),char(0),char(4),char(0),char(61),char(0),char(37),char(0),char(4),char(0), -char(36),char(0),char(62),char(0),char(13),char(0),char(63),char(0),char(4),char(0),char(64),char(0),char(0),char(0),char(37),char(0),char(38),char(0),char(7),char(0), -char(27),char(0),char(38),char(0),char(37),char(0),char(65),char(0),char(25),char(0),char(66),char(0),char(26),char(0),char(67),char(0),char(39),char(0),char(68),char(0), -char(7),char(0),char(43),char(0),char(0),char(0),char(69),char(0),char(40),char(0),char(2),char(0),char(38),char(0),char(70),char(0),char(13),char(0),char(39),char(0), -char(41),char(0),char(4),char(0),char(19),char(0),char(71),char(0),char(27),char(0),char(72),char(0),char(4),char(0),char(73),char(0),char(7),char(0),char(74),char(0), -char(42),char(0),char(4),char(0),char(27),char(0),char(38),char(0),char(41),char(0),char(75),char(0),char(4),char(0),char(76),char(0),char(7),char(0),char(43),char(0), -char(43),char(0),char(3),char(0),char(29),char(0),char(47),char(0),char(4),char(0),char(77),char(0),char(0),char(0),char(37),char(0),char(44),char(0),char(3),char(0), -char(29),char(0),char(47),char(0),char(4),char(0),char(78),char(0),char(0),char(0),char(37),char(0),char(45),char(0),char(3),char(0),char(29),char(0),char(47),char(0), -char(4),char(0),char(77),char(0),char(0),char(0),char(37),char(0),char(46),char(0),char(4),char(0),char(4),char(0),char(79),char(0),char(7),char(0),char(80),char(0), -char(7),char(0),char(81),char(0),char(7),char(0),char(82),char(0),char(39),char(0),char(14),char(0),char(4),char(0),char(83),char(0),char(4),char(0),char(84),char(0), -char(46),char(0),char(85),char(0),char(4),char(0),char(86),char(0),char(7),char(0),char(87),char(0),char(7),char(0),char(88),char(0),char(7),char(0),char(89),char(0), -char(7),char(0),char(90),char(0),char(7),char(0),char(91),char(0),char(4),char(0),char(92),char(0),char(4),char(0),char(93),char(0),char(4),char(0),char(94),char(0), -char(4),char(0),char(95),char(0),char(0),char(0),char(37),char(0),char(47),char(0),char(5),char(0),char(27),char(0),char(38),char(0),char(37),char(0),char(65),char(0), -char(13),char(0),char(39),char(0),char(7),char(0),char(43),char(0),char(4),char(0),char(96),char(0),char(48),char(0),char(5),char(0),char(29),char(0),char(47),char(0), -char(13),char(0),char(97),char(0),char(14),char(0),char(98),char(0),char(4),char(0),char(99),char(0),char(0),char(0),char(100),char(0),char(49),char(0),char(25),char(0), -char(9),char(0),char(101),char(0),char(9),char(0),char(102),char(0),char(27),char(0),char(103),char(0),char(0),char(0),char(35),char(0),char(20),char(0),char(104),char(0), -char(20),char(0),char(105),char(0),char(14),char(0),char(106),char(0),char(14),char(0),char(107),char(0),char(14),char(0),char(108),char(0),char(8),char(0),char(109),char(0), -char(8),char(0),char(110),char(0),char(8),char(0),char(111),char(0),char(8),char(0),char(112),char(0),char(8),char(0),char(113),char(0),char(8),char(0),char(114),char(0), -char(8),char(0),char(115),char(0),char(8),char(0),char(116),char(0),char(4),char(0),char(117),char(0),char(4),char(0),char(118),char(0),char(4),char(0),char(119),char(0), -char(4),char(0),char(120),char(0),char(4),char(0),char(121),char(0),char(4),char(0),char(122),char(0),char(4),char(0),char(123),char(0),char(0),char(0),char(37),char(0), -char(50),char(0),char(25),char(0),char(9),char(0),char(101),char(0),char(9),char(0),char(102),char(0),char(27),char(0),char(103),char(0),char(0),char(0),char(35),char(0), -char(19),char(0),char(104),char(0),char(19),char(0),char(105),char(0),char(13),char(0),char(106),char(0),char(13),char(0),char(107),char(0),char(13),char(0),char(108),char(0), -char(7),char(0),char(109),char(0),char(7),char(0),char(110),char(0),char(7),char(0),char(111),char(0),char(7),char(0),char(112),char(0),char(7),char(0),char(113),char(0), -char(7),char(0),char(114),char(0),char(7),char(0),char(115),char(0),char(7),char(0),char(116),char(0),char(4),char(0),char(117),char(0),char(4),char(0),char(118),char(0), -char(4),char(0),char(119),char(0),char(4),char(0),char(120),char(0),char(4),char(0),char(121),char(0),char(4),char(0),char(122),char(0),char(4),char(0),char(123),char(0), -char(0),char(0),char(37),char(0),char(51),char(0),char(22),char(0),char(8),char(0),char(124),char(0),char(8),char(0),char(125),char(0),char(8),char(0),char(111),char(0), -char(8),char(0),char(126),char(0),char(8),char(0),char(113),char(0),char(8),char(0),char(127),char(0),char(8),char(0),char(-128),char(0),char(8),char(0),char(-127),char(0), -char(8),char(0),char(-126),char(0),char(8),char(0),char(-125),char(0),char(8),char(0),char(-124),char(0),char(8),char(0),char(-123),char(0),char(8),char(0),char(-122),char(0), -char(8),char(0),char(-121),char(0),char(8),char(0),char(-120),char(0),char(8),char(0),char(-119),char(0),char(4),char(0),char(-118),char(0),char(4),char(0),char(-117),char(0), -char(4),char(0),char(-116),char(0),char(4),char(0),char(-115),char(0),char(4),char(0),char(-114),char(0),char(0),char(0),char(37),char(0),char(52),char(0),char(22),char(0), -char(7),char(0),char(124),char(0),char(7),char(0),char(125),char(0),char(7),char(0),char(111),char(0),char(7),char(0),char(126),char(0),char(7),char(0),char(113),char(0), -char(7),char(0),char(127),char(0),char(7),char(0),char(-128),char(0),char(7),char(0),char(-127),char(0),char(7),char(0),char(-126),char(0),char(7),char(0),char(-125),char(0), -char(7),char(0),char(-124),char(0),char(7),char(0),char(-123),char(0),char(7),char(0),char(-122),char(0),char(7),char(0),char(-121),char(0),char(7),char(0),char(-120),char(0), -char(7),char(0),char(-119),char(0),char(4),char(0),char(-118),char(0),char(4),char(0),char(-117),char(0),char(4),char(0),char(-116),char(0),char(4),char(0),char(-115),char(0), -char(4),char(0),char(-114),char(0),char(0),char(0),char(37),char(0),char(53),char(0),char(2),char(0),char(51),char(0),char(-113),char(0),char(14),char(0),char(-112),char(0), -char(54),char(0),char(2),char(0),char(52),char(0),char(-113),char(0),char(13),char(0),char(-112),char(0),char(55),char(0),char(21),char(0),char(50),char(0),char(-111),char(0), -char(17),char(0),char(-110),char(0),char(13),char(0),char(-109),char(0),char(13),char(0),char(-108),char(0),char(13),char(0),char(-107),char(0),char(13),char(0),char(-106),char(0), -char(13),char(0),char(-112),char(0),char(13),char(0),char(-105),char(0),char(13),char(0),char(-104),char(0),char(13),char(0),char(-103),char(0),char(13),char(0),char(-102),char(0), -char(7),char(0),char(-101),char(0),char(7),char(0),char(-100),char(0),char(7),char(0),char(-99),char(0),char(7),char(0),char(-98),char(0),char(7),char(0),char(-97),char(0), -char(7),char(0),char(-96),char(0),char(7),char(0),char(-95),char(0),char(7),char(0),char(-94),char(0),char(7),char(0),char(-93),char(0),char(4),char(0),char(-92),char(0), -char(56),char(0),char(22),char(0),char(49),char(0),char(-111),char(0),char(18),char(0),char(-110),char(0),char(14),char(0),char(-109),char(0),char(14),char(0),char(-108),char(0), -char(14),char(0),char(-107),char(0),char(14),char(0),char(-106),char(0),char(14),char(0),char(-112),char(0),char(14),char(0),char(-105),char(0),char(14),char(0),char(-104),char(0), -char(14),char(0),char(-103),char(0),char(14),char(0),char(-102),char(0),char(8),char(0),char(-101),char(0),char(8),char(0),char(-100),char(0),char(8),char(0),char(-99),char(0), -char(8),char(0),char(-98),char(0),char(8),char(0),char(-97),char(0),char(8),char(0),char(-96),char(0),char(8),char(0),char(-95),char(0),char(8),char(0),char(-94),char(0), -char(8),char(0),char(-93),char(0),char(4),char(0),char(-92),char(0),char(0),char(0),char(37),char(0),char(57),char(0),char(2),char(0),char(4),char(0),char(-91),char(0), -char(4),char(0),char(-90),char(0),char(58),char(0),char(13),char(0),char(55),char(0),char(-89),char(0),char(55),char(0),char(-88),char(0),char(0),char(0),char(35),char(0), -char(4),char(0),char(-87),char(0),char(4),char(0),char(-86),char(0),char(4),char(0),char(-85),char(0),char(4),char(0),char(-84),char(0),char(7),char(0),char(-83),char(0), -char(7),char(0),char(-82),char(0),char(4),char(0),char(-81),char(0),char(4),char(0),char(-80),char(0),char(7),char(0),char(-79),char(0),char(4),char(0),char(-78),char(0), -char(59),char(0),char(13),char(0),char(60),char(0),char(-89),char(0),char(60),char(0),char(-88),char(0),char(0),char(0),char(35),char(0),char(4),char(0),char(-87),char(0), -char(4),char(0),char(-86),char(0),char(4),char(0),char(-85),char(0),char(4),char(0),char(-84),char(0),char(7),char(0),char(-83),char(0),char(7),char(0),char(-82),char(0), -char(4),char(0),char(-81),char(0),char(4),char(0),char(-80),char(0),char(7),char(0),char(-79),char(0),char(4),char(0),char(-78),char(0),char(61),char(0),char(14),char(0), -char(56),char(0),char(-89),char(0),char(56),char(0),char(-88),char(0),char(0),char(0),char(35),char(0),char(4),char(0),char(-87),char(0),char(4),char(0),char(-86),char(0), -char(4),char(0),char(-85),char(0),char(4),char(0),char(-84),char(0),char(8),char(0),char(-83),char(0),char(8),char(0),char(-82),char(0),char(4),char(0),char(-81),char(0), -char(4),char(0),char(-80),char(0),char(8),char(0),char(-79),char(0),char(4),char(0),char(-78),char(0),char(0),char(0),char(-77),char(0),char(62),char(0),char(3),char(0), -char(59),char(0),char(-76),char(0),char(13),char(0),char(-75),char(0),char(13),char(0),char(-74),char(0),char(63),char(0),char(3),char(0),char(61),char(0),char(-76),char(0), -char(14),char(0),char(-75),char(0),char(14),char(0),char(-74),char(0),char(64),char(0),char(3),char(0),char(59),char(0),char(-76),char(0),char(14),char(0),char(-75),char(0), -char(14),char(0),char(-74),char(0),char(65),char(0),char(13),char(0),char(59),char(0),char(-76),char(0),char(20),char(0),char(-73),char(0),char(20),char(0),char(-72),char(0), -char(4),char(0),char(-71),char(0),char(4),char(0),char(-70),char(0),char(4),char(0),char(-69),char(0),char(7),char(0),char(-68),char(0),char(7),char(0),char(-67),char(0), +char(0),char(98),char(116),char(67),char(111),char(110),char(101),char(84),char(119),char(105),char(115),char(116),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105), +char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(110),char(101),char(84), +char(119),char(105),char(115),char(116),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(97),char(116),char(97),char(0),char(98), +char(116),char(71),char(101),char(110),char(101),char(114),char(105),char(99),char(54),char(68),char(111),char(102),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105), +char(110),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(71),char(101),char(110),char(101),char(114),char(105),char(99),char(54),char(68),char(111),char(102), +char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97), +char(50),char(0),char(98),char(116),char(71),char(101),char(110),char(101),char(114),char(105),char(99),char(54),char(68),char(111),char(102),char(83),char(112),char(114),char(105),char(110), +char(103),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(71),char(101), +char(110),char(101),char(114),char(105),char(99),char(54),char(68),char(111),char(102),char(83),char(112),char(114),char(105),char(110),char(103),char(67),char(111),char(110),char(115),char(116), +char(114),char(97),char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(50),char(0),char(98),char(116),char(71), +char(101),char(110),char(101),char(114),char(105),char(99),char(54),char(68),char(111),char(102),char(83),char(112),char(114),char(105),char(110),char(103),char(50),char(67),char(111),char(110), +char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(71),char(101),char(110),char(101),char(114),char(105), +char(99),char(54),char(68),char(111),char(102),char(83),char(112),char(114),char(105),char(110),char(103),char(50),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105), +char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(50),char(0),char(98),char(116),char(83),char(108),char(105),char(100), +char(101),char(114),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(83), +char(108),char(105),char(100),char(101),char(114),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108), +char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(71),char(101),char(97),char(114),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105), +char(110),char(116),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(71),char(101),char(97),char(114),char(67),char(111), +char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(83), +char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(77),char(97),char(116),char(101),char(114),char(105),char(97),char(108),char(68),char(97),char(116),char(97),char(0), +char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(78),char(111),char(100),char(101),char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102), +char(116),char(66),char(111),char(100),char(121),char(76),char(105),char(110),char(107),char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102),char(116),char(66),char(111), +char(100),char(121),char(70),char(97),char(99),char(101),char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(84), +char(101),char(116),char(114),char(97),char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102),char(116),char(82),char(105),char(103),char(105),char(100),char(65),char(110), +char(99),char(104),char(111),char(114),char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(67),char(111),char(110), +char(102),char(105),char(103),char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(80),char(111),char(115),char(101), +char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(67),char(108),char(117),char(115),char(116),char(101),char(114), +char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(74),char(111),char(105),char(110),char(116), +char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(70),char(108),char(111),char(97),char(116), +char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(77),char(117),char(108),char(116),char(105),char(66),char(111),char(100),char(121),char(76),char(105),char(110),char(107), +char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(77),char(117),char(108),char(116),char(105),char(66),char(111), +char(100),char(121),char(76),char(105),char(110),char(107),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(77),char(117), +char(108),char(116),char(105),char(66),char(111),char(100),char(121),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116), +char(77),char(117),char(108),char(116),char(105),char(66),char(111),char(100),char(121),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(0), +char(84),char(76),char(69),char(78),char(1),char(0),char(1),char(0),char(2),char(0),char(2),char(0),char(4),char(0),char(4),char(0),char(4),char(0),char(4),char(0), +char(8),char(0),char(0),char(0),char(12),char(0),char(36),char(0),char(8),char(0),char(16),char(0),char(32),char(0),char(16),char(0),char(32),char(0),char(48),char(0), +char(96),char(0),char(64),char(0),char(-128),char(0),char(20),char(0),char(48),char(0),char(80),char(0),char(16),char(0),char(84),char(0),char(-124),char(0),char(12),char(0), +char(52),char(0),char(52),char(0),char(20),char(0),char(64),char(0),char(4),char(0),char(4),char(0),char(8),char(0),char(4),char(0),char(32),char(0),char(28),char(0), +char(60),char(0),char(56),char(0),char(76),char(0),char(76),char(0),char(24),char(0),char(60),char(0),char(60),char(0),char(60),char(0),char(16),char(0),char(64),char(0), +char(68),char(0),char(-32),char(1),char(8),char(1),char(-104),char(0),char(88),char(0),char(-72),char(0),char(104),char(0),char(-16),char(1),char(-80),char(3),char(8),char(0), +char(52),char(0),char(52),char(0),char(0),char(0),char(68),char(0),char(84),char(0),char(-124),char(0),char(116),char(0),char(92),char(1),char(-36),char(0),char(-116),char(1), +char(124),char(1),char(-44),char(0),char(-4),char(0),char(-52),char(1),char(92),char(1),char(116),char(2),char(-124),char(2),char(-76),char(4),char(-52),char(0),char(108),char(1), +char(92),char(0),char(-116),char(0),char(16),char(0),char(100),char(0),char(20),char(0),char(36),char(0),char(100),char(0),char(92),char(0),char(104),char(0),char(-64),char(0), +char(92),char(1),char(104),char(0),char(-76),char(1),char(-48),char(2),char(120),char(1),char(-64),char(0),char(100),char(0),char(0),char(0),char(83),char(84),char(82),char(67), +char(84),char(0),char(0),char(0),char(10),char(0),char(3),char(0),char(4),char(0),char(0),char(0),char(4),char(0),char(1),char(0),char(9),char(0),char(2),char(0), +char(11),char(0),char(3),char(0),char(10),char(0),char(3),char(0),char(10),char(0),char(4),char(0),char(10),char(0),char(5),char(0),char(12),char(0),char(2),char(0), +char(9),char(0),char(6),char(0),char(9),char(0),char(7),char(0),char(13),char(0),char(1),char(0),char(7),char(0),char(8),char(0),char(14),char(0),char(1),char(0), +char(8),char(0),char(8),char(0),char(15),char(0),char(1),char(0),char(7),char(0),char(8),char(0),char(16),char(0),char(1),char(0),char(8),char(0),char(8),char(0), +char(17),char(0),char(1),char(0),char(13),char(0),char(9),char(0),char(18),char(0),char(1),char(0),char(14),char(0),char(9),char(0),char(19),char(0),char(2),char(0), +char(17),char(0),char(10),char(0),char(13),char(0),char(11),char(0),char(20),char(0),char(2),char(0),char(18),char(0),char(10),char(0),char(14),char(0),char(11),char(0), +char(21),char(0),char(4),char(0),char(4),char(0),char(12),char(0),char(4),char(0),char(13),char(0),char(2),char(0),char(14),char(0),char(2),char(0),char(15),char(0), +char(22),char(0),char(6),char(0),char(13),char(0),char(16),char(0),char(13),char(0),char(17),char(0),char(4),char(0),char(18),char(0),char(4),char(0),char(19),char(0), +char(4),char(0),char(20),char(0),char(0),char(0),char(21),char(0),char(23),char(0),char(6),char(0),char(14),char(0),char(16),char(0),char(14),char(0),char(17),char(0), +char(4),char(0),char(18),char(0),char(4),char(0),char(19),char(0),char(4),char(0),char(20),char(0),char(0),char(0),char(21),char(0),char(24),char(0),char(3),char(0), +char(2),char(0),char(14),char(0),char(2),char(0),char(15),char(0),char(4),char(0),char(22),char(0),char(25),char(0),char(12),char(0),char(13),char(0),char(23),char(0), +char(13),char(0),char(24),char(0),char(13),char(0),char(25),char(0),char(4),char(0),char(26),char(0),char(4),char(0),char(27),char(0),char(4),char(0),char(28),char(0), +char(4),char(0),char(29),char(0),char(22),char(0),char(30),char(0),char(24),char(0),char(31),char(0),char(21),char(0),char(32),char(0),char(4),char(0),char(33),char(0), +char(4),char(0),char(34),char(0),char(26),char(0),char(12),char(0),char(14),char(0),char(23),char(0),char(14),char(0),char(24),char(0),char(14),char(0),char(25),char(0), +char(4),char(0),char(26),char(0),char(4),char(0),char(27),char(0),char(4),char(0),char(28),char(0),char(4),char(0),char(29),char(0),char(23),char(0),char(30),char(0), +char(24),char(0),char(31),char(0),char(4),char(0),char(33),char(0),char(4),char(0),char(34),char(0),char(21),char(0),char(32),char(0),char(27),char(0),char(3),char(0), +char(0),char(0),char(35),char(0),char(4),char(0),char(36),char(0),char(0),char(0),char(37),char(0),char(28),char(0),char(5),char(0),char(27),char(0),char(38),char(0), +char(13),char(0),char(39),char(0),char(13),char(0),char(40),char(0),char(7),char(0),char(41),char(0),char(0),char(0),char(21),char(0),char(29),char(0),char(5),char(0), +char(27),char(0),char(38),char(0),char(13),char(0),char(39),char(0),char(13),char(0),char(42),char(0),char(7),char(0),char(43),char(0),char(4),char(0),char(44),char(0), +char(30),char(0),char(2),char(0),char(13),char(0),char(45),char(0),char(7),char(0),char(46),char(0),char(31),char(0),char(4),char(0),char(29),char(0),char(47),char(0), +char(30),char(0),char(48),char(0),char(4),char(0),char(49),char(0),char(0),char(0),char(37),char(0),char(32),char(0),char(1),char(0),char(4),char(0),char(50),char(0), +char(33),char(0),char(2),char(0),char(2),char(0),char(50),char(0),char(0),char(0),char(51),char(0),char(34),char(0),char(2),char(0),char(2),char(0),char(52),char(0), +char(0),char(0),char(51),char(0),char(35),char(0),char(2),char(0),char(0),char(0),char(52),char(0),char(0),char(0),char(53),char(0),char(36),char(0),char(8),char(0), +char(13),char(0),char(54),char(0),char(14),char(0),char(55),char(0),char(32),char(0),char(56),char(0),char(34),char(0),char(57),char(0),char(35),char(0),char(58),char(0), +char(33),char(0),char(59),char(0),char(4),char(0),char(60),char(0),char(4),char(0),char(61),char(0),char(37),char(0),char(4),char(0),char(36),char(0),char(62),char(0), +char(13),char(0),char(63),char(0),char(4),char(0),char(64),char(0),char(0),char(0),char(37),char(0),char(38),char(0),char(7),char(0),char(27),char(0),char(38),char(0), +char(37),char(0),char(65),char(0),char(25),char(0),char(66),char(0),char(26),char(0),char(67),char(0),char(39),char(0),char(68),char(0),char(7),char(0),char(43),char(0), +char(0),char(0),char(69),char(0),char(40),char(0),char(2),char(0),char(38),char(0),char(70),char(0),char(13),char(0),char(39),char(0),char(41),char(0),char(4),char(0), +char(19),char(0),char(71),char(0),char(27),char(0),char(72),char(0),char(4),char(0),char(73),char(0),char(7),char(0),char(74),char(0),char(42),char(0),char(4),char(0), +char(27),char(0),char(38),char(0),char(41),char(0),char(75),char(0),char(4),char(0),char(76),char(0),char(7),char(0),char(43),char(0),char(43),char(0),char(3),char(0), +char(29),char(0),char(47),char(0),char(4),char(0),char(77),char(0),char(0),char(0),char(37),char(0),char(44),char(0),char(3),char(0),char(29),char(0),char(47),char(0), +char(4),char(0),char(78),char(0),char(0),char(0),char(37),char(0),char(45),char(0),char(3),char(0),char(29),char(0),char(47),char(0),char(4),char(0),char(77),char(0), +char(0),char(0),char(37),char(0),char(46),char(0),char(4),char(0),char(4),char(0),char(79),char(0),char(7),char(0),char(80),char(0),char(7),char(0),char(81),char(0), +char(7),char(0),char(82),char(0),char(39),char(0),char(14),char(0),char(4),char(0),char(83),char(0),char(4),char(0),char(84),char(0),char(46),char(0),char(85),char(0), +char(4),char(0),char(86),char(0),char(7),char(0),char(87),char(0),char(7),char(0),char(88),char(0),char(7),char(0),char(89),char(0),char(7),char(0),char(90),char(0), +char(7),char(0),char(91),char(0),char(4),char(0),char(92),char(0),char(4),char(0),char(93),char(0),char(4),char(0),char(94),char(0),char(4),char(0),char(95),char(0), +char(0),char(0),char(37),char(0),char(47),char(0),char(5),char(0),char(27),char(0),char(38),char(0),char(37),char(0),char(65),char(0),char(13),char(0),char(39),char(0), +char(7),char(0),char(43),char(0),char(4),char(0),char(96),char(0),char(48),char(0),char(5),char(0),char(29),char(0),char(47),char(0),char(13),char(0),char(97),char(0), +char(14),char(0),char(98),char(0),char(4),char(0),char(99),char(0),char(0),char(0),char(100),char(0),char(49),char(0),char(27),char(0),char(9),char(0),char(101),char(0), +char(9),char(0),char(102),char(0),char(27),char(0),char(103),char(0),char(0),char(0),char(35),char(0),char(20),char(0),char(104),char(0),char(20),char(0),char(105),char(0), +char(14),char(0),char(106),char(0),char(14),char(0),char(107),char(0),char(14),char(0),char(108),char(0),char(8),char(0),char(109),char(0),char(8),char(0),char(110),char(0), +char(8),char(0),char(111),char(0),char(8),char(0),char(112),char(0),char(8),char(0),char(113),char(0),char(8),char(0),char(114),char(0),char(8),char(0),char(115),char(0), +char(8),char(0),char(116),char(0),char(8),char(0),char(117),char(0),char(8),char(0),char(118),char(0),char(4),char(0),char(119),char(0),char(4),char(0),char(120),char(0), +char(4),char(0),char(121),char(0),char(4),char(0),char(122),char(0),char(4),char(0),char(123),char(0),char(4),char(0),char(124),char(0),char(4),char(0),char(125),char(0), +char(0),char(0),char(37),char(0),char(50),char(0),char(27),char(0),char(9),char(0),char(101),char(0),char(9),char(0),char(102),char(0),char(27),char(0),char(103),char(0), +char(0),char(0),char(35),char(0),char(19),char(0),char(104),char(0),char(19),char(0),char(105),char(0),char(13),char(0),char(106),char(0),char(13),char(0),char(107),char(0), +char(13),char(0),char(108),char(0),char(7),char(0),char(109),char(0),char(7),char(0),char(110),char(0),char(7),char(0),char(111),char(0),char(7),char(0),char(112),char(0), +char(7),char(0),char(113),char(0),char(7),char(0),char(114),char(0),char(7),char(0),char(115),char(0),char(7),char(0),char(116),char(0),char(7),char(0),char(117),char(0), +char(7),char(0),char(118),char(0),char(4),char(0),char(119),char(0),char(4),char(0),char(120),char(0),char(4),char(0),char(121),char(0),char(4),char(0),char(122),char(0), +char(4),char(0),char(123),char(0),char(4),char(0),char(124),char(0),char(4),char(0),char(125),char(0),char(0),char(0),char(37),char(0),char(51),char(0),char(22),char(0), +char(8),char(0),char(126),char(0),char(8),char(0),char(127),char(0),char(8),char(0),char(111),char(0),char(8),char(0),char(-128),char(0),char(8),char(0),char(115),char(0), +char(8),char(0),char(-127),char(0),char(8),char(0),char(-126),char(0),char(8),char(0),char(-125),char(0),char(8),char(0),char(-124),char(0),char(8),char(0),char(-123),char(0), +char(8),char(0),char(-122),char(0),char(8),char(0),char(-121),char(0),char(8),char(0),char(-120),char(0),char(8),char(0),char(-119),char(0),char(8),char(0),char(-118),char(0), +char(8),char(0),char(-117),char(0),char(4),char(0),char(-116),char(0),char(4),char(0),char(-115),char(0),char(4),char(0),char(-114),char(0),char(4),char(0),char(-113),char(0), +char(4),char(0),char(-112),char(0),char(0),char(0),char(37),char(0),char(52),char(0),char(22),char(0),char(7),char(0),char(126),char(0),char(7),char(0),char(127),char(0), +char(7),char(0),char(111),char(0),char(7),char(0),char(-128),char(0),char(7),char(0),char(115),char(0),char(7),char(0),char(-127),char(0),char(7),char(0),char(-126),char(0), +char(7),char(0),char(-125),char(0),char(7),char(0),char(-124),char(0),char(7),char(0),char(-123),char(0),char(7),char(0),char(-122),char(0),char(7),char(0),char(-121),char(0), +char(7),char(0),char(-120),char(0),char(7),char(0),char(-119),char(0),char(7),char(0),char(-118),char(0),char(7),char(0),char(-117),char(0),char(4),char(0),char(-116),char(0), +char(4),char(0),char(-115),char(0),char(4),char(0),char(-114),char(0),char(4),char(0),char(-113),char(0),char(4),char(0),char(-112),char(0),char(0),char(0),char(37),char(0), +char(53),char(0),char(2),char(0),char(51),char(0),char(-111),char(0),char(14),char(0),char(-110),char(0),char(54),char(0),char(2),char(0),char(52),char(0),char(-111),char(0), +char(13),char(0),char(-110),char(0),char(55),char(0),char(21),char(0),char(50),char(0),char(-109),char(0),char(17),char(0),char(-108),char(0),char(13),char(0),char(-107),char(0), +char(13),char(0),char(-106),char(0),char(13),char(0),char(-105),char(0),char(13),char(0),char(-104),char(0),char(13),char(0),char(-110),char(0),char(13),char(0),char(-103),char(0), +char(13),char(0),char(-102),char(0),char(13),char(0),char(-101),char(0),char(13),char(0),char(-100),char(0),char(7),char(0),char(-99),char(0),char(7),char(0),char(-98),char(0), +char(7),char(0),char(-97),char(0),char(7),char(0),char(-96),char(0),char(7),char(0),char(-95),char(0),char(7),char(0),char(-94),char(0),char(7),char(0),char(-93),char(0), +char(7),char(0),char(-92),char(0),char(7),char(0),char(-91),char(0),char(4),char(0),char(-90),char(0),char(56),char(0),char(22),char(0),char(49),char(0),char(-109),char(0), +char(18),char(0),char(-108),char(0),char(14),char(0),char(-107),char(0),char(14),char(0),char(-106),char(0),char(14),char(0),char(-105),char(0),char(14),char(0),char(-104),char(0), +char(14),char(0),char(-110),char(0),char(14),char(0),char(-103),char(0),char(14),char(0),char(-102),char(0),char(14),char(0),char(-101),char(0),char(14),char(0),char(-100),char(0), +char(8),char(0),char(-99),char(0),char(8),char(0),char(-98),char(0),char(8),char(0),char(-97),char(0),char(8),char(0),char(-96),char(0),char(8),char(0),char(-95),char(0), +char(8),char(0),char(-94),char(0),char(8),char(0),char(-93),char(0),char(8),char(0),char(-92),char(0),char(8),char(0),char(-91),char(0),char(4),char(0),char(-90),char(0), +char(0),char(0),char(37),char(0),char(57),char(0),char(2),char(0),char(4),char(0),char(-89),char(0),char(4),char(0),char(-88),char(0),char(58),char(0),char(13),char(0), +char(55),char(0),char(-87),char(0),char(55),char(0),char(-86),char(0),char(0),char(0),char(35),char(0),char(4),char(0),char(-85),char(0),char(4),char(0),char(-84),char(0), +char(4),char(0),char(-83),char(0),char(4),char(0),char(-82),char(0),char(7),char(0),char(-81),char(0),char(7),char(0),char(-80),char(0),char(4),char(0),char(-79),char(0), +char(4),char(0),char(-78),char(0),char(7),char(0),char(-77),char(0),char(4),char(0),char(-76),char(0),char(59),char(0),char(13),char(0),char(60),char(0),char(-87),char(0), +char(60),char(0),char(-86),char(0),char(0),char(0),char(35),char(0),char(4),char(0),char(-85),char(0),char(4),char(0),char(-84),char(0),char(4),char(0),char(-83),char(0), +char(4),char(0),char(-82),char(0),char(7),char(0),char(-81),char(0),char(7),char(0),char(-80),char(0),char(4),char(0),char(-79),char(0),char(4),char(0),char(-78),char(0), +char(7),char(0),char(-77),char(0),char(4),char(0),char(-76),char(0),char(61),char(0),char(14),char(0),char(56),char(0),char(-87),char(0),char(56),char(0),char(-86),char(0), +char(0),char(0),char(35),char(0),char(4),char(0),char(-85),char(0),char(4),char(0),char(-84),char(0),char(4),char(0),char(-83),char(0),char(4),char(0),char(-82),char(0), +char(8),char(0),char(-81),char(0),char(8),char(0),char(-80),char(0),char(4),char(0),char(-79),char(0),char(4),char(0),char(-78),char(0),char(8),char(0),char(-77),char(0), +char(4),char(0),char(-76),char(0),char(0),char(0),char(-75),char(0),char(62),char(0),char(3),char(0),char(59),char(0),char(-74),char(0),char(13),char(0),char(-73),char(0), +char(13),char(0),char(-72),char(0),char(63),char(0),char(3),char(0),char(61),char(0),char(-74),char(0),char(14),char(0),char(-73),char(0),char(14),char(0),char(-72),char(0), +char(64),char(0),char(3),char(0),char(59),char(0),char(-74),char(0),char(14),char(0),char(-73),char(0),char(14),char(0),char(-72),char(0),char(65),char(0),char(13),char(0), +char(59),char(0),char(-74),char(0),char(20),char(0),char(-71),char(0),char(20),char(0),char(-70),char(0),char(4),char(0),char(-69),char(0),char(4),char(0),char(-68),char(0), +char(4),char(0),char(-67),char(0),char(7),char(0),char(-66),char(0),char(7),char(0),char(-65),char(0),char(7),char(0),char(-64),char(0),char(7),char(0),char(-63),char(0), +char(7),char(0),char(-62),char(0),char(7),char(0),char(-61),char(0),char(7),char(0),char(-60),char(0),char(66),char(0),char(13),char(0),char(59),char(0),char(-74),char(0), +char(19),char(0),char(-71),char(0),char(19),char(0),char(-70),char(0),char(4),char(0),char(-69),char(0),char(4),char(0),char(-68),char(0),char(4),char(0),char(-67),char(0), char(7),char(0),char(-66),char(0),char(7),char(0),char(-65),char(0),char(7),char(0),char(-64),char(0),char(7),char(0),char(-63),char(0),char(7),char(0),char(-62),char(0), -char(66),char(0),char(13),char(0),char(59),char(0),char(-76),char(0),char(19),char(0),char(-73),char(0),char(19),char(0),char(-72),char(0),char(4),char(0),char(-71),char(0), -char(4),char(0),char(-70),char(0),char(4),char(0),char(-69),char(0),char(7),char(0),char(-68),char(0),char(7),char(0),char(-67),char(0),char(7),char(0),char(-66),char(0), -char(7),char(0),char(-65),char(0),char(7),char(0),char(-64),char(0),char(7),char(0),char(-63),char(0),char(7),char(0),char(-62),char(0),char(67),char(0),char(14),char(0), -char(61),char(0),char(-76),char(0),char(20),char(0),char(-73),char(0),char(20),char(0),char(-72),char(0),char(4),char(0),char(-71),char(0),char(4),char(0),char(-70),char(0), -char(4),char(0),char(-69),char(0),char(8),char(0),char(-68),char(0),char(8),char(0),char(-67),char(0),char(8),char(0),char(-66),char(0),char(8),char(0),char(-65),char(0), -char(8),char(0),char(-64),char(0),char(8),char(0),char(-63),char(0),char(8),char(0),char(-62),char(0),char(0),char(0),char(-61),char(0),char(68),char(0),char(10),char(0), -char(61),char(0),char(-76),char(0),char(20),char(0),char(-73),char(0),char(20),char(0),char(-72),char(0),char(8),char(0),char(-60),char(0),char(8),char(0),char(-59),char(0), -char(8),char(0),char(-58),char(0),char(8),char(0),char(-64),char(0),char(8),char(0),char(-63),char(0),char(8),char(0),char(-62),char(0),char(8),char(0),char(125),char(0), -char(69),char(0),char(11),char(0),char(59),char(0),char(-76),char(0),char(19),char(0),char(-73),char(0),char(19),char(0),char(-72),char(0),char(7),char(0),char(-60),char(0), -char(7),char(0),char(-59),char(0),char(7),char(0),char(-58),char(0),char(7),char(0),char(-64),char(0),char(7),char(0),char(-63),char(0),char(7),char(0),char(-62),char(0), -char(7),char(0),char(125),char(0),char(0),char(0),char(21),char(0),char(70),char(0),char(9),char(0),char(59),char(0),char(-76),char(0),char(19),char(0),char(-73),char(0), -char(19),char(0),char(-72),char(0),char(13),char(0),char(-57),char(0),char(13),char(0),char(-56),char(0),char(13),char(0),char(-55),char(0),char(13),char(0),char(-54),char(0), -char(4),char(0),char(-53),char(0),char(4),char(0),char(-52),char(0),char(71),char(0),char(9),char(0),char(61),char(0),char(-76),char(0),char(20),char(0),char(-73),char(0), -char(20),char(0),char(-72),char(0),char(14),char(0),char(-57),char(0),char(14),char(0),char(-56),char(0),char(14),char(0),char(-55),char(0),char(14),char(0),char(-54),char(0), -char(4),char(0),char(-53),char(0),char(4),char(0),char(-52),char(0),char(72),char(0),char(5),char(0),char(70),char(0),char(-51),char(0),char(4),char(0),char(-50),char(0), -char(7),char(0),char(-49),char(0),char(7),char(0),char(-48),char(0),char(7),char(0),char(-47),char(0),char(73),char(0),char(5),char(0),char(71),char(0),char(-51),char(0), -char(4),char(0),char(-50),char(0),char(8),char(0),char(-49),char(0),char(8),char(0),char(-48),char(0),char(8),char(0),char(-47),char(0),char(74),char(0),char(41),char(0), -char(59),char(0),char(-76),char(0),char(19),char(0),char(-73),char(0),char(19),char(0),char(-72),char(0),char(13),char(0),char(-57),char(0),char(13),char(0),char(-56),char(0), -char(13),char(0),char(-46),char(0),char(13),char(0),char(-45),char(0),char(13),char(0),char(-44),char(0),char(13),char(0),char(-43),char(0),char(13),char(0),char(-42),char(0), -char(13),char(0),char(-41),char(0),char(13),char(0),char(-40),char(0),char(13),char(0),char(-39),char(0),char(13),char(0),char(-38),char(0),char(13),char(0),char(-37),char(0), -char(13),char(0),char(-36),char(0),char(0),char(0),char(-35),char(0),char(0),char(0),char(-34),char(0),char(0),char(0),char(-33),char(0),char(0),char(0),char(-32),char(0), -char(0),char(0),char(-31),char(0),char(0),char(0),char(-61),char(0),char(13),char(0),char(-55),char(0),char(13),char(0),char(-54),char(0),char(13),char(0),char(-30),char(0), -char(13),char(0),char(-29),char(0),char(13),char(0),char(-28),char(0),char(13),char(0),char(-27),char(0),char(13),char(0),char(-26),char(0),char(13),char(0),char(-25),char(0), -char(13),char(0),char(-24),char(0),char(13),char(0),char(-23),char(0),char(13),char(0),char(-22),char(0),char(13),char(0),char(-21),char(0),char(13),char(0),char(-20),char(0), -char(0),char(0),char(-19),char(0),char(0),char(0),char(-18),char(0),char(0),char(0),char(-17),char(0),char(0),char(0),char(-16),char(0),char(0),char(0),char(-15),char(0), -char(4),char(0),char(-14),char(0),char(75),char(0),char(41),char(0),char(61),char(0),char(-76),char(0),char(20),char(0),char(-73),char(0),char(20),char(0),char(-72),char(0), -char(14),char(0),char(-57),char(0),char(14),char(0),char(-56),char(0),char(14),char(0),char(-46),char(0),char(14),char(0),char(-45),char(0),char(14),char(0),char(-44),char(0), -char(14),char(0),char(-43),char(0),char(14),char(0),char(-42),char(0),char(14),char(0),char(-41),char(0),char(14),char(0),char(-40),char(0),char(14),char(0),char(-39),char(0), -char(14),char(0),char(-38),char(0),char(14),char(0),char(-37),char(0),char(14),char(0),char(-36),char(0),char(0),char(0),char(-35),char(0),char(0),char(0),char(-34),char(0), -char(0),char(0),char(-33),char(0),char(0),char(0),char(-32),char(0),char(0),char(0),char(-31),char(0),char(0),char(0),char(-61),char(0),char(14),char(0),char(-55),char(0), -char(14),char(0),char(-54),char(0),char(14),char(0),char(-30),char(0),char(14),char(0),char(-29),char(0),char(14),char(0),char(-28),char(0),char(14),char(0),char(-27),char(0), -char(14),char(0),char(-26),char(0),char(14),char(0),char(-25),char(0),char(14),char(0),char(-24),char(0),char(14),char(0),char(-23),char(0),char(14),char(0),char(-22),char(0), -char(14),char(0),char(-21),char(0),char(14),char(0),char(-20),char(0),char(0),char(0),char(-19),char(0),char(0),char(0),char(-18),char(0),char(0),char(0),char(-17),char(0), -char(0),char(0),char(-16),char(0),char(0),char(0),char(-15),char(0),char(4),char(0),char(-14),char(0),char(76),char(0),char(9),char(0),char(59),char(0),char(-76),char(0), -char(19),char(0),char(-73),char(0),char(19),char(0),char(-72),char(0),char(7),char(0),char(-57),char(0),char(7),char(0),char(-56),char(0),char(7),char(0),char(-55),char(0), -char(7),char(0),char(-54),char(0),char(4),char(0),char(-53),char(0),char(4),char(0),char(-52),char(0),char(77),char(0),char(9),char(0),char(61),char(0),char(-76),char(0), -char(20),char(0),char(-73),char(0),char(20),char(0),char(-72),char(0),char(8),char(0),char(-57),char(0),char(8),char(0),char(-56),char(0),char(8),char(0),char(-55),char(0), -char(8),char(0),char(-54),char(0),char(4),char(0),char(-53),char(0),char(4),char(0),char(-52),char(0),char(78),char(0),char(5),char(0),char(58),char(0),char(-76),char(0), -char(13),char(0),char(-13),char(0),char(13),char(0),char(-12),char(0),char(7),char(0),char(-11),char(0),char(0),char(0),char(37),char(0),char(79),char(0),char(4),char(0), -char(61),char(0),char(-76),char(0),char(14),char(0),char(-13),char(0),char(14),char(0),char(-12),char(0),char(8),char(0),char(-11),char(0),char(80),char(0),char(4),char(0), -char(7),char(0),char(-10),char(0),char(7),char(0),char(-9),char(0),char(7),char(0),char(-8),char(0),char(4),char(0),char(79),char(0),char(81),char(0),char(10),char(0), -char(80),char(0),char(-7),char(0),char(13),char(0),char(-6),char(0),char(13),char(0),char(-5),char(0),char(13),char(0),char(-4),char(0),char(13),char(0),char(-3),char(0), -char(13),char(0),char(-2),char(0),char(7),char(0),char(-101),char(0),char(7),char(0),char(-1),char(0),char(4),char(0),char(0),char(1),char(4),char(0),char(53),char(0), -char(82),char(0),char(4),char(0),char(80),char(0),char(-7),char(0),char(4),char(0),char(1),char(1),char(7),char(0),char(2),char(1),char(4),char(0),char(3),char(1), -char(83),char(0),char(4),char(0),char(13),char(0),char(-2),char(0),char(80),char(0),char(-7),char(0),char(4),char(0),char(4),char(1),char(7),char(0),char(5),char(1), -char(84),char(0),char(7),char(0),char(13),char(0),char(6),char(1),char(80),char(0),char(-7),char(0),char(4),char(0),char(7),char(1),char(7),char(0),char(8),char(1), -char(7),char(0),char(9),char(1),char(7),char(0),char(10),char(1),char(4),char(0),char(53),char(0),char(85),char(0),char(6),char(0),char(17),char(0),char(11),char(1), -char(13),char(0),char(9),char(1),char(13),char(0),char(12),char(1),char(60),char(0),char(13),char(1),char(4),char(0),char(14),char(1),char(7),char(0),char(10),char(1), -char(86),char(0),char(26),char(0),char(4),char(0),char(15),char(1),char(7),char(0),char(16),char(1),char(7),char(0),char(125),char(0),char(7),char(0),char(17),char(1), -char(7),char(0),char(18),char(1),char(7),char(0),char(19),char(1),char(7),char(0),char(20),char(1),char(7),char(0),char(21),char(1),char(7),char(0),char(22),char(1), -char(7),char(0),char(23),char(1),char(7),char(0),char(24),char(1),char(7),char(0),char(25),char(1),char(7),char(0),char(26),char(1),char(7),char(0),char(27),char(1), -char(7),char(0),char(28),char(1),char(7),char(0),char(29),char(1),char(7),char(0),char(30),char(1),char(7),char(0),char(31),char(1),char(7),char(0),char(32),char(1), -char(7),char(0),char(33),char(1),char(7),char(0),char(34),char(1),char(4),char(0),char(35),char(1),char(4),char(0),char(36),char(1),char(4),char(0),char(37),char(1), -char(4),char(0),char(38),char(1),char(4),char(0),char(118),char(0),char(87),char(0),char(12),char(0),char(17),char(0),char(39),char(1),char(17),char(0),char(40),char(1), -char(17),char(0),char(41),char(1),char(13),char(0),char(42),char(1),char(13),char(0),char(43),char(1),char(7),char(0),char(44),char(1),char(4),char(0),char(45),char(1), -char(4),char(0),char(46),char(1),char(4),char(0),char(47),char(1),char(4),char(0),char(48),char(1),char(7),char(0),char(8),char(1),char(4),char(0),char(53),char(0), -char(88),char(0),char(27),char(0),char(19),char(0),char(49),char(1),char(17),char(0),char(50),char(1),char(17),char(0),char(51),char(1),char(13),char(0),char(42),char(1), -char(13),char(0),char(52),char(1),char(13),char(0),char(53),char(1),char(13),char(0),char(54),char(1),char(13),char(0),char(55),char(1),char(13),char(0),char(56),char(1), -char(4),char(0),char(57),char(1),char(7),char(0),char(58),char(1),char(4),char(0),char(59),char(1),char(4),char(0),char(60),char(1),char(4),char(0),char(61),char(1), -char(7),char(0),char(62),char(1),char(7),char(0),char(63),char(1),char(4),char(0),char(64),char(1),char(4),char(0),char(65),char(1),char(7),char(0),char(66),char(1), -char(7),char(0),char(67),char(1),char(7),char(0),char(68),char(1),char(7),char(0),char(69),char(1),char(7),char(0),char(70),char(1),char(7),char(0),char(71),char(1), -char(4),char(0),char(72),char(1),char(4),char(0),char(73),char(1),char(4),char(0),char(74),char(1),char(89),char(0),char(12),char(0),char(9),char(0),char(75),char(1), -char(9),char(0),char(76),char(1),char(13),char(0),char(77),char(1),char(7),char(0),char(78),char(1),char(7),char(0),char(-127),char(0),char(7),char(0),char(79),char(1), -char(4),char(0),char(80),char(1),char(13),char(0),char(81),char(1),char(4),char(0),char(82),char(1),char(4),char(0),char(83),char(1),char(4),char(0),char(84),char(1), -char(4),char(0),char(53),char(0),char(90),char(0),char(19),char(0),char(50),char(0),char(-111),char(0),char(87),char(0),char(85),char(1),char(80),char(0),char(86),char(1), -char(81),char(0),char(87),char(1),char(82),char(0),char(88),char(1),char(83),char(0),char(89),char(1),char(84),char(0),char(90),char(1),char(85),char(0),char(91),char(1), -char(88),char(0),char(92),char(1),char(89),char(0),char(93),char(1),char(4),char(0),char(94),char(1),char(4),char(0),char(60),char(1),char(4),char(0),char(95),char(1), -char(4),char(0),char(96),char(1),char(4),char(0),char(97),char(1),char(4),char(0),char(98),char(1),char(4),char(0),char(99),char(1),char(4),char(0),char(100),char(1), -char(86),char(0),char(101),char(1),char(91),char(0),char(20),char(0),char(16),char(0),char(102),char(1),char(14),char(0),char(103),char(1),char(14),char(0),char(104),char(1), -char(14),char(0),char(105),char(1),char(14),char(0),char(106),char(1),char(14),char(0),char(107),char(1),char(8),char(0),char(108),char(1),char(4),char(0),char(109),char(1), -char(4),char(0),char(84),char(1),char(4),char(0),char(110),char(1),char(4),char(0),char(111),char(1),char(8),char(0),char(112),char(1),char(8),char(0),char(113),char(1), -char(8),char(0),char(114),char(1),char(8),char(0),char(115),char(1),char(8),char(0),char(116),char(1),char(0),char(0),char(117),char(1),char(0),char(0),char(118),char(1), -char(49),char(0),char(119),char(1),char(0),char(0),char(120),char(1),char(92),char(0),char(20),char(0),char(15),char(0),char(102),char(1),char(13),char(0),char(103),char(1), -char(13),char(0),char(104),char(1),char(13),char(0),char(105),char(1),char(13),char(0),char(106),char(1),char(13),char(0),char(107),char(1),char(4),char(0),char(110),char(1), -char(7),char(0),char(108),char(1),char(4),char(0),char(109),char(1),char(4),char(0),char(84),char(1),char(7),char(0),char(112),char(1),char(7),char(0),char(113),char(1), -char(7),char(0),char(114),char(1),char(4),char(0),char(111),char(1),char(7),char(0),char(115),char(1),char(7),char(0),char(116),char(1),char(0),char(0),char(117),char(1), -char(0),char(0),char(118),char(1),char(50),char(0),char(119),char(1),char(0),char(0),char(120),char(1),char(93),char(0),char(9),char(0),char(20),char(0),char(121),char(1), -char(14),char(0),char(122),char(1),char(8),char(0),char(123),char(1),char(0),char(0),char(124),char(1),char(91),char(0),char(88),char(1),char(49),char(0),char(125),char(1), -char(0),char(0),char(120),char(1),char(4),char(0),char(95),char(1),char(0),char(0),char(37),char(0),char(94),char(0),char(7),char(0),char(0),char(0),char(124),char(1), -char(92),char(0),char(88),char(1),char(50),char(0),char(125),char(1),char(19),char(0),char(121),char(1),char(13),char(0),char(122),char(1),char(7),char(0),char(123),char(1), -char(4),char(0),char(95),char(1),}; +char(7),char(0),char(-61),char(0),char(7),char(0),char(-60),char(0),char(67),char(0),char(14),char(0),char(61),char(0),char(-74),char(0),char(20),char(0),char(-71),char(0), +char(20),char(0),char(-70),char(0),char(4),char(0),char(-69),char(0),char(4),char(0),char(-68),char(0),char(4),char(0),char(-67),char(0),char(8),char(0),char(-66),char(0), +char(8),char(0),char(-65),char(0),char(8),char(0),char(-64),char(0),char(8),char(0),char(-63),char(0),char(8),char(0),char(-62),char(0),char(8),char(0),char(-61),char(0), +char(8),char(0),char(-60),char(0),char(0),char(0),char(-59),char(0),char(68),char(0),char(10),char(0),char(61),char(0),char(-74),char(0),char(20),char(0),char(-71),char(0), +char(20),char(0),char(-70),char(0),char(8),char(0),char(-58),char(0),char(8),char(0),char(-57),char(0),char(8),char(0),char(-56),char(0),char(8),char(0),char(-62),char(0), +char(8),char(0),char(-61),char(0),char(8),char(0),char(-60),char(0),char(8),char(0),char(127),char(0),char(69),char(0),char(11),char(0),char(59),char(0),char(-74),char(0), +char(19),char(0),char(-71),char(0),char(19),char(0),char(-70),char(0),char(7),char(0),char(-58),char(0),char(7),char(0),char(-57),char(0),char(7),char(0),char(-56),char(0), +char(7),char(0),char(-62),char(0),char(7),char(0),char(-61),char(0),char(7),char(0),char(-60),char(0),char(7),char(0),char(127),char(0),char(0),char(0),char(21),char(0), +char(70),char(0),char(9),char(0),char(59),char(0),char(-74),char(0),char(19),char(0),char(-71),char(0),char(19),char(0),char(-70),char(0),char(13),char(0),char(-55),char(0), +char(13),char(0),char(-54),char(0),char(13),char(0),char(-53),char(0),char(13),char(0),char(-52),char(0),char(4),char(0),char(-51),char(0),char(4),char(0),char(-50),char(0), +char(71),char(0),char(9),char(0),char(61),char(0),char(-74),char(0),char(20),char(0),char(-71),char(0),char(20),char(0),char(-70),char(0),char(14),char(0),char(-55),char(0), +char(14),char(0),char(-54),char(0),char(14),char(0),char(-53),char(0),char(14),char(0),char(-52),char(0),char(4),char(0),char(-51),char(0),char(4),char(0),char(-50),char(0), +char(72),char(0),char(5),char(0),char(70),char(0),char(-49),char(0),char(4),char(0),char(-48),char(0),char(7),char(0),char(-47),char(0),char(7),char(0),char(-46),char(0), +char(7),char(0),char(-45),char(0),char(73),char(0),char(5),char(0),char(71),char(0),char(-49),char(0),char(4),char(0),char(-48),char(0),char(8),char(0),char(-47),char(0), +char(8),char(0),char(-46),char(0),char(8),char(0),char(-45),char(0),char(74),char(0),char(41),char(0),char(59),char(0),char(-74),char(0),char(19),char(0),char(-71),char(0), +char(19),char(0),char(-70),char(0),char(13),char(0),char(-55),char(0),char(13),char(0),char(-54),char(0),char(13),char(0),char(-44),char(0),char(13),char(0),char(-43),char(0), +char(13),char(0),char(-42),char(0),char(13),char(0),char(-41),char(0),char(13),char(0),char(-40),char(0),char(13),char(0),char(-39),char(0),char(13),char(0),char(-38),char(0), +char(13),char(0),char(-37),char(0),char(13),char(0),char(-36),char(0),char(13),char(0),char(-35),char(0),char(13),char(0),char(-34),char(0),char(0),char(0),char(-33),char(0), +char(0),char(0),char(-32),char(0),char(0),char(0),char(-31),char(0),char(0),char(0),char(-30),char(0),char(0),char(0),char(-29),char(0),char(0),char(0),char(-59),char(0), +char(13),char(0),char(-53),char(0),char(13),char(0),char(-52),char(0),char(13),char(0),char(-28),char(0),char(13),char(0),char(-27),char(0),char(13),char(0),char(-26),char(0), +char(13),char(0),char(-25),char(0),char(13),char(0),char(-24),char(0),char(13),char(0),char(-23),char(0),char(13),char(0),char(-22),char(0),char(13),char(0),char(-21),char(0), +char(13),char(0),char(-20),char(0),char(13),char(0),char(-19),char(0),char(13),char(0),char(-18),char(0),char(0),char(0),char(-17),char(0),char(0),char(0),char(-16),char(0), +char(0),char(0),char(-15),char(0),char(0),char(0),char(-14),char(0),char(0),char(0),char(-13),char(0),char(4),char(0),char(-12),char(0),char(75),char(0),char(41),char(0), +char(61),char(0),char(-74),char(0),char(20),char(0),char(-71),char(0),char(20),char(0),char(-70),char(0),char(14),char(0),char(-55),char(0),char(14),char(0),char(-54),char(0), +char(14),char(0),char(-44),char(0),char(14),char(0),char(-43),char(0),char(14),char(0),char(-42),char(0),char(14),char(0),char(-41),char(0),char(14),char(0),char(-40),char(0), +char(14),char(0),char(-39),char(0),char(14),char(0),char(-38),char(0),char(14),char(0),char(-37),char(0),char(14),char(0),char(-36),char(0),char(14),char(0),char(-35),char(0), +char(14),char(0),char(-34),char(0),char(0),char(0),char(-33),char(0),char(0),char(0),char(-32),char(0),char(0),char(0),char(-31),char(0),char(0),char(0),char(-30),char(0), +char(0),char(0),char(-29),char(0),char(0),char(0),char(-59),char(0),char(14),char(0),char(-53),char(0),char(14),char(0),char(-52),char(0),char(14),char(0),char(-28),char(0), +char(14),char(0),char(-27),char(0),char(14),char(0),char(-26),char(0),char(14),char(0),char(-25),char(0),char(14),char(0),char(-24),char(0),char(14),char(0),char(-23),char(0), +char(14),char(0),char(-22),char(0),char(14),char(0),char(-21),char(0),char(14),char(0),char(-20),char(0),char(14),char(0),char(-19),char(0),char(14),char(0),char(-18),char(0), +char(0),char(0),char(-17),char(0),char(0),char(0),char(-16),char(0),char(0),char(0),char(-15),char(0),char(0),char(0),char(-14),char(0),char(0),char(0),char(-13),char(0), +char(4),char(0),char(-12),char(0),char(76),char(0),char(9),char(0),char(59),char(0),char(-74),char(0),char(19),char(0),char(-71),char(0),char(19),char(0),char(-70),char(0), +char(7),char(0),char(-55),char(0),char(7),char(0),char(-54),char(0),char(7),char(0),char(-53),char(0),char(7),char(0),char(-52),char(0),char(4),char(0),char(-51),char(0), +char(4),char(0),char(-50),char(0),char(77),char(0),char(9),char(0),char(61),char(0),char(-74),char(0),char(20),char(0),char(-71),char(0),char(20),char(0),char(-70),char(0), +char(8),char(0),char(-55),char(0),char(8),char(0),char(-54),char(0),char(8),char(0),char(-53),char(0),char(8),char(0),char(-52),char(0),char(4),char(0),char(-51),char(0), +char(4),char(0),char(-50),char(0),char(78),char(0),char(5),char(0),char(58),char(0),char(-74),char(0),char(13),char(0),char(-11),char(0),char(13),char(0),char(-10),char(0), +char(7),char(0),char(-9),char(0),char(0),char(0),char(37),char(0),char(79),char(0),char(4),char(0),char(61),char(0),char(-74),char(0),char(14),char(0),char(-11),char(0), +char(14),char(0),char(-10),char(0),char(8),char(0),char(-9),char(0),char(80),char(0),char(4),char(0),char(7),char(0),char(-8),char(0),char(7),char(0),char(-7),char(0), +char(7),char(0),char(-6),char(0),char(4),char(0),char(79),char(0),char(81),char(0),char(10),char(0),char(80),char(0),char(-5),char(0),char(13),char(0),char(-4),char(0), +char(13),char(0),char(-3),char(0),char(13),char(0),char(-2),char(0),char(13),char(0),char(-1),char(0),char(13),char(0),char(0),char(1),char(7),char(0),char(-99),char(0), +char(7),char(0),char(1),char(1),char(4),char(0),char(2),char(1),char(4),char(0),char(53),char(0),char(82),char(0),char(4),char(0),char(80),char(0),char(-5),char(0), +char(4),char(0),char(3),char(1),char(7),char(0),char(4),char(1),char(4),char(0),char(5),char(1),char(83),char(0),char(4),char(0),char(13),char(0),char(0),char(1), +char(80),char(0),char(-5),char(0),char(4),char(0),char(6),char(1),char(7),char(0),char(7),char(1),char(84),char(0),char(7),char(0),char(13),char(0),char(8),char(1), +char(80),char(0),char(-5),char(0),char(4),char(0),char(9),char(1),char(7),char(0),char(10),char(1),char(7),char(0),char(11),char(1),char(7),char(0),char(12),char(1), +char(4),char(0),char(53),char(0),char(85),char(0),char(6),char(0),char(17),char(0),char(13),char(1),char(13),char(0),char(11),char(1),char(13),char(0),char(14),char(1), +char(60),char(0),char(15),char(1),char(4),char(0),char(16),char(1),char(7),char(0),char(12),char(1),char(86),char(0),char(26),char(0),char(4),char(0),char(17),char(1), +char(7),char(0),char(18),char(1),char(7),char(0),char(127),char(0),char(7),char(0),char(19),char(1),char(7),char(0),char(20),char(1),char(7),char(0),char(21),char(1), +char(7),char(0),char(22),char(1),char(7),char(0),char(23),char(1),char(7),char(0),char(24),char(1),char(7),char(0),char(25),char(1),char(7),char(0),char(26),char(1), +char(7),char(0),char(27),char(1),char(7),char(0),char(28),char(1),char(7),char(0),char(29),char(1),char(7),char(0),char(30),char(1),char(7),char(0),char(31),char(1), +char(7),char(0),char(32),char(1),char(7),char(0),char(33),char(1),char(7),char(0),char(34),char(1),char(7),char(0),char(35),char(1),char(7),char(0),char(36),char(1), +char(4),char(0),char(37),char(1),char(4),char(0),char(38),char(1),char(4),char(0),char(39),char(1),char(4),char(0),char(40),char(1),char(4),char(0),char(120),char(0), +char(87),char(0),char(12),char(0),char(17),char(0),char(41),char(1),char(17),char(0),char(42),char(1),char(17),char(0),char(43),char(1),char(13),char(0),char(44),char(1), +char(13),char(0),char(45),char(1),char(7),char(0),char(46),char(1),char(4),char(0),char(47),char(1),char(4),char(0),char(48),char(1),char(4),char(0),char(49),char(1), +char(4),char(0),char(50),char(1),char(7),char(0),char(10),char(1),char(4),char(0),char(53),char(0),char(88),char(0),char(27),char(0),char(19),char(0),char(51),char(1), +char(17),char(0),char(52),char(1),char(17),char(0),char(53),char(1),char(13),char(0),char(44),char(1),char(13),char(0),char(54),char(1),char(13),char(0),char(55),char(1), +char(13),char(0),char(56),char(1),char(13),char(0),char(57),char(1),char(13),char(0),char(58),char(1),char(4),char(0),char(59),char(1),char(7),char(0),char(60),char(1), +char(4),char(0),char(61),char(1),char(4),char(0),char(62),char(1),char(4),char(0),char(63),char(1),char(7),char(0),char(64),char(1),char(7),char(0),char(65),char(1), +char(4),char(0),char(66),char(1),char(4),char(0),char(67),char(1),char(7),char(0),char(68),char(1),char(7),char(0),char(69),char(1),char(7),char(0),char(70),char(1), +char(7),char(0),char(71),char(1),char(7),char(0),char(72),char(1),char(7),char(0),char(73),char(1),char(4),char(0),char(74),char(1),char(4),char(0),char(75),char(1), +char(4),char(0),char(76),char(1),char(89),char(0),char(12),char(0),char(9),char(0),char(77),char(1),char(9),char(0),char(78),char(1),char(13),char(0),char(79),char(1), +char(7),char(0),char(80),char(1),char(7),char(0),char(-125),char(0),char(7),char(0),char(81),char(1),char(4),char(0),char(82),char(1),char(13),char(0),char(83),char(1), +char(4),char(0),char(84),char(1),char(4),char(0),char(85),char(1),char(4),char(0),char(86),char(1),char(4),char(0),char(53),char(0),char(90),char(0),char(19),char(0), +char(50),char(0),char(-109),char(0),char(87),char(0),char(87),char(1),char(80),char(0),char(88),char(1),char(81),char(0),char(89),char(1),char(82),char(0),char(90),char(1), +char(83),char(0),char(91),char(1),char(84),char(0),char(92),char(1),char(85),char(0),char(93),char(1),char(88),char(0),char(94),char(1),char(89),char(0),char(95),char(1), +char(4),char(0),char(96),char(1),char(4),char(0),char(62),char(1),char(4),char(0),char(97),char(1),char(4),char(0),char(98),char(1),char(4),char(0),char(99),char(1), +char(4),char(0),char(100),char(1),char(4),char(0),char(101),char(1),char(4),char(0),char(102),char(1),char(86),char(0),char(103),char(1),char(91),char(0),char(20),char(0), +char(16),char(0),char(104),char(1),char(14),char(0),char(105),char(1),char(14),char(0),char(106),char(1),char(14),char(0),char(107),char(1),char(14),char(0),char(108),char(1), +char(14),char(0),char(109),char(1),char(8),char(0),char(110),char(1),char(4),char(0),char(111),char(1),char(4),char(0),char(86),char(1),char(4),char(0),char(112),char(1), +char(4),char(0),char(113),char(1),char(8),char(0),char(114),char(1),char(8),char(0),char(115),char(1),char(8),char(0),char(116),char(1),char(8),char(0),char(117),char(1), +char(8),char(0),char(118),char(1),char(0),char(0),char(119),char(1),char(0),char(0),char(120),char(1),char(49),char(0),char(121),char(1),char(0),char(0),char(122),char(1), +char(92),char(0),char(20),char(0),char(15),char(0),char(104),char(1),char(13),char(0),char(105),char(1),char(13),char(0),char(106),char(1),char(13),char(0),char(107),char(1), +char(13),char(0),char(108),char(1),char(13),char(0),char(109),char(1),char(4),char(0),char(112),char(1),char(7),char(0),char(110),char(1),char(4),char(0),char(111),char(1), +char(4),char(0),char(86),char(1),char(7),char(0),char(114),char(1),char(7),char(0),char(115),char(1),char(7),char(0),char(116),char(1),char(4),char(0),char(113),char(1), +char(7),char(0),char(117),char(1),char(7),char(0),char(118),char(1),char(0),char(0),char(119),char(1),char(0),char(0),char(120),char(1),char(50),char(0),char(121),char(1), +char(0),char(0),char(122),char(1),char(93),char(0),char(9),char(0),char(20),char(0),char(123),char(1),char(14),char(0),char(124),char(1),char(8),char(0),char(125),char(1), +char(0),char(0),char(126),char(1),char(91),char(0),char(90),char(1),char(49),char(0),char(127),char(1),char(0),char(0),char(122),char(1),char(4),char(0),char(97),char(1), +char(0),char(0),char(37),char(0),char(94),char(0),char(7),char(0),char(0),char(0),char(126),char(1),char(92),char(0),char(90),char(1),char(50),char(0),char(127),char(1), +char(19),char(0),char(123),char(1),char(13),char(0),char(124),char(1),char(7),char(0),char(125),char(1),char(4),char(0),char(97),char(1),}; int sBulletDNAlen= sizeof(sBulletDNAstr); + char sBulletDNAstr64[]= { -char(83),char(68),char(78),char(65),char(78),char(65),char(77),char(69),char(126),char(1),char(0),char(0),char(109),char(95),char(115),char(105),char(122),char(101),char(0),char(109), +char(83),char(68),char(78),char(65),char(78),char(65),char(77),char(69),char(-128),char(1),char(0),char(0),char(109),char(95),char(115),char(105),char(122),char(101),char(0),char(109), char(95),char(99),char(97),char(112),char(97),char(99),char(105),char(116),char(121),char(0),char(42),char(109),char(95),char(100),char(97),char(116),char(97),char(0),char(109),char(95), char(99),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(83),char(104),char(97),char(112),char(101),char(115),char(0),char(109),char(95),char(99),char(111), char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(79),char(98),char(106),char(101),char(99),char(116),char(115),char(0),char(109),char(95),char(99),char(111),char(110), @@ -682,503 +685,505 @@ char(97),char(110),char(105),char(115),char(111),char(116),char(114),char(111),c char(109),char(95),char(99),char(111),char(110),char(116),char(97),char(99),char(116),char(80),char(114),char(111),char(99),char(101),char(115),char(115),char(105),char(110),char(103),char(84), char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109),char(95),char(100),char(101),char(97),char(99),char(116),char(105),char(118),char(97),char(116), char(105),char(111),char(110),char(84),char(105),char(109),char(101),char(0),char(109),char(95),char(102),char(114),char(105),char(99),char(116),char(105),char(111),char(110),char(0),char(109), -char(95),char(114),char(111),char(108),char(108),char(105),char(110),char(103),char(70),char(114),char(105),char(99),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(114), -char(101),char(115),char(116),char(105),char(116),char(117),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(104),char(105),char(116),char(70),char(114),char(97),char(99), -char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(99),char(99),char(100),char(83),char(119),char(101),char(112),char(116),char(83),char(112),char(104),char(101),char(114), -char(101),char(82),char(97),char(100),char(105),char(117),char(115),char(0),char(109),char(95),char(99),char(99),char(100),char(77),char(111),char(116),char(105),char(111),char(110),char(84), -char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109),char(95),char(104),char(97),char(115),char(65),char(110),char(105),char(115),char(111),char(116), -char(114),char(111),char(112),char(105),char(99),char(70),char(114),char(105),char(99),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(99),char(111),char(108),char(108), -char(105),char(115),char(105),char(111),char(110),char(70),char(108),char(97),char(103),char(115),char(0),char(109),char(95),char(105),char(115),char(108),char(97),char(110),char(100),char(84), -char(97),char(103),char(49),char(0),char(109),char(95),char(99),char(111),char(109),char(112),char(97),char(110),char(105),char(111),char(110),char(73),char(100),char(0),char(109),char(95), -char(97),char(99),char(116),char(105),char(118),char(97),char(116),char(105),char(111),char(110),char(83),char(116),char(97),char(116),char(101),char(49),char(0),char(109),char(95),char(105), -char(110),char(116),char(101),char(114),char(110),char(97),char(108),char(84),char(121),char(112),char(101),char(0),char(109),char(95),char(99),char(104),char(101),char(99),char(107),char(67), -char(111),char(108),char(108),char(105),char(100),char(101),char(87),char(105),char(116),char(104),char(0),char(109),char(95),char(116),char(97),char(117),char(0),char(109),char(95),char(100), -char(97),char(109),char(112),char(105),char(110),char(103),char(0),char(109),char(95),char(116),char(105),char(109),char(101),char(83),char(116),char(101),char(112),char(0),char(109),char(95), -char(109),char(97),char(120),char(69),char(114),char(114),char(111),char(114),char(82),char(101),char(100),char(117),char(99),char(116),char(105),char(111),char(110),char(0),char(109),char(95), -char(115),char(111),char(114),char(0),char(109),char(95),char(101),char(114),char(112),char(0),char(109),char(95),char(101),char(114),char(112),char(50),char(0),char(109),char(95),char(103), -char(108),char(111),char(98),char(97),char(108),char(67),char(102),char(109),char(0),char(109),char(95),char(115),char(112),char(108),char(105),char(116),char(73),char(109),char(112),char(117), -char(108),char(115),char(101),char(80),char(101),char(110),char(101),char(116),char(114),char(97),char(116),char(105),char(111),char(110),char(84),char(104),char(114),char(101),char(115),char(104), -char(111),char(108),char(100),char(0),char(109),char(95),char(115),char(112),char(108),char(105),char(116),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(84),char(117), -char(114),char(110),char(69),char(114),char(112),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83),char(108),char(111),char(112),char(0),char(109), -char(95),char(119),char(97),char(114),char(109),char(115),char(116),char(97),char(114),char(116),char(105),char(110),char(103),char(70),char(97),char(99),char(116),char(111),char(114),char(0), -char(109),char(95),char(109),char(97),char(120),char(71),char(121),char(114),char(111),char(115),char(99),char(111),char(112),char(105),char(99),char(70),char(111),char(114),char(99),char(101), -char(0),char(109),char(95),char(115),char(105),char(110),char(103),char(108),char(101),char(65),char(120),char(105),char(115),char(82),char(111),char(108),char(108),char(105),char(110),char(103), -char(70),char(114),char(105),char(99),char(116),char(105),char(111),char(110),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109),char(95), -char(110),char(117),char(109),char(73),char(116),char(101),char(114),char(97),char(116),char(105),char(111),char(110),char(115),char(0),char(109),char(95),char(115),char(111),char(108),char(118), -char(101),char(114),char(77),char(111),char(100),char(101),char(0),char(109),char(95),char(114),char(101),char(115),char(116),char(105),char(110),char(103),char(67),char(111),char(110),char(116), -char(97),char(99),char(116),char(82),char(101),char(115),char(116),char(105),char(116),char(117),char(116),char(105),char(111),char(110),char(84),char(104),char(114),char(101),char(115),char(104), -char(111),char(108),char(100),char(0),char(109),char(95),char(109),char(105),char(110),char(105),char(109),char(117),char(109),char(83),char(111),char(108),char(118),char(101),char(114),char(66), -char(97),char(116),char(99),char(104),char(83),char(105),char(122),char(101),char(0),char(109),char(95),char(115),char(112),char(108),char(105),char(116),char(73),char(109),char(112),char(117), -char(108),char(115),char(101),char(0),char(109),char(95),char(115),char(111),char(108),char(118),char(101),char(114),char(73),char(110),char(102),char(111),char(0),char(109),char(95),char(103), -char(114),char(97),char(118),char(105),char(116),char(121),char(0),char(109),char(95),char(99),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(79),char(98), -char(106),char(101),char(99),char(116),char(68),char(97),char(116),char(97),char(0),char(109),char(95),char(105),char(110),char(118),char(73),char(110),char(101),char(114),char(116),char(105), -char(97),char(84),char(101),char(110),char(115),char(111),char(114),char(87),char(111),char(114),char(108),char(100),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97), -char(114),char(86),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(86), -char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(70),char(97),char(99), -char(116),char(111),char(114),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(70),char(97),char(99),char(116),char(111),char(114),char(0),char(109), -char(95),char(103),char(114),char(97),char(118),char(105),char(116),char(121),char(95),char(97),char(99),char(99),char(101),char(108),char(101),char(114),char(97),char(116),char(105),char(111), -char(110),char(0),char(109),char(95),char(105),char(110),char(118),char(73),char(110),char(101),char(114),char(116),char(105),char(97),char(76),char(111),char(99),char(97),char(108),char(0), -char(109),char(95),char(116),char(111),char(116),char(97),char(108),char(70),char(111),char(114),char(99),char(101),char(0),char(109),char(95),char(116),char(111),char(116),char(97),char(108), -char(84),char(111),char(114),char(113),char(117),char(101),char(0),char(109),char(95),char(105),char(110),char(118),char(101),char(114),char(115),char(101),char(77),char(97),char(115),char(115), -char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(0),char(109),char(95),char(97), -char(110),char(103),char(117),char(108),char(97),char(114),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(0),char(109),char(95),char(97),char(100),char(100),char(105), -char(116),char(105),char(111),char(110),char(97),char(108),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(70),char(97),char(99),char(116),char(111),char(114),char(0), -char(109),char(95),char(97),char(100),char(100),char(105),char(116),char(105),char(111),char(110),char(97),char(108),char(76),char(105),char(110),char(101),char(97),char(114),char(68),char(97), -char(109),char(112),char(105),char(110),char(103),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(83),char(113),char(114),char(0),char(109),char(95), -char(97),char(100),char(100),char(105),char(116),char(105),char(111),char(110),char(97),char(108),char(65),char(110),char(103),char(117),char(108),char(97),char(114),char(68),char(97),char(109), -char(112),char(105),char(110),char(103),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(83),char(113),char(114),char(0),char(109),char(95),char(97), -char(100),char(100),char(105),char(116),char(105),char(111),char(110),char(97),char(108),char(65),char(110),char(103),char(117),char(108),char(97),char(114),char(68),char(97),char(109),char(112), -char(105),char(110),char(103),char(70),char(97),char(99),char(116),char(111),char(114),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83),char(108), -char(101),char(101),char(112),char(105),char(110),char(103),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109),char(95),char(97),char(110), -char(103),char(117),char(108),char(97),char(114),char(83),char(108),char(101),char(101),char(112),char(105),char(110),char(103),char(84),char(104),char(114),char(101),char(115),char(104),char(111), -char(108),char(100),char(0),char(109),char(95),char(97),char(100),char(100),char(105),char(116),char(105),char(111),char(110),char(97),char(108),char(68),char(97),char(109),char(112),char(105), -char(110),char(103),char(0),char(109),char(95),char(110),char(117),char(109),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(82),char(111), -char(119),char(115),char(0),char(110),char(117),char(98),char(0),char(42),char(109),char(95),char(114),char(98),char(65),char(0),char(42),char(109),char(95),char(114),char(98),char(66), -char(0),char(109),char(95),char(111),char(98),char(106),char(101),char(99),char(116),char(84),char(121),char(112),char(101),char(0),char(109),char(95),char(117),char(115),char(101),char(114), -char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(84),char(121),char(112),char(101),char(0),char(109),char(95),char(117),char(115),char(101), -char(114),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(73),char(100),char(0),char(109),char(95),char(110),char(101),char(101),char(100), -char(115),char(70),char(101),char(101),char(100),char(98),char(97),char(99),char(107),char(0),char(109),char(95),char(97),char(112),char(112),char(108),char(105),char(101),char(100),char(73), -char(109),char(112),char(117),char(108),char(115),char(101),char(0),char(109),char(95),char(100),char(98),char(103),char(68),char(114),char(97),char(119),char(83),char(105),char(122),char(101), -char(0),char(109),char(95),char(100),char(105),char(115),char(97),char(98),char(108),char(101),char(67),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(115), -char(66),char(101),char(116),char(119),char(101),char(101),char(110),char(76),char(105),char(110),char(107),char(101),char(100),char(66),char(111),char(100),char(105),char(101),char(115),char(0), -char(109),char(95),char(111),char(118),char(101),char(114),char(114),char(105),char(100),char(101),char(78),char(117),char(109),char(83),char(111),char(108),char(118),char(101),char(114),char(73), -char(116),char(101),char(114),char(97),char(116),char(105),char(111),char(110),char(115),char(0),char(109),char(95),char(98),char(114),char(101),char(97),char(107),char(105),char(110),char(103), -char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109),char(95),char(105), -char(115),char(69),char(110),char(97),char(98),char(108),char(101),char(100),char(0),char(112),char(97),char(100),char(100),char(105),char(110),char(103),char(91),char(52),char(93),char(0), -char(109),char(95),char(116),char(121),char(112),char(101),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(97),char(116),char(97), -char(0),char(109),char(95),char(112),char(105),char(118),char(111),char(116),char(73),char(110),char(65),char(0),char(109),char(95),char(112),char(105),char(118),char(111),char(116),char(73), -char(110),char(66),char(0),char(109),char(95),char(114),char(98),char(65),char(70),char(114),char(97),char(109),char(101),char(0),char(109),char(95),char(114),char(98),char(66),char(70), -char(114),char(97),char(109),char(101),char(0),char(109),char(95),char(117),char(115),char(101),char(82),char(101),char(102),char(101),char(114),char(101),char(110),char(99),char(101),char(70), -char(114),char(97),char(109),char(101),char(65),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(79),char(110),char(108),char(121),char(0), -char(109),char(95),char(101),char(110),char(97),char(98),char(108),char(101),char(65),char(110),char(103),char(117),char(108),char(97),char(114),char(77),char(111),char(116),char(111),char(114), -char(0),char(109),char(95),char(109),char(111),char(116),char(111),char(114),char(84),char(97),char(114),char(103),char(101),char(116),char(86),char(101),char(108),char(111),char(99),char(105), -char(116),char(121),char(0),char(109),char(95),char(109),char(97),char(120),char(77),char(111),char(116),char(111),char(114),char(73),char(109),char(112),char(117),char(108),char(115),char(101), -char(0),char(109),char(95),char(108),char(111),char(119),char(101),char(114),char(76),char(105),char(109),char(105),char(116),char(0),char(109),char(95),char(117),char(112),char(112),char(101), -char(114),char(76),char(105),char(109),char(105),char(116),char(0),char(109),char(95),char(108),char(105),char(109),char(105),char(116),char(83),char(111),char(102),char(116),char(110),char(101), -char(115),char(115),char(0),char(109),char(95),char(98),char(105),char(97),char(115),char(70),char(97),char(99),char(116),char(111),char(114),char(0),char(109),char(95),char(114),char(101), -char(108),char(97),char(120),char(97),char(116),char(105),char(111),char(110),char(70),char(97),char(99),char(116),char(111),char(114),char(0),char(109),char(95),char(112),char(97),char(100), -char(100),char(105),char(110),char(103),char(49),char(91),char(52),char(93),char(0),char(109),char(95),char(115),char(119),char(105),char(110),char(103),char(83),char(112),char(97),char(110), -char(49),char(0),char(109),char(95),char(115),char(119),char(105),char(110),char(103),char(83),char(112),char(97),char(110),char(50),char(0),char(109),char(95),char(116),char(119),char(105), -char(115),char(116),char(83),char(112),char(97),char(110),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(85),char(112),char(112),char(101),char(114), -char(76),char(105),char(109),char(105),char(116),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(76),char(111),char(119),char(101),char(114),char(76), -char(105),char(109),char(105),char(116),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(85),char(112),char(112),char(101),char(114),char(76), -char(105),char(109),char(105),char(116),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(76),char(111),char(119),char(101),char(114),char(76), -char(105),char(109),char(105),char(116),char(0),char(109),char(95),char(117),char(115),char(101),char(76),char(105),char(110),char(101),char(97),char(114),char(82),char(101),char(102),char(101), -char(114),char(101),char(110),char(99),char(101),char(70),char(114),char(97),char(109),char(101),char(65),char(0),char(109),char(95),char(117),char(115),char(101),char(79),char(102),char(102), -char(115),char(101),char(116),char(70),char(111),char(114),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(70),char(114),char(97),char(109), -char(101),char(0),char(109),char(95),char(54),char(100),char(111),char(102),char(68),char(97),char(116),char(97),char(0),char(109),char(95),char(115),char(112),char(114),char(105),char(110), -char(103),char(69),char(110),char(97),char(98),char(108),char(101),char(100),char(91),char(54),char(93),char(0),char(109),char(95),char(101),char(113),char(117),char(105),char(108),char(105), -char(98),char(114),char(105),char(117),char(109),char(80),char(111),char(105),char(110),char(116),char(91),char(54),char(93),char(0),char(109),char(95),char(115),char(112),char(114),char(105), -char(110),char(103),char(83),char(116),char(105),char(102),char(102),char(110),char(101),char(115),char(115),char(91),char(54),char(93),char(0),char(109),char(95),char(115),char(112),char(114), -char(105),char(110),char(103),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(91),char(54),char(93),char(0),char(109),char(95),char(108),char(105),char(110),char(101), -char(97),char(114),char(66),char(111),char(117),char(110),char(99),char(101),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83),char(116),char(111), -char(112),char(69),char(82),char(80),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83),char(116),char(111),char(112),char(67),char(70),char(77), -char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(77),char(111),char(116),char(111),char(114),char(69),char(82),char(80),char(0),char(109),char(95), -char(108),char(105),char(110),char(101),char(97),char(114),char(77),char(111),char(116),char(111),char(114),char(67),char(70),char(77),char(0),char(109),char(95),char(108),char(105),char(110), -char(101),char(97),char(114),char(84),char(97),char(114),char(103),char(101),char(116),char(86),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(0),char(109),char(95), -char(108),char(105),char(110),char(101),char(97),char(114),char(77),char(97),char(120),char(77),char(111),char(116),char(111),char(114),char(70),char(111),char(114),char(99),char(101),char(0), -char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83),char(101),char(114),char(118),char(111),char(84),char(97),char(114),char(103),char(101),char(116),char(0), -char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83),char(112),char(114),char(105),char(110),char(103),char(83),char(116),char(105),char(102),char(102),char(110), -char(101),char(115),char(115),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83),char(112),char(114),char(105),char(110),char(103),char(68),char(97), -char(109),char(112),char(105),char(110),char(103),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(69),char(113),char(117),char(105),char(108),char(105), -char(98),char(114),char(105),char(117),char(109),char(80),char(111),char(105),char(110),char(116),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(69), -char(110),char(97),char(98),char(108),char(101),char(77),char(111),char(116),char(111),char(114),char(91),char(52),char(93),char(0),char(109),char(95),char(108),char(105),char(110),char(101), -char(97),char(114),char(83),char(101),char(114),char(118),char(111),char(77),char(111),char(116),char(111),char(114),char(91),char(52),char(93),char(0),char(109),char(95),char(108),char(105), -char(110),char(101),char(97),char(114),char(69),char(110),char(97),char(98),char(108),char(101),char(83),char(112),char(114),char(105),char(110),char(103),char(91),char(52),char(93),char(0), -char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83),char(112),char(114),char(105),char(110),char(103),char(83),char(116),char(105),char(102),char(102),char(110), -char(101),char(115),char(115),char(76),char(105),char(109),char(105),char(116),char(101),char(100),char(91),char(52),char(93),char(0),char(109),char(95),char(108),char(105),char(110),char(101), -char(97),char(114),char(83),char(112),char(114),char(105),char(110),char(103),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(76),char(105),char(109),char(105),char(116), -char(101),char(100),char(91),char(52),char(93),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(66),char(111),char(117),char(110),char(99), -char(101),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(83),char(116),char(111),char(112),char(69),char(82),char(80),char(0),char(109), -char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(83),char(116),char(111),char(112),char(67),char(70),char(77),char(0),char(109),char(95),char(97),char(110), -char(103),char(117),char(108),char(97),char(114),char(77),char(111),char(116),char(111),char(114),char(69),char(82),char(80),char(0),char(109),char(95),char(97),char(110),char(103),char(117), -char(108),char(97),char(114),char(77),char(111),char(116),char(111),char(114),char(67),char(70),char(77),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97), -char(114),char(84),char(97),char(114),char(103),char(101),char(116),char(86),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(0),char(109),char(95),char(97),char(110), -char(103),char(117),char(108),char(97),char(114),char(77),char(97),char(120),char(77),char(111),char(116),char(111),char(114),char(70),char(111),char(114),char(99),char(101),char(0),char(109), -char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(83),char(101),char(114),char(118),char(111),char(84),char(97),char(114),char(103),char(101),char(116),char(0), -char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(83),char(112),char(114),char(105),char(110),char(103),char(83),char(116),char(105),char(102),char(102), -char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(83),char(112),char(114),char(105),char(110),char(103), -char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(69),char(113),char(117), -char(105),char(108),char(105),char(98),char(114),char(105),char(117),char(109),char(80),char(111),char(105),char(110),char(116),char(0),char(109),char(95),char(97),char(110),char(103),char(117), -char(108),char(97),char(114),char(69),char(110),char(97),char(98),char(108),char(101),char(77),char(111),char(116),char(111),char(114),char(91),char(52),char(93),char(0),char(109),char(95), -char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(83),char(101),char(114),char(118),char(111),char(77),char(111),char(116),char(111),char(114),char(91),char(52),char(93), -char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(69),char(110),char(97),char(98),char(108),char(101),char(83),char(112),char(114),char(105), -char(110),char(103),char(91),char(52),char(93),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(83),char(112),char(114),char(105),char(110), -char(103),char(83),char(116),char(105),char(102),char(102),char(110),char(101),char(115),char(115),char(76),char(105),char(109),char(105),char(116),char(101),char(100),char(91),char(52),char(93), +char(95),char(114),char(111),char(108),char(108),char(105),char(110),char(103),char(70),char(114),char(105),char(99),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(99), +char(111),char(110),char(116),char(97),char(99),char(116),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(0),char(109),char(95),char(99),char(111),char(110),char(116), +char(97),char(99),char(116),char(83),char(116),char(105),char(102),char(102),char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(114),char(101),char(115),char(116),char(105), +char(116),char(117),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(104),char(105),char(116),char(70),char(114),char(97),char(99),char(116),char(105),char(111),char(110), +char(0),char(109),char(95),char(99),char(99),char(100),char(83),char(119),char(101),char(112),char(116),char(83),char(112),char(104),char(101),char(114),char(101),char(82),char(97),char(100), +char(105),char(117),char(115),char(0),char(109),char(95),char(99),char(99),char(100),char(77),char(111),char(116),char(105),char(111),char(110),char(84),char(104),char(114),char(101),char(115), +char(104),char(111),char(108),char(100),char(0),char(109),char(95),char(104),char(97),char(115),char(65),char(110),char(105),char(115),char(111),char(116),char(114),char(111),char(112),char(105), +char(99),char(70),char(114),char(105),char(99),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(99),char(111),char(108),char(108),char(105),char(115),char(105),char(111), +char(110),char(70),char(108),char(97),char(103),char(115),char(0),char(109),char(95),char(105),char(115),char(108),char(97),char(110),char(100),char(84),char(97),char(103),char(49),char(0), +char(109),char(95),char(99),char(111),char(109),char(112),char(97),char(110),char(105),char(111),char(110),char(73),char(100),char(0),char(109),char(95),char(97),char(99),char(116),char(105), +char(118),char(97),char(116),char(105),char(111),char(110),char(83),char(116),char(97),char(116),char(101),char(49),char(0),char(109),char(95),char(105),char(110),char(116),char(101),char(114), +char(110),char(97),char(108),char(84),char(121),char(112),char(101),char(0),char(109),char(95),char(99),char(104),char(101),char(99),char(107),char(67),char(111),char(108),char(108),char(105), +char(100),char(101),char(87),char(105),char(116),char(104),char(0),char(109),char(95),char(116),char(97),char(117),char(0),char(109),char(95),char(100),char(97),char(109),char(112),char(105), +char(110),char(103),char(0),char(109),char(95),char(116),char(105),char(109),char(101),char(83),char(116),char(101),char(112),char(0),char(109),char(95),char(109),char(97),char(120),char(69), +char(114),char(114),char(111),char(114),char(82),char(101),char(100),char(117),char(99),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(115),char(111),char(114),char(0), +char(109),char(95),char(101),char(114),char(112),char(0),char(109),char(95),char(101),char(114),char(112),char(50),char(0),char(109),char(95),char(103),char(108),char(111),char(98),char(97), +char(108),char(67),char(102),char(109),char(0),char(109),char(95),char(115),char(112),char(108),char(105),char(116),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(80), +char(101),char(110),char(101),char(116),char(114),char(97),char(116),char(105),char(111),char(110),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0), +char(109),char(95),char(115),char(112),char(108),char(105),char(116),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(84),char(117),char(114),char(110),char(69),char(114), +char(112),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83),char(108),char(111),char(112),char(0),char(109),char(95),char(119),char(97),char(114), +char(109),char(115),char(116),char(97),char(114),char(116),char(105),char(110),char(103),char(70),char(97),char(99),char(116),char(111),char(114),char(0),char(109),char(95),char(109),char(97), +char(120),char(71),char(121),char(114),char(111),char(115),char(99),char(111),char(112),char(105),char(99),char(70),char(111),char(114),char(99),char(101),char(0),char(109),char(95),char(115), +char(105),char(110),char(103),char(108),char(101),char(65),char(120),char(105),char(115),char(82),char(111),char(108),char(108),char(105),char(110),char(103),char(70),char(114),char(105),char(99), +char(116),char(105),char(111),char(110),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109),char(95),char(110),char(117),char(109),char(73), +char(116),char(101),char(114),char(97),char(116),char(105),char(111),char(110),char(115),char(0),char(109),char(95),char(115),char(111),char(108),char(118),char(101),char(114),char(77),char(111), +char(100),char(101),char(0),char(109),char(95),char(114),char(101),char(115),char(116),char(105),char(110),char(103),char(67),char(111),char(110),char(116),char(97),char(99),char(116),char(82), +char(101),char(115),char(116),char(105),char(116),char(117),char(116),char(105),char(111),char(110),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0), +char(109),char(95),char(109),char(105),char(110),char(105),char(109),char(117),char(109),char(83),char(111),char(108),char(118),char(101),char(114),char(66),char(97),char(116),char(99),char(104), +char(83),char(105),char(122),char(101),char(0),char(109),char(95),char(115),char(112),char(108),char(105),char(116),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(0), +char(109),char(95),char(115),char(111),char(108),char(118),char(101),char(114),char(73),char(110),char(102),char(111),char(0),char(109),char(95),char(103),char(114),char(97),char(118),char(105), +char(116),char(121),char(0),char(109),char(95),char(99),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(79),char(98),char(106),char(101),char(99),char(116), +char(68),char(97),char(116),char(97),char(0),char(109),char(95),char(105),char(110),char(118),char(73),char(110),char(101),char(114),char(116),char(105),char(97),char(84),char(101),char(110), +char(115),char(111),char(114),char(87),char(111),char(114),char(108),char(100),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(86),char(101),char(108), +char(111),char(99),char(105),char(116),char(121),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(86),char(101),char(108),char(111),char(99), +char(105),char(116),char(121),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(70),char(97),char(99),char(116),char(111),char(114),char(0), +char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(70),char(97),char(99),char(116),char(111),char(114),char(0),char(109),char(95),char(103),char(114),char(97), +char(118),char(105),char(116),char(121),char(95),char(97),char(99),char(99),char(101),char(108),char(101),char(114),char(97),char(116),char(105),char(111),char(110),char(0),char(109),char(95), +char(105),char(110),char(118),char(73),char(110),char(101),char(114),char(116),char(105),char(97),char(76),char(111),char(99),char(97),char(108),char(0),char(109),char(95),char(116),char(111), +char(116),char(97),char(108),char(70),char(111),char(114),char(99),char(101),char(0),char(109),char(95),char(116),char(111),char(116),char(97),char(108),char(84),char(111),char(114),char(113), +char(117),char(101),char(0),char(109),char(95),char(105),char(110),char(118),char(101),char(114),char(115),char(101),char(77),char(97),char(115),char(115),char(0),char(109),char(95),char(108), +char(105),char(110),char(101),char(97),char(114),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108), +char(97),char(114),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(0),char(109),char(95),char(97),char(100),char(100),char(105),char(116),char(105),char(111),char(110), +char(97),char(108),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(70),char(97),char(99),char(116),char(111),char(114),char(0),char(109),char(95),char(97),char(100), +char(100),char(105),char(116),char(105),char(111),char(110),char(97),char(108),char(76),char(105),char(110),char(101),char(97),char(114),char(68),char(97),char(109),char(112),char(105),char(110), +char(103),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(83),char(113),char(114),char(0),char(109),char(95),char(97),char(100),char(100),char(105), +char(116),char(105),char(111),char(110),char(97),char(108),char(65),char(110),char(103),char(117),char(108),char(97),char(114),char(68),char(97),char(109),char(112),char(105),char(110),char(103), +char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(83),char(113),char(114),char(0),char(109),char(95),char(97),char(100),char(100),char(105),char(116), +char(105),char(111),char(110),char(97),char(108),char(65),char(110),char(103),char(117),char(108),char(97),char(114),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(70), +char(97),char(99),char(116),char(111),char(114),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83),char(108),char(101),char(101),char(112),char(105), +char(110),char(103),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97), +char(114),char(83),char(108),char(101),char(101),char(112),char(105),char(110),char(103),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109), +char(95),char(97),char(100),char(100),char(105),char(116),char(105),char(111),char(110),char(97),char(108),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(0),char(109), +char(95),char(110),char(117),char(109),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(82),char(111),char(119),char(115),char(0),char(110), +char(117),char(98),char(0),char(42),char(109),char(95),char(114),char(98),char(65),char(0),char(42),char(109),char(95),char(114),char(98),char(66),char(0),char(109),char(95),char(111), +char(98),char(106),char(101),char(99),char(116),char(84),char(121),char(112),char(101),char(0),char(109),char(95),char(117),char(115),char(101),char(114),char(67),char(111),char(110),char(115), +char(116),char(114),char(97),char(105),char(110),char(116),char(84),char(121),char(112),char(101),char(0),char(109),char(95),char(117),char(115),char(101),char(114),char(67),char(111),char(110), +char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(73),char(100),char(0),char(109),char(95),char(110),char(101),char(101),char(100),char(115),char(70),char(101),char(101), +char(100),char(98),char(97),char(99),char(107),char(0),char(109),char(95),char(97),char(112),char(112),char(108),char(105),char(101),char(100),char(73),char(109),char(112),char(117),char(108), +char(115),char(101),char(0),char(109),char(95),char(100),char(98),char(103),char(68),char(114),char(97),char(119),char(83),char(105),char(122),char(101),char(0),char(109),char(95),char(100), +char(105),char(115),char(97),char(98),char(108),char(101),char(67),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(115),char(66),char(101),char(116),char(119), +char(101),char(101),char(110),char(76),char(105),char(110),char(107),char(101),char(100),char(66),char(111),char(100),char(105),char(101),char(115),char(0),char(109),char(95),char(111),char(118), +char(101),char(114),char(114),char(105),char(100),char(101),char(78),char(117),char(109),char(83),char(111),char(108),char(118),char(101),char(114),char(73),char(116),char(101),char(114),char(97), +char(116),char(105),char(111),char(110),char(115),char(0),char(109),char(95),char(98),char(114),char(101),char(97),char(107),char(105),char(110),char(103),char(73),char(109),char(112),char(117), +char(108),char(115),char(101),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109),char(95),char(105),char(115),char(69),char(110),char(97), +char(98),char(108),char(101),char(100),char(0),char(112),char(97),char(100),char(100),char(105),char(110),char(103),char(91),char(52),char(93),char(0),char(109),char(95),char(116),char(121), +char(112),char(101),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(97),char(116),char(97),char(0),char(109),char(95),char(112), +char(105),char(118),char(111),char(116),char(73),char(110),char(65),char(0),char(109),char(95),char(112),char(105),char(118),char(111),char(116),char(73),char(110),char(66),char(0),char(109), +char(95),char(114),char(98),char(65),char(70),char(114),char(97),char(109),char(101),char(0),char(109),char(95),char(114),char(98),char(66),char(70),char(114),char(97),char(109),char(101), +char(0),char(109),char(95),char(117),char(115),char(101),char(82),char(101),char(102),char(101),char(114),char(101),char(110),char(99),char(101),char(70),char(114),char(97),char(109),char(101), +char(65),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(79),char(110),char(108),char(121),char(0),char(109),char(95),char(101),char(110), +char(97),char(98),char(108),char(101),char(65),char(110),char(103),char(117),char(108),char(97),char(114),char(77),char(111),char(116),char(111),char(114),char(0),char(109),char(95),char(109), +char(111),char(116),char(111),char(114),char(84),char(97),char(114),char(103),char(101),char(116),char(86),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(0),char(109), +char(95),char(109),char(97),char(120),char(77),char(111),char(116),char(111),char(114),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(0),char(109),char(95),char(108), +char(111),char(119),char(101),char(114),char(76),char(105),char(109),char(105),char(116),char(0),char(109),char(95),char(117),char(112),char(112),char(101),char(114),char(76),char(105),char(109), +char(105),char(116),char(0),char(109),char(95),char(108),char(105),char(109),char(105),char(116),char(83),char(111),char(102),char(116),char(110),char(101),char(115),char(115),char(0),char(109), +char(95),char(98),char(105),char(97),char(115),char(70),char(97),char(99),char(116),char(111),char(114),char(0),char(109),char(95),char(114),char(101),char(108),char(97),char(120),char(97), +char(116),char(105),char(111),char(110),char(70),char(97),char(99),char(116),char(111),char(114),char(0),char(109),char(95),char(112),char(97),char(100),char(100),char(105),char(110),char(103), +char(49),char(91),char(52),char(93),char(0),char(109),char(95),char(115),char(119),char(105),char(110),char(103),char(83),char(112),char(97),char(110),char(49),char(0),char(109),char(95), +char(115),char(119),char(105),char(110),char(103),char(83),char(112),char(97),char(110),char(50),char(0),char(109),char(95),char(116),char(119),char(105),char(115),char(116),char(83),char(112), +char(97),char(110),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(85),char(112),char(112),char(101),char(114),char(76),char(105),char(109),char(105), +char(116),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(76),char(111),char(119),char(101),char(114),char(76),char(105),char(109),char(105),char(116), +char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(85),char(112),char(112),char(101),char(114),char(76),char(105),char(109),char(105),char(116), +char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(76),char(111),char(119),char(101),char(114),char(76),char(105),char(109),char(105),char(116), +char(0),char(109),char(95),char(117),char(115),char(101),char(76),char(105),char(110),char(101),char(97),char(114),char(82),char(101),char(102),char(101),char(114),char(101),char(110),char(99), +char(101),char(70),char(114),char(97),char(109),char(101),char(65),char(0),char(109),char(95),char(117),char(115),char(101),char(79),char(102),char(102),char(115),char(101),char(116),char(70), +char(111),char(114),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(70),char(114),char(97),char(109),char(101),char(0),char(109),char(95), +char(54),char(100),char(111),char(102),char(68),char(97),char(116),char(97),char(0),char(109),char(95),char(115),char(112),char(114),char(105),char(110),char(103),char(69),char(110),char(97), +char(98),char(108),char(101),char(100),char(91),char(54),char(93),char(0),char(109),char(95),char(101),char(113),char(117),char(105),char(108),char(105),char(98),char(114),char(105),char(117), +char(109),char(80),char(111),char(105),char(110),char(116),char(91),char(54),char(93),char(0),char(109),char(95),char(115),char(112),char(114),char(105),char(110),char(103),char(83),char(116), +char(105),char(102),char(102),char(110),char(101),char(115),char(115),char(91),char(54),char(93),char(0),char(109),char(95),char(115),char(112),char(114),char(105),char(110),char(103),char(68), +char(97),char(109),char(112),char(105),char(110),char(103),char(91),char(54),char(93),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(66),char(111), +char(117),char(110),char(99),char(101),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83),char(116),char(111),char(112),char(69),char(82),char(80), +char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83),char(116),char(111),char(112),char(67),char(70),char(77),char(0),char(109),char(95),char(108), +char(105),char(110),char(101),char(97),char(114),char(77),char(111),char(116),char(111),char(114),char(69),char(82),char(80),char(0),char(109),char(95),char(108),char(105),char(110),char(101), +char(97),char(114),char(77),char(111),char(116),char(111),char(114),char(67),char(70),char(77),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(84), +char(97),char(114),char(103),char(101),char(116),char(86),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(0),char(109),char(95),char(108),char(105),char(110),char(101), +char(97),char(114),char(77),char(97),char(120),char(77),char(111),char(116),char(111),char(114),char(70),char(111),char(114),char(99),char(101),char(0),char(109),char(95),char(108),char(105), +char(110),char(101),char(97),char(114),char(83),char(101),char(114),char(118),char(111),char(84),char(97),char(114),char(103),char(101),char(116),char(0),char(109),char(95),char(108),char(105), +char(110),char(101),char(97),char(114),char(83),char(112),char(114),char(105),char(110),char(103),char(83),char(116),char(105),char(102),char(102),char(110),char(101),char(115),char(115),char(0), +char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83),char(112),char(114),char(105),char(110),char(103),char(68),char(97),char(109),char(112),char(105),char(110), +char(103),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(69),char(113),char(117),char(105),char(108),char(105),char(98),char(114),char(105),char(117), +char(109),char(80),char(111),char(105),char(110),char(116),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(69),char(110),char(97),char(98),char(108), +char(101),char(77),char(111),char(116),char(111),char(114),char(91),char(52),char(93),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83),char(101), +char(114),char(118),char(111),char(77),char(111),char(116),char(111),char(114),char(91),char(52),char(93),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114), +char(69),char(110),char(97),char(98),char(108),char(101),char(83),char(112),char(114),char(105),char(110),char(103),char(91),char(52),char(93),char(0),char(109),char(95),char(108),char(105), +char(110),char(101),char(97),char(114),char(83),char(112),char(114),char(105),char(110),char(103),char(83),char(116),char(105),char(102),char(102),char(110),char(101),char(115),char(115),char(76), +char(105),char(109),char(105),char(116),char(101),char(100),char(91),char(52),char(93),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83),char(112), +char(114),char(105),char(110),char(103),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(76),char(105),char(109),char(105),char(116),char(101),char(100),char(91),char(52), +char(93),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(66),char(111),char(117),char(110),char(99),char(101),char(0),char(109),char(95), +char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(83),char(116),char(111),char(112),char(69),char(82),char(80),char(0),char(109),char(95),char(97),char(110),char(103), +char(117),char(108),char(97),char(114),char(83),char(116),char(111),char(112),char(67),char(70),char(77),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97), +char(114),char(77),char(111),char(116),char(111),char(114),char(69),char(82),char(80),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(77), +char(111),char(116),char(111),char(114),char(67),char(70),char(77),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(84),char(97),char(114), +char(103),char(101),char(116),char(86),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97), +char(114),char(77),char(97),char(120),char(77),char(111),char(116),char(111),char(114),char(70),char(111),char(114),char(99),char(101),char(0),char(109),char(95),char(97),char(110),char(103), +char(117),char(108),char(97),char(114),char(83),char(101),char(114),char(118),char(111),char(84),char(97),char(114),char(103),char(101),char(116),char(0),char(109),char(95),char(97),char(110), +char(103),char(117),char(108),char(97),char(114),char(83),char(112),char(114),char(105),char(110),char(103),char(83),char(116),char(105),char(102),char(102),char(110),char(101),char(115),char(115), char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(83),char(112),char(114),char(105),char(110),char(103),char(68),char(97),char(109),char(112), -char(105),char(110),char(103),char(76),char(105),char(109),char(105),char(116),char(101),char(100),char(91),char(52),char(93),char(0),char(109),char(95),char(114),char(111),char(116),char(97), -char(116),char(101),char(79),char(114),char(100),char(101),char(114),char(0),char(109),char(95),char(97),char(120),char(105),char(115),char(73),char(110),char(65),char(0),char(109),char(95), -char(97),char(120),char(105),char(115),char(73),char(110),char(66),char(0),char(109),char(95),char(114),char(97),char(116),char(105),char(111),char(0),char(109),char(95),char(108),char(105), -char(110),char(101),char(97),char(114),char(83),char(116),char(105),char(102),char(102),char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(97),char(110),char(103),char(117), -char(108),char(97),char(114),char(83),char(116),char(105),char(102),char(102),char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(118),char(111),char(108),char(117),char(109), -char(101),char(83),char(116),char(105),char(102),char(102),char(110),char(101),char(115),char(115),char(0),char(42),char(109),char(95),char(109),char(97),char(116),char(101),char(114),char(105), -char(97),char(108),char(0),char(109),char(95),char(112),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(112),char(114),char(101),char(118), -char(105),char(111),char(117),char(115),char(80),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(118),char(101),char(108),char(111),char(99), -char(105),char(116),char(121),char(0),char(109),char(95),char(97),char(99),char(99),char(117),char(109),char(117),char(108),char(97),char(116),char(101),char(100),char(70),char(111),char(114), -char(99),char(101),char(0),char(109),char(95),char(110),char(111),char(114),char(109),char(97),char(108),char(0),char(109),char(95),char(97),char(114),char(101),char(97),char(0),char(109), -char(95),char(97),char(116),char(116),char(97),char(99),char(104),char(0),char(109),char(95),char(110),char(111),char(100),char(101),char(73),char(110),char(100),char(105),char(99),char(101), -char(115),char(91),char(50),char(93),char(0),char(109),char(95),char(114),char(101),char(115),char(116),char(76),char(101),char(110),char(103),char(116),char(104),char(0),char(109),char(95), -char(98),char(98),char(101),char(110),char(100),char(105),char(110),char(103),char(0),char(109),char(95),char(110),char(111),char(100),char(101),char(73),char(110),char(100),char(105),char(99), -char(101),char(115),char(91),char(51),char(93),char(0),char(109),char(95),char(114),char(101),char(115),char(116),char(65),char(114),char(101),char(97),char(0),char(109),char(95),char(99), -char(48),char(91),char(52),char(93),char(0),char(109),char(95),char(110),char(111),char(100),char(101),char(73),char(110),char(100),char(105),char(99),char(101),char(115),char(91),char(52), -char(93),char(0),char(109),char(95),char(114),char(101),char(115),char(116),char(86),char(111),char(108),char(117),char(109),char(101),char(0),char(109),char(95),char(99),char(49),char(0), -char(109),char(95),char(99),char(50),char(0),char(109),char(95),char(99),char(48),char(0),char(109),char(95),char(108),char(111),char(99),char(97),char(108),char(70),char(114),char(97), -char(109),char(101),char(0),char(42),char(109),char(95),char(114),char(105),char(103),char(105),char(100),char(66),char(111),char(100),char(121),char(0),char(109),char(95),char(110),char(111), -char(100),char(101),char(73),char(110),char(100),char(101),char(120),char(0),char(109),char(95),char(97),char(101),char(114),char(111),char(77),char(111),char(100),char(101),char(108),char(0), -char(109),char(95),char(98),char(97),char(117),char(109),char(103),char(97),char(114),char(116),char(101),char(0),char(109),char(95),char(100),char(114),char(97),char(103),char(0),char(109), -char(95),char(108),char(105),char(102),char(116),char(0),char(109),char(95),char(112),char(114),char(101),char(115),char(115),char(117),char(114),char(101),char(0),char(109),char(95),char(118), -char(111),char(108),char(117),char(109),char(101),char(0),char(109),char(95),char(100),char(121),char(110),char(97),char(109),char(105),char(99),char(70),char(114),char(105),char(99),char(116), -char(105),char(111),char(110),char(0),char(109),char(95),char(112),char(111),char(115),char(101),char(77),char(97),char(116),char(99),char(104),char(0),char(109),char(95),char(114),char(105), -char(103),char(105),char(100),char(67),char(111),char(110),char(116),char(97),char(99),char(116),char(72),char(97),char(114),char(100),char(110),char(101),char(115),char(115),char(0),char(109), -char(95),char(107),char(105),char(110),char(101),char(116),char(105),char(99),char(67),char(111),char(110),char(116),char(97),char(99),char(116),char(72),char(97),char(114),char(100),char(110), -char(101),char(115),char(115),char(0),char(109),char(95),char(115),char(111),char(102),char(116),char(67),char(111),char(110),char(116),char(97),char(99),char(116),char(72),char(97),char(114), -char(100),char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(97),char(110),char(99),char(104),char(111),char(114),char(72),char(97),char(114),char(100),char(110),char(101), -char(115),char(115),char(0),char(109),char(95),char(115),char(111),char(102),char(116),char(82),char(105),char(103),char(105),char(100),char(67),char(108),char(117),char(115),char(116),char(101), -char(114),char(72),char(97),char(114),char(100),char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(115),char(111),char(102),char(116),char(75),char(105),char(110),char(101), -char(116),char(105),char(99),char(67),char(108),char(117),char(115),char(116),char(101),char(114),char(72),char(97),char(114),char(100),char(110),char(101),char(115),char(115),char(0),char(109), -char(95),char(115),char(111),char(102),char(116),char(83),char(111),char(102),char(116),char(67),char(108),char(117),char(115),char(116),char(101),char(114),char(72),char(97),char(114),char(100), -char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(115),char(111),char(102),char(116),char(82),char(105),char(103),char(105),char(100),char(67),char(108),char(117),char(115), -char(116),char(101),char(114),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(83),char(112),char(108),char(105),char(116),char(0),char(109),char(95),char(115),char(111), -char(102),char(116),char(75),char(105),char(110),char(101),char(116),char(105),char(99),char(67),char(108),char(117),char(115),char(116),char(101),char(114),char(73),char(109),char(112),char(117), -char(108),char(115),char(101),char(83),char(112),char(108),char(105),char(116),char(0),char(109),char(95),char(115),char(111),char(102),char(116),char(83),char(111),char(102),char(116),char(67), -char(108),char(117),char(115),char(116),char(101),char(114),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(83),char(112),char(108),char(105),char(116),char(0),char(109), -char(95),char(109),char(97),char(120),char(86),char(111),char(108),char(117),char(109),char(101),char(0),char(109),char(95),char(116),char(105),char(109),char(101),char(83),char(99),char(97), -char(108),char(101),char(0),char(109),char(95),char(118),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(73),char(116),char(101),char(114),char(97),char(116),char(105), -char(111),char(110),char(115),char(0),char(109),char(95),char(112),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(73),char(116),char(101),char(114),char(97),char(116), -char(105),char(111),char(110),char(115),char(0),char(109),char(95),char(100),char(114),char(105),char(102),char(116),char(73),char(116),char(101),char(114),char(97),char(116),char(105),char(111), -char(110),char(115),char(0),char(109),char(95),char(99),char(108),char(117),char(115),char(116),char(101),char(114),char(73),char(116),char(101),char(114),char(97),char(116),char(105),char(111), -char(110),char(115),char(0),char(109),char(95),char(114),char(111),char(116),char(0),char(109),char(95),char(115),char(99),char(97),char(108),char(101),char(0),char(109),char(95),char(97), -char(113),char(113),char(0),char(109),char(95),char(99),char(111),char(109),char(0),char(42),char(109),char(95),char(112),char(111),char(115),char(105),char(116),char(105),char(111),char(110), -char(115),char(0),char(42),char(109),char(95),char(119),char(101),char(105),char(103),char(104),char(116),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(80),char(111), -char(115),char(105),char(116),char(105),char(111),char(110),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(87),char(101),char(105),char(103),char(116),char(115),char(0), -char(109),char(95),char(98),char(118),char(111),char(108),char(117),char(109),char(101),char(0),char(109),char(95),char(98),char(102),char(114),char(97),char(109),char(101),char(0),char(109), -char(95),char(102),char(114),char(97),char(109),char(101),char(120),char(102),char(111),char(114),char(109),char(0),char(109),char(95),char(108),char(111),char(99),char(105),char(105),char(0), -char(109),char(95),char(105),char(110),char(118),char(119),char(105),char(0),char(109),char(95),char(118),char(105),char(109),char(112),char(117),char(108),char(115),char(101),char(115),char(91), -char(50),char(93),char(0),char(109),char(95),char(100),char(105),char(109),char(112),char(117),char(108),char(115),char(101),char(115),char(91),char(50),char(93),char(0),char(109),char(95), -char(108),char(118),char(0),char(109),char(95),char(97),char(118),char(0),char(42),char(109),char(95),char(102),char(114),char(97),char(109),char(101),char(114),char(101),char(102),char(115), -char(0),char(42),char(109),char(95),char(110),char(111),char(100),char(101),char(73),char(110),char(100),char(105),char(99),char(101),char(115),char(0),char(42),char(109),char(95),char(109), -char(97),char(115),char(115),char(101),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(70),char(114),char(97),char(109),char(101),char(82),char(101),char(102),char(115), -char(0),char(109),char(95),char(110),char(117),char(109),char(78),char(111),char(100),char(101),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(77),char(97),char(115), -char(115),char(101),char(115),char(0),char(109),char(95),char(105),char(100),char(109),char(97),char(115),char(115),char(0),char(109),char(95),char(105),char(109),char(97),char(115),char(115), -char(0),char(109),char(95),char(110),char(118),char(105),char(109),char(112),char(117),char(108),char(115),char(101),char(115),char(0),char(109),char(95),char(110),char(100),char(105),char(109), -char(112),char(117),char(108),char(115),char(101),char(115),char(0),char(109),char(95),char(110),char(100),char(97),char(109),char(112),char(105),char(110),char(103),char(0),char(109),char(95), -char(108),char(100),char(97),char(109),char(112),char(105),char(110),char(103),char(0),char(109),char(95),char(97),char(100),char(97),char(109),char(112),char(105),char(110),char(103),char(0), -char(109),char(95),char(109),char(97),char(116),char(99),char(104),char(105),char(110),char(103),char(0),char(109),char(95),char(109),char(97),char(120),char(83),char(101),char(108),char(102), -char(67),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(0),char(109),char(95),char(115), -char(101),char(108),char(102),char(67),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(70), -char(97),char(99),char(116),char(111),char(114),char(0),char(109),char(95),char(99),char(111),char(110),char(116),char(97),char(105),char(110),char(115),char(65),char(110),char(99),char(104), -char(111),char(114),char(0),char(109),char(95),char(99),char(111),char(108),char(108),char(105),char(100),char(101),char(0),char(109),char(95),char(99),char(108),char(117),char(115),char(116), -char(101),char(114),char(73),char(110),char(100),char(101),char(120),char(0),char(42),char(109),char(95),char(98),char(111),char(100),char(121),char(65),char(0),char(42),char(109),char(95), -char(98),char(111),char(100),char(121),char(66),char(0),char(109),char(95),char(114),char(101),char(102),char(115),char(91),char(50),char(93),char(0),char(109),char(95),char(99),char(102), -char(109),char(0),char(109),char(95),char(115),char(112),char(108),char(105),char(116),char(0),char(109),char(95),char(100),char(101),char(108),char(101),char(116),char(101),char(0),char(109), -char(95),char(114),char(101),char(108),char(80),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(91),char(50),char(93),char(0),char(109),char(95),char(98),char(111), -char(100),char(121),char(65),char(116),char(121),char(112),char(101),char(0),char(109),char(95),char(98),char(111),char(100),char(121),char(66),char(116),char(121),char(112),char(101),char(0), -char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(84),char(121),char(112),char(101),char(0),char(42),char(109),char(95),char(112),char(111),char(115),char(101),char(0), -char(42),char(42),char(109),char(95),char(109),char(97),char(116),char(101),char(114),char(105),char(97),char(108),char(115),char(0),char(42),char(109),char(95),char(110),char(111),char(100), -char(101),char(115),char(0),char(42),char(109),char(95),char(108),char(105),char(110),char(107),char(115),char(0),char(42),char(109),char(95),char(102),char(97),char(99),char(101),char(115), -char(0),char(42),char(109),char(95),char(116),char(101),char(116),char(114),char(97),char(104),char(101),char(100),char(114),char(97),char(0),char(42),char(109),char(95),char(97),char(110), -char(99),char(104),char(111),char(114),char(115),char(0),char(42),char(109),char(95),char(99),char(108),char(117),char(115),char(116),char(101),char(114),char(115),char(0),char(42),char(109), -char(95),char(106),char(111),char(105),char(110),char(116),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(77),char(97),char(116),char(101),char(114),char(105),char(97), -char(108),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(76),char(105),char(110),char(107),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(70), -char(97),char(99),char(101),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(84),char(101),char(116),char(114),char(97),char(104),char(101),char(100),char(114),char(97), -char(0),char(109),char(95),char(110),char(117),char(109),char(65),char(110),char(99),char(104),char(111),char(114),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(67), -char(108),char(117),char(115),char(116),char(101),char(114),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(74),char(111),char(105),char(110),char(116),char(115),char(0), -char(109),char(95),char(99),char(111),char(110),char(102),char(105),char(103),char(0),char(109),char(95),char(122),char(101),char(114),char(111),char(82),char(111),char(116),char(80),char(97), -char(114),char(101),char(110),char(116),char(84),char(111),char(84),char(104),char(105),char(115),char(0),char(109),char(95),char(112),char(97),char(114),char(101),char(110),char(116),char(67), -char(111),char(109),char(84),char(111),char(84),char(104),char(105),char(115),char(67),char(111),char(109),char(79),char(102),char(102),char(115),char(101),char(116),char(0),char(109),char(95), -char(116),char(104),char(105),char(115),char(80),char(105),char(118),char(111),char(116),char(84),char(111),char(84),char(104),char(105),char(115),char(67),char(111),char(109),char(79),char(102), -char(102),char(115),char(101),char(116),char(0),char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(65),char(120),char(105),char(115),char(84),char(111),char(112),char(91), -char(54),char(93),char(0),char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(65),char(120),char(105),char(115),char(66),char(111),char(116),char(116),char(111),char(109), -char(91),char(54),char(93),char(0),char(109),char(95),char(108),char(105),char(110),char(107),char(73),char(110),char(101),char(114),char(116),char(105),char(97),char(0),char(109),char(95), -char(108),char(105),char(110),char(107),char(77),char(97),char(115),char(115),char(0),char(109),char(95),char(112),char(97),char(114),char(101),char(110),char(116),char(73),char(110),char(100), -char(101),char(120),char(0),char(109),char(95),char(100),char(111),char(102),char(67),char(111),char(117),char(110),char(116),char(0),char(109),char(95),char(112),char(111),char(115),char(86), -char(97),char(114),char(67),char(111),char(117),char(110),char(116),char(0),char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(80),char(111),char(115),char(91),char(55), -char(93),char(0),char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(86),char(101),char(108),char(91),char(54),char(93),char(0),char(109),char(95),char(106),char(111), -char(105),char(110),char(116),char(84),char(111),char(114),char(113),char(117),char(101),char(91),char(54),char(93),char(0),char(109),char(95),char(106),char(111),char(105),char(110),char(116), -char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(0),char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(70),char(114),char(105),char(99),char(116), -char(105),char(111),char(110),char(0),char(42),char(109),char(95),char(108),char(105),char(110),char(107),char(78),char(97),char(109),char(101),char(0),char(42),char(109),char(95),char(106), -char(111),char(105),char(110),char(116),char(78),char(97),char(109),char(101),char(0),char(42),char(109),char(95),char(108),char(105),char(110),char(107),char(67),char(111),char(108),char(108), -char(105),char(100),char(101),char(114),char(0),char(42),char(109),char(95),char(112),char(97),char(100),char(100),char(105),char(110),char(103),char(80),char(116),char(114),char(0),char(109), -char(95),char(98),char(97),char(115),char(101),char(87),char(111),char(114),char(108),char(100),char(84),char(114),char(97),char(110),char(115),char(102),char(111),char(114),char(109),char(0), -char(109),char(95),char(98),char(97),char(115),char(101),char(73),char(110),char(101),char(114),char(116),char(105),char(97),char(0),char(109),char(95),char(98),char(97),char(115),char(101), -char(77),char(97),char(115),char(115),char(0),char(42),char(109),char(95),char(98),char(97),char(115),char(101),char(78),char(97),char(109),char(101),char(0),char(42),char(109),char(95), -char(98),char(97),char(115),char(101),char(67),char(111),char(108),char(108),char(105),char(100),char(101),char(114),char(0),char(0),char(0),char(0),char(84),char(89),char(80),char(69), -char(95),char(0),char(0),char(0),char(99),char(104),char(97),char(114),char(0),char(117),char(99),char(104),char(97),char(114),char(0),char(115),char(104),char(111),char(114),char(116), -char(0),char(117),char(115),char(104),char(111),char(114),char(116),char(0),char(105),char(110),char(116),char(0),char(108),char(111),char(110),char(103),char(0),char(117),char(108),char(111), -char(110),char(103),char(0),char(102),char(108),char(111),char(97),char(116),char(0),char(100),char(111),char(117),char(98),char(108),char(101),char(0),char(118),char(111),char(105),char(100), -char(0),char(80),char(111),char(105),char(110),char(116),char(101),char(114),char(65),char(114),char(114),char(97),char(121),char(0),char(98),char(116),char(80),char(104),char(121),char(115), -char(105),char(99),char(115),char(83),char(121),char(115),char(116),char(101),char(109),char(0),char(76),char(105),char(115),char(116),char(66),char(97),char(115),char(101),char(0),char(98), -char(116),char(86),char(101),char(99),char(116),char(111),char(114),char(51),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116), -char(86),char(101),char(99),char(116),char(111),char(114),char(51),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116), -char(81),char(117),char(97),char(116),char(101),char(114),char(110),char(105),char(111),char(110),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0), -char(98),char(116),char(81),char(117),char(97),char(116),char(101),char(114),char(110),char(105),char(111),char(110),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97), -char(116),char(97),char(0),char(98),char(116),char(77),char(97),char(116),char(114),char(105),char(120),char(51),char(120),char(51),char(70),char(108),char(111),char(97),char(116),char(68), -char(97),char(116),char(97),char(0),char(98),char(116),char(77),char(97),char(116),char(114),char(105),char(120),char(51),char(120),char(51),char(68),char(111),char(117),char(98),char(108), -char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(84),char(114),char(97),char(110),char(115),char(102),char(111),char(114),char(109),char(70),char(108),char(111), -char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(84),char(114),char(97),char(110),char(115),char(102),char(111),char(114),char(109),char(68),char(111), -char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(66),char(118),char(104),char(83),char(117),char(98),char(116),char(114),char(101), -char(101),char(73),char(110),char(102),char(111),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(79),char(112),char(116),char(105),char(109),char(105),char(122),char(101), -char(100),char(66),char(118),char(104),char(78),char(111),char(100),char(101),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116), -char(79),char(112),char(116),char(105),char(109),char(105),char(122),char(101),char(100),char(66),char(118),char(104),char(78),char(111),char(100),char(101),char(68),char(111),char(117),char(98), -char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(81),char(117),char(97),char(110),char(116),char(105),char(122),char(101),char(100),char(66),char(118), -char(104),char(78),char(111),char(100),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(81),char(117),char(97),char(110),char(116),char(105),char(122),char(101), -char(100),char(66),char(118),char(104),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(81),char(117),char(97),char(110), -char(116),char(105),char(122),char(101),char(100),char(66),char(118),char(104),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98), -char(116),char(67),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0), -char(98),char(116),char(83),char(116),char(97),char(116),char(105),char(99),char(80),char(108),char(97),char(110),char(101),char(83),char(104),char(97),char(112),char(101),char(68),char(97), -char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(110),char(118),char(101),char(120),char(73),char(110),char(116),char(101),char(114),char(110),char(97),char(108),char(83), -char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(80),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(65), -char(110),char(100),char(82),char(97),char(100),char(105),char(117),char(115),char(0),char(98),char(116),char(77),char(117),char(108),char(116),char(105),char(83),char(112),char(104),char(101), -char(114),char(101),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(73),char(110),char(116),char(73),char(110),char(100), -char(101),char(120),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(83),char(104),char(111),char(114),char(116),char(73),char(110),char(116),char(73),char(110),char(100), -char(101),char(120),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(83),char(104),char(111),char(114),char(116),char(73),char(110),char(116),char(73),char(110),char(100), -char(101),char(120),char(84),char(114),char(105),char(112),char(108),char(101),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(104),char(97),char(114), -char(73),char(110),char(100),char(101),char(120),char(84),char(114),char(105),char(112),char(108),char(101),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(77), -char(101),char(115),char(104),char(80),char(97),char(114),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(83),char(116),char(114),char(105),char(100),char(105), -char(110),char(103),char(77),char(101),char(115),char(104),char(73),char(110),char(116),char(101),char(114),char(102),char(97),char(99),char(101),char(68),char(97),char(116),char(97),char(0), -char(98),char(116),char(84),char(114),char(105),char(97),char(110),char(103),char(108),char(101),char(77),char(101),char(115),char(104),char(83),char(104),char(97),char(112),char(101),char(68), -char(97),char(116),char(97),char(0),char(98),char(116),char(84),char(114),char(105),char(97),char(110),char(103),char(108),char(101),char(73),char(110),char(102),char(111),char(77),char(97), -char(112),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(83),char(99),char(97),char(108),char(101),char(100),char(84),char(114),char(105),char(97),char(110),char(103), -char(108),char(101),char(77),char(101),char(115),char(104),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111), -char(109),char(112),char(111),char(117),char(110),char(100),char(83),char(104),char(97),char(112),char(101),char(67),char(104),char(105),char(108),char(100),char(68),char(97),char(116),char(97), -char(0),char(98),char(116),char(67),char(111),char(109),char(112),char(111),char(117),char(110),char(100),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97), -char(0),char(98),char(116),char(67),char(121),char(108),char(105),char(110),char(100),char(101),char(114),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97), -char(0),char(98),char(116),char(67),char(111),char(110),char(101),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67), -char(97),char(112),char(115),char(117),char(108),char(101),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(84),char(114), -char(105),char(97),char(110),char(103),char(108),char(101),char(73),char(110),char(102),char(111),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(71),char(73),char(109), -char(112),char(97),char(99),char(116),char(77),char(101),char(115),char(104),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116), -char(67),char(111),char(110),char(118),char(101),char(120),char(72),char(117),char(108),char(108),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0), -char(98),char(116),char(67),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(79),char(98),char(106),char(101),char(99),char(116),char(68),char(111),char(117), -char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(79), -char(98),char(106),char(101),char(99),char(116),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(110), -char(116),char(97),char(99),char(116),char(83),char(111),char(108),char(118),char(101),char(114),char(73),char(110),char(102),char(111),char(68),char(111),char(117),char(98),char(108),char(101), -char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(110),char(116),char(97),char(99),char(116),char(83),char(111),char(108),char(118),char(101),char(114), -char(73),char(110),char(102),char(111),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(68),char(121),char(110),char(97), -char(109),char(105),char(99),char(115),char(87),char(111),char(114),char(108),char(100),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0), -char(98),char(116),char(68),char(121),char(110),char(97),char(109),char(105),char(99),char(115),char(87),char(111),char(114),char(108),char(100),char(70),char(108),char(111),char(97),char(116), -char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(82),char(105),char(103),char(105),char(100),char(66),char(111),char(100),char(121),char(70),char(108),char(111),char(97), -char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(82),char(105),char(103),char(105),char(100),char(66),char(111),char(100),char(121),char(68),char(111),char(117), -char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116), -char(73),char(110),char(102),char(111),char(49),char(0),char(98),char(116),char(84),char(121),char(112),char(101),char(100),char(67),char(111),char(110),char(115),char(116),char(114),char(97), -char(105),char(110),char(116),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(84),char(121),char(112),char(101),char(100), -char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(82),char(105),char(103), -char(105),char(100),char(66),char(111),char(100),char(121),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(84),char(121),char(112),char(101),char(100),char(67),char(111), -char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98), -char(116),char(80),char(111),char(105),char(110),char(116),char(50),char(80),char(111),char(105),char(110),char(116),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105), -char(110),char(116),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(80),char(111),char(105),char(110),char(116),char(50), -char(80),char(111),char(105),char(110),char(116),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108), -char(101),char(68),char(97),char(116),char(97),char(50),char(0),char(98),char(116),char(80),char(111),char(105),char(110),char(116),char(50),char(80),char(111),char(105),char(110),char(116), -char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97), -char(0),char(98),char(116),char(72),char(105),char(110),char(103),char(101),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111), -char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(72),char(105),char(110),char(103),char(101),char(67),char(111),char(110),char(115), -char(116),char(114),char(97),char(105),char(110),char(116),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(72),char(105), -char(110),char(103),char(101),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68), -char(97),char(116),char(97),char(50),char(0),char(98),char(116),char(67),char(111),char(110),char(101),char(84),char(119),char(105),char(115),char(116),char(67),char(111),char(110),char(115), -char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67), -char(111),char(110),char(101),char(84),char(119),char(105),char(115),char(116),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(97), -char(116),char(97),char(0),char(98),char(116),char(71),char(101),char(110),char(101),char(114),char(105),char(99),char(54),char(68),char(111),char(102),char(67),char(111),char(110),char(115), -char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(71),char(101),char(110),char(101),char(114),char(105),char(99), -char(54),char(68),char(111),char(102),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101), -char(68),char(97),char(116),char(97),char(50),char(0),char(98),char(116),char(71),char(101),char(110),char(101),char(114),char(105),char(99),char(54),char(68),char(111),char(102),char(83), -char(112),char(114),char(105),char(110),char(103),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(97),char(116),char(97),char(0), -char(98),char(116),char(71),char(101),char(110),char(101),char(114),char(105),char(99),char(54),char(68),char(111),char(102),char(83),char(112),char(114),char(105),char(110),char(103),char(67), +char(105),char(110),char(103),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(69),char(113),char(117),char(105),char(108),char(105),char(98), +char(114),char(105),char(117),char(109),char(80),char(111),char(105),char(110),char(116),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(69), +char(110),char(97),char(98),char(108),char(101),char(77),char(111),char(116),char(111),char(114),char(91),char(52),char(93),char(0),char(109),char(95),char(97),char(110),char(103),char(117), +char(108),char(97),char(114),char(83),char(101),char(114),char(118),char(111),char(77),char(111),char(116),char(111),char(114),char(91),char(52),char(93),char(0),char(109),char(95),char(97), +char(110),char(103),char(117),char(108),char(97),char(114),char(69),char(110),char(97),char(98),char(108),char(101),char(83),char(112),char(114),char(105),char(110),char(103),char(91),char(52), +char(93),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(83),char(112),char(114),char(105),char(110),char(103),char(83),char(116),char(105), +char(102),char(102),char(110),char(101),char(115),char(115),char(76),char(105),char(109),char(105),char(116),char(101),char(100),char(91),char(52),char(93),char(0),char(109),char(95),char(97), +char(110),char(103),char(117),char(108),char(97),char(114),char(83),char(112),char(114),char(105),char(110),char(103),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(76), +char(105),char(109),char(105),char(116),char(101),char(100),char(91),char(52),char(93),char(0),char(109),char(95),char(114),char(111),char(116),char(97),char(116),char(101),char(79),char(114), +char(100),char(101),char(114),char(0),char(109),char(95),char(97),char(120),char(105),char(115),char(73),char(110),char(65),char(0),char(109),char(95),char(97),char(120),char(105),char(115), +char(73),char(110),char(66),char(0),char(109),char(95),char(114),char(97),char(116),char(105),char(111),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114), +char(83),char(116),char(105),char(102),char(102),char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(83), +char(116),char(105),char(102),char(102),char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(118),char(111),char(108),char(117),char(109),char(101),char(83),char(116),char(105), +char(102),char(102),char(110),char(101),char(115),char(115),char(0),char(42),char(109),char(95),char(109),char(97),char(116),char(101),char(114),char(105),char(97),char(108),char(0),char(109), +char(95),char(112),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(112),char(114),char(101),char(118),char(105),char(111),char(117),char(115), +char(80),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(118),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(0), +char(109),char(95),char(97),char(99),char(99),char(117),char(109),char(117),char(108),char(97),char(116),char(101),char(100),char(70),char(111),char(114),char(99),char(101),char(0),char(109), +char(95),char(110),char(111),char(114),char(109),char(97),char(108),char(0),char(109),char(95),char(97),char(114),char(101),char(97),char(0),char(109),char(95),char(97),char(116),char(116), +char(97),char(99),char(104),char(0),char(109),char(95),char(110),char(111),char(100),char(101),char(73),char(110),char(100),char(105),char(99),char(101),char(115),char(91),char(50),char(93), +char(0),char(109),char(95),char(114),char(101),char(115),char(116),char(76),char(101),char(110),char(103),char(116),char(104),char(0),char(109),char(95),char(98),char(98),char(101),char(110), +char(100),char(105),char(110),char(103),char(0),char(109),char(95),char(110),char(111),char(100),char(101),char(73),char(110),char(100),char(105),char(99),char(101),char(115),char(91),char(51), +char(93),char(0),char(109),char(95),char(114),char(101),char(115),char(116),char(65),char(114),char(101),char(97),char(0),char(109),char(95),char(99),char(48),char(91),char(52),char(93), +char(0),char(109),char(95),char(110),char(111),char(100),char(101),char(73),char(110),char(100),char(105),char(99),char(101),char(115),char(91),char(52),char(93),char(0),char(109),char(95), +char(114),char(101),char(115),char(116),char(86),char(111),char(108),char(117),char(109),char(101),char(0),char(109),char(95),char(99),char(49),char(0),char(109),char(95),char(99),char(50), +char(0),char(109),char(95),char(99),char(48),char(0),char(109),char(95),char(108),char(111),char(99),char(97),char(108),char(70),char(114),char(97),char(109),char(101),char(0),char(42), +char(109),char(95),char(114),char(105),char(103),char(105),char(100),char(66),char(111),char(100),char(121),char(0),char(109),char(95),char(110),char(111),char(100),char(101),char(73),char(110), +char(100),char(101),char(120),char(0),char(109),char(95),char(97),char(101),char(114),char(111),char(77),char(111),char(100),char(101),char(108),char(0),char(109),char(95),char(98),char(97), +char(117),char(109),char(103),char(97),char(114),char(116),char(101),char(0),char(109),char(95),char(100),char(114),char(97),char(103),char(0),char(109),char(95),char(108),char(105),char(102), +char(116),char(0),char(109),char(95),char(112),char(114),char(101),char(115),char(115),char(117),char(114),char(101),char(0),char(109),char(95),char(118),char(111),char(108),char(117),char(109), +char(101),char(0),char(109),char(95),char(100),char(121),char(110),char(97),char(109),char(105),char(99),char(70),char(114),char(105),char(99),char(116),char(105),char(111),char(110),char(0), +char(109),char(95),char(112),char(111),char(115),char(101),char(77),char(97),char(116),char(99),char(104),char(0),char(109),char(95),char(114),char(105),char(103),char(105),char(100),char(67), +char(111),char(110),char(116),char(97),char(99),char(116),char(72),char(97),char(114),char(100),char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(107),char(105),char(110), +char(101),char(116),char(105),char(99),char(67),char(111),char(110),char(116),char(97),char(99),char(116),char(72),char(97),char(114),char(100),char(110),char(101),char(115),char(115),char(0), +char(109),char(95),char(115),char(111),char(102),char(116),char(67),char(111),char(110),char(116),char(97),char(99),char(116),char(72),char(97),char(114),char(100),char(110),char(101),char(115), +char(115),char(0),char(109),char(95),char(97),char(110),char(99),char(104),char(111),char(114),char(72),char(97),char(114),char(100),char(110),char(101),char(115),char(115),char(0),char(109), +char(95),char(115),char(111),char(102),char(116),char(82),char(105),char(103),char(105),char(100),char(67),char(108),char(117),char(115),char(116),char(101),char(114),char(72),char(97),char(114), +char(100),char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(115),char(111),char(102),char(116),char(75),char(105),char(110),char(101),char(116),char(105),char(99),char(67), +char(108),char(117),char(115),char(116),char(101),char(114),char(72),char(97),char(114),char(100),char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(115),char(111),char(102), +char(116),char(83),char(111),char(102),char(116),char(67),char(108),char(117),char(115),char(116),char(101),char(114),char(72),char(97),char(114),char(100),char(110),char(101),char(115),char(115), +char(0),char(109),char(95),char(115),char(111),char(102),char(116),char(82),char(105),char(103),char(105),char(100),char(67),char(108),char(117),char(115),char(116),char(101),char(114),char(73), +char(109),char(112),char(117),char(108),char(115),char(101),char(83),char(112),char(108),char(105),char(116),char(0),char(109),char(95),char(115),char(111),char(102),char(116),char(75),char(105), +char(110),char(101),char(116),char(105),char(99),char(67),char(108),char(117),char(115),char(116),char(101),char(114),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(83), +char(112),char(108),char(105),char(116),char(0),char(109),char(95),char(115),char(111),char(102),char(116),char(83),char(111),char(102),char(116),char(67),char(108),char(117),char(115),char(116), +char(101),char(114),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(83),char(112),char(108),char(105),char(116),char(0),char(109),char(95),char(109),char(97),char(120), +char(86),char(111),char(108),char(117),char(109),char(101),char(0),char(109),char(95),char(116),char(105),char(109),char(101),char(83),char(99),char(97),char(108),char(101),char(0),char(109), +char(95),char(118),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(73),char(116),char(101),char(114),char(97),char(116),char(105),char(111),char(110),char(115),char(0), +char(109),char(95),char(112),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(73),char(116),char(101),char(114),char(97),char(116),char(105),char(111),char(110),char(115), +char(0),char(109),char(95),char(100),char(114),char(105),char(102),char(116),char(73),char(116),char(101),char(114),char(97),char(116),char(105),char(111),char(110),char(115),char(0),char(109), +char(95),char(99),char(108),char(117),char(115),char(116),char(101),char(114),char(73),char(116),char(101),char(114),char(97),char(116),char(105),char(111),char(110),char(115),char(0),char(109), +char(95),char(114),char(111),char(116),char(0),char(109),char(95),char(115),char(99),char(97),char(108),char(101),char(0),char(109),char(95),char(97),char(113),char(113),char(0),char(109), +char(95),char(99),char(111),char(109),char(0),char(42),char(109),char(95),char(112),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(115),char(0),char(42),char(109), +char(95),char(119),char(101),char(105),char(103),char(104),char(116),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(80),char(111),char(115),char(105),char(116),char(105), +char(111),char(110),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(87),char(101),char(105),char(103),char(116),char(115),char(0),char(109),char(95),char(98),char(118), +char(111),char(108),char(117),char(109),char(101),char(0),char(109),char(95),char(98),char(102),char(114),char(97),char(109),char(101),char(0),char(109),char(95),char(102),char(114),char(97), +char(109),char(101),char(120),char(102),char(111),char(114),char(109),char(0),char(109),char(95),char(108),char(111),char(99),char(105),char(105),char(0),char(109),char(95),char(105),char(110), +char(118),char(119),char(105),char(0),char(109),char(95),char(118),char(105),char(109),char(112),char(117),char(108),char(115),char(101),char(115),char(91),char(50),char(93),char(0),char(109), +char(95),char(100),char(105),char(109),char(112),char(117),char(108),char(115),char(101),char(115),char(91),char(50),char(93),char(0),char(109),char(95),char(108),char(118),char(0),char(109), +char(95),char(97),char(118),char(0),char(42),char(109),char(95),char(102),char(114),char(97),char(109),char(101),char(114),char(101),char(102),char(115),char(0),char(42),char(109),char(95), +char(110),char(111),char(100),char(101),char(73),char(110),char(100),char(105),char(99),char(101),char(115),char(0),char(42),char(109),char(95),char(109),char(97),char(115),char(115),char(101), +char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(70),char(114),char(97),char(109),char(101),char(82),char(101),char(102),char(115),char(0),char(109),char(95),char(110), +char(117),char(109),char(78),char(111),char(100),char(101),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(77),char(97),char(115),char(115),char(101),char(115),char(0), +char(109),char(95),char(105),char(100),char(109),char(97),char(115),char(115),char(0),char(109),char(95),char(105),char(109),char(97),char(115),char(115),char(0),char(109),char(95),char(110), +char(118),char(105),char(109),char(112),char(117),char(108),char(115),char(101),char(115),char(0),char(109),char(95),char(110),char(100),char(105),char(109),char(112),char(117),char(108),char(115), +char(101),char(115),char(0),char(109),char(95),char(110),char(100),char(97),char(109),char(112),char(105),char(110),char(103),char(0),char(109),char(95),char(108),char(100),char(97),char(109), +char(112),char(105),char(110),char(103),char(0),char(109),char(95),char(97),char(100),char(97),char(109),char(112),char(105),char(110),char(103),char(0),char(109),char(95),char(109),char(97), +char(116),char(99),char(104),char(105),char(110),char(103),char(0),char(109),char(95),char(109),char(97),char(120),char(83),char(101),char(108),char(102),char(67),char(111),char(108),char(108), +char(105),char(115),char(105),char(111),char(110),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(0),char(109),char(95),char(115),char(101),char(108),char(102),char(67), +char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(70),char(97),char(99),char(116),char(111), +char(114),char(0),char(109),char(95),char(99),char(111),char(110),char(116),char(97),char(105),char(110),char(115),char(65),char(110),char(99),char(104),char(111),char(114),char(0),char(109), +char(95),char(99),char(111),char(108),char(108),char(105),char(100),char(101),char(0),char(109),char(95),char(99),char(108),char(117),char(115),char(116),char(101),char(114),char(73),char(110), +char(100),char(101),char(120),char(0),char(42),char(109),char(95),char(98),char(111),char(100),char(121),char(65),char(0),char(42),char(109),char(95),char(98),char(111),char(100),char(121), +char(66),char(0),char(109),char(95),char(114),char(101),char(102),char(115),char(91),char(50),char(93),char(0),char(109),char(95),char(99),char(102),char(109),char(0),char(109),char(95), +char(115),char(112),char(108),char(105),char(116),char(0),char(109),char(95),char(100),char(101),char(108),char(101),char(116),char(101),char(0),char(109),char(95),char(114),char(101),char(108), +char(80),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(91),char(50),char(93),char(0),char(109),char(95),char(98),char(111),char(100),char(121),char(65),char(116), +char(121),char(112),char(101),char(0),char(109),char(95),char(98),char(111),char(100),char(121),char(66),char(116),char(121),char(112),char(101),char(0),char(109),char(95),char(106),char(111), +char(105),char(110),char(116),char(84),char(121),char(112),char(101),char(0),char(42),char(109),char(95),char(112),char(111),char(115),char(101),char(0),char(42),char(42),char(109),char(95), +char(109),char(97),char(116),char(101),char(114),char(105),char(97),char(108),char(115),char(0),char(42),char(109),char(95),char(110),char(111),char(100),char(101),char(115),char(0),char(42), +char(109),char(95),char(108),char(105),char(110),char(107),char(115),char(0),char(42),char(109),char(95),char(102),char(97),char(99),char(101),char(115),char(0),char(42),char(109),char(95), +char(116),char(101),char(116),char(114),char(97),char(104),char(101),char(100),char(114),char(97),char(0),char(42),char(109),char(95),char(97),char(110),char(99),char(104),char(111),char(114), +char(115),char(0),char(42),char(109),char(95),char(99),char(108),char(117),char(115),char(116),char(101),char(114),char(115),char(0),char(42),char(109),char(95),char(106),char(111),char(105), +char(110),char(116),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(77),char(97),char(116),char(101),char(114),char(105),char(97),char(108),char(115),char(0),char(109), +char(95),char(110),char(117),char(109),char(76),char(105),char(110),char(107),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(70),char(97),char(99),char(101),char(115), +char(0),char(109),char(95),char(110),char(117),char(109),char(84),char(101),char(116),char(114),char(97),char(104),char(101),char(100),char(114),char(97),char(0),char(109),char(95),char(110), +char(117),char(109),char(65),char(110),char(99),char(104),char(111),char(114),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(67),char(108),char(117),char(115),char(116), +char(101),char(114),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(74),char(111),char(105),char(110),char(116),char(115),char(0),char(109),char(95),char(99),char(111), +char(110),char(102),char(105),char(103),char(0),char(109),char(95),char(122),char(101),char(114),char(111),char(82),char(111),char(116),char(80),char(97),char(114),char(101),char(110),char(116), +char(84),char(111),char(84),char(104),char(105),char(115),char(0),char(109),char(95),char(112),char(97),char(114),char(101),char(110),char(116),char(67),char(111),char(109),char(84),char(111), +char(84),char(104),char(105),char(115),char(67),char(111),char(109),char(79),char(102),char(102),char(115),char(101),char(116),char(0),char(109),char(95),char(116),char(104),char(105),char(115), +char(80),char(105),char(118),char(111),char(116),char(84),char(111),char(84),char(104),char(105),char(115),char(67),char(111),char(109),char(79),char(102),char(102),char(115),char(101),char(116), +char(0),char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(65),char(120),char(105),char(115),char(84),char(111),char(112),char(91),char(54),char(93),char(0),char(109), +char(95),char(106),char(111),char(105),char(110),char(116),char(65),char(120),char(105),char(115),char(66),char(111),char(116),char(116),char(111),char(109),char(91),char(54),char(93),char(0), +char(109),char(95),char(108),char(105),char(110),char(107),char(73),char(110),char(101),char(114),char(116),char(105),char(97),char(0),char(109),char(95),char(108),char(105),char(110),char(107), +char(77),char(97),char(115),char(115),char(0),char(109),char(95),char(112),char(97),char(114),char(101),char(110),char(116),char(73),char(110),char(100),char(101),char(120),char(0),char(109), +char(95),char(100),char(111),char(102),char(67),char(111),char(117),char(110),char(116),char(0),char(109),char(95),char(112),char(111),char(115),char(86),char(97),char(114),char(67),char(111), +char(117),char(110),char(116),char(0),char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(80),char(111),char(115),char(91),char(55),char(93),char(0),char(109),char(95), +char(106),char(111),char(105),char(110),char(116),char(86),char(101),char(108),char(91),char(54),char(93),char(0),char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(84), +char(111),char(114),char(113),char(117),char(101),char(91),char(54),char(93),char(0),char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(68),char(97),char(109),char(112), +char(105),char(110),char(103),char(0),char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(70),char(114),char(105),char(99),char(116),char(105),char(111),char(110),char(0), +char(42),char(109),char(95),char(108),char(105),char(110),char(107),char(78),char(97),char(109),char(101),char(0),char(42),char(109),char(95),char(106),char(111),char(105),char(110),char(116), +char(78),char(97),char(109),char(101),char(0),char(42),char(109),char(95),char(108),char(105),char(110),char(107),char(67),char(111),char(108),char(108),char(105),char(100),char(101),char(114), +char(0),char(42),char(109),char(95),char(112),char(97),char(100),char(100),char(105),char(110),char(103),char(80),char(116),char(114),char(0),char(109),char(95),char(98),char(97),char(115), +char(101),char(87),char(111),char(114),char(108),char(100),char(84),char(114),char(97),char(110),char(115),char(102),char(111),char(114),char(109),char(0),char(109),char(95),char(98),char(97), +char(115),char(101),char(73),char(110),char(101),char(114),char(116),char(105),char(97),char(0),char(109),char(95),char(98),char(97),char(115),char(101),char(77),char(97),char(115),char(115), +char(0),char(42),char(109),char(95),char(98),char(97),char(115),char(101),char(78),char(97),char(109),char(101),char(0),char(42),char(109),char(95),char(98),char(97),char(115),char(101), +char(67),char(111),char(108),char(108),char(105),char(100),char(101),char(114),char(0),char(0),char(0),char(0),char(84),char(89),char(80),char(69),char(95),char(0),char(0),char(0), +char(99),char(104),char(97),char(114),char(0),char(117),char(99),char(104),char(97),char(114),char(0),char(115),char(104),char(111),char(114),char(116),char(0),char(117),char(115),char(104), +char(111),char(114),char(116),char(0),char(105),char(110),char(116),char(0),char(108),char(111),char(110),char(103),char(0),char(117),char(108),char(111),char(110),char(103),char(0),char(102), +char(108),char(111),char(97),char(116),char(0),char(100),char(111),char(117),char(98),char(108),char(101),char(0),char(118),char(111),char(105),char(100),char(0),char(80),char(111),char(105), +char(110),char(116),char(101),char(114),char(65),char(114),char(114),char(97),char(121),char(0),char(98),char(116),char(80),char(104),char(121),char(115),char(105),char(99),char(115),char(83), +char(121),char(115),char(116),char(101),char(109),char(0),char(76),char(105),char(115),char(116),char(66),char(97),char(115),char(101),char(0),char(98),char(116),char(86),char(101),char(99), +char(116),char(111),char(114),char(51),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(86),char(101),char(99),char(116), +char(111),char(114),char(51),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(81),char(117),char(97),char(116), +char(101),char(114),char(110),char(105),char(111),char(110),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(81),char(117), +char(97),char(116),char(101),char(114),char(110),char(105),char(111),char(110),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98), +char(116),char(77),char(97),char(116),char(114),char(105),char(120),char(51),char(120),char(51),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0), +char(98),char(116),char(77),char(97),char(116),char(114),char(105),char(120),char(51),char(120),char(51),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116), +char(97),char(0),char(98),char(116),char(84),char(114),char(97),char(110),char(115),char(102),char(111),char(114),char(109),char(70),char(108),char(111),char(97),char(116),char(68),char(97), +char(116),char(97),char(0),char(98),char(116),char(84),char(114),char(97),char(110),char(115),char(102),char(111),char(114),char(109),char(68),char(111),char(117),char(98),char(108),char(101), +char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(66),char(118),char(104),char(83),char(117),char(98),char(116),char(114),char(101),char(101),char(73),char(110),char(102), +char(111),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(79),char(112),char(116),char(105),char(109),char(105),char(122),char(101),char(100),char(66),char(118),char(104), +char(78),char(111),char(100),char(101),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(79),char(112),char(116),char(105), +char(109),char(105),char(122),char(101),char(100),char(66),char(118),char(104),char(78),char(111),char(100),char(101),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97), +char(116),char(97),char(0),char(98),char(116),char(81),char(117),char(97),char(110),char(116),char(105),char(122),char(101),char(100),char(66),char(118),char(104),char(78),char(111),char(100), +char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(81),char(117),char(97),char(110),char(116),char(105),char(122),char(101),char(100),char(66),char(118),char(104), +char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(81),char(117),char(97),char(110),char(116),char(105),char(122),char(101), +char(100),char(66),char(118),char(104),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(108), +char(108),char(105),char(115),char(105),char(111),char(110),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(83),char(116), +char(97),char(116),char(105),char(99),char(80),char(108),char(97),char(110),char(101),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98), +char(116),char(67),char(111),char(110),char(118),char(101),char(120),char(73),char(110),char(116),char(101),char(114),char(110),char(97),char(108),char(83),char(104),char(97),char(112),char(101), +char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(80),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(65),char(110),char(100),char(82),char(97), +char(100),char(105),char(117),char(115),char(0),char(98),char(116),char(77),char(117),char(108),char(116),char(105),char(83),char(112),char(104),char(101),char(114),char(101),char(83),char(104), +char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(73),char(110),char(116),char(73),char(110),char(100),char(101),char(120),char(68),char(97), +char(116),char(97),char(0),char(98),char(116),char(83),char(104),char(111),char(114),char(116),char(73),char(110),char(116),char(73),char(110),char(100),char(101),char(120),char(68),char(97), +char(116),char(97),char(0),char(98),char(116),char(83),char(104),char(111),char(114),char(116),char(73),char(110),char(116),char(73),char(110),char(100),char(101),char(120),char(84),char(114), +char(105),char(112),char(108),char(101),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(104),char(97),char(114),char(73),char(110),char(100),char(101), +char(120),char(84),char(114),char(105),char(112),char(108),char(101),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(77),char(101),char(115),char(104),char(80), +char(97),char(114),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(83),char(116),char(114),char(105),char(100),char(105),char(110),char(103),char(77),char(101), +char(115),char(104),char(73),char(110),char(116),char(101),char(114),char(102),char(97),char(99),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(84),char(114), +char(105),char(97),char(110),char(103),char(108),char(101),char(77),char(101),char(115),char(104),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0), +char(98),char(116),char(84),char(114),char(105),char(97),char(110),char(103),char(108),char(101),char(73),char(110),char(102),char(111),char(77),char(97),char(112),char(68),char(97),char(116), +char(97),char(0),char(98),char(116),char(83),char(99),char(97),char(108),char(101),char(100),char(84),char(114),char(105),char(97),char(110),char(103),char(108),char(101),char(77),char(101), +char(115),char(104),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(109),char(112),char(111),char(117), +char(110),char(100),char(83),char(104),char(97),char(112),char(101),char(67),char(104),char(105),char(108),char(100),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67), +char(111),char(109),char(112),char(111),char(117),char(110),char(100),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67), +char(121),char(108),char(105),char(110),char(100),char(101),char(114),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67), +char(111),char(110),char(101),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(97),char(112),char(115),char(117), +char(108),char(101),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(84),char(114),char(105),char(97),char(110),char(103), +char(108),char(101),char(73),char(110),char(102),char(111),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(71),char(73),char(109),char(112),char(97),char(99),char(116), +char(77),char(101),char(115),char(104),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(110),char(118), +char(101),char(120),char(72),char(117),char(108),char(108),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111), +char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(79),char(98),char(106),char(101),char(99),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68), +char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(79),char(98),char(106),char(101),char(99), +char(116),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(110),char(116),char(97),char(99),char(116), +char(83),char(111),char(108),char(118),char(101),char(114),char(73),char(110),char(102),char(111),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97), +char(0),char(98),char(116),char(67),char(111),char(110),char(116),char(97),char(99),char(116),char(83),char(111),char(108),char(118),char(101),char(114),char(73),char(110),char(102),char(111), +char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(68),char(121),char(110),char(97),char(109),char(105),char(99),char(115), +char(87),char(111),char(114),char(108),char(100),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(68),char(121), +char(110),char(97),char(109),char(105),char(99),char(115),char(87),char(111),char(114),char(108),char(100),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97), +char(0),char(98),char(116),char(82),char(105),char(103),char(105),char(100),char(66),char(111),char(100),char(121),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116), +char(97),char(0),char(98),char(116),char(82),char(105),char(103),char(105),char(100),char(66),char(111),char(100),char(121),char(68),char(111),char(117),char(98),char(108),char(101),char(68), +char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(73),char(110),char(102),char(111), +char(49),char(0),char(98),char(116),char(84),char(121),char(112),char(101),char(100),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(70), +char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(84),char(121),char(112),char(101),char(100),char(67),char(111),char(110),char(115), +char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(82),char(105),char(103),char(105),char(100),char(66),char(111), +char(100),char(121),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(84),char(121),char(112),char(101),char(100),char(67),char(111),char(110),char(115),char(116),char(114), +char(97),char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(80),char(111),char(105), +char(110),char(116),char(50),char(80),char(111),char(105),char(110),char(116),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(70),char(108), +char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(80),char(111),char(105),char(110),char(116),char(50),char(80),char(111),char(105),char(110), +char(116),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116), +char(97),char(50),char(0),char(98),char(116),char(80),char(111),char(105),char(110),char(116),char(50),char(80),char(111),char(105),char(110),char(116),char(67),char(111),char(110),char(115), +char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(72), +char(105),char(110),char(103),char(101),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101), +char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(72),char(105),char(110),char(103),char(101),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105), +char(110),char(116),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(72),char(105),char(110),char(103),char(101),char(67), char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(50), -char(0),char(98),char(116),char(71),char(101),char(110),char(101),char(114),char(105),char(99),char(54),char(68),char(111),char(102),char(83),char(112),char(114),char(105),char(110),char(103), -char(50),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(71),char(101), -char(110),char(101),char(114),char(105),char(99),char(54),char(68),char(111),char(102),char(83),char(112),char(114),char(105),char(110),char(103),char(50),char(67),char(111),char(110),char(115), -char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(50),char(0),char(98),char(116), -char(83),char(108),char(105),char(100),char(101),char(114),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(97),char(116),char(97), -char(0),char(98),char(116),char(83),char(108),char(105),char(100),char(101),char(114),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68), -char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(71),char(101),char(97),char(114),char(67),char(111),char(110),char(115), -char(116),char(114),char(97),char(105),char(110),char(116),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(71),char(101), -char(97),char(114),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97), -char(116),char(97),char(0),char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(77),char(97),char(116),char(101),char(114),char(105),char(97),char(108),char(68), -char(97),char(116),char(97),char(0),char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(78),char(111),char(100),char(101),char(68),char(97),char(116),char(97), -char(0),char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(76),char(105),char(110),char(107),char(68),char(97),char(116),char(97),char(0),char(83),char(111), -char(102),char(116),char(66),char(111),char(100),char(121),char(70),char(97),char(99),char(101),char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102),char(116),char(66), -char(111),char(100),char(121),char(84),char(101),char(116),char(114),char(97),char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102),char(116),char(82),char(105),char(103), -char(105),char(100),char(65),char(110),char(99),char(104),char(111),char(114),char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102),char(116),char(66),char(111),char(100), -char(121),char(67),char(111),char(110),char(102),char(105),char(103),char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121), -char(80),char(111),char(115),char(101),char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(67),char(108),char(117), -char(115),char(116),char(101),char(114),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(74), -char(111),char(105),char(110),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(70), -char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(77),char(117),char(108),char(116),char(105),char(66),char(111),char(100),char(121), -char(76),char(105),char(110),char(107),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(77),char(117),char(108), -char(116),char(105),char(66),char(111),char(100),char(121),char(76),char(105),char(110),char(107),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0), -char(98),char(116),char(77),char(117),char(108),char(116),char(105),char(66),char(111),char(100),char(121),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116), -char(97),char(0),char(98),char(116),char(77),char(117),char(108),char(116),char(105),char(66),char(111),char(100),char(121),char(70),char(108),char(111),char(97),char(116),char(68),char(97), -char(116),char(97),char(0),char(0),char(84),char(76),char(69),char(78),char(1),char(0),char(1),char(0),char(2),char(0),char(2),char(0),char(4),char(0),char(4),char(0), -char(4),char(0),char(4),char(0),char(8),char(0),char(0),char(0),char(16),char(0),char(48),char(0),char(16),char(0),char(16),char(0),char(32),char(0),char(16),char(0), -char(32),char(0),char(48),char(0),char(96),char(0),char(64),char(0),char(-128),char(0),char(20),char(0),char(48),char(0),char(80),char(0),char(16),char(0),char(96),char(0), -char(-112),char(0),char(16),char(0),char(56),char(0),char(56),char(0),char(20),char(0),char(72),char(0),char(4),char(0),char(4),char(0),char(8),char(0),char(4),char(0), -char(56),char(0),char(32),char(0),char(80),char(0),char(72),char(0),char(96),char(0),char(80),char(0),char(32),char(0),char(64),char(0),char(64),char(0),char(64),char(0), -char(16),char(0),char(72),char(0),char(80),char(0),char(-32),char(1),char(16),char(1),char(-104),char(0),char(88),char(0),char(-72),char(0),char(104),char(0),char(-8),char(1), -char(-80),char(3),char(8),char(0),char(64),char(0),char(64),char(0),char(0),char(0),char(80),char(0),char(96),char(0),char(-112),char(0),char(-128),char(0),char(104),char(1), -char(-24),char(0),char(-104),char(1),char(-120),char(1),char(-32),char(0),char(8),char(1),char(-40),char(1),char(104),char(1),char(-128),char(2),char(-112),char(2),char(-64),char(4), -char(-40),char(0),char(120),char(1),char(104),char(0),char(-104),char(0),char(16),char(0),char(104),char(0),char(24),char(0),char(40),char(0),char(104),char(0),char(96),char(0), -char(104),char(0),char(-56),char(0),char(104),char(1),char(112),char(0),char(-32),char(1),char(-32),char(2),char(-120),char(1),char(-48),char(0),char(112),char(0),char(0),char(0), -char(83),char(84),char(82),char(67),char(84),char(0),char(0),char(0),char(10),char(0),char(3),char(0),char(4),char(0),char(0),char(0),char(4),char(0),char(1),char(0), -char(9),char(0),char(2),char(0),char(11),char(0),char(3),char(0),char(10),char(0),char(3),char(0),char(10),char(0),char(4),char(0),char(10),char(0),char(5),char(0), -char(12),char(0),char(2),char(0),char(9),char(0),char(6),char(0),char(9),char(0),char(7),char(0),char(13),char(0),char(1),char(0),char(7),char(0),char(8),char(0), -char(14),char(0),char(1),char(0),char(8),char(0),char(8),char(0),char(15),char(0),char(1),char(0),char(7),char(0),char(8),char(0),char(16),char(0),char(1),char(0), -char(8),char(0),char(8),char(0),char(17),char(0),char(1),char(0),char(13),char(0),char(9),char(0),char(18),char(0),char(1),char(0),char(14),char(0),char(9),char(0), -char(19),char(0),char(2),char(0),char(17),char(0),char(10),char(0),char(13),char(0),char(11),char(0),char(20),char(0),char(2),char(0),char(18),char(0),char(10),char(0), -char(14),char(0),char(11),char(0),char(21),char(0),char(4),char(0),char(4),char(0),char(12),char(0),char(4),char(0),char(13),char(0),char(2),char(0),char(14),char(0), -char(2),char(0),char(15),char(0),char(22),char(0),char(6),char(0),char(13),char(0),char(16),char(0),char(13),char(0),char(17),char(0),char(4),char(0),char(18),char(0), -char(4),char(0),char(19),char(0),char(4),char(0),char(20),char(0),char(0),char(0),char(21),char(0),char(23),char(0),char(6),char(0),char(14),char(0),char(16),char(0), -char(14),char(0),char(17),char(0),char(4),char(0),char(18),char(0),char(4),char(0),char(19),char(0),char(4),char(0),char(20),char(0),char(0),char(0),char(21),char(0), -char(24),char(0),char(3),char(0),char(2),char(0),char(14),char(0),char(2),char(0),char(15),char(0),char(4),char(0),char(22),char(0),char(25),char(0),char(12),char(0), -char(13),char(0),char(23),char(0),char(13),char(0),char(24),char(0),char(13),char(0),char(25),char(0),char(4),char(0),char(26),char(0),char(4),char(0),char(27),char(0), -char(4),char(0),char(28),char(0),char(4),char(0),char(29),char(0),char(22),char(0),char(30),char(0),char(24),char(0),char(31),char(0),char(21),char(0),char(32),char(0), -char(4),char(0),char(33),char(0),char(4),char(0),char(34),char(0),char(26),char(0),char(12),char(0),char(14),char(0),char(23),char(0),char(14),char(0),char(24),char(0), -char(14),char(0),char(25),char(0),char(4),char(0),char(26),char(0),char(4),char(0),char(27),char(0),char(4),char(0),char(28),char(0),char(4),char(0),char(29),char(0), -char(23),char(0),char(30),char(0),char(24),char(0),char(31),char(0),char(4),char(0),char(33),char(0),char(4),char(0),char(34),char(0),char(21),char(0),char(32),char(0), -char(27),char(0),char(3),char(0),char(0),char(0),char(35),char(0),char(4),char(0),char(36),char(0),char(0),char(0),char(37),char(0),char(28),char(0),char(5),char(0), -char(27),char(0),char(38),char(0),char(13),char(0),char(39),char(0),char(13),char(0),char(40),char(0),char(7),char(0),char(41),char(0),char(0),char(0),char(21),char(0), -char(29),char(0),char(5),char(0),char(27),char(0),char(38),char(0),char(13),char(0),char(39),char(0),char(13),char(0),char(42),char(0),char(7),char(0),char(43),char(0), -char(4),char(0),char(44),char(0),char(30),char(0),char(2),char(0),char(13),char(0),char(45),char(0),char(7),char(0),char(46),char(0),char(31),char(0),char(4),char(0), -char(29),char(0),char(47),char(0),char(30),char(0),char(48),char(0),char(4),char(0),char(49),char(0),char(0),char(0),char(37),char(0),char(32),char(0),char(1),char(0), -char(4),char(0),char(50),char(0),char(33),char(0),char(2),char(0),char(2),char(0),char(50),char(0),char(0),char(0),char(51),char(0),char(34),char(0),char(2),char(0), -char(2),char(0),char(52),char(0),char(0),char(0),char(51),char(0),char(35),char(0),char(2),char(0),char(0),char(0),char(52),char(0),char(0),char(0),char(53),char(0), -char(36),char(0),char(8),char(0),char(13),char(0),char(54),char(0),char(14),char(0),char(55),char(0),char(32),char(0),char(56),char(0),char(34),char(0),char(57),char(0), -char(35),char(0),char(58),char(0),char(33),char(0),char(59),char(0),char(4),char(0),char(60),char(0),char(4),char(0),char(61),char(0),char(37),char(0),char(4),char(0), -char(36),char(0),char(62),char(0),char(13),char(0),char(63),char(0),char(4),char(0),char(64),char(0),char(0),char(0),char(37),char(0),char(38),char(0),char(7),char(0), -char(27),char(0),char(38),char(0),char(37),char(0),char(65),char(0),char(25),char(0),char(66),char(0),char(26),char(0),char(67),char(0),char(39),char(0),char(68),char(0), -char(7),char(0),char(43),char(0),char(0),char(0),char(69),char(0),char(40),char(0),char(2),char(0),char(38),char(0),char(70),char(0),char(13),char(0),char(39),char(0), -char(41),char(0),char(4),char(0),char(19),char(0),char(71),char(0),char(27),char(0),char(72),char(0),char(4),char(0),char(73),char(0),char(7),char(0),char(74),char(0), -char(42),char(0),char(4),char(0),char(27),char(0),char(38),char(0),char(41),char(0),char(75),char(0),char(4),char(0),char(76),char(0),char(7),char(0),char(43),char(0), -char(43),char(0),char(3),char(0),char(29),char(0),char(47),char(0),char(4),char(0),char(77),char(0),char(0),char(0),char(37),char(0),char(44),char(0),char(3),char(0), -char(29),char(0),char(47),char(0),char(4),char(0),char(78),char(0),char(0),char(0),char(37),char(0),char(45),char(0),char(3),char(0),char(29),char(0),char(47),char(0), -char(4),char(0),char(77),char(0),char(0),char(0),char(37),char(0),char(46),char(0),char(4),char(0),char(4),char(0),char(79),char(0),char(7),char(0),char(80),char(0), -char(7),char(0),char(81),char(0),char(7),char(0),char(82),char(0),char(39),char(0),char(14),char(0),char(4),char(0),char(83),char(0),char(4),char(0),char(84),char(0), -char(46),char(0),char(85),char(0),char(4),char(0),char(86),char(0),char(7),char(0),char(87),char(0),char(7),char(0),char(88),char(0),char(7),char(0),char(89),char(0), -char(7),char(0),char(90),char(0),char(7),char(0),char(91),char(0),char(4),char(0),char(92),char(0),char(4),char(0),char(93),char(0),char(4),char(0),char(94),char(0), -char(4),char(0),char(95),char(0),char(0),char(0),char(37),char(0),char(47),char(0),char(5),char(0),char(27),char(0),char(38),char(0),char(37),char(0),char(65),char(0), -char(13),char(0),char(39),char(0),char(7),char(0),char(43),char(0),char(4),char(0),char(96),char(0),char(48),char(0),char(5),char(0),char(29),char(0),char(47),char(0), -char(13),char(0),char(97),char(0),char(14),char(0),char(98),char(0),char(4),char(0),char(99),char(0),char(0),char(0),char(100),char(0),char(49),char(0),char(25),char(0), -char(9),char(0),char(101),char(0),char(9),char(0),char(102),char(0),char(27),char(0),char(103),char(0),char(0),char(0),char(35),char(0),char(20),char(0),char(104),char(0), -char(20),char(0),char(105),char(0),char(14),char(0),char(106),char(0),char(14),char(0),char(107),char(0),char(14),char(0),char(108),char(0),char(8),char(0),char(109),char(0), -char(8),char(0),char(110),char(0),char(8),char(0),char(111),char(0),char(8),char(0),char(112),char(0),char(8),char(0),char(113),char(0),char(8),char(0),char(114),char(0), -char(8),char(0),char(115),char(0),char(8),char(0),char(116),char(0),char(4),char(0),char(117),char(0),char(4),char(0),char(118),char(0),char(4),char(0),char(119),char(0), -char(4),char(0),char(120),char(0),char(4),char(0),char(121),char(0),char(4),char(0),char(122),char(0),char(4),char(0),char(123),char(0),char(0),char(0),char(37),char(0), -char(50),char(0),char(25),char(0),char(9),char(0),char(101),char(0),char(9),char(0),char(102),char(0),char(27),char(0),char(103),char(0),char(0),char(0),char(35),char(0), -char(19),char(0),char(104),char(0),char(19),char(0),char(105),char(0),char(13),char(0),char(106),char(0),char(13),char(0),char(107),char(0),char(13),char(0),char(108),char(0), -char(7),char(0),char(109),char(0),char(7),char(0),char(110),char(0),char(7),char(0),char(111),char(0),char(7),char(0),char(112),char(0),char(7),char(0),char(113),char(0), -char(7),char(0),char(114),char(0),char(7),char(0),char(115),char(0),char(7),char(0),char(116),char(0),char(4),char(0),char(117),char(0),char(4),char(0),char(118),char(0), -char(4),char(0),char(119),char(0),char(4),char(0),char(120),char(0),char(4),char(0),char(121),char(0),char(4),char(0),char(122),char(0),char(4),char(0),char(123),char(0), -char(0),char(0),char(37),char(0),char(51),char(0),char(22),char(0),char(8),char(0),char(124),char(0),char(8),char(0),char(125),char(0),char(8),char(0),char(111),char(0), -char(8),char(0),char(126),char(0),char(8),char(0),char(113),char(0),char(8),char(0),char(127),char(0),char(8),char(0),char(-128),char(0),char(8),char(0),char(-127),char(0), -char(8),char(0),char(-126),char(0),char(8),char(0),char(-125),char(0),char(8),char(0),char(-124),char(0),char(8),char(0),char(-123),char(0),char(8),char(0),char(-122),char(0), -char(8),char(0),char(-121),char(0),char(8),char(0),char(-120),char(0),char(8),char(0),char(-119),char(0),char(4),char(0),char(-118),char(0),char(4),char(0),char(-117),char(0), -char(4),char(0),char(-116),char(0),char(4),char(0),char(-115),char(0),char(4),char(0),char(-114),char(0),char(0),char(0),char(37),char(0),char(52),char(0),char(22),char(0), -char(7),char(0),char(124),char(0),char(7),char(0),char(125),char(0),char(7),char(0),char(111),char(0),char(7),char(0),char(126),char(0),char(7),char(0),char(113),char(0), -char(7),char(0),char(127),char(0),char(7),char(0),char(-128),char(0),char(7),char(0),char(-127),char(0),char(7),char(0),char(-126),char(0),char(7),char(0),char(-125),char(0), -char(7),char(0),char(-124),char(0),char(7),char(0),char(-123),char(0),char(7),char(0),char(-122),char(0),char(7),char(0),char(-121),char(0),char(7),char(0),char(-120),char(0), -char(7),char(0),char(-119),char(0),char(4),char(0),char(-118),char(0),char(4),char(0),char(-117),char(0),char(4),char(0),char(-116),char(0),char(4),char(0),char(-115),char(0), -char(4),char(0),char(-114),char(0),char(0),char(0),char(37),char(0),char(53),char(0),char(2),char(0),char(51),char(0),char(-113),char(0),char(14),char(0),char(-112),char(0), -char(54),char(0),char(2),char(0),char(52),char(0),char(-113),char(0),char(13),char(0),char(-112),char(0),char(55),char(0),char(21),char(0),char(50),char(0),char(-111),char(0), -char(17),char(0),char(-110),char(0),char(13),char(0),char(-109),char(0),char(13),char(0),char(-108),char(0),char(13),char(0),char(-107),char(0),char(13),char(0),char(-106),char(0), -char(13),char(0),char(-112),char(0),char(13),char(0),char(-105),char(0),char(13),char(0),char(-104),char(0),char(13),char(0),char(-103),char(0),char(13),char(0),char(-102),char(0), -char(7),char(0),char(-101),char(0),char(7),char(0),char(-100),char(0),char(7),char(0),char(-99),char(0),char(7),char(0),char(-98),char(0),char(7),char(0),char(-97),char(0), -char(7),char(0),char(-96),char(0),char(7),char(0),char(-95),char(0),char(7),char(0),char(-94),char(0),char(7),char(0),char(-93),char(0),char(4),char(0),char(-92),char(0), -char(56),char(0),char(22),char(0),char(49),char(0),char(-111),char(0),char(18),char(0),char(-110),char(0),char(14),char(0),char(-109),char(0),char(14),char(0),char(-108),char(0), -char(14),char(0),char(-107),char(0),char(14),char(0),char(-106),char(0),char(14),char(0),char(-112),char(0),char(14),char(0),char(-105),char(0),char(14),char(0),char(-104),char(0), -char(14),char(0),char(-103),char(0),char(14),char(0),char(-102),char(0),char(8),char(0),char(-101),char(0),char(8),char(0),char(-100),char(0),char(8),char(0),char(-99),char(0), -char(8),char(0),char(-98),char(0),char(8),char(0),char(-97),char(0),char(8),char(0),char(-96),char(0),char(8),char(0),char(-95),char(0),char(8),char(0),char(-94),char(0), -char(8),char(0),char(-93),char(0),char(4),char(0),char(-92),char(0),char(0),char(0),char(37),char(0),char(57),char(0),char(2),char(0),char(4),char(0),char(-91),char(0), -char(4),char(0),char(-90),char(0),char(58),char(0),char(13),char(0),char(55),char(0),char(-89),char(0),char(55),char(0),char(-88),char(0),char(0),char(0),char(35),char(0), -char(4),char(0),char(-87),char(0),char(4),char(0),char(-86),char(0),char(4),char(0),char(-85),char(0),char(4),char(0),char(-84),char(0),char(7),char(0),char(-83),char(0), -char(7),char(0),char(-82),char(0),char(4),char(0),char(-81),char(0),char(4),char(0),char(-80),char(0),char(7),char(0),char(-79),char(0),char(4),char(0),char(-78),char(0), -char(59),char(0),char(13),char(0),char(60),char(0),char(-89),char(0),char(60),char(0),char(-88),char(0),char(0),char(0),char(35),char(0),char(4),char(0),char(-87),char(0), -char(4),char(0),char(-86),char(0),char(4),char(0),char(-85),char(0),char(4),char(0),char(-84),char(0),char(7),char(0),char(-83),char(0),char(7),char(0),char(-82),char(0), -char(4),char(0),char(-81),char(0),char(4),char(0),char(-80),char(0),char(7),char(0),char(-79),char(0),char(4),char(0),char(-78),char(0),char(61),char(0),char(14),char(0), -char(56),char(0),char(-89),char(0),char(56),char(0),char(-88),char(0),char(0),char(0),char(35),char(0),char(4),char(0),char(-87),char(0),char(4),char(0),char(-86),char(0), -char(4),char(0),char(-85),char(0),char(4),char(0),char(-84),char(0),char(8),char(0),char(-83),char(0),char(8),char(0),char(-82),char(0),char(4),char(0),char(-81),char(0), -char(4),char(0),char(-80),char(0),char(8),char(0),char(-79),char(0),char(4),char(0),char(-78),char(0),char(0),char(0),char(-77),char(0),char(62),char(0),char(3),char(0), -char(59),char(0),char(-76),char(0),char(13),char(0),char(-75),char(0),char(13),char(0),char(-74),char(0),char(63),char(0),char(3),char(0),char(61),char(0),char(-76),char(0), -char(14),char(0),char(-75),char(0),char(14),char(0),char(-74),char(0),char(64),char(0),char(3),char(0),char(59),char(0),char(-76),char(0),char(14),char(0),char(-75),char(0), -char(14),char(0),char(-74),char(0),char(65),char(0),char(13),char(0),char(59),char(0),char(-76),char(0),char(20),char(0),char(-73),char(0),char(20),char(0),char(-72),char(0), -char(4),char(0),char(-71),char(0),char(4),char(0),char(-70),char(0),char(4),char(0),char(-69),char(0),char(7),char(0),char(-68),char(0),char(7),char(0),char(-67),char(0), +char(0),char(98),char(116),char(67),char(111),char(110),char(101),char(84),char(119),char(105),char(115),char(116),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105), +char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(110),char(101),char(84), +char(119),char(105),char(115),char(116),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(97),char(116),char(97),char(0),char(98), +char(116),char(71),char(101),char(110),char(101),char(114),char(105),char(99),char(54),char(68),char(111),char(102),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105), +char(110),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(71),char(101),char(110),char(101),char(114),char(105),char(99),char(54),char(68),char(111),char(102), +char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97), +char(50),char(0),char(98),char(116),char(71),char(101),char(110),char(101),char(114),char(105),char(99),char(54),char(68),char(111),char(102),char(83),char(112),char(114),char(105),char(110), +char(103),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(71),char(101), +char(110),char(101),char(114),char(105),char(99),char(54),char(68),char(111),char(102),char(83),char(112),char(114),char(105),char(110),char(103),char(67),char(111),char(110),char(115),char(116), +char(114),char(97),char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(50),char(0),char(98),char(116),char(71), +char(101),char(110),char(101),char(114),char(105),char(99),char(54),char(68),char(111),char(102),char(83),char(112),char(114),char(105),char(110),char(103),char(50),char(67),char(111),char(110), +char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(71),char(101),char(110),char(101),char(114),char(105), +char(99),char(54),char(68),char(111),char(102),char(83),char(112),char(114),char(105),char(110),char(103),char(50),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105), +char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(50),char(0),char(98),char(116),char(83),char(108),char(105),char(100), +char(101),char(114),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(83), +char(108),char(105),char(100),char(101),char(114),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108), +char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(71),char(101),char(97),char(114),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105), +char(110),char(116),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(71),char(101),char(97),char(114),char(67),char(111), +char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(83), +char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(77),char(97),char(116),char(101),char(114),char(105),char(97),char(108),char(68),char(97),char(116),char(97),char(0), +char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(78),char(111),char(100),char(101),char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102), +char(116),char(66),char(111),char(100),char(121),char(76),char(105),char(110),char(107),char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102),char(116),char(66),char(111), +char(100),char(121),char(70),char(97),char(99),char(101),char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(84), +char(101),char(116),char(114),char(97),char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102),char(116),char(82),char(105),char(103),char(105),char(100),char(65),char(110), +char(99),char(104),char(111),char(114),char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(67),char(111),char(110), +char(102),char(105),char(103),char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(80),char(111),char(115),char(101), +char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(67),char(108),char(117),char(115),char(116),char(101),char(114), +char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(74),char(111),char(105),char(110),char(116), +char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(70),char(108),char(111),char(97),char(116), +char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(77),char(117),char(108),char(116),char(105),char(66),char(111),char(100),char(121),char(76),char(105),char(110),char(107), +char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(77),char(117),char(108),char(116),char(105),char(66),char(111), +char(100),char(121),char(76),char(105),char(110),char(107),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(77),char(117), +char(108),char(116),char(105),char(66),char(111),char(100),char(121),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116), +char(77),char(117),char(108),char(116),char(105),char(66),char(111),char(100),char(121),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(0), +char(84),char(76),char(69),char(78),char(1),char(0),char(1),char(0),char(2),char(0),char(2),char(0),char(4),char(0),char(4),char(0),char(4),char(0),char(4),char(0), +char(8),char(0),char(0),char(0),char(16),char(0),char(48),char(0),char(16),char(0),char(16),char(0),char(32),char(0),char(16),char(0),char(32),char(0),char(48),char(0), +char(96),char(0),char(64),char(0),char(-128),char(0),char(20),char(0),char(48),char(0),char(80),char(0),char(16),char(0),char(96),char(0),char(-112),char(0),char(16),char(0), +char(56),char(0),char(56),char(0),char(20),char(0),char(72),char(0),char(4),char(0),char(4),char(0),char(8),char(0),char(4),char(0),char(56),char(0),char(32),char(0), +char(80),char(0),char(72),char(0),char(96),char(0),char(80),char(0),char(32),char(0),char(64),char(0),char(64),char(0),char(64),char(0),char(16),char(0),char(72),char(0), +char(80),char(0),char(-16),char(1),char(24),char(1),char(-104),char(0),char(88),char(0),char(-72),char(0),char(104),char(0),char(0),char(2),char(-64),char(3),char(8),char(0), +char(64),char(0),char(64),char(0),char(0),char(0),char(80),char(0),char(96),char(0),char(-112),char(0),char(-128),char(0),char(104),char(1),char(-24),char(0),char(-104),char(1), +char(-120),char(1),char(-32),char(0),char(8),char(1),char(-40),char(1),char(104),char(1),char(-128),char(2),char(-112),char(2),char(-64),char(4),char(-40),char(0),char(120),char(1), +char(104),char(0),char(-104),char(0),char(16),char(0),char(104),char(0),char(24),char(0),char(40),char(0),char(104),char(0),char(96),char(0),char(104),char(0),char(-56),char(0), +char(104),char(1),char(112),char(0),char(-24),char(1),char(-32),char(2),char(-120),char(1),char(-48),char(0),char(112),char(0),char(0),char(0),char(83),char(84),char(82),char(67), +char(84),char(0),char(0),char(0),char(10),char(0),char(3),char(0),char(4),char(0),char(0),char(0),char(4),char(0),char(1),char(0),char(9),char(0),char(2),char(0), +char(11),char(0),char(3),char(0),char(10),char(0),char(3),char(0),char(10),char(0),char(4),char(0),char(10),char(0),char(5),char(0),char(12),char(0),char(2),char(0), +char(9),char(0),char(6),char(0),char(9),char(0),char(7),char(0),char(13),char(0),char(1),char(0),char(7),char(0),char(8),char(0),char(14),char(0),char(1),char(0), +char(8),char(0),char(8),char(0),char(15),char(0),char(1),char(0),char(7),char(0),char(8),char(0),char(16),char(0),char(1),char(0),char(8),char(0),char(8),char(0), +char(17),char(0),char(1),char(0),char(13),char(0),char(9),char(0),char(18),char(0),char(1),char(0),char(14),char(0),char(9),char(0),char(19),char(0),char(2),char(0), +char(17),char(0),char(10),char(0),char(13),char(0),char(11),char(0),char(20),char(0),char(2),char(0),char(18),char(0),char(10),char(0),char(14),char(0),char(11),char(0), +char(21),char(0),char(4),char(0),char(4),char(0),char(12),char(0),char(4),char(0),char(13),char(0),char(2),char(0),char(14),char(0),char(2),char(0),char(15),char(0), +char(22),char(0),char(6),char(0),char(13),char(0),char(16),char(0),char(13),char(0),char(17),char(0),char(4),char(0),char(18),char(0),char(4),char(0),char(19),char(0), +char(4),char(0),char(20),char(0),char(0),char(0),char(21),char(0),char(23),char(0),char(6),char(0),char(14),char(0),char(16),char(0),char(14),char(0),char(17),char(0), +char(4),char(0),char(18),char(0),char(4),char(0),char(19),char(0),char(4),char(0),char(20),char(0),char(0),char(0),char(21),char(0),char(24),char(0),char(3),char(0), +char(2),char(0),char(14),char(0),char(2),char(0),char(15),char(0),char(4),char(0),char(22),char(0),char(25),char(0),char(12),char(0),char(13),char(0),char(23),char(0), +char(13),char(0),char(24),char(0),char(13),char(0),char(25),char(0),char(4),char(0),char(26),char(0),char(4),char(0),char(27),char(0),char(4),char(0),char(28),char(0), +char(4),char(0),char(29),char(0),char(22),char(0),char(30),char(0),char(24),char(0),char(31),char(0),char(21),char(0),char(32),char(0),char(4),char(0),char(33),char(0), +char(4),char(0),char(34),char(0),char(26),char(0),char(12),char(0),char(14),char(0),char(23),char(0),char(14),char(0),char(24),char(0),char(14),char(0),char(25),char(0), +char(4),char(0),char(26),char(0),char(4),char(0),char(27),char(0),char(4),char(0),char(28),char(0),char(4),char(0),char(29),char(0),char(23),char(0),char(30),char(0), +char(24),char(0),char(31),char(0),char(4),char(0),char(33),char(0),char(4),char(0),char(34),char(0),char(21),char(0),char(32),char(0),char(27),char(0),char(3),char(0), +char(0),char(0),char(35),char(0),char(4),char(0),char(36),char(0),char(0),char(0),char(37),char(0),char(28),char(0),char(5),char(0),char(27),char(0),char(38),char(0), +char(13),char(0),char(39),char(0),char(13),char(0),char(40),char(0),char(7),char(0),char(41),char(0),char(0),char(0),char(21),char(0),char(29),char(0),char(5),char(0), +char(27),char(0),char(38),char(0),char(13),char(0),char(39),char(0),char(13),char(0),char(42),char(0),char(7),char(0),char(43),char(0),char(4),char(0),char(44),char(0), +char(30),char(0),char(2),char(0),char(13),char(0),char(45),char(0),char(7),char(0),char(46),char(0),char(31),char(0),char(4),char(0),char(29),char(0),char(47),char(0), +char(30),char(0),char(48),char(0),char(4),char(0),char(49),char(0),char(0),char(0),char(37),char(0),char(32),char(0),char(1),char(0),char(4),char(0),char(50),char(0), +char(33),char(0),char(2),char(0),char(2),char(0),char(50),char(0),char(0),char(0),char(51),char(0),char(34),char(0),char(2),char(0),char(2),char(0),char(52),char(0), +char(0),char(0),char(51),char(0),char(35),char(0),char(2),char(0),char(0),char(0),char(52),char(0),char(0),char(0),char(53),char(0),char(36),char(0),char(8),char(0), +char(13),char(0),char(54),char(0),char(14),char(0),char(55),char(0),char(32),char(0),char(56),char(0),char(34),char(0),char(57),char(0),char(35),char(0),char(58),char(0), +char(33),char(0),char(59),char(0),char(4),char(0),char(60),char(0),char(4),char(0),char(61),char(0),char(37),char(0),char(4),char(0),char(36),char(0),char(62),char(0), +char(13),char(0),char(63),char(0),char(4),char(0),char(64),char(0),char(0),char(0),char(37),char(0),char(38),char(0),char(7),char(0),char(27),char(0),char(38),char(0), +char(37),char(0),char(65),char(0),char(25),char(0),char(66),char(0),char(26),char(0),char(67),char(0),char(39),char(0),char(68),char(0),char(7),char(0),char(43),char(0), +char(0),char(0),char(69),char(0),char(40),char(0),char(2),char(0),char(38),char(0),char(70),char(0),char(13),char(0),char(39),char(0),char(41),char(0),char(4),char(0), +char(19),char(0),char(71),char(0),char(27),char(0),char(72),char(0),char(4),char(0),char(73),char(0),char(7),char(0),char(74),char(0),char(42),char(0),char(4),char(0), +char(27),char(0),char(38),char(0),char(41),char(0),char(75),char(0),char(4),char(0),char(76),char(0),char(7),char(0),char(43),char(0),char(43),char(0),char(3),char(0), +char(29),char(0),char(47),char(0),char(4),char(0),char(77),char(0),char(0),char(0),char(37),char(0),char(44),char(0),char(3),char(0),char(29),char(0),char(47),char(0), +char(4),char(0),char(78),char(0),char(0),char(0),char(37),char(0),char(45),char(0),char(3),char(0),char(29),char(0),char(47),char(0),char(4),char(0),char(77),char(0), +char(0),char(0),char(37),char(0),char(46),char(0),char(4),char(0),char(4),char(0),char(79),char(0),char(7),char(0),char(80),char(0),char(7),char(0),char(81),char(0), +char(7),char(0),char(82),char(0),char(39),char(0),char(14),char(0),char(4),char(0),char(83),char(0),char(4),char(0),char(84),char(0),char(46),char(0),char(85),char(0), +char(4),char(0),char(86),char(0),char(7),char(0),char(87),char(0),char(7),char(0),char(88),char(0),char(7),char(0),char(89),char(0),char(7),char(0),char(90),char(0), +char(7),char(0),char(91),char(0),char(4),char(0),char(92),char(0),char(4),char(0),char(93),char(0),char(4),char(0),char(94),char(0),char(4),char(0),char(95),char(0), +char(0),char(0),char(37),char(0),char(47),char(0),char(5),char(0),char(27),char(0),char(38),char(0),char(37),char(0),char(65),char(0),char(13),char(0),char(39),char(0), +char(7),char(0),char(43),char(0),char(4),char(0),char(96),char(0),char(48),char(0),char(5),char(0),char(29),char(0),char(47),char(0),char(13),char(0),char(97),char(0), +char(14),char(0),char(98),char(0),char(4),char(0),char(99),char(0),char(0),char(0),char(100),char(0),char(49),char(0),char(27),char(0),char(9),char(0),char(101),char(0), +char(9),char(0),char(102),char(0),char(27),char(0),char(103),char(0),char(0),char(0),char(35),char(0),char(20),char(0),char(104),char(0),char(20),char(0),char(105),char(0), +char(14),char(0),char(106),char(0),char(14),char(0),char(107),char(0),char(14),char(0),char(108),char(0),char(8),char(0),char(109),char(0),char(8),char(0),char(110),char(0), +char(8),char(0),char(111),char(0),char(8),char(0),char(112),char(0),char(8),char(0),char(113),char(0),char(8),char(0),char(114),char(0),char(8),char(0),char(115),char(0), +char(8),char(0),char(116),char(0),char(8),char(0),char(117),char(0),char(8),char(0),char(118),char(0),char(4),char(0),char(119),char(0),char(4),char(0),char(120),char(0), +char(4),char(0),char(121),char(0),char(4),char(0),char(122),char(0),char(4),char(0),char(123),char(0),char(4),char(0),char(124),char(0),char(4),char(0),char(125),char(0), +char(0),char(0),char(37),char(0),char(50),char(0),char(27),char(0),char(9),char(0),char(101),char(0),char(9),char(0),char(102),char(0),char(27),char(0),char(103),char(0), +char(0),char(0),char(35),char(0),char(19),char(0),char(104),char(0),char(19),char(0),char(105),char(0),char(13),char(0),char(106),char(0),char(13),char(0),char(107),char(0), +char(13),char(0),char(108),char(0),char(7),char(0),char(109),char(0),char(7),char(0),char(110),char(0),char(7),char(0),char(111),char(0),char(7),char(0),char(112),char(0), +char(7),char(0),char(113),char(0),char(7),char(0),char(114),char(0),char(7),char(0),char(115),char(0),char(7),char(0),char(116),char(0),char(7),char(0),char(117),char(0), +char(7),char(0),char(118),char(0),char(4),char(0),char(119),char(0),char(4),char(0),char(120),char(0),char(4),char(0),char(121),char(0),char(4),char(0),char(122),char(0), +char(4),char(0),char(123),char(0),char(4),char(0),char(124),char(0),char(4),char(0),char(125),char(0),char(0),char(0),char(37),char(0),char(51),char(0),char(22),char(0), +char(8),char(0),char(126),char(0),char(8),char(0),char(127),char(0),char(8),char(0),char(111),char(0),char(8),char(0),char(-128),char(0),char(8),char(0),char(115),char(0), +char(8),char(0),char(-127),char(0),char(8),char(0),char(-126),char(0),char(8),char(0),char(-125),char(0),char(8),char(0),char(-124),char(0),char(8),char(0),char(-123),char(0), +char(8),char(0),char(-122),char(0),char(8),char(0),char(-121),char(0),char(8),char(0),char(-120),char(0),char(8),char(0),char(-119),char(0),char(8),char(0),char(-118),char(0), +char(8),char(0),char(-117),char(0),char(4),char(0),char(-116),char(0),char(4),char(0),char(-115),char(0),char(4),char(0),char(-114),char(0),char(4),char(0),char(-113),char(0), +char(4),char(0),char(-112),char(0),char(0),char(0),char(37),char(0),char(52),char(0),char(22),char(0),char(7),char(0),char(126),char(0),char(7),char(0),char(127),char(0), +char(7),char(0),char(111),char(0),char(7),char(0),char(-128),char(0),char(7),char(0),char(115),char(0),char(7),char(0),char(-127),char(0),char(7),char(0),char(-126),char(0), +char(7),char(0),char(-125),char(0),char(7),char(0),char(-124),char(0),char(7),char(0),char(-123),char(0),char(7),char(0),char(-122),char(0),char(7),char(0),char(-121),char(0), +char(7),char(0),char(-120),char(0),char(7),char(0),char(-119),char(0),char(7),char(0),char(-118),char(0),char(7),char(0),char(-117),char(0),char(4),char(0),char(-116),char(0), +char(4),char(0),char(-115),char(0),char(4),char(0),char(-114),char(0),char(4),char(0),char(-113),char(0),char(4),char(0),char(-112),char(0),char(0),char(0),char(37),char(0), +char(53),char(0),char(2),char(0),char(51),char(0),char(-111),char(0),char(14),char(0),char(-110),char(0),char(54),char(0),char(2),char(0),char(52),char(0),char(-111),char(0), +char(13),char(0),char(-110),char(0),char(55),char(0),char(21),char(0),char(50),char(0),char(-109),char(0),char(17),char(0),char(-108),char(0),char(13),char(0),char(-107),char(0), +char(13),char(0),char(-106),char(0),char(13),char(0),char(-105),char(0),char(13),char(0),char(-104),char(0),char(13),char(0),char(-110),char(0),char(13),char(0),char(-103),char(0), +char(13),char(0),char(-102),char(0),char(13),char(0),char(-101),char(0),char(13),char(0),char(-100),char(0),char(7),char(0),char(-99),char(0),char(7),char(0),char(-98),char(0), +char(7),char(0),char(-97),char(0),char(7),char(0),char(-96),char(0),char(7),char(0),char(-95),char(0),char(7),char(0),char(-94),char(0),char(7),char(0),char(-93),char(0), +char(7),char(0),char(-92),char(0),char(7),char(0),char(-91),char(0),char(4),char(0),char(-90),char(0),char(56),char(0),char(22),char(0),char(49),char(0),char(-109),char(0), +char(18),char(0),char(-108),char(0),char(14),char(0),char(-107),char(0),char(14),char(0),char(-106),char(0),char(14),char(0),char(-105),char(0),char(14),char(0),char(-104),char(0), +char(14),char(0),char(-110),char(0),char(14),char(0),char(-103),char(0),char(14),char(0),char(-102),char(0),char(14),char(0),char(-101),char(0),char(14),char(0),char(-100),char(0), +char(8),char(0),char(-99),char(0),char(8),char(0),char(-98),char(0),char(8),char(0),char(-97),char(0),char(8),char(0),char(-96),char(0),char(8),char(0),char(-95),char(0), +char(8),char(0),char(-94),char(0),char(8),char(0),char(-93),char(0),char(8),char(0),char(-92),char(0),char(8),char(0),char(-91),char(0),char(4),char(0),char(-90),char(0), +char(0),char(0),char(37),char(0),char(57),char(0),char(2),char(0),char(4),char(0),char(-89),char(0),char(4),char(0),char(-88),char(0),char(58),char(0),char(13),char(0), +char(55),char(0),char(-87),char(0),char(55),char(0),char(-86),char(0),char(0),char(0),char(35),char(0),char(4),char(0),char(-85),char(0),char(4),char(0),char(-84),char(0), +char(4),char(0),char(-83),char(0),char(4),char(0),char(-82),char(0),char(7),char(0),char(-81),char(0),char(7),char(0),char(-80),char(0),char(4),char(0),char(-79),char(0), +char(4),char(0),char(-78),char(0),char(7),char(0),char(-77),char(0),char(4),char(0),char(-76),char(0),char(59),char(0),char(13),char(0),char(60),char(0),char(-87),char(0), +char(60),char(0),char(-86),char(0),char(0),char(0),char(35),char(0),char(4),char(0),char(-85),char(0),char(4),char(0),char(-84),char(0),char(4),char(0),char(-83),char(0), +char(4),char(0),char(-82),char(0),char(7),char(0),char(-81),char(0),char(7),char(0),char(-80),char(0),char(4),char(0),char(-79),char(0),char(4),char(0),char(-78),char(0), +char(7),char(0),char(-77),char(0),char(4),char(0),char(-76),char(0),char(61),char(0),char(14),char(0),char(56),char(0),char(-87),char(0),char(56),char(0),char(-86),char(0), +char(0),char(0),char(35),char(0),char(4),char(0),char(-85),char(0),char(4),char(0),char(-84),char(0),char(4),char(0),char(-83),char(0),char(4),char(0),char(-82),char(0), +char(8),char(0),char(-81),char(0),char(8),char(0),char(-80),char(0),char(4),char(0),char(-79),char(0),char(4),char(0),char(-78),char(0),char(8),char(0),char(-77),char(0), +char(4),char(0),char(-76),char(0),char(0),char(0),char(-75),char(0),char(62),char(0),char(3),char(0),char(59),char(0),char(-74),char(0),char(13),char(0),char(-73),char(0), +char(13),char(0),char(-72),char(0),char(63),char(0),char(3),char(0),char(61),char(0),char(-74),char(0),char(14),char(0),char(-73),char(0),char(14),char(0),char(-72),char(0), +char(64),char(0),char(3),char(0),char(59),char(0),char(-74),char(0),char(14),char(0),char(-73),char(0),char(14),char(0),char(-72),char(0),char(65),char(0),char(13),char(0), +char(59),char(0),char(-74),char(0),char(20),char(0),char(-71),char(0),char(20),char(0),char(-70),char(0),char(4),char(0),char(-69),char(0),char(4),char(0),char(-68),char(0), +char(4),char(0),char(-67),char(0),char(7),char(0),char(-66),char(0),char(7),char(0),char(-65),char(0),char(7),char(0),char(-64),char(0),char(7),char(0),char(-63),char(0), +char(7),char(0),char(-62),char(0),char(7),char(0),char(-61),char(0),char(7),char(0),char(-60),char(0),char(66),char(0),char(13),char(0),char(59),char(0),char(-74),char(0), +char(19),char(0),char(-71),char(0),char(19),char(0),char(-70),char(0),char(4),char(0),char(-69),char(0),char(4),char(0),char(-68),char(0),char(4),char(0),char(-67),char(0), char(7),char(0),char(-66),char(0),char(7),char(0),char(-65),char(0),char(7),char(0),char(-64),char(0),char(7),char(0),char(-63),char(0),char(7),char(0),char(-62),char(0), -char(66),char(0),char(13),char(0),char(59),char(0),char(-76),char(0),char(19),char(0),char(-73),char(0),char(19),char(0),char(-72),char(0),char(4),char(0),char(-71),char(0), -char(4),char(0),char(-70),char(0),char(4),char(0),char(-69),char(0),char(7),char(0),char(-68),char(0),char(7),char(0),char(-67),char(0),char(7),char(0),char(-66),char(0), -char(7),char(0),char(-65),char(0),char(7),char(0),char(-64),char(0),char(7),char(0),char(-63),char(0),char(7),char(0),char(-62),char(0),char(67),char(0),char(14),char(0), -char(61),char(0),char(-76),char(0),char(20),char(0),char(-73),char(0),char(20),char(0),char(-72),char(0),char(4),char(0),char(-71),char(0),char(4),char(0),char(-70),char(0), -char(4),char(0),char(-69),char(0),char(8),char(0),char(-68),char(0),char(8),char(0),char(-67),char(0),char(8),char(0),char(-66),char(0),char(8),char(0),char(-65),char(0), -char(8),char(0),char(-64),char(0),char(8),char(0),char(-63),char(0),char(8),char(0),char(-62),char(0),char(0),char(0),char(-61),char(0),char(68),char(0),char(10),char(0), -char(61),char(0),char(-76),char(0),char(20),char(0),char(-73),char(0),char(20),char(0),char(-72),char(0),char(8),char(0),char(-60),char(0),char(8),char(0),char(-59),char(0), -char(8),char(0),char(-58),char(0),char(8),char(0),char(-64),char(0),char(8),char(0),char(-63),char(0),char(8),char(0),char(-62),char(0),char(8),char(0),char(125),char(0), -char(69),char(0),char(11),char(0),char(59),char(0),char(-76),char(0),char(19),char(0),char(-73),char(0),char(19),char(0),char(-72),char(0),char(7),char(0),char(-60),char(0), -char(7),char(0),char(-59),char(0),char(7),char(0),char(-58),char(0),char(7),char(0),char(-64),char(0),char(7),char(0),char(-63),char(0),char(7),char(0),char(-62),char(0), -char(7),char(0),char(125),char(0),char(0),char(0),char(21),char(0),char(70),char(0),char(9),char(0),char(59),char(0),char(-76),char(0),char(19),char(0),char(-73),char(0), -char(19),char(0),char(-72),char(0),char(13),char(0),char(-57),char(0),char(13),char(0),char(-56),char(0),char(13),char(0),char(-55),char(0),char(13),char(0),char(-54),char(0), -char(4),char(0),char(-53),char(0),char(4),char(0),char(-52),char(0),char(71),char(0),char(9),char(0),char(61),char(0),char(-76),char(0),char(20),char(0),char(-73),char(0), -char(20),char(0),char(-72),char(0),char(14),char(0),char(-57),char(0),char(14),char(0),char(-56),char(0),char(14),char(0),char(-55),char(0),char(14),char(0),char(-54),char(0), -char(4),char(0),char(-53),char(0),char(4),char(0),char(-52),char(0),char(72),char(0),char(5),char(0),char(70),char(0),char(-51),char(0),char(4),char(0),char(-50),char(0), -char(7),char(0),char(-49),char(0),char(7),char(0),char(-48),char(0),char(7),char(0),char(-47),char(0),char(73),char(0),char(5),char(0),char(71),char(0),char(-51),char(0), -char(4),char(0),char(-50),char(0),char(8),char(0),char(-49),char(0),char(8),char(0),char(-48),char(0),char(8),char(0),char(-47),char(0),char(74),char(0),char(41),char(0), -char(59),char(0),char(-76),char(0),char(19),char(0),char(-73),char(0),char(19),char(0),char(-72),char(0),char(13),char(0),char(-57),char(0),char(13),char(0),char(-56),char(0), -char(13),char(0),char(-46),char(0),char(13),char(0),char(-45),char(0),char(13),char(0),char(-44),char(0),char(13),char(0),char(-43),char(0),char(13),char(0),char(-42),char(0), -char(13),char(0),char(-41),char(0),char(13),char(0),char(-40),char(0),char(13),char(0),char(-39),char(0),char(13),char(0),char(-38),char(0),char(13),char(0),char(-37),char(0), -char(13),char(0),char(-36),char(0),char(0),char(0),char(-35),char(0),char(0),char(0),char(-34),char(0),char(0),char(0),char(-33),char(0),char(0),char(0),char(-32),char(0), -char(0),char(0),char(-31),char(0),char(0),char(0),char(-61),char(0),char(13),char(0),char(-55),char(0),char(13),char(0),char(-54),char(0),char(13),char(0),char(-30),char(0), -char(13),char(0),char(-29),char(0),char(13),char(0),char(-28),char(0),char(13),char(0),char(-27),char(0),char(13),char(0),char(-26),char(0),char(13),char(0),char(-25),char(0), -char(13),char(0),char(-24),char(0),char(13),char(0),char(-23),char(0),char(13),char(0),char(-22),char(0),char(13),char(0),char(-21),char(0),char(13),char(0),char(-20),char(0), -char(0),char(0),char(-19),char(0),char(0),char(0),char(-18),char(0),char(0),char(0),char(-17),char(0),char(0),char(0),char(-16),char(0),char(0),char(0),char(-15),char(0), -char(4),char(0),char(-14),char(0),char(75),char(0),char(41),char(0),char(61),char(0),char(-76),char(0),char(20),char(0),char(-73),char(0),char(20),char(0),char(-72),char(0), -char(14),char(0),char(-57),char(0),char(14),char(0),char(-56),char(0),char(14),char(0),char(-46),char(0),char(14),char(0),char(-45),char(0),char(14),char(0),char(-44),char(0), -char(14),char(0),char(-43),char(0),char(14),char(0),char(-42),char(0),char(14),char(0),char(-41),char(0),char(14),char(0),char(-40),char(0),char(14),char(0),char(-39),char(0), -char(14),char(0),char(-38),char(0),char(14),char(0),char(-37),char(0),char(14),char(0),char(-36),char(0),char(0),char(0),char(-35),char(0),char(0),char(0),char(-34),char(0), -char(0),char(0),char(-33),char(0),char(0),char(0),char(-32),char(0),char(0),char(0),char(-31),char(0),char(0),char(0),char(-61),char(0),char(14),char(0),char(-55),char(0), -char(14),char(0),char(-54),char(0),char(14),char(0),char(-30),char(0),char(14),char(0),char(-29),char(0),char(14),char(0),char(-28),char(0),char(14),char(0),char(-27),char(0), -char(14),char(0),char(-26),char(0),char(14),char(0),char(-25),char(0),char(14),char(0),char(-24),char(0),char(14),char(0),char(-23),char(0),char(14),char(0),char(-22),char(0), -char(14),char(0),char(-21),char(0),char(14),char(0),char(-20),char(0),char(0),char(0),char(-19),char(0),char(0),char(0),char(-18),char(0),char(0),char(0),char(-17),char(0), -char(0),char(0),char(-16),char(0),char(0),char(0),char(-15),char(0),char(4),char(0),char(-14),char(0),char(76),char(0),char(9),char(0),char(59),char(0),char(-76),char(0), -char(19),char(0),char(-73),char(0),char(19),char(0),char(-72),char(0),char(7),char(0),char(-57),char(0),char(7),char(0),char(-56),char(0),char(7),char(0),char(-55),char(0), -char(7),char(0),char(-54),char(0),char(4),char(0),char(-53),char(0),char(4),char(0),char(-52),char(0),char(77),char(0),char(9),char(0),char(61),char(0),char(-76),char(0), -char(20),char(0),char(-73),char(0),char(20),char(0),char(-72),char(0),char(8),char(0),char(-57),char(0),char(8),char(0),char(-56),char(0),char(8),char(0),char(-55),char(0), -char(8),char(0),char(-54),char(0),char(4),char(0),char(-53),char(0),char(4),char(0),char(-52),char(0),char(78),char(0),char(5),char(0),char(58),char(0),char(-76),char(0), -char(13),char(0),char(-13),char(0),char(13),char(0),char(-12),char(0),char(7),char(0),char(-11),char(0),char(0),char(0),char(37),char(0),char(79),char(0),char(4),char(0), -char(61),char(0),char(-76),char(0),char(14),char(0),char(-13),char(0),char(14),char(0),char(-12),char(0),char(8),char(0),char(-11),char(0),char(80),char(0),char(4),char(0), -char(7),char(0),char(-10),char(0),char(7),char(0),char(-9),char(0),char(7),char(0),char(-8),char(0),char(4),char(0),char(79),char(0),char(81),char(0),char(10),char(0), -char(80),char(0),char(-7),char(0),char(13),char(0),char(-6),char(0),char(13),char(0),char(-5),char(0),char(13),char(0),char(-4),char(0),char(13),char(0),char(-3),char(0), -char(13),char(0),char(-2),char(0),char(7),char(0),char(-101),char(0),char(7),char(0),char(-1),char(0),char(4),char(0),char(0),char(1),char(4),char(0),char(53),char(0), -char(82),char(0),char(4),char(0),char(80),char(0),char(-7),char(0),char(4),char(0),char(1),char(1),char(7),char(0),char(2),char(1),char(4),char(0),char(3),char(1), -char(83),char(0),char(4),char(0),char(13),char(0),char(-2),char(0),char(80),char(0),char(-7),char(0),char(4),char(0),char(4),char(1),char(7),char(0),char(5),char(1), -char(84),char(0),char(7),char(0),char(13),char(0),char(6),char(1),char(80),char(0),char(-7),char(0),char(4),char(0),char(7),char(1),char(7),char(0),char(8),char(1), -char(7),char(0),char(9),char(1),char(7),char(0),char(10),char(1),char(4),char(0),char(53),char(0),char(85),char(0),char(6),char(0),char(17),char(0),char(11),char(1), -char(13),char(0),char(9),char(1),char(13),char(0),char(12),char(1),char(60),char(0),char(13),char(1),char(4),char(0),char(14),char(1),char(7),char(0),char(10),char(1), -char(86),char(0),char(26),char(0),char(4),char(0),char(15),char(1),char(7),char(0),char(16),char(1),char(7),char(0),char(125),char(0),char(7),char(0),char(17),char(1), -char(7),char(0),char(18),char(1),char(7),char(0),char(19),char(1),char(7),char(0),char(20),char(1),char(7),char(0),char(21),char(1),char(7),char(0),char(22),char(1), -char(7),char(0),char(23),char(1),char(7),char(0),char(24),char(1),char(7),char(0),char(25),char(1),char(7),char(0),char(26),char(1),char(7),char(0),char(27),char(1), -char(7),char(0),char(28),char(1),char(7),char(0),char(29),char(1),char(7),char(0),char(30),char(1),char(7),char(0),char(31),char(1),char(7),char(0),char(32),char(1), -char(7),char(0),char(33),char(1),char(7),char(0),char(34),char(1),char(4),char(0),char(35),char(1),char(4),char(0),char(36),char(1),char(4),char(0),char(37),char(1), -char(4),char(0),char(38),char(1),char(4),char(0),char(118),char(0),char(87),char(0),char(12),char(0),char(17),char(0),char(39),char(1),char(17),char(0),char(40),char(1), -char(17),char(0),char(41),char(1),char(13),char(0),char(42),char(1),char(13),char(0),char(43),char(1),char(7),char(0),char(44),char(1),char(4),char(0),char(45),char(1), -char(4),char(0),char(46),char(1),char(4),char(0),char(47),char(1),char(4),char(0),char(48),char(1),char(7),char(0),char(8),char(1),char(4),char(0),char(53),char(0), -char(88),char(0),char(27),char(0),char(19),char(0),char(49),char(1),char(17),char(0),char(50),char(1),char(17),char(0),char(51),char(1),char(13),char(0),char(42),char(1), -char(13),char(0),char(52),char(1),char(13),char(0),char(53),char(1),char(13),char(0),char(54),char(1),char(13),char(0),char(55),char(1),char(13),char(0),char(56),char(1), -char(4),char(0),char(57),char(1),char(7),char(0),char(58),char(1),char(4),char(0),char(59),char(1),char(4),char(0),char(60),char(1),char(4),char(0),char(61),char(1), -char(7),char(0),char(62),char(1),char(7),char(0),char(63),char(1),char(4),char(0),char(64),char(1),char(4),char(0),char(65),char(1),char(7),char(0),char(66),char(1), -char(7),char(0),char(67),char(1),char(7),char(0),char(68),char(1),char(7),char(0),char(69),char(1),char(7),char(0),char(70),char(1),char(7),char(0),char(71),char(1), -char(4),char(0),char(72),char(1),char(4),char(0),char(73),char(1),char(4),char(0),char(74),char(1),char(89),char(0),char(12),char(0),char(9),char(0),char(75),char(1), -char(9),char(0),char(76),char(1),char(13),char(0),char(77),char(1),char(7),char(0),char(78),char(1),char(7),char(0),char(-127),char(0),char(7),char(0),char(79),char(1), -char(4),char(0),char(80),char(1),char(13),char(0),char(81),char(1),char(4),char(0),char(82),char(1),char(4),char(0),char(83),char(1),char(4),char(0),char(84),char(1), -char(4),char(0),char(53),char(0),char(90),char(0),char(19),char(0),char(50),char(0),char(-111),char(0),char(87),char(0),char(85),char(1),char(80),char(0),char(86),char(1), -char(81),char(0),char(87),char(1),char(82),char(0),char(88),char(1),char(83),char(0),char(89),char(1),char(84),char(0),char(90),char(1),char(85),char(0),char(91),char(1), -char(88),char(0),char(92),char(1),char(89),char(0),char(93),char(1),char(4),char(0),char(94),char(1),char(4),char(0),char(60),char(1),char(4),char(0),char(95),char(1), -char(4),char(0),char(96),char(1),char(4),char(0),char(97),char(1),char(4),char(0),char(98),char(1),char(4),char(0),char(99),char(1),char(4),char(0),char(100),char(1), -char(86),char(0),char(101),char(1),char(91),char(0),char(20),char(0),char(16),char(0),char(102),char(1),char(14),char(0),char(103),char(1),char(14),char(0),char(104),char(1), -char(14),char(0),char(105),char(1),char(14),char(0),char(106),char(1),char(14),char(0),char(107),char(1),char(8),char(0),char(108),char(1),char(4),char(0),char(109),char(1), -char(4),char(0),char(84),char(1),char(4),char(0),char(110),char(1),char(4),char(0),char(111),char(1),char(8),char(0),char(112),char(1),char(8),char(0),char(113),char(1), -char(8),char(0),char(114),char(1),char(8),char(0),char(115),char(1),char(8),char(0),char(116),char(1),char(0),char(0),char(117),char(1),char(0),char(0),char(118),char(1), -char(49),char(0),char(119),char(1),char(0),char(0),char(120),char(1),char(92),char(0),char(20),char(0),char(15),char(0),char(102),char(1),char(13),char(0),char(103),char(1), -char(13),char(0),char(104),char(1),char(13),char(0),char(105),char(1),char(13),char(0),char(106),char(1),char(13),char(0),char(107),char(1),char(4),char(0),char(110),char(1), -char(7),char(0),char(108),char(1),char(4),char(0),char(109),char(1),char(4),char(0),char(84),char(1),char(7),char(0),char(112),char(1),char(7),char(0),char(113),char(1), -char(7),char(0),char(114),char(1),char(4),char(0),char(111),char(1),char(7),char(0),char(115),char(1),char(7),char(0),char(116),char(1),char(0),char(0),char(117),char(1), -char(0),char(0),char(118),char(1),char(50),char(0),char(119),char(1),char(0),char(0),char(120),char(1),char(93),char(0),char(9),char(0),char(20),char(0),char(121),char(1), -char(14),char(0),char(122),char(1),char(8),char(0),char(123),char(1),char(0),char(0),char(124),char(1),char(91),char(0),char(88),char(1),char(49),char(0),char(125),char(1), -char(0),char(0),char(120),char(1),char(4),char(0),char(95),char(1),char(0),char(0),char(37),char(0),char(94),char(0),char(7),char(0),char(0),char(0),char(124),char(1), -char(92),char(0),char(88),char(1),char(50),char(0),char(125),char(1),char(19),char(0),char(121),char(1),char(13),char(0),char(122),char(1),char(7),char(0),char(123),char(1), -char(4),char(0),char(95),char(1),}; +char(7),char(0),char(-61),char(0),char(7),char(0),char(-60),char(0),char(67),char(0),char(14),char(0),char(61),char(0),char(-74),char(0),char(20),char(0),char(-71),char(0), +char(20),char(0),char(-70),char(0),char(4),char(0),char(-69),char(0),char(4),char(0),char(-68),char(0),char(4),char(0),char(-67),char(0),char(8),char(0),char(-66),char(0), +char(8),char(0),char(-65),char(0),char(8),char(0),char(-64),char(0),char(8),char(0),char(-63),char(0),char(8),char(0),char(-62),char(0),char(8),char(0),char(-61),char(0), +char(8),char(0),char(-60),char(0),char(0),char(0),char(-59),char(0),char(68),char(0),char(10),char(0),char(61),char(0),char(-74),char(0),char(20),char(0),char(-71),char(0), +char(20),char(0),char(-70),char(0),char(8),char(0),char(-58),char(0),char(8),char(0),char(-57),char(0),char(8),char(0),char(-56),char(0),char(8),char(0),char(-62),char(0), +char(8),char(0),char(-61),char(0),char(8),char(0),char(-60),char(0),char(8),char(0),char(127),char(0),char(69),char(0),char(11),char(0),char(59),char(0),char(-74),char(0), +char(19),char(0),char(-71),char(0),char(19),char(0),char(-70),char(0),char(7),char(0),char(-58),char(0),char(7),char(0),char(-57),char(0),char(7),char(0),char(-56),char(0), +char(7),char(0),char(-62),char(0),char(7),char(0),char(-61),char(0),char(7),char(0),char(-60),char(0),char(7),char(0),char(127),char(0),char(0),char(0),char(21),char(0), +char(70),char(0),char(9),char(0),char(59),char(0),char(-74),char(0),char(19),char(0),char(-71),char(0),char(19),char(0),char(-70),char(0),char(13),char(0),char(-55),char(0), +char(13),char(0),char(-54),char(0),char(13),char(0),char(-53),char(0),char(13),char(0),char(-52),char(0),char(4),char(0),char(-51),char(0),char(4),char(0),char(-50),char(0), +char(71),char(0),char(9),char(0),char(61),char(0),char(-74),char(0),char(20),char(0),char(-71),char(0),char(20),char(0),char(-70),char(0),char(14),char(0),char(-55),char(0), +char(14),char(0),char(-54),char(0),char(14),char(0),char(-53),char(0),char(14),char(0),char(-52),char(0),char(4),char(0),char(-51),char(0),char(4),char(0),char(-50),char(0), +char(72),char(0),char(5),char(0),char(70),char(0),char(-49),char(0),char(4),char(0),char(-48),char(0),char(7),char(0),char(-47),char(0),char(7),char(0),char(-46),char(0), +char(7),char(0),char(-45),char(0),char(73),char(0),char(5),char(0),char(71),char(0),char(-49),char(0),char(4),char(0),char(-48),char(0),char(8),char(0),char(-47),char(0), +char(8),char(0),char(-46),char(0),char(8),char(0),char(-45),char(0),char(74),char(0),char(41),char(0),char(59),char(0),char(-74),char(0),char(19),char(0),char(-71),char(0), +char(19),char(0),char(-70),char(0),char(13),char(0),char(-55),char(0),char(13),char(0),char(-54),char(0),char(13),char(0),char(-44),char(0),char(13),char(0),char(-43),char(0), +char(13),char(0),char(-42),char(0),char(13),char(0),char(-41),char(0),char(13),char(0),char(-40),char(0),char(13),char(0),char(-39),char(0),char(13),char(0),char(-38),char(0), +char(13),char(0),char(-37),char(0),char(13),char(0),char(-36),char(0),char(13),char(0),char(-35),char(0),char(13),char(0),char(-34),char(0),char(0),char(0),char(-33),char(0), +char(0),char(0),char(-32),char(0),char(0),char(0),char(-31),char(0),char(0),char(0),char(-30),char(0),char(0),char(0),char(-29),char(0),char(0),char(0),char(-59),char(0), +char(13),char(0),char(-53),char(0),char(13),char(0),char(-52),char(0),char(13),char(0),char(-28),char(0),char(13),char(0),char(-27),char(0),char(13),char(0),char(-26),char(0), +char(13),char(0),char(-25),char(0),char(13),char(0),char(-24),char(0),char(13),char(0),char(-23),char(0),char(13),char(0),char(-22),char(0),char(13),char(0),char(-21),char(0), +char(13),char(0),char(-20),char(0),char(13),char(0),char(-19),char(0),char(13),char(0),char(-18),char(0),char(0),char(0),char(-17),char(0),char(0),char(0),char(-16),char(0), +char(0),char(0),char(-15),char(0),char(0),char(0),char(-14),char(0),char(0),char(0),char(-13),char(0),char(4),char(0),char(-12),char(0),char(75),char(0),char(41),char(0), +char(61),char(0),char(-74),char(0),char(20),char(0),char(-71),char(0),char(20),char(0),char(-70),char(0),char(14),char(0),char(-55),char(0),char(14),char(0),char(-54),char(0), +char(14),char(0),char(-44),char(0),char(14),char(0),char(-43),char(0),char(14),char(0),char(-42),char(0),char(14),char(0),char(-41),char(0),char(14),char(0),char(-40),char(0), +char(14),char(0),char(-39),char(0),char(14),char(0),char(-38),char(0),char(14),char(0),char(-37),char(0),char(14),char(0),char(-36),char(0),char(14),char(0),char(-35),char(0), +char(14),char(0),char(-34),char(0),char(0),char(0),char(-33),char(0),char(0),char(0),char(-32),char(0),char(0),char(0),char(-31),char(0),char(0),char(0),char(-30),char(0), +char(0),char(0),char(-29),char(0),char(0),char(0),char(-59),char(0),char(14),char(0),char(-53),char(0),char(14),char(0),char(-52),char(0),char(14),char(0),char(-28),char(0), +char(14),char(0),char(-27),char(0),char(14),char(0),char(-26),char(0),char(14),char(0),char(-25),char(0),char(14),char(0),char(-24),char(0),char(14),char(0),char(-23),char(0), +char(14),char(0),char(-22),char(0),char(14),char(0),char(-21),char(0),char(14),char(0),char(-20),char(0),char(14),char(0),char(-19),char(0),char(14),char(0),char(-18),char(0), +char(0),char(0),char(-17),char(0),char(0),char(0),char(-16),char(0),char(0),char(0),char(-15),char(0),char(0),char(0),char(-14),char(0),char(0),char(0),char(-13),char(0), +char(4),char(0),char(-12),char(0),char(76),char(0),char(9),char(0),char(59),char(0),char(-74),char(0),char(19),char(0),char(-71),char(0),char(19),char(0),char(-70),char(0), +char(7),char(0),char(-55),char(0),char(7),char(0),char(-54),char(0),char(7),char(0),char(-53),char(0),char(7),char(0),char(-52),char(0),char(4),char(0),char(-51),char(0), +char(4),char(0),char(-50),char(0),char(77),char(0),char(9),char(0),char(61),char(0),char(-74),char(0),char(20),char(0),char(-71),char(0),char(20),char(0),char(-70),char(0), +char(8),char(0),char(-55),char(0),char(8),char(0),char(-54),char(0),char(8),char(0),char(-53),char(0),char(8),char(0),char(-52),char(0),char(4),char(0),char(-51),char(0), +char(4),char(0),char(-50),char(0),char(78),char(0),char(5),char(0),char(58),char(0),char(-74),char(0),char(13),char(0),char(-11),char(0),char(13),char(0),char(-10),char(0), +char(7),char(0),char(-9),char(0),char(0),char(0),char(37),char(0),char(79),char(0),char(4),char(0),char(61),char(0),char(-74),char(0),char(14),char(0),char(-11),char(0), +char(14),char(0),char(-10),char(0),char(8),char(0),char(-9),char(0),char(80),char(0),char(4),char(0),char(7),char(0),char(-8),char(0),char(7),char(0),char(-7),char(0), +char(7),char(0),char(-6),char(0),char(4),char(0),char(79),char(0),char(81),char(0),char(10),char(0),char(80),char(0),char(-5),char(0),char(13),char(0),char(-4),char(0), +char(13),char(0),char(-3),char(0),char(13),char(0),char(-2),char(0),char(13),char(0),char(-1),char(0),char(13),char(0),char(0),char(1),char(7),char(0),char(-99),char(0), +char(7),char(0),char(1),char(1),char(4),char(0),char(2),char(1),char(4),char(0),char(53),char(0),char(82),char(0),char(4),char(0),char(80),char(0),char(-5),char(0), +char(4),char(0),char(3),char(1),char(7),char(0),char(4),char(1),char(4),char(0),char(5),char(1),char(83),char(0),char(4),char(0),char(13),char(0),char(0),char(1), +char(80),char(0),char(-5),char(0),char(4),char(0),char(6),char(1),char(7),char(0),char(7),char(1),char(84),char(0),char(7),char(0),char(13),char(0),char(8),char(1), +char(80),char(0),char(-5),char(0),char(4),char(0),char(9),char(1),char(7),char(0),char(10),char(1),char(7),char(0),char(11),char(1),char(7),char(0),char(12),char(1), +char(4),char(0),char(53),char(0),char(85),char(0),char(6),char(0),char(17),char(0),char(13),char(1),char(13),char(0),char(11),char(1),char(13),char(0),char(14),char(1), +char(60),char(0),char(15),char(1),char(4),char(0),char(16),char(1),char(7),char(0),char(12),char(1),char(86),char(0),char(26),char(0),char(4),char(0),char(17),char(1), +char(7),char(0),char(18),char(1),char(7),char(0),char(127),char(0),char(7),char(0),char(19),char(1),char(7),char(0),char(20),char(1),char(7),char(0),char(21),char(1), +char(7),char(0),char(22),char(1),char(7),char(0),char(23),char(1),char(7),char(0),char(24),char(1),char(7),char(0),char(25),char(1),char(7),char(0),char(26),char(1), +char(7),char(0),char(27),char(1),char(7),char(0),char(28),char(1),char(7),char(0),char(29),char(1),char(7),char(0),char(30),char(1),char(7),char(0),char(31),char(1), +char(7),char(0),char(32),char(1),char(7),char(0),char(33),char(1),char(7),char(0),char(34),char(1),char(7),char(0),char(35),char(1),char(7),char(0),char(36),char(1), +char(4),char(0),char(37),char(1),char(4),char(0),char(38),char(1),char(4),char(0),char(39),char(1),char(4),char(0),char(40),char(1),char(4),char(0),char(120),char(0), +char(87),char(0),char(12),char(0),char(17),char(0),char(41),char(1),char(17),char(0),char(42),char(1),char(17),char(0),char(43),char(1),char(13),char(0),char(44),char(1), +char(13),char(0),char(45),char(1),char(7),char(0),char(46),char(1),char(4),char(0),char(47),char(1),char(4),char(0),char(48),char(1),char(4),char(0),char(49),char(1), +char(4),char(0),char(50),char(1),char(7),char(0),char(10),char(1),char(4),char(0),char(53),char(0),char(88),char(0),char(27),char(0),char(19),char(0),char(51),char(1), +char(17),char(0),char(52),char(1),char(17),char(0),char(53),char(1),char(13),char(0),char(44),char(1),char(13),char(0),char(54),char(1),char(13),char(0),char(55),char(1), +char(13),char(0),char(56),char(1),char(13),char(0),char(57),char(1),char(13),char(0),char(58),char(1),char(4),char(0),char(59),char(1),char(7),char(0),char(60),char(1), +char(4),char(0),char(61),char(1),char(4),char(0),char(62),char(1),char(4),char(0),char(63),char(1),char(7),char(0),char(64),char(1),char(7),char(0),char(65),char(1), +char(4),char(0),char(66),char(1),char(4),char(0),char(67),char(1),char(7),char(0),char(68),char(1),char(7),char(0),char(69),char(1),char(7),char(0),char(70),char(1), +char(7),char(0),char(71),char(1),char(7),char(0),char(72),char(1),char(7),char(0),char(73),char(1),char(4),char(0),char(74),char(1),char(4),char(0),char(75),char(1), +char(4),char(0),char(76),char(1),char(89),char(0),char(12),char(0),char(9),char(0),char(77),char(1),char(9),char(0),char(78),char(1),char(13),char(0),char(79),char(1), +char(7),char(0),char(80),char(1),char(7),char(0),char(-125),char(0),char(7),char(0),char(81),char(1),char(4),char(0),char(82),char(1),char(13),char(0),char(83),char(1), +char(4),char(0),char(84),char(1),char(4),char(0),char(85),char(1),char(4),char(0),char(86),char(1),char(4),char(0),char(53),char(0),char(90),char(0),char(19),char(0), +char(50),char(0),char(-109),char(0),char(87),char(0),char(87),char(1),char(80),char(0),char(88),char(1),char(81),char(0),char(89),char(1),char(82),char(0),char(90),char(1), +char(83),char(0),char(91),char(1),char(84),char(0),char(92),char(1),char(85),char(0),char(93),char(1),char(88),char(0),char(94),char(1),char(89),char(0),char(95),char(1), +char(4),char(0),char(96),char(1),char(4),char(0),char(62),char(1),char(4),char(0),char(97),char(1),char(4),char(0),char(98),char(1),char(4),char(0),char(99),char(1), +char(4),char(0),char(100),char(1),char(4),char(0),char(101),char(1),char(4),char(0),char(102),char(1),char(86),char(0),char(103),char(1),char(91),char(0),char(20),char(0), +char(16),char(0),char(104),char(1),char(14),char(0),char(105),char(1),char(14),char(0),char(106),char(1),char(14),char(0),char(107),char(1),char(14),char(0),char(108),char(1), +char(14),char(0),char(109),char(1),char(8),char(0),char(110),char(1),char(4),char(0),char(111),char(1),char(4),char(0),char(86),char(1),char(4),char(0),char(112),char(1), +char(4),char(0),char(113),char(1),char(8),char(0),char(114),char(1),char(8),char(0),char(115),char(1),char(8),char(0),char(116),char(1),char(8),char(0),char(117),char(1), +char(8),char(0),char(118),char(1),char(0),char(0),char(119),char(1),char(0),char(0),char(120),char(1),char(49),char(0),char(121),char(1),char(0),char(0),char(122),char(1), +char(92),char(0),char(20),char(0),char(15),char(0),char(104),char(1),char(13),char(0),char(105),char(1),char(13),char(0),char(106),char(1),char(13),char(0),char(107),char(1), +char(13),char(0),char(108),char(1),char(13),char(0),char(109),char(1),char(4),char(0),char(112),char(1),char(7),char(0),char(110),char(1),char(4),char(0),char(111),char(1), +char(4),char(0),char(86),char(1),char(7),char(0),char(114),char(1),char(7),char(0),char(115),char(1),char(7),char(0),char(116),char(1),char(4),char(0),char(113),char(1), +char(7),char(0),char(117),char(1),char(7),char(0),char(118),char(1),char(0),char(0),char(119),char(1),char(0),char(0),char(120),char(1),char(50),char(0),char(121),char(1), +char(0),char(0),char(122),char(1),char(93),char(0),char(9),char(0),char(20),char(0),char(123),char(1),char(14),char(0),char(124),char(1),char(8),char(0),char(125),char(1), +char(0),char(0),char(126),char(1),char(91),char(0),char(90),char(1),char(49),char(0),char(127),char(1),char(0),char(0),char(122),char(1),char(4),char(0),char(97),char(1), +char(0),char(0),char(37),char(0),char(94),char(0),char(7),char(0),char(0),char(0),char(126),char(1),char(92),char(0),char(90),char(1),char(50),char(0),char(127),char(1), +char(19),char(0),char(123),char(1),char(13),char(0),char(124),char(1),char(7),char(0),char(125),char(1),char(4),char(0),char(97),char(1),}; int sBulletDNAlen64= sizeof(sBulletDNAstr64); diff --git a/src/LinearMath/btSerializer.h b/src/LinearMath/btSerializer.h index 454068d6a..6f03df158 100644 --- a/src/LinearMath/btSerializer.h +++ b/src/LinearMath/btSerializer.h @@ -391,7 +391,8 @@ public: btDefaultSerializer(int totalSize=0, unsigned char* buffer=0) - :m_totalSize(totalSize), + :m_uniqueIdGenerator(0), + m_totalSize(totalSize), m_currentSize(0), m_dna(0), m_dnaLength(0), @@ -446,6 +447,26 @@ public: btAlignedFree(m_dna); } + static int getMemoryDnaSizeInBytes() + { + const bool VOID_IS_8 = ((sizeof(void*) == 8)); + + if (VOID_IS_8) + { + return sBulletDNAlen64; + } + return sBulletDNAlen; + } + static const char* getMemoryDna() + { + const bool VOID_IS_8 = ((sizeof(void*) == 8)); + if (VOID_IS_8) + { + return (const char*)sBulletDNAstr64; + } + return (const char*)sBulletDNAstr; + } + void insertHeader() { writeHeader(m_buffer); @@ -541,6 +562,7 @@ public: virtual void* getUniquePointer(void*oldPtr) { + btAssert(m_uniqueIdGenerator >= 0); if (!oldPtr) return 0; diff --git a/src/LinearMath/btThreads.cpp b/src/LinearMath/btThreads.cpp new file mode 100644 index 000000000..4bef499f7 --- /dev/null +++ b/src/LinearMath/btThreads.cpp @@ -0,0 +1,230 @@ +/* +Copyright (c) 2003-2014 Erwin Coumans http://bullet.googlecode.com + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + + +#include "btThreads.h" + +// +// Lightweight spin-mutex based on atomics +// Using ordinary system-provided mutexes like Windows critical sections was noticeably slower +// presumably because when it fails to lock at first it would sleep the thread and trigger costly +// context switching. +// + +#if BT_THREADSAFE + +#if __cplusplus >= 201103L + +// for anything claiming full C++11 compliance, use C++11 atomics +// on GCC or Clang you need to compile with -std=c++11 +#define USE_CPP11_ATOMICS 1 + +#elif defined( _MSC_VER ) + +// on MSVC, use intrinsics instead +#define USE_MSVC_INTRINSICS 1 + +#elif defined( __GNUC__ ) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7)) + +// available since GCC 4.7 and some versions of clang +// todo: check for clang +#define USE_GCC_BUILTIN_ATOMICS 1 + +#elif defined( __GNUC__ ) && (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) + +// available since GCC 4.1 +#define USE_GCC_BUILTIN_ATOMICS_OLD 1 + +#endif + + +#if USE_CPP11_ATOMICS + +#include +#include + +#define THREAD_LOCAL_STATIC thread_local static + +bool btSpinMutex::tryLock() +{ + std::atomic* aDest = reinterpret_cast*>(&mLock); + int expected = 0; + return std::atomic_compare_exchange_weak_explicit( aDest, &expected, int(1), std::memory_order_acq_rel, std::memory_order_acquire ); +} + +void btSpinMutex::lock() +{ + // note: this lock does not sleep the thread. + while (! tryLock()) + { + // spin + } +} + +void btSpinMutex::unlock() +{ + std::atomic* aDest = reinterpret_cast*>(&mLock); + std::atomic_store_explicit( aDest, int(0), std::memory_order_release ); +} + + +#elif USE_MSVC_INTRINSICS + +#define WIN32_LEAN_AND_MEAN + +#include +#include + +#define THREAD_LOCAL_STATIC __declspec( thread ) static + + +bool btSpinMutex::tryLock() +{ + volatile long* aDest = reinterpret_cast(&mLock); + return ( 0 == _InterlockedCompareExchange( aDest, 1, 0) ); +} + +void btSpinMutex::lock() +{ + // note: this lock does not sleep the thread + while (! tryLock()) + { + // spin + } +} + +void btSpinMutex::unlock() +{ + volatile long* aDest = reinterpret_cast( &mLock ); + _InterlockedExchange( aDest, 0 ); +} + +#elif USE_GCC_BUILTIN_ATOMICS + +#define THREAD_LOCAL_STATIC static __thread + + +bool btSpinMutex::tryLock() +{ + int expected = 0; + bool weak = false; + const int memOrderSuccess = __ATOMIC_ACQ_REL; + const int memOrderFail = __ATOMIC_ACQUIRE; + return __atomic_compare_exchange_n(&mLock, &expected, int(1), weak, memOrderSuccess, memOrderFail); +} + +void btSpinMutex::lock() +{ + // note: this lock does not sleep the thread + while (! tryLock()) + { + // spin + } +} + +void btSpinMutex::unlock() +{ + __atomic_store_n(&mLock, int(0), __ATOMIC_RELEASE); +} + +#elif USE_GCC_BUILTIN_ATOMICS_OLD + + +#define THREAD_LOCAL_STATIC static __thread + +bool btSpinMutex::tryLock() +{ + return __sync_bool_compare_and_swap(&mLock, int(0), int(1)); +} + +void btSpinMutex::lock() +{ + // note: this lock does not sleep the thread + while (! tryLock()) + { + // spin + } +} + +void btSpinMutex::unlock() +{ + // write 0 + __sync_fetch_and_and(&mLock, int(0)); +} + +#else //#elif USE_MSVC_INTRINSICS + +#error "no threading primitives defined -- unknown platform" + +#endif //#else //#elif USE_MSVC_INTRINSICS + + +struct ThreadsafeCounter +{ + unsigned int mCounter; + btSpinMutex mMutex; + + ThreadsafeCounter() {mCounter=0;} + + unsigned int getNext() + { + // no need to optimize this with atomics, it is only called ONCE per thread! + mMutex.lock(); + unsigned int val = mCounter++; + mMutex.unlock(); + return val; + } +}; + +static ThreadsafeCounter gThreadCounter; + + +// return a unique index per thread, starting with 0 and counting up +unsigned int btGetCurrentThreadIndex() +{ + const unsigned int kNullIndex = ~0U; + THREAD_LOCAL_STATIC unsigned int sThreadIndex = kNullIndex; + if ( sThreadIndex == kNullIndex ) + { + sThreadIndex = gThreadCounter.getNext(); + } + return sThreadIndex; +} + +bool btIsMainThread() +{ + return btGetCurrentThreadIndex() == 0; +} + +#else // #if BT_THREADSAFE + +// These should not be called ever +void btSpinMutex::lock() +{ + btAssert(!"unimplemented btSpinMutex::lock() called"); +} + +void btSpinMutex::unlock() +{ + btAssert(!"unimplemented btSpinMutex::unlock() called"); +} + +bool btSpinMutex::tryLock() +{ + btAssert(!"unimplemented btSpinMutex::tryLock() called"); + return true; +} + +#endif // #else // #if BT_THREADSAFE + diff --git a/src/LinearMath/btThreads.h b/src/LinearMath/btThreads.h new file mode 100644 index 000000000..db710979f --- /dev/null +++ b/src/LinearMath/btThreads.h @@ -0,0 +1,76 @@ +/* +Copyright (c) 2003-2014 Erwin Coumans http://bullet.googlecode.com + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + + + +#ifndef BT_THREADS_H +#define BT_THREADS_H + +#include "btScalar.h" // has definitions like SIMD_FORCE_INLINE + +/// +/// btSpinMutex -- lightweight spin-mutex implemented with atomic ops, never puts +/// a thread to sleep because it is designed to be used with a task scheduler +/// which has one thread per core and the threads don't sleep until they +/// run out of tasks. Not good for general purpose use. +/// +class btSpinMutex +{ + int mLock; + +public: + btSpinMutex() + { + mLock = 0; + } + void lock(); + void unlock(); + bool tryLock(); +}; + +#if BT_THREADSAFE + +// for internal Bullet use only +SIMD_FORCE_INLINE void btMutexLock( btSpinMutex* mutex ) +{ + mutex->lock(); +} + +SIMD_FORCE_INLINE void btMutexUnlock( btSpinMutex* mutex ) +{ + mutex->unlock(); +} + +SIMD_FORCE_INLINE bool btMutexTryLock( btSpinMutex* mutex ) +{ + return mutex->tryLock(); +} + +// for internal use only +bool btIsMainThread(); +unsigned int btGetCurrentThreadIndex(); +const unsigned int BT_MAX_THREAD_COUNT = 64; + +#else + +// for internal Bullet use only +// if BT_THREADSAFE is undefined or 0, should optimize away to nothing +SIMD_FORCE_INLINE void btMutexLock( btSpinMutex* ) {} +SIMD_FORCE_INLINE void btMutexUnlock( btSpinMutex* ) {} +SIMD_FORCE_INLINE bool btMutexTryLock( btSpinMutex* ) {return true;} + +#endif + + +#endif //BT_THREADS_H diff --git a/test/SharedMemory/CMakeLists.txt b/test/SharedMemory/CMakeLists.txt index 8ece789cc..52297594c 100644 --- a/test/SharedMemory/CMakeLists.txt +++ b/test/SharedMemory/CMakeLists.txt @@ -41,7 +41,10 @@ ENDIF() ../../examples/SharedMemory/PhysicsServerCommandProcessor.h ../../examples/SharedMemory/PhysicsClientSharedMemory.cpp ../../examples/SharedMemory/PhysicsClientSharedMemory.h - ../../examples/SharedMemory/PhysicsClientC_API.cpp + ../../examples/SharedMemory/PhysicsClientSharedMemory_C_API.cpp + ../../examples/SharedMemory/PhysicsClientSharedMemory_C_API.h + + ../../examples/SharedMemory/PhysicsClientC_API.cpp ../../examples/SharedMemory/PhysicsClientC_API.h ../../examples/SharedMemory/PhysicsLoopBack.cpp ../../examples/SharedMemory/PhysicsLoopBack.h diff --git a/test/SharedMemory/premake4.lua b/test/SharedMemory/premake4.lua index 1974ba471..ca48cfea0 100644 --- a/test/SharedMemory/premake4.lua +++ b/test/SharedMemory/premake4.lua @@ -17,6 +17,8 @@ project ("Test_SharedMemoryPhysicsClient") "../../examples/SharedMemory/PhysicsClient.h", "../../examples/SharedMemory/PhysicsClientSharedMemory.cpp", "../../examples/SharedMemory/PhysicsClientSharedMemory.h", + "../../examples/SharedMemory/PhysicsClientSharedMemory_C_API.cpp", + "../../examples/SharedMemory/PhysicsClientSharedMemory_C_API.h", "../../examples/SharedMemory/PhysicsClientC_API.cpp", "../../examples/SharedMemory/PhysicsClientC_API.h", "../../examples/SharedMemory/Win32SharedMemory.cpp", diff --git a/test/SharedMemory/test.c b/test/SharedMemory/test.c index c366ab3a5..6037b693e 100644 --- a/test/SharedMemory/test.c +++ b/test/SharedMemory/test.c @@ -3,6 +3,10 @@ #include "SharedMemory/PhysicsClientC_API.h" #endif //PHYSICS_SHARED_MEMORY +#ifdef PHYSICS_UDP +#include "SharedMemory/PhysicsClientUDP_C_API.h" +#endif//PHYSICS_UDP + #ifdef PHYSICS_LOOP_BACK #include "SharedMemory/PhysicsLoopBackC_API.h" #endif //PHYSICS_LOOP_BACK @@ -224,7 +228,7 @@ void testSharedMemory(b3PhysicsClientHandle sm) #endif } ///perform some simulation steps for testing - for ( i=0;i<100;i++) + for ( i=0;i<1000;i++) { b3SharedMemoryStatusHandle statusHandle; int statusType; @@ -319,11 +323,17 @@ int main(int argc, char* argv[]) b3PhysicsClientHandle sm = b3CreateInProcessPhysicsServerAndConnect(argc,argv); #endif //__APPLE__ #endif + #ifdef PHYSICS_SHARED_MEMORY b3PhysicsClientHandle sm = b3ConnectSharedMemory(SHARED_MEMORY_KEY); #endif //PHYSICS_SHARED_MEMORY +#ifdef PHYSICS_UDP + b3PhysicsClientHandle sm = b3ConnectPhysicsUDP("localhost",1234); +#endif //PHYSICS_UDP + testSharedMemory(sm); } #endif + diff --git a/test/enet/chat/client/main.cpp b/test/enet/chat/client/main.cpp new file mode 100644 index 000000000..b7387fac1 --- /dev/null +++ b/test/enet/chat/client/main.cpp @@ -0,0 +1,168 @@ + +/* client.cpp */ +#include +#include +#include + + +int main(int argc, char* argv[]) { + ENetHost *client; + ENetAddress address; + ENetPeer *peer; + ENetEvent event; + char message[1024]; + int serviceResult; + + puts("Starting client"); + + if (enet_initialize() != 0) { + fprintf(stderr, "Error initialising enet"); + exit(EXIT_FAILURE); + + } + + client = enet_host_create(NULL, /* create a client host */ + 1, /* number of clients */ + 2, /* number of channels */ + 57600 / 8, /* incoming bandwith */ + 14400 / 8); /* outgoing bandwith */ + + if (client == NULL) { + fprintf(stderr, "Could not create client host"); + exit(EXIT_FAILURE); + + } + + + enet_address_set_host(&address, "localhost"); + address.port = 1234; + + peer = enet_host_connect(client, + &address, /* address to connect to */ + 2, /* number of channels */ + 0); /* user data supplied to + the receiving host */ + + if (peer == NULL) { + fprintf(stderr, "No available peers for initiating an ENet " + "connection.\n"); + exit(EXIT_FAILURE); + + } + + + /* Try to connect to server within 5 seconds */ + if (enet_host_service(client, &event, 5000) > 0 && + event.type == ENET_EVENT_TYPE_CONNECT) + { + puts("Connection to server succeeded."); + } + else + { + /* Either the 5 seconds are up or a disconnect event was */ + /* received. Reset the peer in the event the 5 seconds */ + /* had run out without any significant event. */ + enet_peer_reset(peer); + + fprintf(stderr, "Connection to server failed."); + exit(EXIT_FAILURE); + } + + while (true) + { + serviceResult = 1; + + /* Keep doing host_service until no events are left */ + while (serviceResult > 0) + { + serviceResult = enet_host_service(client, &event, 0); + + if (serviceResult > 0) + { + switch (event.type) + { + case ENET_EVENT_TYPE_CONNECT: + printf("A new client connected from %x:%u.\n", + event.peer->address.host, + event.peer->address.port); + + event.peer->data = (void*)"New User"; + break; + + case ENET_EVENT_TYPE_RECEIVE: + printf("A packet of length %u containing '%s' was " + "received from %s on channel %u.\n", + event.packet->dataLength, + event.packet->data, + event.peer->data, + event.channelID); + + /* Clean up the packet now that we're done using it. + > */ + enet_packet_destroy(event.packet); + + break; + + case ENET_EVENT_TYPE_DISCONNECT: + printf("%s disconected.\n", event.peer->data); + + break; + } + } + else if (serviceResult > 0) + { + puts("Error with servicing the client"); + exit(EXIT_FAILURE); + } + + } + + + printf("Say> "); +#ifdef _WIN32 + gets_s(message, 1024); +#else + gets(message); +#endif + if (strcmp(message, "exit") == 0 || + strcmp(message, "quit") == 0) { + break; + + } + + if (strlen(message) > 0) { + ENetPacket *packet = enet_packet_create(message, strlen + (message) + 1, ENET_PACKET_FLAG_RELIABLE); + enet_peer_send(peer, 0, packet); + + } + + } + + enet_peer_disconnect(peer, 0); + + /* Allow up to 3 seconds for the disconnect to succeed */ + /* and drop any packets received packets */ + while (enet_host_service(client, &event, 3000) > 0) + { + + switch (event.type) + { + case ENET_EVENT_TYPE_RECEIVE: + enet_packet_destroy(event.packet); + break; + + case ENET_EVENT_TYPE_DISCONNECT: + puts("Disconnection succeeded."); + break; + } + } + + + enet_host_destroy(client); + enet_deinitialize(); + + return 0; + + +} diff --git a/test/enet/client/premake4.lua b/test/enet/chat/client/premake4.lua similarity index 70% rename from test/enet/client/premake4.lua rename to test/enet/chat/client/premake4.lua index 2a2327f24..24a71d6df 100644 --- a/test/enet/client/premake4.lua +++ b/test/enet/chat/client/premake4.lua @@ -1,12 +1,12 @@ -project ("Test_enet_client") +project ("Test_enet_chat_client") language "C++" kind "ConsoleApp" - includedirs {"../../../examples/ThirdPartyLibs/enet/include"} + includedirs {"../../../../examples/ThirdPartyLibs/enet/include"} if os.is("Windows") then defines { "WIN32" } diff --git a/test/enet/chat/server/main.cpp b/test/enet/chat/server/main.cpp new file mode 100644 index 000000000..cc15bd6a6 --- /dev/null +++ b/test/enet/chat/server/main.cpp @@ -0,0 +1,103 @@ +/* server.cpp */ +#include +#include + +int main(int argc, char *argv[]) +{ + ENetAddress address; + ENetHost *server; + ENetEvent event; + int serviceResult; + + puts("Starting server"); + + if (enet_initialize() != 0) + { + puts("Error initialising enet"); + exit(EXIT_FAILURE); + } + + + /* Bind the server to the default localhost. */ + /* A specific host address can be specified by */ + /* enet_address_set_host (& address, "x.x.x.x"); */ + address.host = ENET_HOST_ANY; + /* Bind the server to port 1234. */ + address.port = 1234; + + server = enet_host_create(&address, + 32, /* number of clients */ + 2, /* number of channels */ + 0, /* Any incoming bandwith */ + 0); /* Any outgoing bandwith */ + + if (server == NULL) + { + puts("Could not create server host"); + exit(EXIT_FAILURE); + } + + + while (true) + { + serviceResult = 1; + + /* Keep doing host_service until no events are left */ + while (serviceResult > 0) + { + /* Wait up to 1000 milliseconds for an event. */ + serviceResult = enet_host_service(server, &event, 1000); + + if (serviceResult > 0) + { + + switch (event.type) + { + case ENET_EVENT_TYPE_CONNECT: + printf("A new client connected from %x:%u.\n", + event.peer->address.host, + event.peer->address.port); + + /* Store any relevant client information here. */ + event.peer->data = (void*)"Client information"; + + break; + + case ENET_EVENT_TYPE_RECEIVE: + printf("A packet of length %u containing '%s' was " + "received from %s on channel %u.\n", + event.packet->dataLength, + event.packet->data, + event.peer->data, + event.channelID); + + /* Tell all clients about this message */ + enet_host_broadcast(server, 0, event.packet); + + break; + + case ENET_EVENT_TYPE_DISCONNECT: + printf("%s disconected.\n", event.peer->data); + + /* Reset the peer's client information. */ + + event.peer->data = NULL; + + break; + } + } + else if (serviceResult > 0) + { + puts("Error with servicing the server"); + exit(EXIT_FAILURE); + } + } + + } + + enet_host_destroy(server); + enet_deinitialize(); + + return 0; + +} diff --git a/test/enet/server/premake4.lua b/test/enet/chat/server/premake4.lua similarity index 70% rename from test/enet/server/premake4.lua rename to test/enet/chat/server/premake4.lua index 50f1c9b16..2069c2f01 100644 --- a/test/enet/server/premake4.lua +++ b/test/enet/chat/server/premake4.lua @@ -1,12 +1,12 @@ -project ("Test_enet_server") +project ("Test_enet_chat_server") language "C++" kind "ConsoleApp" - includedirs {"../../../examples/ThirdPartyLibs/enet/include"} + includedirs {"../../../../examples/ThirdPartyLibs/enet/include"} if os.is("Windows") then defines { "WIN32" } diff --git a/test/enet/client/main.cpp b/test/enet/nat_punchthrough/client/main.cpp similarity index 100% rename from test/enet/client/main.cpp rename to test/enet/nat_punchthrough/client/main.cpp diff --git a/test/enet/nat_punchthrough/client/premake4.lua b/test/enet/nat_punchthrough/client/premake4.lua new file mode 100644 index 000000000..feabb3429 --- /dev/null +++ b/test/enet/nat_punchthrough/client/premake4.lua @@ -0,0 +1,25 @@ + + +project ("Test_enet_nat_punchthrough_client") + + language "C++" + + kind "ConsoleApp" + + includedirs {"../../../../examples/ThirdPartyLibs/enet/include"} + + if os.is("Windows") then + defines { "WIN32" } + links {"Ws2_32","Winmm"} + end + if os.is("Linux") then + end + if os.is("MacOSX") then + end + + links {"enet"} + + files { + "main.cpp", + } + diff --git a/test/enet/server/main.cpp b/test/enet/nat_punchthrough/server/main.cpp similarity index 100% rename from test/enet/server/main.cpp rename to test/enet/nat_punchthrough/server/main.cpp diff --git a/test/enet/nat_punchthrough/server/premake4.lua b/test/enet/nat_punchthrough/server/premake4.lua new file mode 100644 index 000000000..2d8f4b7a8 --- /dev/null +++ b/test/enet/nat_punchthrough/server/premake4.lua @@ -0,0 +1,26 @@ + + +project ("Test_enet_nat_punchthrough_server") + + language "C++" + + kind "ConsoleApp" + + includedirs {"../../../../examples/ThirdPartyLibs/enet/include"} + + if os.is("Windows") then + defines { "WIN32" } + + links {"Ws2_32","Winmm"} + end + if os.is("Linux") then + end + if os.is("MacOSX") then + end + + links {"enet"} + + files { + "main.cpp", + } +