From 737a2829bb570cb783aa8238dd9be349b2bfe2f5 Mon Sep 17 00:00:00 2001 From: "erwin.coumans" Date: Thu, 13 Sep 2012 00:07:58 +0000 Subject: [PATCH] remove rigid body gpu pipeline, the latest version is at https://github.com/erwincoumans/experiments --- Extras/RigidBodyGpuPipeline/bin/glut32.dll | Bin 160256 -> 0 bytes Extras/RigidBodyGpuPipeline/bin/glut64.dll | Bin 272896 -> 0 bytes .../build/findDirectX11.lua | 36 - .../RigidBodyGpuPipeline/build/findOpenCL.lua | 84 - .../build/findOpenGLGlewGlut.lua | 52 - .../RigidBodyGpuPipeline/build/premake4.lua | 55 - Extras/RigidBodyGpuPipeline/build/vs2008.bat | 10 - Extras/RigidBodyGpuPipeline/build/vs2010.bat | 5 - .../dynamics/basic_demo/AMD/premake4.lua | 45 - .../dynamics/basic_demo/BasicDemo.cpp | 538 ----- .../dynamics/basic_demo/BasicDemo.h | 86 - .../basic_demo/ConvexHeightFieldShape.cpp | 507 ----- .../basic_demo/ConvexHeightFieldShape.h | 143 -- .../dynamics/basic_demo/CubeMapUtils.h | 111 -- .../basic_demo/CustomCollisionDispatcher.cpp | 699 ------- .../basic_demo/CustomCollisionDispatcher.h | 70 - .../basic_demo/CustomConvexPairCollision.cpp | 409 ---- .../basic_demo/CustomConvexPairCollision.h | 56 - .../dynamics/basic_demo/CustomConvexShape.cpp | 45 - .../dynamics/basic_demo/CustomConvexShape.h | 35 - .../dynamics/basic_demo/Stubs/AdlAabb.cpp | 0 .../dynamics/basic_demo/Stubs/AdlAabb.h | 230 --- .../dynamics/basic_demo/Stubs/AdlArray.h | 212 -- .../basic_demo/Stubs/AdlCollideUtils.h | 111 -- .../basic_demo/Stubs/AdlCollisionShape.h | 49 - .../basic_demo/Stubs/AdlConstraint4.h | 49 - .../dynamics/basic_demo/Stubs/AdlContact4.h | 102 - .../dynamics/basic_demo/Stubs/AdlError.h | 80 - .../dynamics/basic_demo/Stubs/AdlMath.h | 216 -- .../dynamics/basic_demo/Stubs/AdlMatrix3x3.h | 194 -- .../dynamics/basic_demo/Stubs/AdlQuaternion.h | 155 -- .../dynamics/basic_demo/Stubs/AdlRigidBody.h | 59 - .../dynamics/basic_demo/Stubs/AdlTransform.h | 61 - .../dynamics/basic_demo/Stubs/Adlfloat4.inl | 373 ---- .../basic_demo/Stubs/Adlfloat4SSE.inl | 381 ---- .../dynamics/basic_demo/Stubs/ChNarrowPhase.h | 154 -- .../basic_demo/Stubs/ChNarrowphase.inl | 303 --- .../basic_demo/Stubs/ChNarrowphaseKernels.cl | 1629 --------------- .../basic_demo/Stubs/ChNarrowphaseKernels.h | 1616 --------------- .../dynamics/basic_demo/Stubs/Solver.h | 203 -- .../dynamics/basic_demo/Stubs/Solver.inl | 762 ------- .../dynamics/basic_demo/Stubs/SolverHost.inl | 848 -------- .../basic_demo/Stubs/SolverKernels.cl | 1051 ---------- .../dynamics/basic_demo/Stubs/SolverKernels.h | 1037 ---------- .../basic_demo/Stubs/batchingKernels.cl | 338 ---- .../basic_demo/Stubs/batchingKernels.h | 371 ---- .../dynamics/basic_demo/Stubs/stringify.py | 13 - .../basic_demo/Stubs/stringifykernels.bat | 6 - .../basic_demo/Stubs/stringifykernelsAll.bat | 10 - .../Stubs/stringifykernelsBatching.bat | 8 - .../Stubs/stringifykernelsNarrowphase.bat | 8 - .../Stubs/stringifykernelsSolver.bat | 8 - .../dynamics/basic_demo/main.cpp | 77 - .../dynamics/basic_demo/premake4.lua | 34 - .../dynamics/testbed/DebugCastResult.h | 88 - .../dynamics/testbed/DemoApplication.cpp | 1375 ------------- .../dynamics/testbed/DemoApplication.h | 257 --- .../dynamics/testbed/GLDebugDrawer.cpp | 139 -- .../dynamics/testbed/GLDebugDrawer.h | 38 - .../dynamics/testbed/GLDebugFont.cpp | 1000 ---------- .../dynamics/testbed/GLDebugFont.h | 29 - .../dynamics/testbed/GL_ShapeDrawer.cpp | 1058 ---------- .../dynamics/testbed/GL_ShapeDrawer.h | 70 - .../dynamics/testbed/GL_Simplex1to4.cpp | 76 - .../dynamics/testbed/GL_Simplex1to4.h | 40 - .../dynamics/testbed/GlutDemoApplication.cpp | 87 - .../dynamics/testbed/GlutDemoApplication.h | 34 - .../dynamics/testbed/GlutStuff.cpp | 119 -- .../dynamics/testbed/GlutStuff.h | 86 - .../dynamics/testbed/RenderTexture.cpp | 86 - .../dynamics/testbed/RenderTexture.h | 73 - .../dynamics/testbed/Win32AppMain.cpp | 405 ---- .../dynamics/testbed/Win32DemoApplication.cpp | 79 - .../dynamics/testbed/Win32DemoApplication.h | 40 - .../dynamics/testbed/premake4.lua | 18 - .../opencl/3dGridBroadphase/AMD/premake4.lua | 29 - .../MiniCL/MiniCLTaskWrap.cpp | 23 - .../Shared/bt3dGridBroadphaseOCL.cl | 349 ---- .../Shared/bt3dGridBroadphaseOCL.cpp | 695 ------- .../Shared/bt3dGridBroadphaseOCL.h | 145 -- .../Shared/btGpu3DGridBroadphase.cpp | 626 ------ .../Shared/btGpu3DGridBroadphase.h | 154 -- .../Shared/btGpu3DGridBroadphaseSharedCode.h | 428 ---- .../Shared/btGpu3DGridBroadphaseSharedDefs.h | 61 - .../Shared/btGpu3DGridBroadphaseSharedTypes.h | 64 - .../3dGridBroadphase/Shared/btGpuDefines.h | 211 -- .../Shared/btGpuUtilsSharedCode.h | 55 - .../Shared/btGpuUtilsSharedDefs.h | 52 - .../opencl/3dGridBroadphase/premake4.lua | 5 - .../opencl/basic_initialize/AMD/premake4.lua | 23 - .../basic_initialize/Intel/premake4.lua | 23 - .../basic_initialize/NVIDIA/premake4.lua | 23 - .../opencl/basic_initialize/btOpenCLInclude.h | 43 - .../opencl/basic_initialize/btOpenCLUtils.cpp | 731 ------- .../opencl/basic_initialize/btOpenCLUtils.h | 104 - .../opencl/basic_initialize/main.cpp | 92 - .../opencl/basic_initialize/premake4.lua | 4 - .../broadphase_benchmark/AMD/premake4.lua | 49 - .../broadphase_benchmark/Intel/premake4.lua | 49 - .../broadphase_benchmark/NVIDIA/premake4.lua | 49 - .../broadphase_benchmark/broadphaseKernel.cl | 335 ---- .../btGridBroadphaseCL.cpp | 230 --- .../broadphase_benchmark/btGridBroadphaseCL.h | 72 - .../computeAabbKernelOCL.cl | 112 -- .../broadphase_benchmark/findPairsOpenCL.cpp | 204 -- .../broadphase_benchmark/findPairsOpenCL.h | 90 - .../broadphase_benchmark/integrateKernel.cl | 116 -- .../opencl/broadphase_benchmark/main.cpp | 1565 --------------- .../opencl/broadphase_benchmark/premake4.lua | 5 - .../opencl/global_atomics/AMD/premake4.lua | 23 - .../global_atomics/globalAtomicsKernel.h | 36 - .../opencl/global_atomics/global_atomics.cl | 34 - .../opencl/global_atomics/main.cpp | 201 -- .../opencl/global_atomics/premake4.lua | 4 - .../opencl/global_atomics/stringify.py | 13 - .../global_atomics/stringifykernels.bat | 5 - .../gpu_rigidbody_pipeline/AMD/premake4.lua | 58 - .../gpu_rigidbody_pipeline/CommandLineArgs.h | 91 - .../gpu_rigidbody_pipeline/Intel/premake4.lua | 58 - .../NVIDIA/premake4.lua | 57 - .../btConvexUtility.cpp | 240 --- .../gpu_rigidbody_pipeline/btConvexUtility.h | 41 - .../btGpuNarrowPhaseAndSolver.cpp | 730 ------- .../btGpuNarrowPhaseAndSolver.h | 72 - .../opencl/gpu_rigidbody_pipeline/main.cpp | 1775 ----------------- .../gpu_rigidbody_pipeline/premake4.lua | 5 - .../gpu_rigidbody_pipeline2/AMD/premake4.lua | 64 - .../gpu_rigidbody_pipeline2/CLPhysicsDemo.cpp | 533 ----- .../gpu_rigidbody_pipeline2/CLPhysicsDemo.h | 53 - .../gpu_rigidbody_pipeline2/DemoSettings.h | 24 - .../GLInstancingRenderer.cpp | 861 -------- .../GLInstancingRenderer.h | 45 - .../gpu_rigidbody_pipeline2/GlutRenderer.cpp | 107 - .../gpu_rigidbody_pipeline2/GlutRenderer.h | 59 - .../NVIDIA/premake4.lua | 64 - .../gpu_rigidbody_pipeline2/OpenGLInclude.h | 41 - .../gpu_rigidbody_pipeline2/ShapeData.h | 210 -- .../Win32OpenGLRenderManager.cpp | 465 ----- .../Win32OpenGLRenderManager.h | 70 - .../opencl/gpu_rigidbody_pipeline2/main.cpp | 224 --- .../gpu_rigidbody_pipeline2/premake4.lua | 5 - .../opencl/integration/AMD/premake4.lua | 34 - .../opencl/integration/Intel/premake4.lua | 36 - .../opencl/integration/NVIDIA/premake4.lua | 35 - .../opencl/integration/integrateKernel.cl | 73 - .../opencl/integration/main.cpp | 1106 ---------- .../opencl/integration/premake4.lua | 5 - .../opencl/opengl_interop/AMD/premake4.lua | 33 - .../opencl/opengl_interop/Intel/premake4.lua | 34 - .../opencl/opengl_interop/NVIDIA/premake4.lua | 34 - .../btOpenCLGLInteropBuffer.cpp | 60 - .../opengl_interop/btOpenCLGLInteropBuffer.h | 49 - .../opencl/opengl_interop/btStopwatch.cpp | 182 -- .../opencl/opengl_interop/btStopwatch.h | 45 - .../opencl/opengl_interop/interopKernel.cl | 13 - .../opencl/opengl_interop/main.cpp | 1057 ---------- .../opencl/opengl_interop/premake4.lua | 5 - .../opencl/primitives/Adl/Adl.cpp | 19 - .../opencl/primitives/Adl/Adl.h | 235 --- .../opencl/primitives/Adl/Adl.inl | 344 ---- .../opencl/primitives/Adl/AdlConfig.h | 27 - .../opencl/primitives/Adl/AdlError.h | 80 - .../opencl/primitives/Adl/AdlKernel.h | 142 -- .../opencl/primitives/Adl/AdlKernel.inl | 223 --- .../opencl/primitives/Adl/AdlStopwatch.h | 81 - .../opencl/primitives/Adl/AdlStopwatch.inl | 59 - .../opencl/primitives/Adl/CL/AdlCL.inl | 384 ---- .../primitives/Adl/CL/AdlKernelUtilsCL.inl | 541 ----- .../opencl/primitives/Adl/DX11/AdlDX11.inl | 512 ----- .../Adl/DX11/AdlKernelUtilsDX11.inl | 348 ---- .../primitives/Adl/DX11/AdlStopwatchDX11.inl | 131 -- .../opencl/primitives/Adl/Host/AdlHost.inl | 107 - .../primitives/Adl/Host/AdlStopwatchHost.inl | 119 -- .../primitives/AdlPrimitives/Copy/Copy.h | 73 - .../primitives/AdlPrimitives/Copy/Copy.inl | 151 -- .../AdlPrimitives/Copy/CopyHost.inl | 85 - .../AdlPrimitives/Copy/CopyKernels.cl | 128 -- .../AdlPrimitives/Copy/CopyKernels.hlsl | 130 -- .../AdlPrimitives/Copy/CopyKernelsCL.h | 119 -- .../AdlPrimitives/Copy/CopyKernelsDX11.h | 120 -- .../primitives/AdlPrimitives/Fill/Fill.h | 77 - .../primitives/AdlPrimitives/Fill/Fill.inl | 123 -- .../AdlPrimitives/Fill/FillHost.inl | 99 - .../AdlPrimitives/Fill/FillKernels.cl | 81 - .../AdlPrimitives/Fill/FillKernels.hlsl | 79 - .../AdlPrimitives/Fill/FillKernelsCL.h | 71 - .../AdlPrimitives/Fill/FillKernelsDX11.h | 69 - .../primitives/AdlPrimitives/Math/Array.h | 231 --- .../primitives/AdlPrimitives/Math/Float2.inl | 173 -- .../primitives/AdlPrimitives/Math/Float4.inl | 375 ---- .../primitives/AdlPrimitives/Math/Math.h | 224 --- .../primitives/AdlPrimitives/Math/MathCL.h | 357 ---- .../primitives/AdlPrimitives/Math/Matrix3x3.h | 197 -- .../AdlPrimitives/Math/Quaternion.h | 159 -- .../AdlPrimitives/Scan/PrefixScan.h | 73 - .../AdlPrimitives/Scan/PrefixScan.inl | 125 -- .../AdlPrimitives/Scan/PrefixScanHost.inl | 74 - .../AdlPrimitives/Scan/PrefixScanKernels.cl | 153 -- .../AdlPrimitives/Scan/PrefixScanKernels.hlsl | 157 -- .../AdlPrimitives/Scan/PrefixScanKernelsCL.h | 143 -- .../Scan/PrefixScanKernelsDX11.h | 147 -- .../AdlPrimitives/Search/BoundSearch.h | 73 - .../AdlPrimitives/Search/BoundSearch.inl | 128 -- .../AdlPrimitives/Search/BoundSearchHost.inl | 111 -- .../Search/BoundSearchKernels.cl | 112 -- .../Search/BoundSearchKernels.hlsl | 104 - .../Search/BoundSearchKernelsCL.h | 102 - .../Search/BoundSearchKernelsDX11.h | 94 - .../primitives/AdlPrimitives/Sort/RadixSort.h | 53 - .../AdlPrimitives/Sort/RadixSort.inl | 58 - .../AdlPrimitives/Sort/RadixSort32.h | 98 - .../AdlPrimitives/Sort/RadixSort32.inl | 346 ---- .../AdlPrimitives/Sort/RadixSort32Host.inl | 163 -- .../AdlPrimitives/Sort/RadixSort32Kernels.cl | 1104 ---------- .../Sort/RadixSort32Kernels.hlsl | 1011 ---------- .../AdlPrimitives/Sort/RadixSort32KernelsCL.h | 1106 ---------- .../Sort/RadixSort32KernelsDX11.h | 1013 ---------- .../Sort/RadixSortAdvancedKernels.hlsl | 985 --------- .../Sort/RadixSortAdvancedKernelsDX11.h | 987 --------- .../AdlPrimitives/Sort/RadixSortHost.inl | 93 - .../AdlPrimitives/Sort/RadixSortSimpleCL.h | 134 -- .../AdlPrimitives/Sort/RadixSortSimpleDX11.h | 131 -- .../Sort/RadixSortSimpleKernels.cl | 147 -- .../Sort/RadixSortSimpleKernels.hlsl | 133 -- .../Sort/RadixSortSimpleKernelsCL.h | 149 -- .../Sort/RadixSortSimpleKernelsDX11.h | 135 -- .../AdlPrimitives/Sort/RadixSortStandard.inl | 177 -- .../Sort/RadixSortStandardKernels.cl | 345 ---- .../Sort/RadixSortStandardKernels.hlsl | 322 --- .../Sort/RadixSortStandardKernelsCL.h | 347 ---- .../Sort/RadixSortStandardKernelsDX11.h | 324 --- .../primitives/AdlPrimitives/Sort/SortData.h | 31 - .../AdlPrimitives/Sort/radixsortadvanced.inl | 146 -- .../AdlPrimitives/Sort/radixsortsimple.inl | 149 -- .../primitives/AdlPrimitives/stringify.py | 13 - .../AdlPrimitives/stringifykernels.bat | 22 - .../primitives/AdlTest/AMD/premake4.lua | 31 - .../primitives/AdlTest/Intel/premake4.lua | 31 - .../AdlTest/LaunchOverheadBenchmark.h | 103 - .../primitives/AdlTest/NVIDIA/premake4.lua | 31 - .../primitives/AdlTest/RadixSortBenchmark.h | 121 -- .../opencl/primitives/AdlTest/UnitTests.h | 801 -------- .../opencl/primitives/AdlTest/main.cpp | 118 -- .../opencl/primitives/AdlTest/premake4.lua | 4 - .../primitives/benchmark/AMD/premake4.lua | 29 - .../primitives/benchmark/NVIDIA/premake4.lua | 29 - .../opencl/primitives/benchmark/premake4.lua | 2 - .../benchmark/test_large_problem_sorting.cpp | 705 ------- .../opencl/vector_add/AMD/premake4.lua | 21 - .../opencl/vector_add/Intel/premake4.lua | 23 - .../opencl/vector_add/NVIDIA/premake4.lua | 23 - .../opencl/vector_add/VectorAddKernels.cl | 16 - .../opencl/vector_add/VectorAddKernels.h | 18 - .../opencl/vector_add/main.cpp | 367 ---- .../opencl/vector_add/premake4.lua | 4 - .../opencl/vector_add/stringify.py | 13 - .../vector_add/stringifyVectorAddKernel.bat | 8 - Extras/RigidBodyGpuPipeline/readme.txt | 8 - 258 files changed, 55113 deletions(-) delete mode 100644 Extras/RigidBodyGpuPipeline/bin/glut32.dll delete mode 100644 Extras/RigidBodyGpuPipeline/bin/glut64.dll delete mode 100644 Extras/RigidBodyGpuPipeline/build/findDirectX11.lua delete mode 100644 Extras/RigidBodyGpuPipeline/build/findOpenCL.lua delete mode 100644 Extras/RigidBodyGpuPipeline/build/findOpenGLGlewGlut.lua delete mode 100644 Extras/RigidBodyGpuPipeline/build/premake4.lua delete mode 100644 Extras/RigidBodyGpuPipeline/build/vs2008.bat delete mode 100644 Extras/RigidBodyGpuPipeline/build/vs2010.bat delete mode 100644 Extras/RigidBodyGpuPipeline/dynamics/basic_demo/AMD/premake4.lua delete mode 100644 Extras/RigidBodyGpuPipeline/dynamics/basic_demo/BasicDemo.cpp delete mode 100644 Extras/RigidBodyGpuPipeline/dynamics/basic_demo/BasicDemo.h delete mode 100644 Extras/RigidBodyGpuPipeline/dynamics/basic_demo/ConvexHeightFieldShape.cpp delete mode 100644 Extras/RigidBodyGpuPipeline/dynamics/basic_demo/ConvexHeightFieldShape.h delete mode 100644 Extras/RigidBodyGpuPipeline/dynamics/basic_demo/CubeMapUtils.h delete mode 100644 Extras/RigidBodyGpuPipeline/dynamics/basic_demo/CustomCollisionDispatcher.cpp delete mode 100644 Extras/RigidBodyGpuPipeline/dynamics/basic_demo/CustomCollisionDispatcher.h delete mode 100644 Extras/RigidBodyGpuPipeline/dynamics/basic_demo/CustomConvexPairCollision.cpp delete mode 100644 Extras/RigidBodyGpuPipeline/dynamics/basic_demo/CustomConvexPairCollision.h delete mode 100644 Extras/RigidBodyGpuPipeline/dynamics/basic_demo/CustomConvexShape.cpp delete mode 100644 Extras/RigidBodyGpuPipeline/dynamics/basic_demo/CustomConvexShape.h delete mode 100644 Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/AdlAabb.cpp delete mode 100644 Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/AdlAabb.h delete mode 100644 Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/AdlArray.h delete mode 100644 Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/AdlCollideUtils.h delete mode 100644 Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/AdlCollisionShape.h delete mode 100644 Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/AdlConstraint4.h delete mode 100644 Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/AdlContact4.h delete mode 100644 Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/AdlError.h delete mode 100644 Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/AdlMath.h delete mode 100644 Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/AdlMatrix3x3.h delete mode 100644 Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/AdlQuaternion.h delete mode 100644 Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/AdlRigidBody.h delete mode 100644 Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/AdlTransform.h delete mode 100644 Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/Adlfloat4.inl delete mode 100644 Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/Adlfloat4SSE.inl delete mode 100644 Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/ChNarrowPhase.h delete mode 100644 Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/ChNarrowphase.inl delete mode 100644 Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/ChNarrowphaseKernels.cl delete mode 100644 Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/ChNarrowphaseKernels.h delete mode 100644 Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/Solver.h delete mode 100644 Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/Solver.inl delete mode 100644 Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/SolverHost.inl delete mode 100644 Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/SolverKernels.cl delete mode 100644 Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/SolverKernels.h delete mode 100644 Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/batchingKernels.cl delete mode 100644 Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/batchingKernels.h delete mode 100644 Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/stringify.py delete mode 100644 Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/stringifykernels.bat delete mode 100644 Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/stringifykernelsAll.bat delete mode 100644 Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/stringifykernelsBatching.bat delete mode 100644 Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/stringifykernelsNarrowphase.bat delete mode 100644 Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/stringifykernelsSolver.bat delete mode 100644 Extras/RigidBodyGpuPipeline/dynamics/basic_demo/main.cpp delete mode 100644 Extras/RigidBodyGpuPipeline/dynamics/basic_demo/premake4.lua delete mode 100644 Extras/RigidBodyGpuPipeline/dynamics/testbed/DebugCastResult.h delete mode 100644 Extras/RigidBodyGpuPipeline/dynamics/testbed/DemoApplication.cpp delete mode 100644 Extras/RigidBodyGpuPipeline/dynamics/testbed/DemoApplication.h delete mode 100644 Extras/RigidBodyGpuPipeline/dynamics/testbed/GLDebugDrawer.cpp delete mode 100644 Extras/RigidBodyGpuPipeline/dynamics/testbed/GLDebugDrawer.h delete mode 100644 Extras/RigidBodyGpuPipeline/dynamics/testbed/GLDebugFont.cpp delete mode 100644 Extras/RigidBodyGpuPipeline/dynamics/testbed/GLDebugFont.h delete mode 100644 Extras/RigidBodyGpuPipeline/dynamics/testbed/GL_ShapeDrawer.cpp delete mode 100644 Extras/RigidBodyGpuPipeline/dynamics/testbed/GL_ShapeDrawer.h delete mode 100644 Extras/RigidBodyGpuPipeline/dynamics/testbed/GL_Simplex1to4.cpp delete mode 100644 Extras/RigidBodyGpuPipeline/dynamics/testbed/GL_Simplex1to4.h delete mode 100644 Extras/RigidBodyGpuPipeline/dynamics/testbed/GlutDemoApplication.cpp delete mode 100644 Extras/RigidBodyGpuPipeline/dynamics/testbed/GlutDemoApplication.h delete mode 100644 Extras/RigidBodyGpuPipeline/dynamics/testbed/GlutStuff.cpp delete mode 100644 Extras/RigidBodyGpuPipeline/dynamics/testbed/GlutStuff.h delete mode 100644 Extras/RigidBodyGpuPipeline/dynamics/testbed/RenderTexture.cpp delete mode 100644 Extras/RigidBodyGpuPipeline/dynamics/testbed/RenderTexture.h delete mode 100644 Extras/RigidBodyGpuPipeline/dynamics/testbed/Win32AppMain.cpp delete mode 100644 Extras/RigidBodyGpuPipeline/dynamics/testbed/Win32DemoApplication.cpp delete mode 100644 Extras/RigidBodyGpuPipeline/dynamics/testbed/Win32DemoApplication.h delete mode 100644 Extras/RigidBodyGpuPipeline/dynamics/testbed/premake4.lua delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/3dGridBroadphase/AMD/premake4.lua delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/3dGridBroadphase/MiniCL/MiniCLTaskWrap.cpp delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/3dGridBroadphase/Shared/bt3dGridBroadphaseOCL.cl delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/3dGridBroadphase/Shared/bt3dGridBroadphaseOCL.cpp delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/3dGridBroadphase/Shared/bt3dGridBroadphaseOCL.h delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/3dGridBroadphase/Shared/btGpu3DGridBroadphase.cpp delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/3dGridBroadphase/Shared/btGpu3DGridBroadphase.h delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/3dGridBroadphase/Shared/btGpu3DGridBroadphaseSharedCode.h delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/3dGridBroadphase/Shared/btGpu3DGridBroadphaseSharedDefs.h delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/3dGridBroadphase/Shared/btGpu3DGridBroadphaseSharedTypes.h delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/3dGridBroadphase/Shared/btGpuDefines.h delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/3dGridBroadphase/Shared/btGpuUtilsSharedCode.h delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/3dGridBroadphase/Shared/btGpuUtilsSharedDefs.h delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/3dGridBroadphase/premake4.lua delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/basic_initialize/AMD/premake4.lua delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/basic_initialize/Intel/premake4.lua delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/basic_initialize/NVIDIA/premake4.lua delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/basic_initialize/btOpenCLInclude.h delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/basic_initialize/btOpenCLUtils.cpp delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/basic_initialize/btOpenCLUtils.h delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/basic_initialize/main.cpp delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/basic_initialize/premake4.lua delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/broadphase_benchmark/AMD/premake4.lua delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/broadphase_benchmark/Intel/premake4.lua delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/broadphase_benchmark/NVIDIA/premake4.lua delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/broadphase_benchmark/broadphaseKernel.cl delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/broadphase_benchmark/btGridBroadphaseCL.cpp delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/broadphase_benchmark/btGridBroadphaseCL.h delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/broadphase_benchmark/computeAabbKernelOCL.cl delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/broadphase_benchmark/findPairsOpenCL.cpp delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/broadphase_benchmark/findPairsOpenCL.h delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/broadphase_benchmark/integrateKernel.cl delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/broadphase_benchmark/main.cpp delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/broadphase_benchmark/premake4.lua delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/global_atomics/AMD/premake4.lua delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/global_atomics/globalAtomicsKernel.h delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/global_atomics/global_atomics.cl delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/global_atomics/main.cpp delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/global_atomics/premake4.lua delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/global_atomics/stringify.py delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/global_atomics/stringifykernels.bat delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline/AMD/premake4.lua delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline/CommandLineArgs.h delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline/Intel/premake4.lua delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline/NVIDIA/premake4.lua delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline/btConvexUtility.cpp delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline/btConvexUtility.h delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline/btGpuNarrowPhaseAndSolver.cpp delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline/btGpuNarrowPhaseAndSolver.h delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline/main.cpp delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline/premake4.lua delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline2/AMD/premake4.lua delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline2/CLPhysicsDemo.cpp delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline2/CLPhysicsDemo.h delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline2/DemoSettings.h delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline2/GLInstancingRenderer.cpp delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline2/GLInstancingRenderer.h delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline2/GlutRenderer.cpp delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline2/GlutRenderer.h delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline2/NVIDIA/premake4.lua delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline2/OpenGLInclude.h delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline2/ShapeData.h delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline2/Win32OpenGLRenderManager.cpp delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline2/Win32OpenGLRenderManager.h delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline2/main.cpp delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline2/premake4.lua delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/integration/AMD/premake4.lua delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/integration/Intel/premake4.lua delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/integration/NVIDIA/premake4.lua delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/integration/integrateKernel.cl delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/integration/main.cpp delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/integration/premake4.lua delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/opengl_interop/AMD/premake4.lua delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/opengl_interop/Intel/premake4.lua delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/opengl_interop/NVIDIA/premake4.lua delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/opengl_interop/btOpenCLGLInteropBuffer.cpp delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/opengl_interop/btOpenCLGLInteropBuffer.h delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/opengl_interop/btStopwatch.cpp delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/opengl_interop/btStopwatch.h delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/opengl_interop/interopKernel.cl delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/opengl_interop/main.cpp delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/opengl_interop/premake4.lua delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/Adl/Adl.cpp delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/Adl/Adl.h delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/Adl/Adl.inl delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/Adl/AdlConfig.h delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/Adl/AdlError.h delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/Adl/AdlKernel.h delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/Adl/AdlKernel.inl delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/Adl/AdlStopwatch.h delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/Adl/AdlStopwatch.inl delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/Adl/CL/AdlCL.inl delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/Adl/CL/AdlKernelUtilsCL.inl delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/Adl/DX11/AdlDX11.inl delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/Adl/DX11/AdlKernelUtilsDX11.inl delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/Adl/DX11/AdlStopwatchDX11.inl delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/Adl/Host/AdlHost.inl delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/Adl/Host/AdlStopwatchHost.inl delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Copy/Copy.h delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Copy/Copy.inl delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Copy/CopyHost.inl delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Copy/CopyKernels.cl delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Copy/CopyKernels.hlsl delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Copy/CopyKernelsCL.h delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Copy/CopyKernelsDX11.h delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Fill/Fill.h delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Fill/Fill.inl delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Fill/FillHost.inl delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Fill/FillKernels.cl delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Fill/FillKernels.hlsl delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Fill/FillKernelsCL.h delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Fill/FillKernelsDX11.h delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Math/Array.h delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Math/Float2.inl delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Math/Float4.inl delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Math/Math.h delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Math/MathCL.h delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Math/Matrix3x3.h delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Math/Quaternion.h delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Scan/PrefixScan.h delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Scan/PrefixScan.inl delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Scan/PrefixScanHost.inl delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Scan/PrefixScanKernels.cl delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Scan/PrefixScanKernels.hlsl delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Scan/PrefixScanKernelsCL.h delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Scan/PrefixScanKernelsDX11.h delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Search/BoundSearch.h delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Search/BoundSearch.inl delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Search/BoundSearchHost.inl delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Search/BoundSearchKernels.cl delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Search/BoundSearchKernels.hlsl delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Search/BoundSearchKernelsCL.h delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Search/BoundSearchKernelsDX11.h delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Sort/RadixSort.h delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Sort/RadixSort.inl delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Sort/RadixSort32.h delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Sort/RadixSort32.inl delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Sort/RadixSort32Host.inl delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Sort/RadixSort32Kernels.cl delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Sort/RadixSort32Kernels.hlsl delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Sort/RadixSort32KernelsCL.h delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Sort/RadixSort32KernelsDX11.h delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Sort/RadixSortAdvancedKernels.hlsl delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Sort/RadixSortAdvancedKernelsDX11.h delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Sort/RadixSortHost.inl delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Sort/RadixSortSimpleCL.h delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Sort/RadixSortSimpleDX11.h delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Sort/RadixSortSimpleKernels.cl delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Sort/RadixSortSimpleKernels.hlsl delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Sort/RadixSortSimpleKernelsCL.h delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Sort/RadixSortSimpleKernelsDX11.h delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Sort/RadixSortStandard.inl delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Sort/RadixSortStandardKernels.cl delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Sort/RadixSortStandardKernels.hlsl delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Sort/RadixSortStandardKernelsCL.h delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Sort/RadixSortStandardKernelsDX11.h delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Sort/SortData.h delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Sort/radixsortadvanced.inl delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Sort/radixsortsimple.inl delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/stringify.py delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/stringifykernels.bat delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/AdlTest/AMD/premake4.lua delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/AdlTest/Intel/premake4.lua delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/AdlTest/LaunchOverheadBenchmark.h delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/AdlTest/NVIDIA/premake4.lua delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/AdlTest/RadixSortBenchmark.h delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/AdlTest/UnitTests.h delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/AdlTest/main.cpp delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/AdlTest/premake4.lua delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/benchmark/AMD/premake4.lua delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/benchmark/NVIDIA/premake4.lua delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/benchmark/premake4.lua delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/primitives/benchmark/test_large_problem_sorting.cpp delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/vector_add/AMD/premake4.lua delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/vector_add/Intel/premake4.lua delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/vector_add/NVIDIA/premake4.lua delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/vector_add/VectorAddKernels.cl delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/vector_add/VectorAddKernels.h delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/vector_add/main.cpp delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/vector_add/premake4.lua delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/vector_add/stringify.py delete mode 100644 Extras/RigidBodyGpuPipeline/opencl/vector_add/stringifyVectorAddKernel.bat delete mode 100644 Extras/RigidBodyGpuPipeline/readme.txt diff --git a/Extras/RigidBodyGpuPipeline/bin/glut32.dll b/Extras/RigidBodyGpuPipeline/bin/glut32.dll deleted file mode 100644 index 3297bd0783b702755a952ad50e518d3e1a922595..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 160256 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 G;J*P491%kR diff --git a/Extras/RigidBodyGpuPipeline/build/findDirectX11.lua b/Extras/RigidBodyGpuPipeline/build/findDirectX11.lua deleted file mode 100644 index 68771c4a0..000000000 --- a/Extras/RigidBodyGpuPipeline/build/findDirectX11.lua +++ /dev/null @@ -1,36 +0,0 @@ -function findDirectX11() - local dx11path = os.getenv("DXSDK_DIR") - if (dx11path) then - local filepath = string.format("%s%s",dx11path,"Include/D3D11.h") - headerdx11 = io.open(filepath, "r") - if (headerdx11) then - printf("Found DX11: '%s'", filepath) - return true - end - end - return false - end - -function initDirectX11() - configuration {} - - local dx11path = os.getenv("DXSDK_DIR") - defines { "ADL_ENABLE_DX11"} - includedirs {"$(DXSDK_DIR)/include"} - - configuration "x32" - libdirs {"$(DXSDK_DIR)/Lib/x86"} - configuration "x64" - libdirs {"$(DXSDK_DIR)/Lib/x64"} - configuration {} - links {"d3dcompiler", - "dxerr", - "dxguid", - "d3dx9", - "d3d9", - "winmm", - "comctl32", - "d3dx11" - } - return true -end \ No newline at end of file diff --git a/Extras/RigidBodyGpuPipeline/build/findOpenCL.lua b/Extras/RigidBodyGpuPipeline/build/findOpenCL.lua deleted file mode 100644 index 913b8406d..000000000 --- a/Extras/RigidBodyGpuPipeline/build/findOpenCL.lua +++ /dev/null @@ -1,84 +0,0 @@ - -- todo: add Apple OpenCL environment vars - - function findOpenCL_AMD() - local amdopenclpath = os.getenv("AMDAPPSDKROOT") - if (amdopenclpath) then - return true - end - return false - end - - function findOpenCL_NVIDIA() - local nvidiaopenclpath = os.getenv("CUDA_PATH") - if (nvidiaopenclpath) then - return true - end - return false - end - - function findOpenCL_Intel() - local intelopenclpath = os.getenv("INTELOCLSDKROOT") - if (intelopenclpath) then - return true - end - return false - end - - function initOpenCL_AMD() - configuration {} - local amdopenclpath = os.getenv("AMDAPPSDKROOT") - if (amdopenclpath) then - defines { "ADL_ENABLE_CL" , "CL_PLATFORM_AMD"} - includedirs { - "$(AMDAPPSDKROOT)/include" - } - configuration "x32" - libdirs {"$(AMDAPPSDKROOT)/lib/x86"} - configuration "x64" - libdirs {"$(AMDAPPSDKROOT)/lib/x86_64"} - configuration {} - links {"OpenCL"} - return true - end - return false - end - - - function initOpenCL_NVIDIA() - configuration {} - local nvidiaopenclpath = os.getenv("CUDA_PATH") - if (nvidiaopenclpath) then - defines { "ADL_ENABLE_CL" , "CL_PLATFORM_NVIDIA"} - includedirs { - "$(CUDA_PATH)/include" - } - configuration "x32" - libdirs {"$(CUDA_PATH)/lib/Win32"} - configuration "x64" - libdirs {"$(CUDA_PATH)/lib/x64"} - configuration {} - links {"OpenCL"} - return true - end - return false - end - - function initOpenCL_Intel() - configuration {} - local intelopenclpath = os.getenv("INTELOCLSDKROOT") - if (intelopenclpath) then - defines { "ADL_ENABLE_CL" , "CL_PLATFORM_INTEL"} - includedirs { - "$(INTELOCLSDKROOT)/include" - } - configuration "x32" - libdirs {"$(INTELOCLSDKROOT)/lib/x86"} - configuration "x64" - libdirs {"$(INTELOCLSDKROOT)/lib/x64"} - configuration {} - links {"OpenCL"} - return true - end - return false - end - \ No newline at end of file diff --git a/Extras/RigidBodyGpuPipeline/build/findOpenGLGlewGlut.lua b/Extras/RigidBodyGpuPipeline/build/findOpenGLGlewGlut.lua deleted file mode 100644 index 2a04c6d70..000000000 --- a/Extras/RigidBodyGpuPipeline/build/findOpenGLGlewGlut.lua +++ /dev/null @@ -1,52 +0,0 @@ - -- todo: add Apple OpenCL environment vars - - function initOpenGL() - configuration {} - configuration {"Windows"} - links {"opengl32"} - configuration {"MacOSX"} - links { "Carbon.framework","OpenGL.framework","AGL.framework"} - configuration {"not Windows", "not MacOSX"} - links {"GL","GLU"} - configuration{} - end - - function initGlut() - configuration {} - configuration {"Windows"} - - includedirs { - projectRootDir .. "../../Glut" - } - libdirs { projectRootDir .. "../../Glut"} - configuration {"Windows", "x32"} - links {"glut32"} - configuration {"Windows", "x64"} - links {"glut64"} - - configuration {"MacOSX"} - links { "Glut.framework" } - - configuration {"not Windows", "not MacOSX"} - links {"glut"} - configuration{} - end - - function initGlew() - configuration {} - configuration {"Windows"} - defines { "GLEW_STATIC"} - includedirs { - projectRootDir .. "../../Glut" - } - libdirs { projectRootDir .. "../../Glut"} - configuration {"Windows", "x32"} - links {"glew32s"} - configuration {"Windows", "x64"} - links {"glew64s"} - - configuration{} - end - - - diff --git a/Extras/RigidBodyGpuPipeline/build/premake4.lua b/Extras/RigidBodyGpuPipeline/build/premake4.lua deleted file mode 100644 index b317d35f7..000000000 --- a/Extras/RigidBodyGpuPipeline/build/premake4.lua +++ /dev/null @@ -1,55 +0,0 @@ -solution "0MySolution" - - -- Multithreaded compiling - if _ACTION == "vs2010" then - buildoptions { "/MP" } - end - - - - configurations {"Release", "Debug"} - configuration "Release" - flags { "Optimize", "StaticRuntime", "NoMinimalRebuild", "FloatFast"} - configuration "Debug" - flags { "Symbols", "StaticRuntime" , "NoMinimalRebuild", "NoEditAndContinue" ,"FloatFast"} - - platforms {"x32", "x64"} - - configuration "x64" - targetsuffix "_64" - configuration {"x64", "debug"} - targetsuffix "_x64_debug" - configuration {"x64", "release"} - targetsuffix "_x64" - configuration {"x32", "debug"} - targetsuffix "_debug" - - configuration{} - - flags { "NoRTTI", "NoExceptions"} - defines { "_HAS_EXCEPTIONS=0" } - targetdir "../bin" - location("./" .. _ACTION) - - - projectRootDir = os.getcwd() .. "/../" - print("Project root directroy: " .. projectRootDir); - - dofile ("findOpenCL.lua") - dofile ("findDirectX11.lua") - dofile ("findOpenGLGlewGlut.lua") - - language "C++" - - include "../opencl/gpu_rigidbody_pipeline2" - include "../opencl/gpu_rigidbody_pipeline" - - include "../opencl/basic_initialize" - include "../opencl/vector_add" - - include "../opencl/primitives/AdlTest" - include "../opencl/primitives/benchmark" - include "../opencl/3dGridBroadphase" - include "../opencl/broadphase_benchmark" - - \ No newline at end of file diff --git a/Extras/RigidBodyGpuPipeline/build/vs2008.bat b/Extras/RigidBodyGpuPipeline/build/vs2008.bat deleted file mode 100644 index 50c8617d7..000000000 --- a/Extras/RigidBodyGpuPipeline/build/vs2008.bat +++ /dev/null @@ -1,10 +0,0 @@ - -rem premake4 --no-pelibs vs2008 -rem premake4 --no-pedemos vs2008 -rem premake4 --no-bulletlibs --no-pelibs vs2008 -rem premake4 --with-nacl vs2008 - -..\..\..\build\premake4 vs2008 -mkdir vs2008\cache - -pause \ No newline at end of file diff --git a/Extras/RigidBodyGpuPipeline/build/vs2010.bat b/Extras/RigidBodyGpuPipeline/build/vs2010.bat deleted file mode 100644 index 6b77748fb..000000000 --- a/Extras/RigidBodyGpuPipeline/build/vs2010.bat +++ /dev/null @@ -1,5 +0,0 @@ - -..\..\..\build\premake4 vs2010 - -mkdir vs2010\cache -pause \ No newline at end of file diff --git a/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/AMD/premake4.lua b/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/AMD/premake4.lua deleted file mode 100644 index 159e25fbc..000000000 --- a/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/AMD/premake4.lua +++ /dev/null @@ -1,45 +0,0 @@ -if os.is("Windows") then - - hasCL = findOpenCL_AMD() - - if (hasCL) then - - project "basic_bullet2_demo_AMD" - - initOpenCL_AMD() - - language "C++" - - kind "ConsoleApp" - targetdir "../../../bin" - - includedirs { - "..", - "../../../bullet2", - "../../testbed", - "../../../rendering/Gwen", - "../../../opencl/basic_initialize", - "../../../opencl/primitives" - } - - - links { "testbed", - "bullet2", - "gwen" - } - - - initOpenGL() - initGlut() - - - files { - "../**.cpp", - "../**.h", - "../../../opencl/basic_initialize/btOpenCLUtils.cpp", - "../../../opencl/basic_initialize/btOpenCLUtils.h" - } - - end - -end diff --git a/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/BasicDemo.cpp b/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/BasicDemo.cpp deleted file mode 100644 index 0b6d452ac..000000000 --- a/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/BasicDemo.cpp +++ /dev/null @@ -1,538 +0,0 @@ -/* -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 "BasicDemo.h" -#include "GlutStuff.h" -///btBulletDynamicsCommon.h is the main Bullet include file, contains most common include files. -#include "btBulletDynamicsCommon.h" -#include "CustomConvexShape.h" -#include "CustomConvexPairCollision.h" -#include "CustomCollisionDispatcher.h" - -#include "ConvexHeightFieldShape.h" -#include "GLDebugDrawer.h" -static GLDebugDrawer sDebugDraw; - -#include //printf debugging - -#ifdef CL_PLATFORM_AMD -#include "../../opencl/basic_initialize/btOpenCLUtils.h" - -cl_context g_cxMainContext=0; -cl_command_queue g_cqCommandQue=0; -cl_device_id g_clDevice=0; -#endif - -///create 125 (5x5x5) dynamic object -#define ARRAY_SIZE_X 6 -#define ARRAY_SIZE_Y 6 -#define ARRAY_SIZE_Z 4 - -//maximum number of objects (and allow user to shoot additional boxes) -#define MAX_PROXIES (ARRAY_SIZE_X*ARRAY_SIZE_Y*ARRAY_SIZE_Z + 1024) - -///scaling of the objects (0.1 = 20 centimeter boxes ) -#define SCALING 1. -#define START_POS_X 0 -#define START_POS_Y -0.8 -#define START_POS_Z 0 - -#define BoxVtxCount 8 - -static float BoxVtx[] = { --0.5,-0.5,-0.5, --0.5,-0.5,0.5, --0.5,0.5,-0.5, --0.5,0.5,0.5, -0.5,-0.5,-0.5, -0.5,-0.5,0.5, -0.5,0.5,-0.5, -0.5,0.5,0.5, -}; - -static float BoxVtx2[] = { --20.3,-10.3,-20.3, --20.3,-10.3,20.3, --20.3,10.3,-20.3, --20.3,10.3,20.3, -20.3,-10.3,-20.3, -20.3,-10.3,20.3, -20.3,10.3,-20.3, -20.3,10.3,20.3, -}; - - -#define BarrelVtxCount2 57 - -static float BarrelVtx2[] = { -0.0f,-0.5f,0.0f, 0.0f,-1.0f,0.0f, -0.282362f,-0.5f,-0.205148f, 0.0f,-1.0f,0.0f, -0.349018f,-0.5f,0.0f, 0.0f,-1.0f,0.0f, -0.107853f,-0.5f,-0.331936f, 0.0f,-1.0f,0.0f, --0.107853f,-0.5f,-0.331936f, 0.0f,-1.0f,0.0f, -0.107853f,-0.5f,-0.331936f, 0.0f,-1.0f,0.0f, --0.282362f,-0.5f,-0.205148f, 0.0f,-1.0f,0.0f, --0.349018f,-0.5f,0.0f, 0.0f,-1.0f,0.0f, --0.282362f,-0.5f,0.205148f, 0.0f,-1.0f,0.0f, --0.107853f,-0.5f,0.331936f, 0.0f,-1.0f,0.0f, -0.107853f,-0.5f,0.331936f, 0.0f,-1.0f,0.0f, -0.282362f,-0.5f,0.205148f, 0.0f,-1.0f,0.0f, -0.0f,0.5f,0.0f, 0.0f,1.0f,0.0f, -0.349018f,0.5f,0.0f, 0.0f,1.0f,0.0f, -0.282362f,0.5f,-0.205148f, 0.0f,1.0f,0.0f, -0.107853f,0.5f,-0.331936f, 0.0f,1.0f,0.0f, -0.107853f,0.5f,-0.331936f, 0.0f,1.0f,0.0f, --0.107853f,0.5f,-0.331936f, 0.0f,1.0f,0.0f, --0.282362f,0.5f,-0.205148f, 0.0f,1.0f,0.0f, --0.349018f,0.5f,0.0f, 0.0f,1.0f,0.0f, --0.282362f,0.5f,0.205148f, 0.0f,1.0f,0.0f, --0.107853f,0.5f,0.331936f, 0.0f,1.0f,0.0f, -0.107853f,0.5f,0.331936f, 0.0f,1.0f,0.0f, -0.282362f,0.5f,0.205148f, 0.0f,1.0f,0.0f, -0.349018f,-0.5f,0.0f, 0.957307f,-0.289072f,0.0f, -0.404509f,0.0f,-0.293893f, 0.809017f,0.0f,-0.587785f, -0.5f,0.0f,0.0f, 1.0f,0.0f,0.0f, -0.282362f,-0.5f,-0.205148f, 0.774478f,-0.289072f,-0.562691f, -0.154508f,0.0f,-0.475528f, 0.309017f,0.0f,-0.951057f, -0.107853f,-0.5f,-0.331936f, 0.295824f,-0.289072f,-0.910453f, -0.107853f,-0.5f,-0.331936f, 0.295824f,-0.289072f,-0.910453f, --0.154509f,0.0f,-0.475528f, -0.309017f,0.0f,-0.951057f, -0.154508f,0.0f,-0.475528f, 0.309017f,0.0f,-0.951057f, --0.107853f,-0.5f,-0.331936f, -0.295824f,-0.289072f,-0.910453f, --0.404509f,0.0f,-0.293893f, -0.809017f,0.0f,-0.587785f, --0.282362f,-0.5f,-0.205148f, -0.774478f,-0.289072f,-0.562691f, --0.5f,0.0f,0.0f, -1.0f,0.0f,0.0f, --0.349018f,-0.5f,0.0f, -0.957307f,-0.289072f,0.0f, --0.404508f,0.0f,0.293893f, -0.809017f,0.0f,0.587785f, --0.282362f,-0.5f,0.205148f, -0.774478f,-0.289072f,0.562691f, --0.154509f,0.0f,0.475528f, -0.309017f,0.0f,0.951056f, --0.107853f,-0.5f,0.331936f, -0.295824f,-0.289072f,0.910453f, -0.154509f,0.0f,0.475528f, 0.309017f,0.0f,0.951056f, -0.107853f,-0.5f,0.331936f, 0.295824f,-0.289072f,0.910453f, -0.404509f,0.0f,0.293892f, 0.809017f,0.0f,0.587785f, -0.282362f,-0.5f,0.205148f, 0.774478f,-0.289072f,0.562691f, -0.282362f,0.5f,-0.205148f, 0.774478f,0.289072f,-0.562691f, -0.349018f,0.5f,0.0f, 0.957307f,0.289072f,0.0f, -0.107853f,0.5f,-0.331936f, 0.295824f,0.289072f,-0.910453f, --0.107853f,0.5f,-0.331936f, -0.295824f,0.289072f,-0.910453f, -0.107853f,0.5f,-0.331936f, 0.295824f,0.289072f,-0.910453f, --0.282362f,0.5f,-0.205148f, -0.774478f,0.289072f,-0.562691f, --0.349018f,0.5f,0.0f, -0.957307f,0.289072f,0.0f, --0.282362f,0.5f,0.205148f, -0.774478f,0.289072f,0.562691f, --0.107853f,0.5f,0.331936f, -0.295824f,0.289072f,0.910453f, -0.107853f,0.5f,0.331936f, 0.295824f,0.289072f,0.910453f, -0.282362f,0.5f,0.205148f, 0.774478f,0.289072f,0.562691f, -}; - - -static int BarrelIdx[] = { -0,1,2, -0,3,1, -0,4,5, -0,6,4, -0,7,6, -0,8,7, -0,9,8, -0,10,9, -0,11,10, -0,2,11, -12,13,14, -12,14,15, -12,16,17, -12,17,18, -12,18,19, -12,19,20, -12,20,21, -12,21,22, -12,22,23, -12,23,13, -24,25,26, -24,27,25, -27,28,25, -27,29,28, -30,31,32, -30,33,31, -33,34,31, -33,35,34, -35,36,34, -35,37,36, -37,38,36, -37,39,38, -39,40,38, -39,41,40, -41,42,40, -41,43,42, -43,44,42, -43,45,44, -45,26,44, -45,24,26, -26,46,47, -26,25,46, -25,48,46, -25,28,48, -32,49,50, -32,31,49, -31,51,49, -31,34,51, -34,52,51, -34,36,52, -36,53,52, -36,38,53, -38,54,53, -38,40,54, -40,55,54, -40,42,55, -42,56,55, -42,44,56, -44,47,56, -44,26,47, -}; - - -__inline void glVertexFloat4( const float4& v ) -{ - glVertex3f( v.x, v.y, v.z ); -} - -__inline void drawPointListTransformed(const float4* vtx, int nVtx, const float4& translation, const Quaternion& quat) -{ - glPushMatrix(); - - Matrix3x3 rotMat = mtTranspose( qtGetRotationMatrix( quat ) ); - float transformMat[16] = - { - rotMat.m_row[0].x, rotMat.m_row[0].y, rotMat.m_row[0].z, 0, - rotMat.m_row[1].x, rotMat.m_row[1].y, rotMat.m_row[1].z, 0, - rotMat.m_row[2].x, rotMat.m_row[2].y, rotMat.m_row[2].z, 0, - translation.x, translation.y, translation.z,1 - }; - - glMultMatrixf( transformMat ); - - float4 c = make_float4(1,1,0,0); - - glPointSize(3.f); - glBegin(GL_POINTS); - for(int i=0; igetDebugDrawer()->getDebugMode()& btIDebugDraw::DBG_DrawContactPoints) - for (int i=0;igetCollisionObjectArray().size();i++) - { - btCollisionObject* ob = m_dynamicsWorld->getCollisionObjectArray()[i]; - if (ob->getCollisionShape()->getShapeType() == CUSTOM_POLYHEDRAL_SHAPE_TYPE) - { - CustomConvexShape* customConvex = (CustomConvexShape*)ob->getCollisionShape(); - ConvexHeightField* cvxShape= customConvex->m_ConvexHeightField; - if (!cvxShape) - { - printf("aargh\n"); - } - - float4 bodyApos; - Quaternion bodyAquat; - - - const btVector3& pA = ob->getWorldTransform().getOrigin(); - btQuaternion qA = ob->getWorldTransform().getRotation(); - - bodyApos.x = pA.getX(); - bodyApos.y = pA.getY(); - bodyApos.z = pA.getZ(); - bodyApos.w = 0.f; - bodyAquat.x = qA.getX(); - bodyAquat.y = qA.getY(); - bodyAquat.z = qA.getZ(); - bodyAquat.w = qA.getW(); - - - displaySamples(cvxShape->getSamplePoints(),cvxShape->getNumSamplePoints(),bodyApos,bodyAquat); - - } - - } -} -void BasicDemo::clientMoveAndDisplay() -{ - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - //simple dynamics world doesn't handle fixed-time-stepping - float ms = getDeltaTimeMicroseconds(); - - ///step the simulation - if (m_dynamicsWorld) - { - m_dynamicsWorld->stepSimulation(ms / 1000000.f); - //optional but useful: debug drawing - m_dynamicsWorld->debugDrawWorld(); - } - - renderme(); - - renderSurfacePoints(); - - - glFlush(); - - swapBuffers(); - -} - - - -void BasicDemo::displayCallback(void) { - - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - renderme(); - - renderSurfacePoints(); - - //optional but useful: debug drawing to detect problems - if (m_dynamicsWorld) - m_dynamicsWorld->debugDrawWorld(); - - glFlush(); - swapBuffers(); -} - - - - - -void BasicDemo::initPhysics() -{ - setTexturing(true); - setShadows(true); - - m_acceleratedRigidBodies = 0; - - setCameraDistance(btScalar(SCALING*20.)); - - ///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); - - -#ifdef CL_PLATFORM_AMD - m_dispatcher = new CustomCollisionDispatcher(m_collisionConfiguration, g_cxMainContext,g_clDevice,g_cqCommandQue); -#else - m_dispatcher = new CustomCollisionDispatcher(m_collisionConfiguration); -#endif - - m_dispatcher->registerCollisionCreateFunc(CUSTOM_POLYHEDRAL_SHAPE_TYPE,CUSTOM_POLYHEDRAL_SHAPE_TYPE,new CustomConvexConvexPairCollision::CreateFunc(m_collisionConfiguration->getSimplexSolver(), m_collisionConfiguration->getPenetrationDepthSolver())); - - 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->setGravity(btVector3(0,-10,0)); - - m_dynamicsWorld->setDebugDrawer(&sDebugDraw); - - ///create a few basic rigid bodies - //btCollisionShape* groundShape = new btBoxShape(btVector3(btScalar(50.),btScalar(50.),btScalar(50.))); -#if 1 - CustomConvexShape* groundShape = new CustomConvexShape(BoxVtx2,BoxVtxCount,3*sizeof(float)); - //btCollisionShape* groundShape = new btStaticPlaneShape(btVector3(0,1,0),0); - - m_collisionShapes.push_back(groundShape); - - btTransform groundTransform; - groundTransform.setIdentity(); - groundTransform.setOrigin(btVector3(0,-11,0)); - - //We can also use DemoApplication::localCreateRigidBody, but for clarity it is provided here: - { - btScalar mass(0.); - - //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) - groundShape->calculateLocalInertia(mass,localInertia); - - //using motionstate is recommended, it provides interpolation capabilities, and only synchronizes 'active' objects - btDefaultMotionState* myMotionState = new btDefaultMotionState(groundTransform); - btRigidBody::btRigidBodyConstructionInfo rbInfo(mass,myMotionState,groundShape,localInertia); - btRigidBody* body = new btRigidBody(rbInfo); - - //add the body to the dynamics world - m_dynamicsWorld->addRigidBody(body); - } -#endif - - - { - //create a few dynamic rigidbodies - // Re-using the same collision is better for memory usage and performance - - //btCollisionShape* colShape = new btBoxShape(btVector3(SCALING*1,SCALING*1,SCALING*1)); - //btCollisionShape* colShape = new btSphereShape(btScalar(1.)); -#define USE_CUSTOM_HEIGHTFIELD_SHAPE -#ifdef USE_CUSTOM_HEIGHTFIELD_SHAPE - CustomConvexShape* colShape = new CustomConvexShape(BarrelVtx2,BarrelVtxCount2,6*sizeof(float)); - - //CustomConvexShape* colShape = new CustomConvexShape(BoxVtx,BoxVtxCount,3*sizeof(float)); -#else - btConvexHullShape* colShape = new btConvexHullShape(BarrelVtx2,BarrelVtxCount2,6*sizeof(float)); - colShape->setLocalScaling(btVector3(0.9,0.9,0.9)); - -#endif //USE_CUSTOM_HEIGHTFIELD_SHAPE - btScalar scale = 0.5f; - - //btScalar scale = 1.f; - - //next line is already called inside the CustomConvexShape constructor - //colShape->initializePolyhedralFeatures(); - - m_collisionShapes.push_back(colShape); - - /// Create Dynamic Objects - btTransform startTransform; - startTransform.setIdentity(); - - btScalar mass(1.f); - - //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) - colShape->calculateLocalInertia(mass,localInertia); - - float start_x = START_POS_X - ARRAY_SIZE_X/2; - float start_y = START_POS_Y; - float start_z = START_POS_Z - ARRAY_SIZE_Z/2; - - for (int k=0;k0) && ((j<2) || (j>(ARRAY_SIZE_Z-3)))) - // continue; - // if ((k>0) && ((i<2) || (i>(ARRAY_SIZE_X-3)))) - // continue; - - startTransform.setOrigin(SCALING*btVector3( - btScalar(scale*2.0*i + start_x), - btScalar(scale*1+scale*2.0*k + start_y), - btScalar(scale*2.0*j + start_z))); - - - //using motionstate is recommended, it provides interpolation capabilities, and only synchronizes 'active' objects - btDefaultMotionState* myMotionState = new btDefaultMotionState(startTransform); - btRigidBody* body=0; - - if (0)//k==0) - { - btVector3 zeroInertia(0,0,0); - btRigidBody::btRigidBodyConstructionInfo rbInfo(0.f,myMotionState,colShape,zeroInertia); - body = new btRigidBody(rbInfo); - } else - { - btRigidBody::btRigidBodyConstructionInfo rbInfo(mass,myMotionState,colShape,localInertia); - body = new btRigidBody(rbInfo); - } - - //m_acceleratedRigidBodies is used as a mapping to the accelerated rigid body index - body->setCompanionId(m_acceleratedRigidBodies++); - m_dynamicsWorld->addRigidBody(body); - - } - } - } - } - } - - -} -void BasicDemo::clientResetScene() -{ - exitPhysics(); - initPhysics(); -} - - -void BasicDemo::exitPhysics() -{ - - //cleanup in the reverse order of creation/initialization - - //remove the rigidbodies from the dynamics world and delete them - int 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;j m_collisionShapes; - - btBroadphaseInterface* m_broadphase; - - btCollisionDispatcher* m_dispatcher; - - btConstraintSolver* m_solver; - - btDefaultCollisionConfiguration* m_collisionConfiguration; - - int m_acceleratedRigidBodies; - - public: - - BasicDemo() - { - } - virtual ~BasicDemo() - { - exitPhysics(); - } - void initPhysics(); - - void exitPhysics(); - - virtual void clientMoveAndDisplay(); - - virtual void displayCallback(); - virtual void clientResetScene(); - - static DemoApplication* Create() - { - BasicDemo* demo = new BasicDemo; - demo->myinit(); - demo->initPhysics(); - return demo; - } - - void renderSurfacePoints(); - - -}; - -#endif //BASIC_DEMO_H - diff --git a/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/ConvexHeightFieldShape.cpp b/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/ConvexHeightFieldShape.cpp deleted file mode 100644 index e5e0d649e..000000000 --- a/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/ConvexHeightFieldShape.cpp +++ /dev/null @@ -1,507 +0,0 @@ -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Takahiro Harada - - -#include "ConvexHeightFieldShape.h" -#include "Stubs/AdlCollideUtils.h" -#include "CubeMapUtils.h" -//#include -//#include -//#include "GlutStuff.h" - -//#define USE_OLD - -ConvexHeightField::ConvexHeightField(const float4* vtxBuffer, const int4* idxBuffer, int nTriangles) -: CollisionShape( SHAPE_CONVEX_HEIGHT_FIELD ) -{ - create( vtxBuffer, idxBuffer, nTriangles ); -} - -void ConvexHeightField::create( const float4* vtxBuffer, const int4* idxBuffer, int nTriangles ) -{ - { - float maxDx2 = -1.f; - int maxIdx = -1; - for(int i=0; i maxDx2 ) - { - maxDx2 = dx2; - maxIdx = idx.s[j]; - } - } - } - ADLASSERT( maxIdx != -1 ); - m_scale = sqrtf( maxDx2 ); - } - - // cast ray to find intersectPlaneLineions - { - for(u32 faceIdx=0; faceIdx<6; faceIdx++) - { - for(int i=0; i 0.f ) - { - minFraction = min2( minFraction, fraction ); // todo. have to check if this is the min to replace normal? - float4 ab = vtxBuffer[idxBuffer[itri].y]-vtxBuffer[idxBuffer[itri].x]; - float4 ac = vtxBuffer[idxBuffer[itri].z]-vtxBuffer[idxBuffer[itri].x]; - minNormal = cross3( ab, ac ); - minBCrd = bCrd; - } - } - - if( minFraction == FLT_MAX ) - minFraction = 0.f; - - { - u8 quantizedHeight = (u8)(minFraction*255.f); - sample( (Face)faceIdx, i,j ) = quantizedHeight; - sampleNormal( (Face)faceIdx, i,j ) = normalize3(minNormal); - float minValue = 3.f*(1.f/3.f)*(1.f/3.f); - sampleNormal( (Face)faceIdx, i,j ).w = (dot3F4( minBCrd, minBCrd ) - minValue )/(1.f-minValue); - } - } - } - } - - calcSamplePoints( m_samplePoints ); - - // calc support height using m_samplePoints - { - for(u32 faceIdx=0; faceIdx<6; faceIdx++) for(int i=0; i maxHeight ) maxHeight = h; - } - - { - u8 quantizedHeight = min2((u8)(maxHeight*255.f)+1, 255); - sampleSupport( (Face)faceIdx, i, j ) = quantizedHeight; - } - } - } - - m_aabb.setEmpty(); - for(int i=0; i 0.f ) - { - if( fraction < minFraction ) - { - minFraction = fraction; - minNormal = iEqn; - } - } - } - - ADLASSERT( minFraction != FLT_MAX ); - - minNormal.w = minFraction; - sampleNormal( (Face)faceIdx, i, j ) = minNormal; - } - } - } - - { - m_scale = -FLT_MAX; - for(u32 faceIdx=0; faceIdx<6; faceIdx++) - { - for(int i=0; i1.f) - h=1.f; -// ADLASSERT( h <= 1.f ); - if( h > maxHeight ) maxHeight = h; - } - - { - u8 quantizedHeight = min2((u8)(maxHeight*255.f)+1, 255); - sampleSupport( (Face)faceIdx, i, j ) = quantizedHeight; - } - } - } - - for(int i=0; i<6; i++) - { - m_faceAabbs[i].setEmpty(); - for(int j=0; jm_type == ADL_SHAPE_SPHERE ) - { - SphereShape* sphere = (SphereShape*)shape; - - m_scale = sphere->m_radius; - for(u32 faceIdx=0; faceIdx<6; faceIdx++) - { - for(int i=0; im_radius ); - m_aabb.m_min = make_float4( -sphere->m_radius ); - - m_aabb.expandBy( make_float4( m_collisionMargin ) ); - - for(int i=0; i<6; i++) - { - m_faceAabbs[i].setEmpty(); - for(int j=0; jgetVertexBuffer(), s->getTriangleBuffer(), s->getNumTris() ); - } -} -#endif - -ConvexHeightField::~ConvexHeightField() -{ - -} - -float ConvexHeightField::queryDistance(const float4& p ) const -{ - const float4 majorAxes[] = {make_float4(1,0,0,0), make_float4(0,1,0,0), make_float4(0,0,1,0)}; - - if( dot3F4( p, p ) >= m_scale*m_scale ) return FLT_MAX; - - int faceIdx; - float x, y; - CubeMapUtils::calcCrd( p, faceIdx, x, y ); - x = (x*HEIGHT_RES) - 0.5f; - y = (y*HEIGHT_RES) - 0.5f; - - float height; - { - int xi = (int)(x); - int yi = (int)(y); - float dx = x-xi; - float dy = y-yi; - - { - int xip = min2((int)(HEIGHT_RES-1), xi+1); - int yip = min2((int)(HEIGHT_RES-1), yi+1); - - u8 xy = sample( (Face)faceIdx, xi, yi ); - u8 xpy = sample( (Face)faceIdx, xip, yi ); - u8 xpyp = sample( (Face)faceIdx, xip, yip ); - u8 xyp = sample( (Face)faceIdx, xi, yip ); - - height = (xy*(1.f-dx)+xpy*dx)*(1.f-dy) + (xyp*(1.f-dx)+xpyp*dx)*dy; - height = height/255.f*m_scale; - - height = length3( p ) - height; - } - } - - return height; -} - -float ConvexHeightField::querySupportHeight(const float4& p ) const -{ - const float4 majorAxes[] = {make_float4(1,0,0,0), make_float4(0,1,0,0), make_float4(0,0,1,0)}; - -// if( dot3F4( p, p ) >= m_scale*m_scale ) return FLT_MAX; - - int faceIdx; - float x, y; - CubeMapUtils::calcCrd( p, faceIdx, x, y ); - x = (x*HEIGHT_RES) - 0.5f; - y = (y*HEIGHT_RES) - 0.5f; - - float height; - { - int xi = (int)(x); - int yi = (int)(y); - float dx = x-xi; - float dy = y-yi; - - { - int xip = min2((int)(HEIGHT_RES-1), xi+1); - int yip = min2((int)(HEIGHT_RES-1), yi+1); - - u8 xy = sampleSupport( (Face)faceIdx, xi, yi ); - u8 xpy = sampleSupport( (Face)faceIdx, xip, yi ); - u8 xpyp = sampleSupport( (Face)faceIdx, xip, yip ); - u8 xyp = sampleSupport( (Face)faceIdx, xi, yip ); - - height = max2( xy, max2( xpy, max2( xpyp, xyp ) ) ); - height = height/255.f*m_scale; - } - } - - return height; -} - -float ConvexHeightField::queryW(const float4& p ) const -{ - const float4 majorAxes[] = {make_float4(1,0,0,0), make_float4(0,1,0,0), make_float4(0,0,1,0)}; - - float value; - if( dot3F4( p, p ) >= m_scale*m_scale ) return 0; - - int faceIdx; - float x, y; - CubeMapUtils::calcCrd( p, faceIdx, x, y ); - x = (x*HEIGHT_RES) - 0.5f; - y = (y*HEIGHT_RES) - 0.5f; - - { - int xi = (int)(x); - int yi = (int)(y); - - value = sampleNormal( (Face)faceIdx, xi, yi ).w; - } - return value; -} - -bool ConvexHeightField::queryDistanceWithNormal( const float4& p, float4& normalOut ) const -{ - int faceIdx; - float x, y; - CubeMapUtils::calcCrd( p, faceIdx, x, y ); - x = (x*HEIGHT_RES) - 0.5f; - y = (y*HEIGHT_RES) - 0.5f; - - { - int xi = (int)(x); - int yi = (int)(y); - - normalOut = sampleNormal( (Face)faceIdx, xi, yi ); - } - return true; -} - -void ConvexHeightField::calcSamplePoints(float4* points) const -{ - for(u32 faceIdx=0; faceIdx<6; faceIdx++) - { - for(int i=0; ir2[0])? 1:0; - idx = (r2[2]>r2[idx])? 2:idx; - majorAxis = majorAxes[idx]; - - bool isNeg = dot3F4( p, majorAxis ) < 0.f; - - faceIdxOut = (idx*2+((isNeg)? 0:1)); -//== - float4 abs = make_float4( fabs(p.x), fabs(p.y), fabs(p.z), 0.f ); - - float d; - if( idx == 0 ) - { - x = p.y; - y = p.z; - d = abs.x; - } - else if( idx == 1 ) - { - x = p.z; - y = p.x; - d = abs.y; - } - else - { - x = p.x; - y = p.y; - d = abs.z; - } - - float dInv = (d==0.f)? 0.f: (1.f/d); - x = (x*dInv+1.f)*0.5f; - y = (y*dInv+1.f)*0.5f; - } -} - -__inline -float4 CubeMapUtils::calcVector(int faceIdx, float x, float y) -{ - int dir = faceIdx/2; - float z = (faceIdx%2 == 0)? -1.f:1.f; - - x = x*2.f-1.f; - y = y*2.f-1.f; - - if( dir == 0 ) - { - return make_float4(z, x, y); - } - else if( dir == 1 ) - { - return make_float4(y,z,x); - } - else - { - return make_float4(x,y,z); - } -} - diff --git a/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/CustomCollisionDispatcher.cpp b/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/CustomCollisionDispatcher.cpp deleted file mode 100644 index 762afd2cb..000000000 --- a/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/CustomCollisionDispatcher.cpp +++ /dev/null @@ -1,699 +0,0 @@ -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Erwin Coumans - -#include "CustomCollisionDispatcher.h" -#include "BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h" -#include "BulletCollision/CollisionDispatch/btCollisionObject.h" -#include "CustomConvexShape.h" -#include "CustomConvexPairCollision.h" -#include "LinearMath/btQuickprof.h" - - - -#ifdef CL_PLATFORM_AMD - -#include "Adl/Adl.h" -#include "Stubs/AdlMath.h" -#include "Stubs/AdlContact4.h" -#include "Stubs/AdlQuaternion.h" -#include "Stubs/ChNarrowPhase.h" - -#include "Stubs/Solver.h" - - -struct CustomDispatchData -{ - adl::DeviceCL* m_ddcl; - adl::Device* m_deviceHost; - ShapeDataType m_ShapeBuffer; - - adl::HostBuffer* m_pBufPairsCPU; - adl::Buffer* m_pBufPairsGPU; - adl::Buffer* m_pBufContactOutGPU; - adl::HostBuffer* m_pBufContactOutCPU; - adl::ChNarrowphase::Data* m_Data; - - adl::HostBuffer* m_pBufRBodiesCPU; - adl::Buffer* m_pBufRBodiesGPU; - - adl::Buffer* m_bodyInfoBufferCPU; - adl::Buffer* m_bodyInfoBufferGPU; - - adl::Solver::Data* m_solverDataGPU; - SolverData m_contactCGPU; - void* m_frictionCGPU; - - int m_numAcceleratedShapes; -}; -#endif //CL_PLATFORM_AMD - -CustomCollisionDispatcher::CustomCollisionDispatcher(btCollisionConfiguration* collisionConfiguration -#ifdef CL_PLATFORM_AMD - , cl_context context,cl_device_id device,cl_command_queue queue -#endif //CL_PLATFORM_AMD -):btCollisionDispatcher(collisionConfiguration), -m_internalData(0) -{ -#ifdef CL_PLATFORM_AMD - - if (context && queue) - { - m_internalData = new CustomDispatchData(); - memset(m_internalData,0,sizeof(CustomDispatchData)); - - adl::DeviceUtils::Config cfg; - m_internalData->m_ddcl = new adl::DeviceCL(); - m_internalData->m_ddcl->m_deviceIdx = device; - m_internalData->m_ddcl->m_context = context; - m_internalData->m_ddcl->m_commandQueue = queue; - m_internalData->m_ddcl->m_kernelManager = new adl::KernelManager; - - - m_internalData->m_deviceHost = adl::DeviceUtils::allocate( adl::TYPE_HOST, cfg ); - m_internalData->m_pBufPairsCPU = new adl::HostBuffer(m_internalData->m_deviceHost, MAX_BROADPHASE_COLLISION_CL); - m_internalData->m_pBufContactOutCPU = new adl::HostBuffer(m_internalData->m_deviceHost, MAX_BROADPHASE_COLLISION_CL); - m_internalData->m_pBufRBodiesCPU = new adl::HostBuffer(m_internalData->m_deviceHost, MAX_CONVEX_BODIES_CL); - - m_internalData->m_bodyInfoBufferCPU = new adl::Buffer(m_internalData->m_deviceHost,MAX_CONVEX_BODIES_CL); - m_internalData->m_pBufContactOutGPU = new adl::Buffer(m_internalData->m_ddcl, MAX_BROADPHASE_COLLISION_CL); - m_internalData->m_bodyInfoBufferGPU = new adl::Buffer(m_internalData->m_ddcl,MAX_CONVEX_BODIES_CL); - m_internalData->m_pBufPairsGPU = new adl::Buffer(m_internalData->m_ddcl, MAX_BROADPHASE_COLLISION_CL); - m_internalData->m_solverDataGPU = adl::Solver::allocate( m_internalData->m_ddcl, MAX_BROADPHASE_COLLISION_CL); - m_internalData->m_pBufRBodiesGPU = new adl::Buffer(m_internalData->m_ddcl, MAX_CONVEX_BODIES_CL); - m_internalData->m_Data = adl::ChNarrowphase::allocate(m_internalData->m_ddcl); - m_internalData->m_ShapeBuffer = adl::ChNarrowphase::allocateShapeBuffer(m_internalData->m_ddcl, MAX_CONVEX_SHAPES_CL); - m_internalData->m_numAcceleratedShapes = 0; - - m_internalData->m_contactCGPU = adl::Solver::allocateConstraint4( m_internalData->m_ddcl, MAX_BROADPHASE_COLLISION_CL); - m_internalData->m_frictionCGPU = adl::Solver::allocateFrictionConstraint( m_internalData->m_ddcl, MAX_BROADPHASE_COLLISION_CL); - - } - - - -#endif //CL_PLATFORM_AMD -} - -CustomCollisionDispatcher::~CustomCollisionDispatcher(void) -{ -#ifdef CL_PLATFORM_AMD - if (m_internalData) - { - delete m_internalData->m_pBufPairsCPU; - delete m_internalData->m_pBufPairsGPU; - delete m_internalData->m_pBufContactOutGPU; - delete m_internalData->m_pBufContactOutCPU; - - adl::Solver::deallocateConstraint4( m_internalData->m_contactCGPU ); - adl::Solver::deallocateFrictionConstraint( m_internalData->m_frictionCGPU ); - - - adl::Solver::deallocate(m_internalData->m_solverDataGPU); - - adl::DeviceUtils::deallocate(m_internalData->m_deviceHost); - delete m_internalData->m_ddcl; - delete m_internalData; - } - -#endif //CL_PLATFORM_AMD - -} - - -#ifdef CL_PLATFORM_AMD -#include "BulletDynamics/Dynamics/btRigidBody.h" - -RigidBodyBase::Shape CreateBodyInfo(const btCollisionObject& colObj) -{ - RigidBodyBase::Shape shape; - const btRigidBody* bulletBody = btRigidBody::upcast(&colObj); - if( colObj.isStaticOrKinematicObject() || !bulletBody) - { - - //body.m_quat = qtGetIdentity(); - //body.m_invMass = 0.f; - shape.m_initInvInertia = mtZero(); - shape.m_invInertia = mtZero(); - } - else - { - - btVector3 invLocalInertia = bulletBody->getInvInertiaDiagLocal(); - shape.m_initInvInertia = mtZero(); - shape.m_initInvInertia.m_row[0].x = invLocalInertia.x(); - shape.m_initInvInertia.m_row[1].y = invLocalInertia.y(); - shape.m_initInvInertia.m_row[2].z = invLocalInertia.z(); - - btQuaternion q = colObj.getWorldTransform().getRotation(); - Quaternion qBody; - qBody.x = q.getX(); - qBody.y = q.getY(); - qBody.z = q.getZ(); - qBody.w = q.getW(); - - Matrix3x3 m = qtGetRotationMatrix( qBody); - Matrix3x3 mT = mtTranspose( m ); - shape.m_invInertia = mtMul( mtMul( m, shape.m_initInvInertia ), mT ); - //bulletBody->getInvInertiaTensorWorld(); - - - - - // shape.m_initInvInertia = mtInvert( localInertia ); - } - return shape; -} - -RigidBodyBase::Body CreateRBodyCL(const btCollisionObject& colObj, int shapeIdx) -{ - RigidBodyBase::Body bodyCL; - - - // position - const btVector3& p = colObj.getWorldTransform().getOrigin(); - bodyCL.m_pos.x = p.getX(); - bodyCL.m_pos.y = p.getY(); - bodyCL.m_pos.z = p.getZ(); - bodyCL.m_pos.w = 0.0f; - - // quaternion - btQuaternion q = colObj.getWorldTransform().getRotation(); - bodyCL.m_quat.x = q.getX(); - bodyCL.m_quat.y = q.getY(); - bodyCL.m_quat.z = q.getZ(); - bodyCL.m_quat.w = q.getW(); - - const btRigidBody* bulletBody = btRigidBody::upcast(&colObj); - if( colObj.isStaticOrKinematicObject() || !bulletBody) - { - // linear velocity - bodyCL.m_linVel = make_float4(0.0f, 0.0f, 0.0f); - - // angular velocity - bodyCL.m_angVel = make_float4(0.0f, 0.0f, 0.0f); - bodyCL.m_invMass = 0.f; - } else - { - // linear velocity - const btVector3& lv = bulletBody->getLinearVelocity(); - const btVector3& av = bulletBody->getAngularVelocity(); - - bodyCL.m_linVel = make_float4(lv.x(),lv.y(),lv.z(),0.0f); - // angular velocity - bodyCL.m_angVel = make_float4(av.x(),av.y(),av.z(),0.0f); - bodyCL.m_invMass = bulletBody->getInvMass(); - } - // shape index - bodyCL.m_shapeIdx = shapeIdx; - - - // restituition coefficient - bodyCL.m_restituitionCoeff = colObj.getRestitution(); - - // friction coefficient - bodyCL.m_frictionCoeff = colObj.getFriction(); - - return bodyCL; -} -#endif //CL_PLATFORM_AMD - -void CustomCollisionDispatcher::dispatchAllCollisionPairs(btOverlappingPairCache* pairCache,const btDispatcherInfo& dispatchInfo,btDispatcher* dispatcher) -{ - BT_PROFILE("CustomCollisionDispatcher::dispatchAllCollisionPairs"); - { - btBroadphasePairArray& overlappingPairArray = pairCache->getOverlappingPairArray(); - bool bGPU = (m_internalData != 0); -#ifdef CL_PLATFORM_AMD - if ( !bGPU ) -#endif //CL_PLATFORM_AMD - { - BT_PROFILE("btCollisionDispatcher::dispatchAllCollisionPairs"); - btCollisionDispatcher::dispatchAllCollisionPairs(pairCache,dispatchInfo,dispatcher); - } -#ifdef CL_PLATFORM_AMD - - else - { - { - BT_PROFILE("refreshContactPoints"); - //---------------------------------------------------------------- - // GPU version of convex heightmap narrowphase collision detection - //---------------------------------------------------------------- - for ( int i = 0; i < getNumManifolds(); i++ ) - { - btPersistentManifold* manifold = getManifoldByIndexInternal(i); - - - btCollisionObject* body0 = (btCollisionObject*)manifold->getBody0(); - btCollisionObject* body1 = (btCollisionObject*)manifold->getBody1(); - - manifold->refreshContactPoints(body0->getWorldTransform(),body1->getWorldTransform()); - } - } - - // OpenCL - int nColPairsFromBP = overlappingPairArray.size(); - btAssert(MAX_BROADPHASE_COLLISION_CL >= nColPairsFromBP); - - int maxBodyIndex = -1; - - { - BT_PROFILE("CreateRBodyCL and GPU pairs"); - for ( int i=0; im_pProxy0->m_clientObject; - btCollisionObject* colObj1 = (btCollisionObject*)pair->m_pProxy1->m_clientObject; - - int bodyIndex0 = colObj0->getCompanionId(); - int bodyIndex1 = colObj1->getCompanionId(); - - //keep a one-to-one mapping between Bullet and Adl broadphase pairs - (*m_internalData->m_pBufPairsCPU)[i].x = bodyIndex0; - (*m_internalData->m_pBufPairsCPU)[i].y = bodyIndex1; - - if (bodyIndex0>=0 && bodyIndex1>=0) - { - //create companion shapes (if necessary) - - btAssert(colObj0->getCollisionShape()->getShapeType() == CUSTOM_POLYHEDRAL_SHAPE_TYPE); - btAssert(colObj1->getCollisionShape()->getShapeType() == CUSTOM_POLYHEDRAL_SHAPE_TYPE); - - CustomConvexShape* convexShape0 = (CustomConvexShape*)colObj0->getCollisionShape(); - CustomConvexShape* convexShape1 = (CustomConvexShape*)colObj1->getCollisionShape(); - - if (convexShape0->m_acceleratedCompanionShapeIndex<0) - { - convexShape0->m_acceleratedCompanionShapeIndex = m_internalData->m_numAcceleratedShapes; - adl::ChNarrowphase::setShape(m_internalData->m_ShapeBuffer, convexShape0->m_ConvexHeightField, convexShape0->m_acceleratedCompanionShapeIndex, 0.0f); - m_internalData->m_numAcceleratedShapes++; - } - if (convexShape1->m_acceleratedCompanionShapeIndex<0) - { - convexShape1->m_acceleratedCompanionShapeIndex = m_internalData->m_numAcceleratedShapes; - adl::ChNarrowphase::setShape(m_internalData->m_ShapeBuffer, convexShape1->m_ConvexHeightField, convexShape1->m_acceleratedCompanionShapeIndex, 0.0f); - m_internalData->m_numAcceleratedShapes++; - } - - btAssert(m_internalData->m_numAcceleratedShapesmaxBodyIndex) - maxBodyIndex = bodyIndex0; - if (bodyIndex1>maxBodyIndex) - maxBodyIndex = bodyIndex1; - - btAssert(maxBodyIndex=MAX_CONVEX_BODIES_CL) - { - printf("error: maxBodyIndex(%d)>MAX_CONVEX_BODIES_CL(%d)\n",maxBodyIndex,MAX_CONVEX_BODIES_CL); - } - - (*m_internalData->m_pBufRBodiesCPU)[bodyIndex0] = CreateRBodyCL(*colObj0, convexShape0->m_acceleratedCompanionShapeIndex); - m_internalData->m_bodyInfoBufferCPU->m_ptr[bodyIndex0] = CreateBodyInfo(*colObj0); - (*m_internalData->m_pBufRBodiesCPU)[bodyIndex1] = CreateRBodyCL(*colObj1, convexShape0->m_acceleratedCompanionShapeIndex); - m_internalData->m_bodyInfoBufferCPU->m_ptr[bodyIndex1] = CreateBodyInfo(*colObj1); - } else - { - //TODO: dispatch using default dispatcher - btAssert(0); - } - } - } - - - if (maxBodyIndex>=0) - { - - int numOfConvexRBodies = maxBodyIndex+1; - - - - adl::ChNarrowphaseBase::Config cfgNP; - cfgNP.m_collisionMargin = 0.01f; - int nContactOut = 0; - - { - BT_PROFILE("ChNarrowphase::execute"); - adl::ChNarrowphase::execute(m_internalData->m_Data, m_internalData->m_pBufPairsGPU, nColPairsFromBP, m_internalData->m_pBufRBodiesGPU, m_internalData->m_ShapeBuffer, m_internalData->m_pBufContactOutGPU, nContactOut, cfgNP); - adl::DeviceUtils::waitForCompletion(m_internalData->m_ddcl); - } - - - bool useCpu = false;//true; - bool useSolver = true;//true;//false; - - if (useSolver) - { - float dt=1./60.; - adl::SolverBase::ConstraintCfg csCfg( dt ); - csCfg.m_enableParallelSolve = true; - csCfg.m_averageExtent = 0.2f;//@TODO m_averageObjExtent; - csCfg.m_staticIdx = -1;//numOfConvexRBodies-1;//m_nBodies-1; - - - if (useCpu) - { - - { - BT_PROFILE("read m_pBufContactOutGPU"); - m_internalData->m_pBufContactOutGPU->read(m_internalData->m_pBufContactOutCPU->m_ptr, nContactOut);//MAX_BROADPHASE_COLLISION_CL); - adl::DeviceUtils::waitForCompletion(m_internalData->m_ddcl); - } - - BT_PROFILE("CPU stuff"); - adl::Solver::Data* solverData = adl::Solver::allocate( m_internalData->m_deviceHost, nContactOut); - - SolverData contactCPU = adl::Solver::allocateConstraint4( - m_internalData->m_deviceHost, - numOfConvexRBodies*MAX_PAIRS_PER_BODY_CL ); - - void* frictionCPU = adl::Solver::allocateFrictionConstraint( - m_internalData->m_deviceHost, - numOfConvexRBodies*MAX_PAIRS_PER_BODY_CL ); - - //write body with current linear/angluar velocities to GPU - m_internalData->m_bodyInfoBufferGPU->write(m_internalData->m_bodyInfoBufferCPU->m_ptr,numOfConvexRBodies); - adl::DeviceUtils::waitForCompletion(m_internalData->m_ddcl); - - - if (nContactOut) - { - reorderConvertToConstraints2( - solverData, - m_internalData->m_pBufRBodiesCPU, - m_internalData->m_bodyInfoBufferCPU, - m_internalData->m_pBufContactOutCPU, - contactCPU, - frictionCPU, - nContactOut, - csCfg ); - - bool forceGPU = true; - - if (forceGPU) - { - - SolverData contactCPUcopy = adl::Solver::allocateConstraint4( - m_internalData->m_deviceHost, - numOfConvexRBodies*MAX_PAIRS_PER_BODY_CL ); - - adl::Solver::reorderConvertToConstraints( - m_internalData->m_solverDataGPU, - m_internalData->m_pBufRBodiesGPU, - m_internalData->m_bodyInfoBufferGPU, - m_internalData->m_pBufContactOutGPU, - m_internalData->m_contactCGPU, - m_internalData->m_frictionCGPU, - nContactOut, - csCfg ); - - adl::DeviceUtils::waitForCompletion(m_internalData->m_ddcl); - m_internalData->m_contactCGPU->read(contactCPUcopy->m_ptr,nContactOut); - adl::DeviceUtils::waitForCompletion(m_internalData->m_ddcl); - - - //m_internalData->m_contactCGPU->write(contactCPU->m_ptr,nContactOut); - adl::DeviceUtils::waitForCompletion(m_internalData->m_ddcl); - m_internalData->m_solverDataGPU->m_nIterations = 4; - - adl::Solver::solveContactConstraint( m_internalData->m_solverDataGPU, - m_internalData->m_pBufRBodiesGPU, - m_internalData->m_bodyInfoBufferGPU, - m_internalData->m_contactCGPU, - 0, - nContactOut ); - - adl::DeviceUtils::waitForCompletion( m_internalData->m_ddcl ); - - //read body updated linear/angular velocities back to CPU - m_internalData->m_pBufRBodiesGPU->read( - m_internalData->m_pBufRBodiesCPU->m_ptr,numOfConvexRBodies); - adl::DeviceUtils::waitForCompletion( m_internalData->m_ddcl ); - - } else - { - solverData->m_nIterations = 4; - adl::Solver::solveContactConstraint( solverData, - m_internalData->m_pBufRBodiesCPU, - m_internalData->m_bodyInfoBufferCPU, - contactCPU, - 0, - nContactOut ); - } - - - - } - - adl::Solver::deallocateConstraint4( contactCPU ); - adl::Solver::deallocateFrictionConstraint( frictionCPU ); - adl::Solver::deallocate( solverData ); - - - - } - else - { - - { - BT_PROFILE("rigid body data to GPU buffer"); - // Transfer rigid body data from CPU buffer to GPU buffer - m_internalData->m_pBufRBodiesGPU->write(m_internalData->m_pBufRBodiesCPU->m_ptr, numOfConvexRBodies); - m_internalData->m_pBufPairsGPU->write(m_internalData->m_pBufPairsCPU->m_ptr, MAX_BROADPHASE_COLLISION_CL); - //write body with current linear/angluar velocities to GPU - m_internalData->m_bodyInfoBufferGPU->write(m_internalData->m_bodyInfoBufferCPU->m_ptr,numOfConvexRBodies); - adl::DeviceUtils::waitForCompletion(m_internalData->m_ddcl); - } - { - BT_PROFILE("GPU reorderConvertToConstraints"); - adl::Solver::reorderConvertToConstraints( - m_internalData->m_solverDataGPU, - m_internalData->m_pBufRBodiesGPU, - m_internalData->m_bodyInfoBufferGPU, - m_internalData->m_pBufContactOutGPU, - m_internalData->m_contactCGPU, - m_internalData->m_frictionCGPU, - nContactOut, - csCfg ); - } - - { - BT_PROFILE("GPU solveContactConstraint"); - m_internalData->m_solverDataGPU->m_nIterations = 4; - - adl::Solver::solveContactConstraint( m_internalData->m_solverDataGPU, - m_internalData->m_pBufRBodiesGPU, - m_internalData->m_bodyInfoBufferGPU, - m_internalData->m_contactCGPU, - 0, - nContactOut ); - - adl::DeviceUtils::waitForCompletion( m_internalData->m_ddcl ); - } - { - BT_PROFILE("read body velocities back to CPU"); - //read body updated linear/angular velocities back to CPU - m_internalData->m_pBufRBodiesGPU->read( - m_internalData->m_pBufRBodiesCPU->m_ptr,numOfConvexRBodies); - adl::DeviceUtils::waitForCompletion( m_internalData->m_ddcl ); - } - - - } - -#if 0 - if( !m_useGPUPipeline ) - { // CPU - BT_PROFILE("CPU solve"); - { - BT_PROFILE("CPU reorderConvertToConstraints"); - - SOLVER_CLASS::reorderConvertToConstraints( solver, m_bodyBuffer, m_bodyInfoBufferCPU, (Buffer*)m_contactBuffer, - contactC, frictionC, m_numContacts, csCfg ); - } - { - BT_PROFILE("CPU solveContactConstraint"); - - solver->m_nIterations = 4; - SOLVER_CLASS::solveContactConstraint( solver, m_bodyBuffer, m_bodyInfoBufferCPU, contactC, 0, m_numContacts ); - } - } - else - { - BT_PROFILE("GPU solve"); - { // GPU using host buffers - { - BT_PROFILE("GPU reorderConvertToConstraints"); - - Solver::reorderConvertToConstraints( m_solver, m_bodyBuffer, m_bodyInfoBufferCPU, (Buffer*)m_contactBuffer, - contactC, frictionC, m_numContacts, csCfg ); - } - timerEnd(); - - timerStart(0); - //for(int iter=0; iter<4; iter++) - { - BT_PROFILE("GPU solveContactConstraint"); - - Solver::solveContactConstraint( m_solver, m_bodyBuffer, m_bodyInfoBufferCPU, contactC, frictionC, m_numContacts ); - } - DeviceUtils::waitForCompletion( m_device ); - } - } - timerEnd(); -#endif - - - } - - //if we ran the solver, it will overwrite the batchIdx so we cannot write back the results - //try to make it work by writing velocity back to rigid body - - if (useSolver) - { - - BT_PROFILE("writing velocity back to btRigidBody"); - - for ( int i=0; im_pProxy0->m_clientObject; - btCollisionObject* colObj1 = (btCollisionObject*)pair->m_pProxy1->m_clientObject; - - int bodyIndex0 = colObj0->getCompanionId(); - int bodyIndex1 = colObj1->getCompanionId(); - - RigidBodyBase::Body* bA = &m_internalData->m_pBufRBodiesCPU->m_ptr[bodyIndex0]; - RigidBodyBase::Body* bB = &m_internalData->m_pBufRBodiesCPU->m_ptr[bodyIndex1]; - btRigidBody* bodyA = btRigidBody::upcast(colObj0); - if (bodyA && !bodyA->isStaticOrKinematicObject()) - { - bodyA->setLinearVelocity(btVector3( - bA->m_linVel.x, - bA->m_linVel.y, - bA->m_linVel.z)); - - bodyA->setAngularVelocity(btVector3( - bA->m_angVel.x, - bA->m_angVel.y, - bA->m_angVel.z)); - } - btRigidBody* bodyB = btRigidBody::upcast(colObj1); - if (bodyB && !bodyB->isStaticOrKinematicObject()) - { - bodyB->setLinearVelocity(btVector3( - bB->m_linVel.x, - bB->m_linVel.y, - bB->m_linVel.z)); - bodyB->setAngularVelocity(btVector3( - bB->m_angVel.x, - bB->m_angVel.y, - bB->m_angVel.z)); - - } - - - - - } - } else - { - BT_PROFILE("copy Contact4 to btPersistentManifold"); - // Now we got the narrowphase info from GPU and need to update rigid bodies with the info and go back to the original pipeline in Bullet physics. - for ( int i = 0; i < nContactOut; i++ ) - { - Contact4 contact = (*m_internalData->m_pBufContactOutCPU)[i]; - - int idxBodyA = contact.m_bodyAPtr; - int idxBodyB = contact.m_bodyBPtr; - - btAssert(contact.m_batchIdx>=0); - btAssert(contact.m_batchIdxm_pProxy0->m_clientObject; - btCollisionObject* colObj1 = (btCollisionObject*)pair->m_pProxy1->m_clientObject; - - if (!pair->m_algorithm) - { - pair->m_algorithm = findAlgorithm(colObj0,colObj1,0); - } - - btManifoldResult contactPointResult(colObj0, colObj1); - - - CustomConvexConvexPairCollision* pairAlgo = (CustomConvexConvexPairCollision*) pair->m_algorithm; - - if (!pairAlgo->getManifoldPtr()) - { - pairAlgo->createManifoldPtr(colObj0,colObj1,dispatchInfo); - } - - contactPointResult.setPersistentManifold(pairAlgo->getManifoldPtr()); - - contactPointResult.getPersistentManifold()->refreshContactPoints(colObj0->getWorldTransform(),colObj1->getWorldTransform()); - - const btTransform& transA = colObj0->getWorldTransform(); - const btTransform& transB = colObj1->getWorldTransform(); - - int numPoints = contact.getNPoints(); - - for ( int k=0; k < numPoints; k++ ) - { - btVector3 normalOnBInWorld( - contact.m_worldNormal.x, - contact.m_worldNormal.y, - contact.m_worldNormal.z); - btVector3 pointInWorldOnB( - contact.m_worldPos[k].x, - contact.m_worldPos[k].y, - contact.m_worldPos[k].z); - - btScalar depth = contact.m_worldPos[k].w; - - if (depth<0) - { - const btVector3 deltaC = transB.getOrigin() - transA.getOrigin(); - - normalOnBInWorld.normalize(); - - if((deltaC.dot(normalOnBInWorld))>0.0f) - { - normalOnBInWorld= -normalOnBInWorld; - - contactPointResult.addContactPoint(normalOnBInWorld, pointInWorldOnB, depth); - } - else - { - contactPointResult.addContactPoint(normalOnBInWorld, pointInWorldOnB-normalOnBInWorld*depth, depth); - } - } - } - } - } - } - } -#endif //CL_PLATFORM_AMD - } - -} - diff --git a/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/CustomCollisionDispatcher.h b/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/CustomCollisionDispatcher.h deleted file mode 100644 index 315a4ba48..000000000 --- a/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/CustomCollisionDispatcher.h +++ /dev/null @@ -1,70 +0,0 @@ -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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 CUSTOM_COLLISION_DISPATCHER_H -#define CUSTOM_COLLISION_DISPATCHER_H - - -#include "BulletCollision/CollisionDispatch/btCollisionDispatcher.h" -#include "BulletCollision/BroadphaseCollision/btOverlappingPairCache.h" - - -#define MAX_CONVEX_BODIES_CL 64*1024 -#define MAX_PAIRS_PER_BODY_CL 32 -#define MAX_CONVEX_SHAPES_CL 8192 -#define MAX_BROADPHASE_COLLISION_CL (MAX_CONVEX_BODIES_CL*MAX_PAIRS_PER_BODY_CL) - - - -struct CustomDispatchData; - -#ifdef CL_PLATFORM_AMD -#ifdef __APPLE__ - #ifdef USE_MINICL - #include - #else - #include - #endif -#else //__APPLE__ - #ifdef USE_MINICL - #include - #else - #include - #endif -#endif //__APPLE__ -#endif - -class CustomCollisionDispatcher : public btCollisionDispatcher -{ -public: - CustomCollisionDispatcher (btCollisionConfiguration* collisionConfiguration -#ifdef CL_PLATFORM_AMD - , cl_context context = NULL,cl_device_id device = NULL,cl_command_queue queue = NULL -#endif //CL_PLATFORM_AMD - ); - - virtual ~CustomCollisionDispatcher(void); - -protected: - - CustomDispatchData* m_internalData; - - btBroadphasePair* GetPair(btBroadphasePairArray& pairArray, int idxBodyA, int idxBodyB); - -public: - virtual void dispatchAllCollisionPairs(btOverlappingPairCache* pairCache,const btDispatcherInfo& dispatchInfo,btDispatcher* dispatcher); -}; - -#endif //CUSTOM_COLLISION_DISPATCHER_H diff --git a/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/CustomConvexPairCollision.cpp b/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/CustomConvexPairCollision.cpp deleted file mode 100644 index d0fd32c31..000000000 --- a/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/CustomConvexPairCollision.cpp +++ /dev/null @@ -1,409 +0,0 @@ -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Erwin Coumans - -#include "CustomConvexPairCollision.h" -#include "ConvexHeightFieldShape.h" -#include "CustomConvexShape.h" -#include "BulletCollision/CollisionDispatch/btCollisionObject.h" -#include "Stubs/AdlContact4.h" -#include "Stubs/AdlTransform.h" - - -CustomConvexConvexPairCollision::CustomConvexConvexPairCollision(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* body0,btCollisionObject* body1, btSimplexSolverInterface* simplexSolver, btConvexPenetrationDepthSolver* pdSolver, int numPerturbationIterations, int minimumPointsPerturbationThreshold) -:btConvexConvexAlgorithm(mf,ci,body0,body1,simplexSolver,pdSolver,numPerturbationIterations, minimumPointsPerturbationThreshold) -{ - -} - -CustomConvexConvexPairCollision::~CustomConvexConvexPairCollision() -{ - -} - - -#include - -template -T atomAdd(const T* ptr, int value) -{ - return (T)InterlockedExchangeAdd((LONG*)ptr, value); -} - - - -#define PARALLEL_SUM(v, n) for(int j=1; j v[i+offset].y)? v[i]: v[i+offset]; } -#define REDUCE_MIN(v, n) {int i=0;\ - for(int offset=0; offset a[ie].x )? a[0].x: a[ie].x; - a[0].y = (a[0].y > a[ie].y )? a[0].y: a[ie].y; - a[0].z = (a[0].z > a[ie].z )? a[0].z: a[ie].z; - a[0].w = (a[0].w > a[ie].w )? a[0].w: a[ie].w; - } - - idx[0] = (int)a[0].x & 0xff; - idx[1] = (int)a[0].y & 0xff; - idx[2] = (int)a[0].z & 0xff; - idx[3] = (int)a[0].w & 0xff; - } - } - - { - float2 h[64]; - PARALLEL_DO( h[ie] = make_float2((float)ie, p[ie].w), nPoints ); - REDUCE_MIN( h, nPoints ); - max00 = h[0]; - } - } - - contactIdx[0] = idx[0]; - contactIdx[1] = idx[1]; - contactIdx[2] = idx[2]; - contactIdx[3] = idx[3]; - -// if( max00.y < 0.0f ) -// contactIdx[0] = (int)max00.x; - - std::sort( contactIdx, contactIdx+4 ); - - return 4; - } -} - -#undef PARALLEL_SUM -#undef PARALLEL_DO -#undef REDUCE_MAX -#undef REDUCE_MIX - -int collideStraight(const ConvexHeightField* shapeA,const ConvexHeightField* shapeB, - const float4& bodyApos, Quaternion& bodyAquat,const float4& bodyBpos,const Quaternion& bodyBquat, - ContactPoint4* contactsOut, int& numContacts, int contactCapacity, - float collisionMargin ) -{ -// Stopwatch sw; - - Transform trA; - trA = trSetTransform(bodyApos,bodyAquat); - Transform trB; - trB = trSetTransform(bodyBpos, bodyBquat); - - Transform B2A; - { - Transform invTrA = trInvert( trA ); - B2A = trMul( invTrA, trB ); - } - - int nContacts = 0; - { // testB against A - float4 p[ConvexHeightField::HEIGHT_RES*ConvexHeightField::HEIGHT_RES*6]; - int nHits = 0; - - const float4* pInB = shapeB->getSamplePoints(); - - float4 baInB = qtInvRotate( bodyBquat, bodyApos - bodyBpos ); - if( shapeA->m_type == CollisionShape::SHAPE_HEIGHT_FIELD ) - baInB = make_float4(0,0,0,0); - -// sw.start(); - for(int iface=0; iface<6; iface++) - { - Aabb aabb = shapeB->m_faceAabbs[iface]; - - aabb.transform( B2A.m_translation, B2A.m_rotation ); - - if( !shapeA->m_aabb.overlaps( aabb ) ) continue; - - for(int ip=0; ipm_aabb.overlaps( pInA ) ) - { -// Stopwatch sw1; -// sw1.start(); - float dist = shapeA->queryDistance( pInA ); -// sw1.stop(); -// m_times[TIME_SAMPLE] += sw1.getMs(); - - if( dist < collisionMargin ) - { - p[nHits] = make_float4(pInA.x, pInA.y, pInA.z, dist); - nHits++; - } - } - } - } -// sw.stop(); -// m_times[TIME_TEST] += sw.getMs(); - -// sw.start(); - if( nHits ) - { - float4 ab = bodyBpos - bodyApos; - ab = qtInvRotate( bodyAquat, ab ); - if( shapeA->m_type == CollisionShape::SHAPE_HEIGHT_FIELD ) - { - //todo. sample normal from height field but just fake here - ab = make_float4(0,1,0,0); - } - - int cIdx[4]; - float4 center; - - nContacts = extractManifold( p, nHits, ab, center, cIdx ); - - float4 contactNormal; - { - shapeA->queryDistanceWithNormal( center, contactNormal ); - contactNormal = normalize3( contactNormal ); - -// u32 cmp = u8vCompress( contactNormal ); -// contactNormal = make_float4( u8vGetX(cmp), u8vGetY(cmp), u8vGetZ(cmp), 0 ); - } - - int writeIdx = atomAdd( &numContacts, 1 ); - if( writeIdx+1 < contactCapacity ) - { - ContactPoint4& c = contactsOut[writeIdx]; - nContacts = min2( nContacts, 4 ); - for(int i=0; igetNewManifold(body0,body1); - m_ownManifold = true; -} - - -void CustomConvexConvexPairCollision::processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) -{ -#if 1 - if (!m_manifoldPtr) - { - //swapped? - m_manifoldPtr = m_dispatcher->getNewManifold(body0,body1); - m_ownManifold = true; - } - resultOut->setPersistentManifold(m_manifoldPtr); - - - CustomConvexShape* convex0 = (CustomConvexShape*)body0->getCollisionShape(); - CustomConvexShape* convex1 = (CustomConvexShape*)body1->getCollisionShape(); - - - float4 bodyApos; - float4 bodyBpos; - Quaternion bodyAquat; - Quaternion bodyBquat; - - const btTransform& transA = body0->getWorldTransform(); - const btTransform& transB = body1->getWorldTransform(); - - const btVector3& pA = body0->getWorldTransform().getOrigin(); - const btVector3& pB = body1->getWorldTransform().getOrigin(); - - btQuaternion qA = body0->getWorldTransform().getRotation(); - btQuaternion qB = body1->getWorldTransform().getRotation(); - - bodyApos.x = pA.getX(); - bodyApos.y = pA.getY(); - bodyApos.z = pA.getZ(); - bodyApos.w = 0.f; - - bodyBpos.x = pB.getX(); - bodyBpos.y = pB.getY(); - bodyBpos.z = pB.getZ(); - bodyBpos.w = 0.f; - - bodyAquat.x = qA.getX(); - bodyAquat.y = qA.getY(); - bodyAquat.z = qA.getZ(); - bodyAquat.w = qA.getW(); - - bodyBquat.x = qB.getX(); - bodyBquat.y = qB.getY(); - bodyBquat.z = qB.getZ(); - bodyBquat.w = qB.getW(); - - -#define CAPACITY_CONTACTS 4 - - ContactPoint4 contactsOut[CAPACITY_CONTACTS]; - int freeContactIndex = 0; - int contactCapacity = CAPACITY_CONTACTS; - float collisionMargin = 0.001f; - - m_manifoldPtr->refreshContactPoints(body0->getWorldTransform(),body1->getWorldTransform()); - - collideStraight(convex0->m_ConvexHeightField,convex1->m_ConvexHeightField, - bodyApos, bodyAquat,bodyBpos,bodyBquat, - contactsOut, freeContactIndex, contactCapacity, - collisionMargin ); - collideStraight(convex1->m_ConvexHeightField,convex0->m_ConvexHeightField, - bodyBpos, bodyBquat,bodyApos,bodyAquat, - contactsOut, freeContactIndex, contactCapacity, - collisionMargin ); - - //copy points into manifold - //refresh manifold - - btAssert(freeContactIndex<3); - for (int j=0;j0.0f) - { - normalOnBInWorld= -normalOnBInWorld; - } - normalOnBInWorld.normalize(); - if (j) - { - resultOut->addContactPoint(normalOnBInWorld, pointInWorldOnB, depth); - } else - { - resultOut->addContactPoint(normalOnBInWorld, pointInWorldOnB-normalOnBInWorld*depth, depth); - } - } - } - } -#else - btConvexConvexAlgorithm::processCollision(body0,body1,dispatchInfo,resultOut); -#endif -} - - - -CustomConvexConvexPairCollision::CreateFunc::CreateFunc(btSimplexSolverInterface* simplexSolver, btConvexPenetrationDepthSolver* pdSolver) -:btConvexConvexAlgorithm::CreateFunc(simplexSolver,pdSolver) -{ -} - -CustomConvexConvexPairCollision::CreateFunc::~CreateFunc() -{ - -} \ No newline at end of file diff --git a/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/CustomConvexPairCollision.h b/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/CustomConvexPairCollision.h deleted file mode 100644 index bd3a085ca..000000000 --- a/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/CustomConvexPairCollision.h +++ /dev/null @@ -1,56 +0,0 @@ -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Erwin Coumans - -#ifndef CUSTOM_CONVEX_CONVEX_PAIR_COLLISION_H -#define CUSTOM_CONVEX_CONVEX_PAIR_COLLISION_H - - -#include "BulletCollision/CollisionDispatch/btConvexConvexAlgorithm.h" - -class CustomConvexConvexPairCollision : public btConvexConvexAlgorithm -{ - public: - - CustomConvexConvexPairCollision(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* body0,btCollisionObject* body1, btSimplexSolverInterface* simplexSolver, btConvexPenetrationDepthSolver* pdSolver, int numPerturbationIterations, int minimumPointsPerturbationThreshold); - virtual ~CustomConvexConvexPairCollision(); - - virtual void processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); - - btPersistentManifold* getManifoldPtr() - { - return m_manifoldPtr; - } - - void createManifoldPtr(btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo); - - struct CreateFunc :public btConvexConvexAlgorithm::CreateFunc - { - - CreateFunc(btSimplexSolverInterface* simplexSolver, btConvexPenetrationDepthSolver* pdSolver); - - virtual ~CreateFunc(); - - virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1) - { - void* mem = ci.m_dispatcher1->allocateCollisionAlgorithm(sizeof(CustomConvexConvexPairCollision)); - return new(mem) CustomConvexConvexPairCollision(ci.m_manifold,ci,body0,body1,m_simplexSolver,m_pdSolver,m_numPerturbationIterations,m_minimumPointsPerturbationThreshold); - } - }; - - -}; - - -#endif //CUSTOM_CONVEX_CONVEX_PAIR_COLLISION_H diff --git a/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/CustomConvexShape.cpp b/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/CustomConvexShape.cpp deleted file mode 100644 index de7d74dfa..000000000 --- a/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/CustomConvexShape.cpp +++ /dev/null @@ -1,45 +0,0 @@ -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Erwin Coumans - -#include "CustomConvexShape.h" -#include "ConvexHeightFieldShape.h" -#include "BulletCollision/CollisionShapes/btConvexPolyhedron.h" - - -CustomConvexShape::CustomConvexShape(const btScalar* points,int numPoints, int stride) -:btConvexHullShape(points,numPoints,stride), -m_acceleratedCompanionShapeIndex(-1) -{ - m_shapeType = CUSTOM_POLYHEDRAL_SHAPE_TYPE; - - initializePolyhedralFeatures(); - int numFaces= m_polyhedron->m_faces.size(); - float4* eqn = new float4[numFaces]; - for (int i=0;im_faces[i].m_plane[0]; - eqn[i].y = m_polyhedron->m_faces[i].m_plane[1]; - eqn[i].z = m_polyhedron->m_faces[i].m_plane[2]; - eqn[i].w = m_polyhedron->m_faces[i].m_plane[3]; - } - - m_ConvexHeightField = new ConvexHeightField(eqn,numFaces); - -} - -CustomConvexShape::~CustomConvexShape() -{ - delete m_ConvexHeightField; -} \ No newline at end of file diff --git a/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/CustomConvexShape.h b/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/CustomConvexShape.h deleted file mode 100644 index a514c94e8..000000000 --- a/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/CustomConvexShape.h +++ /dev/null @@ -1,35 +0,0 @@ -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Erwin Coumans - -#ifndef CUSTOM_CONVEX_SHAPE_H -#define CUSTOM_CONVEX_SHAPE_H - -#include "BulletCollision/CollisionShapes/btConvexHullShape.h" - -class CustomConvexShape : public btConvexHullShape -{ - public: - - class ConvexHeightField* m_ConvexHeightField; - - int m_acceleratedCompanionShapeIndex; - - CustomConvexShape(const btScalar* points,int numPoints,int stride); - virtual ~CustomConvexShape(); - -}; - -#endif //CUSTOM_CONVEX_SHAPE_H - diff --git a/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/AdlAabb.cpp b/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/AdlAabb.cpp deleted file mode 100644 index e69de29bb..000000000 diff --git a/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/AdlAabb.h b/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/AdlAabb.h deleted file mode 100644 index 0c6709020..000000000 --- a/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/AdlAabb.h +++ /dev/null @@ -1,230 +0,0 @@ -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Takahiro Harada - -#ifndef AABB_H -#define AABB_H - -#include "Stubs/AdlMath.h" -#include "Stubs/AdlQuaternion.h" - -enum AdlCollisionShapeTypes -{ - ADL_SHAPE_SPHERE=2, - ADL_SHAPE_HEIGHT_FIELD, - SHAPE_CONVEX_HEIGHT_FIELD, -}; - -_MEM_CLASSALIGN16 -struct Aabb -{ - public: - _MEM_ALIGNED_ALLOCATOR16; - - __inline - void setEmpty(); - __inline - void includeVolume( const Aabb& aabb ); - __inline - void includePoint( const float4& p ); - __inline - bool overlaps( const float4& p ) const; - __inline - bool overlaps( const Aabb& aabb ) const; - __inline - float4 center() const; - __inline - int getMajorAxis() const; - __inline - float4 getExtent() const; - __inline - void expandBy( const float4& r ); - - __inline - static bool overlaps( const Aabb& a, const Aabb& b ); - - __inline - bool intersect(const float4* from, const float4* to, const float4* invRay) const; - - __inline - void transform(const float4& translation, const Quaternion& quat); - - __inline - void transform(const float4& translation, const Matrix3x3& rot); - - public: - float4 m_max; - float4 m_min; -}; - -void Aabb::setEmpty() -{ - m_max = make_float4( -FLT_MAX ); - m_min = make_float4( FLT_MAX ); -} - -void Aabb::includeVolume(const Aabb& aabb) -{ - m_max.x = max2( m_max.x, aabb.m_max.x ); - m_min.x = min2( m_min.x, aabb.m_min.x ); - - m_max.y = max2( m_max.y, aabb.m_max.y ); - m_min.y = min2( m_min.y, aabb.m_min.y ); - - m_max.z = max2( m_max.z, aabb.m_max.z ); - m_min.z = min2( m_min.z, aabb.m_min.z ); -} - -void Aabb::includePoint( const float4& p ) -{ - m_max.x = max2( m_max.x, p.x ); - m_min.x = min2( m_min.x, p.x ); - - m_max.y = max2( m_max.y, p.y ); - m_min.y = min2( m_min.y, p.y ); - - m_max.z = max2( m_max.z, p.z ); - m_min.z = min2( m_min.z, p.z ); -} - -bool Aabb::overlaps( const float4& p ) const -{ - float4 dx = m_max-p; - float4 dm = p-m_min; - - return (dx.x >= 0 && dx.y >= 0 && dx.z >= 0) - && (dm.x >= 0 && dm.y >= 0 && dm.z >= 0); -} - -bool Aabb::overlaps( const Aabb& in ) const -{ -/* - if( m_max.x < in.m_min.x || m_min.x > in.m_max.x ) return false; - if( m_max.y < in.m_min.y || m_min.y > in.m_max.y ) return false; - if( m_max.z < in.m_min.z || m_min.z > in.m_max.z ) return false; - - return true; -*/ - return overlaps( *this, in ); -} - -bool Aabb::overlaps( const Aabb& a, const Aabb& b ) -{ - if( a.m_max.x < b.m_min.x || a.m_min.x > b.m_max.x ) return false; - if( a.m_max.y < b.m_min.y || a.m_min.y > b.m_max.y ) return false; - if( a.m_max.z < b.m_min.z || a.m_min.z > b.m_max.z ) return false; - - return true; -} - -float4 Aabb::center() const -{ - return 0.5f*(m_max+m_min); -} - -int Aabb::getMajorAxis() const -{ - float4 extent = getExtent(); - - int majorAxis = 0; - if( extent.s[1] > extent.s[0] ) - majorAxis = 1; - if( extent.s[2] > extent.s[majorAxis] ) - majorAxis = 2; - - return majorAxis; -} - -float4 Aabb::getExtent() const -{ - return m_max-m_min; -} - -void Aabb::expandBy( const float4& r ) -{ - m_max += r; - m_min -= r; -} - -bool Aabb::intersect(const float4* from, const float4* to, const float4* invRay) const -{ - float4 dFar; - dFar = (m_max - *from); - dFar *= *invRay; - float4 dNear; - dNear = (m_min - *from); - dNear *= *invRay; - - float4 tFar; - tFar = max2(dFar, dNear); - float4 tNear; - tNear = min2(dFar, dNear); - - float farf[] = { tFar.x, tFar.y, tFar.z }; - - float nearf[] = { tNear.x, tNear.y, tNear.z }; - - float minFar = min2(farf[0], min2(farf[1], farf[2])); - float maxNear = max2(nearf[0], max2(nearf[1], nearf[2])); - - minFar = min2(1.0f, minFar ); - maxNear = max2(0.0f, maxNear); - - return (minFar >= maxNear); -} - -void Aabb::transform(const float4& translation, const Matrix3x3& m) -{ - float4 c = center(); - - Aabb& ans = *this; - - float4 e[] = { m.m_row[0]*m_min, m.m_row[1]*m_min, m.m_row[2]*m_min }; - float4 f[] = { m.m_row[0]*m_max, m.m_row[1]*m_max, m.m_row[2]*m_max }; - ans.m_max = ans.m_min = translation; - - { int j=0; - float4 mi = make_float4( min2( e[j].x, f[j].x ), min2( e[j].y, f[j].y ), min2( e[j].z, f[j].z ) ); - float4 ma = make_float4( max2( e[j].x, f[j].x ), max2( e[j].y, f[j].y ), max2( e[j].z, f[j].z ) ); - - ans.m_min.x += mi.x+mi.y+mi.z; - ans.m_max.x += ma.x+ma.y+ma.z; - } - - { int j=1; - float4 mi = make_float4( min2( e[j].x, f[j].x ), min2( e[j].y, f[j].y ), min2( e[j].z, f[j].z ) ); - float4 ma = make_float4( max2( e[j].x, f[j].x ), max2( e[j].y, f[j].y ), max2( e[j].z, f[j].z ) ); - - ans.m_min.y += mi.x+mi.y+mi.z; - ans.m_max.y += ma.x+ma.y+ma.z; - } - - { int j=2; - float4 mi = make_float4( min2( e[j].x, f[j].x ), min2( e[j].y, f[j].y ), min2( e[j].z, f[j].z ) ); - float4 ma = make_float4( max2( e[j].x, f[j].x ), max2( e[j].y, f[j].y ), max2( e[j].z, f[j].z ) ); - - ans.m_min.z += mi.x+mi.y+mi.z; - ans.m_max.z += ma.x+ma.y+ma.z; - } -} - -void Aabb::transform(const float4& translation, const Quaternion& quat) -{ - Matrix3x3 m = qtGetRotationMatrix( quat ); - - transform( translation, m ); -} - -#endif - diff --git a/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/AdlArray.h b/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/AdlArray.h deleted file mode 100644 index e7fe5e3d1..000000000 --- a/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/AdlArray.h +++ /dev/null @@ -1,212 +0,0 @@ -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Takahiro Harada - - -#ifndef ARRAY_H -#define ARRAY_H - -#include -#include -#include -#include - - -template -class Array -{ - public: - __inline - Array(); - __inline - Array(int size); - __inline - ~Array(); - __inline - T& operator[] (int idx); - __inline - const T& operator[] (int idx) const; - __inline - void pushBack(const T& elem); - __inline - void popBack(); - __inline - void clear(); - __inline - void setSize(int size); - __inline - int getSize() const; - __inline - T* begin(); - __inline - const T* begin() const; - __inline - int indexOf(const T& data) const; - __inline - void removeAt(int idx); - __inline - T& expandOne(); - - private: - Array(const Array& a){} - - private: - enum - { - DEFAULT_SIZE = 128, - INCREASE_SIZE = 128, - }; - - T* m_data; - int m_size; - int m_capacity; -}; - -template -Array::Array() -{ - m_size = 0; - m_capacity = DEFAULT_SIZE; -// m_data = new T[ m_capacity ]; - m_data = (T*)_aligned_malloc(sizeof(T)*m_capacity, 16); - for(int i=0; i -Array::Array(int size) -{ - m_size = size; - m_capacity = size; -// m_data = new T[ m_capacity ]; - m_data = (T*)_aligned_malloc(sizeof(T)*m_capacity, 16); - for(int i=0; i -Array::~Array() -{ - if( m_data ) - { -// delete [] m_data; - _aligned_free( m_data ); - m_data = NULL; - } -} - -template -T& Array::operator[](int idx) -{ - CLASSERT(idx -const T& Array::operator[](int idx) const -{ - CLASSERT(idx -void Array::pushBack(const T& elem) -{ - if( m_size == m_capacity ) - { - int oldCap = m_capacity; - m_capacity += INCREASE_SIZE; -// T* s = new T[m_capacity]; - T* s = (T*)_aligned_malloc(sizeof(T)*m_capacity, 16); - memcpy( s, m_data, sizeof(T)*oldCap ); -// delete [] m_data; - _aligned_free( m_data ); - m_data = s; - } - m_data[ m_size++ ] = elem; -} - -template -void Array::popBack() -{ - CLASSERT( m_size>0 ); - m_size--; -} - -template -void Array::clear() -{ - m_size = 0; -} - -template -void Array::setSize(int size) -{ - if( size > m_capacity ) - { - int oldCap = m_capacity; - m_capacity = size; -// T* s = new T[m_capacity]; - T* s = (T*)_aligned_malloc(sizeof(T)*m_capacity, 16); - for(int i=0; i -int Array::getSize() const -{ - return m_size; -} - -template -const T* Array::begin() const -{ - return m_data; -} - -template -T* Array::begin() -{ - return m_data; -} - -template -int Array::indexOf(const T& data) const -{ - for(int i=0; i -void Array::removeAt(int idx) -{ - CLASSERT(idx -T& Array::expandOne() -{ - setSize( m_size+1 ); - return m_data[ m_size-1 ]; -} - -#endif - diff --git a/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/AdlCollideUtils.h b/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/AdlCollideUtils.h deleted file mode 100644 index 84d658318..000000000 --- a/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/AdlCollideUtils.h +++ /dev/null @@ -1,111 +0,0 @@ -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Takahiro Harada - - -#ifndef COLLIDE_UTILS_H -#define COLLIDE_UTILS_H - -#include "Stubs/AdlMath.h" - - -class CollideUtils -{ - public: - template - static bool collide(const float4& a, const float4& b, const float4& c, const float4& p, float4& normalOut, float margin = 0.f); - - __inline - static float castRay(const float4& v0, const float4& v1, const float4& v2, - const float4& rayFrom, const float4& rayTo, float margin = 0.0f, float4* bCrdOut = NULL); - -}; - - -template -bool CollideUtils::collide(const float4& a, const float4& b, const float4& c, const float4& p, float4& normalOut, float margin) -{ - float4 ab, bc, ca; - ab = b-a; - bc = c-b; - ca = a-c; - - float4 ap, bp, cp; - ap = p-a; - bp = p-b; - cp = p-c; - - float4 n; - n = cross3(ab, -1.f*ca); - - float4 abp = cross3( ab, ap ); - float4 bcp = cross3( bc, bp ); - float4 cap = cross3( ca, cp ); - - float s0 = dot3F4(n,abp); - float s1 = dot3F4(n,bcp); - float s2 = dot3F4(n,cap); - -// if(( s0<0.f && s1<0.f && s2<0.f ) || ( s0>0.f && s1>0.f && s2>0.f )) - if(( s0-margin && s1>-margin && s2>-margin )) - { - n = normalize3( n ); - n.w = dot3F4(n,ap); - - normalOut = (FLIPSIGN)? -n : n; - return true; - } - - return false; -} - -__inline -float CollideUtils::castRay(const float4& v0, const float4& v1, const float4& v2, - const float4& rayFrom, const float4& rayTo, float margin, float4* bCrdOut) -{ - float t, v, w; - float4 ab; ab = v1 - v0; - float4 ac; ac = v2 - v0; - float4 qp; qp = rayFrom - rayTo; - float4 normal = cross3( ab, ac ); - float d = dot3F4( qp, normal ); - float odd = 1.f/d; - float4 ap; ap = rayFrom - v0; - t = dot3F4( ap, normal ); - t *= odd; -// if( t < 0.f || t > 1.f ) return -1; - - float4 e = cross3( qp, ap ); - v = dot3F4( ac, e ); - v *= odd; - if( v < -margin || v > 1.f+margin ) return -1; - w = -dot3F4( ab, e ); - w *= odd; -// if( w < 0.f || w > 1.f ) return -1; - if( w < -margin || w > 1.f+margin ) return -1; - - float u = 1.f-v-w; - if( u < -margin || u > 1.f+margin ) return -1; - - if( bCrdOut ) - { - bCrdOut->x = u; - bCrdOut->y = v; - bCrdOut->z = w; - } - return t; -} - -#endif - diff --git a/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/AdlCollisionShape.h b/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/AdlCollisionShape.h deleted file mode 100644 index 834c88c94..000000000 --- a/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/AdlCollisionShape.h +++ /dev/null @@ -1,49 +0,0 @@ -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Takahiro Harada - - -#ifndef COLLISION_SHAPE_H -#define COLLISION_SHAPE_H - -#include "Stubs/AdlMath.h" -#include "Stubs/AdlAabb.h" - - -_MEM_CLASSALIGN16 -class CollisionShape -{ - public: - _MEM_ALIGNED_ALLOCATOR16; - - enum Type - { - SHAPE_HEIGHT_FIELD, - SHAPE_CONVEX_HEIGHT_FIELD, - SHAPE_PLANE, - MAX_NUM_SHAPE_TYPES, - }; - - CollisionShape( Type type, float collisionMargin = 0.0025f ) : m_type( type ){ m_collisionMargin = collisionMargin; } - virtual ~CollisionShape(){} - virtual float queryDistance(const float4& p) const = 0; - virtual bool queryDistanceWithNormal(const float4& p, float4& normalOut) const = 0; - - public: - Type m_type; - Aabb m_aabb; - float m_collisionMargin; -}; - -#endif diff --git a/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/AdlConstraint4.h b/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/AdlConstraint4.h deleted file mode 100644 index 8f5078122..000000000 --- a/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/AdlConstraint4.h +++ /dev/null @@ -1,49 +0,0 @@ -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Takahiro Harada - - -#ifndef ADL_CONSTRAINT4_H -#define ADL_CONSTRAINT4_H - - - -struct Constraint4 - { - _MEM_ALIGNED_ALLOCATOR16; - - float4 m_linear; - float4 m_worldPos[4]; - float4 m_center; // friction - float m_jacCoeffInv[4]; - float m_b[4]; - float m_appliedRambdaDt[4]; - - float m_fJacCoeffInv[2]; // friction - float m_fAppliedRambdaDt[2]; // friction - - u32 m_bodyA; - u32 m_bodyB; - - u32 m_batchIdx; - u32 m_paddings[1]; - - __inline - void setFrictionCoeff(float value) { m_linear.w = value; } - __inline - float getFrictionCoeff() const { return m_linear.w; } - }; - -#endif //ADL_CONSTRAINT4_H - \ No newline at end of file diff --git a/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/AdlContact4.h b/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/AdlContact4.h deleted file mode 100644 index 29e36ade7..000000000 --- a/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/AdlContact4.h +++ /dev/null @@ -1,102 +0,0 @@ -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Takahiro Harada - - -#ifndef ADL_CONTACT4_H -#define ADL_CONTACT4_H - -#ifdef CL_PLATFORM_AMD -#include "AdlConstraint4.h" -#include "Adl/Adl.h" - -typedef adl::Buffer* SolverData; -#else -typedef void* SolverData; -#endif - -typedef void* ShapeDataType; - - -struct Contact4 -{ - _MEM_ALIGNED_ALLOCATOR16; - - float4 m_worldPos[4]; - float4 m_worldNormal; -// float m_restituitionCoeff; -// float m_frictionCoeff; - u16 m_restituitionCoeffCmp; - u16 m_frictionCoeffCmp; - int m_batchIdx; - - u32 m_bodyAPtr; - u32 m_bodyBPtr; - - // todo. make it safer - int& getBatchIdx() { return m_batchIdx; } - float getRestituitionCoeff() const { return ((float)m_restituitionCoeffCmp/(float)0xffff); } - void setRestituitionCoeff( float c ) { ADLASSERT( c >= 0.f && c <= 1.f ); m_restituitionCoeffCmp = (u16)(c*0xffff); } - float getFrictionCoeff() const { return ((float)m_frictionCoeffCmp/(float)0xffff); } - void setFrictionCoeff( float c ) { ADLASSERT( c >= 0.f && c <= 1.f ); m_frictionCoeffCmp = (u16)(c*0xffff); } - - float& getNPoints() { return m_worldNormal.w; } - float getNPoints() const { return m_worldNormal.w; } - - float getPenetration(int idx) const { return m_worldPos[idx].w; } - - bool isInvalid() const { return ((u32)m_bodyAPtr+(u32)m_bodyBPtr) == 0; } -}; - -struct ContactPoint4 - { - float4 m_worldPos[4]; - union - { - float4 m_worldNormal; - - struct Data - { - int m_padding[3]; - float m_nPoints; // for cl - }m_data; - - }; - float m_restituitionCoeff; - float m_frictionCoeff; -// int m_nPoints; -// int m_padding0; - - void* m_bodyAPtr; - void* m_bodyBPtr; -// int m_padding1; -// int m_padding2; - - float& getNPoints() { return m_data.m_nPoints; } - float getNPoints() const { return m_data.m_nPoints; } - - float getPenetration(int idx) const { return m_worldPos[idx].w; } - -// __inline -// void load(int idx, const ContactPoint& src); -// __inline -// void store(int idx, ContactPoint& dst) const; - - bool isInvalid() const { return ((u32)m_bodyAPtr+(u32)m_bodyBPtr) == 0; } - - }; - - -#endif //ADL_CONTACT4_H - diff --git a/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/AdlError.h b/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/AdlError.h deleted file mode 100644 index e1f9ad8e9..000000000 --- a/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/AdlError.h +++ /dev/null @@ -1,80 +0,0 @@ -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Takahiro Harada - - -#ifndef CL_ERROR_H -#define CL_ERROR_H - -#ifdef DX11RENDER -#include -#endif - -#ifdef _DEBUG - #include - #define CLASSERT(x) if(!(x)){__debugbreak(); } - #define ADLASSERT(x) if(!(x)){__debugbreak(); } -#else - #define CLASSERT(x) if(x){} - #define ADLASSERT(x) if(x){} - -#endif - - - - -#ifdef _DEBUG - #define COMPILE_TIME_ASSERT(x) {int compileTimeAssertFailed[x]; compileTimeAssertFailed[0];} -#else - #define COMPILE_TIME_ASSERT(x) -#endif - -#ifdef _DEBUG - #include - #include - __inline - void debugPrintf(const char *fmt, ...) - { - va_list arg; - va_start(arg, fmt); -#ifdef DX11RENDER - char buf[256]; - vsprintf_s( buf, 256, fmt, arg ); -#ifdef UNICODE - WCHAR wbuf[256]; - int sizeWide = MultiByteToWideChar(0,0,buf,-1,wbuf,0); - MultiByteToWideChar(0,0,buf,-1,wbuf,sizeWide); - -// swprintf_s( wbuf, 256, L"%s", buf ); - OutputDebugString( wbuf ); -#else - OutputDebugString( buf ); -#endif -#else - vprintf(fmt, arg); -#endif - va_end(arg); - } -#else - __inline - void debugPrintf(const char *fmt, ...) - { - } -#endif - - -#define WARN(msg) debugPrintf("WARNING: %s\n", msg); - -#endif - diff --git a/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/AdlMath.h b/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/AdlMath.h deleted file mode 100644 index a72422047..000000000 --- a/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/AdlMath.h +++ /dev/null @@ -1,216 +0,0 @@ -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Takahiro Harada - - -#ifndef CL_MATH_H -#define CL_MATH_H - -#include -#include -#include -#include - - -#include "AdlError.h" -#include -#define pxSort std::sort - -#define PI 3.14159265358979323846f -#define NEXTMULTIPLEOF(num, alignment) (((num)/(alignment) + (((num)%(alignment)==0)?0:1))*(alignment)) - - -#define _MEM_CLASSALIGN16 __declspec(align(16)) -#define _MEM_ALIGNED_ALLOCATOR16 void* operator new(size_t size) { return _aligned_malloc( size, 16 ); } \ - void operator delete(void *p) { _aligned_free( p ); } \ - void* operator new[](size_t size) { return _aligned_malloc( size, 16 ); } \ - void operator delete[](void *p) { _aligned_free( p ); } \ - void* operator new(size_t size, void* p) { return p; } \ - void operator delete(void *p, void* pp) {} - - - -template -T nextPowerOf2(T n) -{ - n -= 1; - for(int i=0; i>i); - return n+1; -} - - -_MEM_CLASSALIGN16 -struct float4 -{ - _MEM_ALIGNED_ALLOCATOR16; - union - { - struct - { - float x,y,z,w; - }; - struct - { - float s[4]; - }; - __m128 m_quad; - }; -}; - -__forceinline -unsigned int isZero(const float4& a) -{ - return (a.x == 0.f) & (a.y == 0.f) & (a.z == 0.f) & (a.w == 0.f); -} - -_MEM_CLASSALIGN16 -struct int4 -{ - _MEM_ALIGNED_ALLOCATOR16; - union - { - struct - { - int x,y,z,w; - }; - struct - { - int s[4]; - }; - }; -}; - -struct int2 -{ - union - { - struct - { - int x,y; - }; - struct - { - int s[2]; - }; - }; -}; - -struct float2 -{ - union - { - struct - { - float x,y; - }; - struct - { - float s[2]; - }; - }; -}; - - -typedef unsigned int u32; -typedef unsigned short u16; -typedef unsigned char u8; - - - -#include "Adlfloat4.inl" -//#include - - - - -template -void swap2(T& a, T& b) -{ - T tmp = a; - a = b; - b = tmp; -} - - -__inline -void randSeed(int seed) -{ - srand( seed ); -} - -template -__inline -T randRange(const T& minV, const T& maxV) -{ - float r = (rand()%10000)/10000.f; - T range = maxV - minV; - return (T)(minV + r*range); -} - -template<> -__inline -float4 randRange(const float4& minV, const float4& maxV) -{ - float4 r = make_float4( (rand()%10000)/10000.f, (rand()%10000)/10000.f, (rand()%10000)/10000.f, (rand()%10000)/10000.f ); - float4 range = maxV - minV; - return (minV + r*range); -} - - -struct SortData -{ - union - { - u32 m_key; - struct { u16 m_key16[2]; }; - }; - u32 m_value; - - friend bool operator <(const SortData& a, const SortData& b) - { - return a.m_key < b.m_key; - } -}; - - - -template -T* addByteOffset(void* baseAddr, u32 offset) -{ - return (T*)(((u32)baseAddr)+offset); -} - - -struct Pair32 -{ - Pair32(){} - Pair32(u32 a, u32 b) : m_a(a), m_b(b){} - - u32 m_a; - u32 m_b; -}; - -struct PtrPair -{ - PtrPair(){} - PtrPair(void* a, void* b) : m_a(a), m_b(b){} - template - PtrPair(T* a, T* b) : m_a((void*)a), m_b((void*)b){} - - void* m_a; - void* m_b; -}; - -#endif diff --git a/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/AdlMatrix3x3.h b/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/AdlMatrix3x3.h deleted file mode 100644 index fbd82aac2..000000000 --- a/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/AdlMatrix3x3.h +++ /dev/null @@ -1,194 +0,0 @@ -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Takahiro Harada - - -#ifndef MATRIX3X3_H -#define MATRIX3X3_H - -#include "AdlMath.h" - -/////////////////////////////////////// -// Matrix3x3 -/////////////////////////////////////// - -typedef -_MEM_CLASSALIGN16 struct -{ - _MEM_ALIGNED_ALLOCATOR16; - float4 m_row[3]; -}Matrix3x3; - -__inline -Matrix3x3 mtZero(); - -__inline -Matrix3x3 mtIdentity(); - -__inline -Matrix3x3 mtDiagonal(float a, float b, float c); - -__inline -Matrix3x3 mtTranspose(const Matrix3x3& m); - -__inline -Matrix3x3 mtMul(const Matrix3x3& a, const Matrix3x3& b); - -__inline -float4 mtMul1(const Matrix3x3& a, const float4& b); - -__inline -Matrix3x3 mtMul2(float a, const Matrix3x3& b); - -__inline -float4 mtMul3(const float4& b, const Matrix3x3& a); - -__inline -Matrix3x3 mtInvert(const Matrix3x3& m); - -__inline -Matrix3x3 mtZero() -{ - Matrix3x3 m; - m.m_row[0] = make_float4(0.f); - m.m_row[1] = make_float4(0.f); - m.m_row[2] = make_float4(0.f); - return m; -} - -__inline -Matrix3x3 mtIdentity() -{ - Matrix3x3 m; - m.m_row[0] = make_float4(1,0,0); - m.m_row[1] = make_float4(0,1,0); - m.m_row[2] = make_float4(0,0,1); - return m; -} - -__inline -Matrix3x3 mtDiagonal(float a, float b, float c) -{ - Matrix3x3 m; - m.m_row[0] = make_float4(a,0,0); - m.m_row[1] = make_float4(0,b,0); - m.m_row[2] = make_float4(0,0,c); - return m; -} - -__inline -Matrix3x3 mtTranspose(const Matrix3x3& m) -{ - Matrix3x3 out; - out.m_row[0] = make_float4(m.m_row[0].s[0], m.m_row[1].s[0], m.m_row[2].s[0], 0.f); - out.m_row[1] = make_float4(m.m_row[0].s[1], m.m_row[1].s[1], m.m_row[2].s[1], 0.f); - out.m_row[2] = make_float4(m.m_row[0].s[2], m.m_row[1].s[2], m.m_row[2].s[2], 0.f); - return out; -} - -__inline -Matrix3x3 mtMul(const Matrix3x3& a, const Matrix3x3& b) -{ - Matrix3x3 transB; - transB = mtTranspose( b ); - Matrix3x3 ans; - for(int i=0; i<3; i++) - { - ans.m_row[i].s[0] = dot3F4(a.m_row[i],transB.m_row[0]); - ans.m_row[i].s[1] = dot3F4(a.m_row[i],transB.m_row[1]); - ans.m_row[i].s[2] = dot3F4(a.m_row[i],transB.m_row[2]); - } - return ans; -} - -__inline -float4 mtMul1(const Matrix3x3& a, const float4& b) -{ - float4 ans; - ans.s[0] = dot3F4( a.m_row[0], b ); - ans.s[1] = dot3F4( a.m_row[1], b ); - ans.s[2] = dot3F4( a.m_row[2], b ); - return ans; -} - -__inline -Matrix3x3 mtMul2(float a, const Matrix3x3& b) -{ - Matrix3x3 ans; - ans.m_row[0] = a*b.m_row[0]; - ans.m_row[1] = a*b.m_row[1]; - ans.m_row[2] = a*b.m_row[2]; - return ans; -} - -__inline -float4 mtMul3(const float4& a, const Matrix3x3& b) -{ - float4 ans; - ans.x = a.x*b.m_row[0].x + a.y*b.m_row[1].x + a.z*b.m_row[2].x; - ans.y = a.x*b.m_row[0].y + a.y*b.m_row[1].y + a.z*b.m_row[2].y; - ans.z = a.x*b.m_row[0].z + a.y*b.m_row[1].z + a.z*b.m_row[2].z; - return ans; -} - -__inline -Matrix3x3 mtInvert(const Matrix3x3& m) -{ - float det = m.m_row[0].s[0]*m.m_row[1].s[1]*m.m_row[2].s[2]+m.m_row[1].s[0]*m.m_row[2].s[1]*m.m_row[0].s[2]+m.m_row[2].s[0]*m.m_row[0].s[1]*m.m_row[1].s[2] - -m.m_row[0].s[0]*m.m_row[2].s[1]*m.m_row[1].s[2]-m.m_row[2].s[0]*m.m_row[1].s[1]*m.m_row[0].s[2]-m.m_row[1].s[0]*m.m_row[0].s[1]*m.m_row[2].s[2]; - - CLASSERT( det ); - - Matrix3x3 ans; - ans.m_row[0].s[0] = m.m_row[1].s[1]*m.m_row[2].s[2] - m.m_row[1].s[2]*m.m_row[2].s[1]; - ans.m_row[0].s[1] = m.m_row[0].s[2]*m.m_row[2].s[1] - m.m_row[0].s[1]*m.m_row[2].s[2]; - ans.m_row[0].s[2] = m.m_row[0].s[1]*m.m_row[1].s[2] - m.m_row[0].s[2]*m.m_row[1].s[1]; - ans.m_row[0].w = 0.f; - - ans.m_row[1].s[0] = m.m_row[1].s[2]*m.m_row[2].s[0] - m.m_row[1].s[0]*m.m_row[2].s[2]; - ans.m_row[1].s[1] = m.m_row[0].s[0]*m.m_row[2].s[2] - m.m_row[0].s[2]*m.m_row[2].s[0]; - ans.m_row[1].s[2] = m.m_row[0].s[2]*m.m_row[1].s[0] - m.m_row[0].s[0]*m.m_row[1].s[2]; - ans.m_row[1].w = 0.f; - - ans.m_row[2].s[0] = m.m_row[1].s[0]*m.m_row[2].s[1] - m.m_row[1].s[1]*m.m_row[2].s[0]; - ans.m_row[2].s[1] = m.m_row[0].s[1]*m.m_row[2].s[0] - m.m_row[0].s[0]*m.m_row[2].s[1]; - ans.m_row[2].s[2] = m.m_row[0].s[0]*m.m_row[1].s[1] - m.m_row[0].s[1]*m.m_row[1].s[0]; - ans.m_row[2].w = 0.f; - - ans = mtMul2((1.0f/det), ans); - return ans; -} - -__inline -Matrix3x3 mtSet( const float4& a, const float4& b, const float4& c ) -{ - Matrix3x3 m; - m.m_row[0] = a; - m.m_row[1] = b; - m.m_row[2] = c; - return m; -} - -__inline -Matrix3x3 operator+(const Matrix3x3& a, const Matrix3x3& b) -{ - Matrix3x3 out; - out.m_row[0] = a.m_row[0] + b.m_row[0]; - out.m_row[1] = a.m_row[1] + b.m_row[1]; - out.m_row[2] = a.m_row[2] + b.m_row[2]; - return out; -} - -#endif - diff --git a/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/AdlQuaternion.h b/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/AdlQuaternion.h deleted file mode 100644 index 979e5fec5..000000000 --- a/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/AdlQuaternion.h +++ /dev/null @@ -1,155 +0,0 @@ -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Takahiro Harada - - -#ifndef QUATERNION_H -#define QUATERNION_H - -#include "AdlMatrix3x3.h" - - -typedef float4 Quaternion; - -__inline -Quaternion qtSet(const float4& axis, float angle); - -__inline -Quaternion qtMul(const Quaternion& a, const Quaternion& b); - -__inline -float4 qtRotate(const Quaternion& q, const float4& vec); - -__inline -float4 qtInvRotate(const Quaternion& q, const float4& vec); - -__inline -Quaternion qtInvert(const Quaternion& q); - -__inline -Matrix3x3 qtGetRotationMatrix(const Quaternion& quat); - -__inline -Quaternion qtNormalize(const Quaternion& q); - -__inline -Quaternion qtGetIdentity() { return make_float4(0,0,0,1); } - -__inline -Quaternion qtSet(const float4& axis, float angle) -{ - float4 nAxis = normalize3( axis ); - - Quaternion q; - q.s[0] = nAxis.s[0]*sin(angle/2); - q.s[1] = nAxis.s[1]*sin(angle/2); - q.s[2] = nAxis.s[2]*sin(angle/2); - q.s[3] = cos(angle/2); - return q; -} - -__inline -Quaternion qtMul(const Quaternion& a, const Quaternion& b) -{ - Quaternion ans; - ans = cross3( a, b ); - ans += a.s[3]*b + b.s[3]*a; - ans.s[3] = a.s[3]*b.s[3] - (a.s[0]*b.s[0]+a.s[1]*b.s[1]+a.s[2]*b.s[2]); - return ans; -} - -__inline -float4 qtRotate(const Quaternion& q, const float4& vec) -{ - Quaternion vecQ = vec; - vecQ.s[3] = 0.f; - Quaternion qInv = qtInvert( q ); - float4 out = qtMul(qtMul(q,vecQ),qInv); - return out; -} - -__inline -float4 qtInvRotate(const Quaternion& q, const float4& vec) -{ - return qtRotate( qtInvert( q ), vec ); -} - -__inline -Quaternion qtInvert(const Quaternion& q) -{ - Quaternion ans; - ans.s[0] = -q.s[0]; - ans.s[1] = -q.s[1]; - ans.s[2] = -q.s[2]; - ans.s[3] = q.s[3]; - return ans; -} - -__inline -Matrix3x3 qtGetRotationMatrix(const Quaternion& quat) -{ - float4 quat2 = make_float4(quat.s[0]*quat.s[0], quat.s[1]*quat.s[1], quat.s[2]*quat.s[2], 0.f); - Matrix3x3 out; - - out.m_row[0].s[0]=1-2*quat2.s[1]-2*quat2.s[2]; - out.m_row[0].s[1]=2*quat.s[0]*quat.s[1]-2*quat.s[3]*quat.s[2]; - out.m_row[0].s[2]=2*quat.s[0]*quat.s[2]+2*quat.s[3]*quat.s[1]; - out.m_row[0].s[3] = 0.f; - - out.m_row[1].s[0]=2*quat.s[0]*quat.s[1]+2*quat.s[3]*quat.s[2]; - out.m_row[1].s[1]=1-2*quat2.s[0]-2*quat2.s[2]; - out.m_row[1].s[2]=2*quat.s[1]*quat.s[2]-2*quat.s[3]*quat.s[0]; - out.m_row[1].s[3] = 0.f; - - out.m_row[2].s[0]=2*quat.s[0]*quat.s[2]-2*quat.s[3]*quat.s[1]; - out.m_row[2].s[1]=2*quat.s[1]*quat.s[2]+2*quat.s[3]*quat.s[0]; - out.m_row[2].s[2]=1-2*quat2.s[0]-2*quat2.s[1]; - out.m_row[2].s[3] = 0.f; - - return out; -} - -__inline -Quaternion qtGetQuaternion(const Matrix3x3* m) -{ - Quaternion q; - q.w = sqrtf( m[0].m_row[0].x + m[0].m_row[1].y + m[0].m_row[2].z + 1 ) * 0.5f; - float inv4w = 1.f/(4.f*q.w); - q.x = (m[0].m_row[2].y-m[0].m_row[1].z)*inv4w; - q.y = (m[0].m_row[0].z-m[0].m_row[2].x)*inv4w; - q.z = (m[0].m_row[1].x-m[0].m_row[0].y)*inv4w; - - return q; -} - -__inline -Quaternion qtNormalize(const Quaternion& q) -{ - return normalize4(q); -} - -__inline -float4 transform(const float4& p, const float4& translation, const Quaternion& orientation) -{ - return qtRotate( orientation, p ) + translation; -} - -__inline -float4 invTransform(const float4& p, const float4& translation, const Quaternion& orientation) -{ - return qtRotate( qtInvert( orientation ), p-translation ); // use qtInvRotate -} - -#endif - diff --git a/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/AdlRigidBody.h b/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/AdlRigidBody.h deleted file mode 100644 index b374cd032..000000000 --- a/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/AdlRigidBody.h +++ /dev/null @@ -1,59 +0,0 @@ -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Takahiro Harada - - -#ifndef ADL_RIGID_BODY_H -#define ADL_RIGID_BODY_H - -#include "AdlQuaternion.h" - -class RigidBodyBase -{ - public: - - _MEM_CLASSALIGN16 - struct Body - { - _MEM_ALIGNED_ALLOCATOR16; - - float4 m_pos; - Quaternion m_quat; - float4 m_linVel; - float4 m_angVel; - - u32 m_shapeIdx; - u32 m_shapeType; - - float m_invMass; - float m_restituitionCoeff; - float m_frictionCoeff; - - }; - - struct Inertia - { -/* u16 m_shapeType; - u16 m_shapeIdx; - float m_restituitionCoeff; - float m_frictionCoeff; - int m_padding; -*/ - Matrix3x3 m_invInertia; - Matrix3x3 m_initInvInertia; - }; -}; - -#endif// ADL_RIGID_BODY_H - diff --git a/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/AdlTransform.h b/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/AdlTransform.h deleted file mode 100644 index d9464babf..000000000 --- a/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/AdlTransform.h +++ /dev/null @@ -1,61 +0,0 @@ -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Takahiro Harada - - -#ifndef _ADL_TRANSFORM_H -#define _ADL_TRANSFORM_H - -#include "AdlMath.h" -#include "AdlQuaternion.h" -#include "AdlMatrix3x3.h" - -struct Transform -{ - float4 m_translation; - Matrix3x3 m_rotation; -}; - -Transform trSetTransform(const float4& translation, const Quaternion& quat) -{ - Transform tr; - tr.m_translation = translation; - tr.m_rotation = qtGetRotationMatrix( quat ); - return tr; -} - -Transform trInvert( const Transform& tr ) -{ - Transform ans; - ans.m_rotation = mtTranspose( tr.m_rotation ); - ans.m_translation = mtMul1( ans.m_rotation, -tr.m_translation ); - return ans; -} - -Transform trMul(const Transform& trA, const Transform& trB) -{ - Transform ans; - ans.m_rotation = mtMul( trA.m_rotation, trB.m_rotation ); - ans.m_translation = mtMul1( trA.m_rotation, trB.m_translation ) + trA.m_translation; - return ans; -} - -float4 trMul1(const Transform& tr, const float4& p) -{ - return mtMul1( tr.m_rotation, p ) + tr.m_translation; -} - - -#endif //_ADL_TRANSFORM_H - diff --git a/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/Adlfloat4.inl b/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/Adlfloat4.inl deleted file mode 100644 index 4e98a087a..000000000 --- a/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/Adlfloat4.inl +++ /dev/null @@ -1,373 +0,0 @@ -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Takahiro Harada - - -//#define CHECK_ALIGNMENT(a) CLASSERT((u32(&(a)) & 0xf) == 0); -#define CHECK_ALIGNMENT(a) a; - - -__inline -float4 make_float4(float x, float y, float z, float w = 0.f) -{ - float4 v; - v.x = x; v.y = y; v.z = z; v.w = w; - return v; -} - -__inline -float4 make_float4(float x) -{ - return make_float4(x,x,x,x); -} - -__inline -float4 make_float4(const int4& x) -{ - return make_float4((float)x.s[0], (float)x.s[1], (float)x.s[2], (float)x.s[3]); -} - -__inline -float2 make_float2(float x, float y) -{ - float2 v; - v.s[0] = x; v.s[1] = y; - return v; -} - -__inline -float2 make_float2(float x) -{ - return make_float2(x,x); -} - -__inline -float2 make_float2(const int2& x) -{ - return make_float2((float)x.s[0], (float)x.s[1]); -} - -__inline -int4 make_int4(int x, int y, int z, int w = 0) -{ - int4 v; - v.s[0] = x; v.s[1] = y; v.s[2] = z; v.s[3] = w; - return v; -} - -__inline -int4 make_int4(int x) -{ - return make_int4(x,x,x,x); -} - -__inline -int4 make_int4(const float4& x) -{ - return make_int4((int)x.x, (int)x.y, (int)x.z, (int)x.w); -} - -__inline -int2 make_int2(int a, int b) -{ - int2 ans; ans.x = a; ans.y = b; - return ans; -} - -__inline -float4 operator-(const float4& a) -{ - return make_float4(-a.x, -a.y, -a.z, -a.w); -} - -__inline -float4 operator*(const float4& a, const float4& b) -{ - CLASSERT((u32(&a) & 0xf) == 0); - - float4 out; - out.s[0] = a.s[0]*b.s[0]; - out.s[1] = a.s[1]*b.s[1]; - out.s[2] = a.s[2]*b.s[2]; - out.s[3] = a.s[3]*b.s[3]; - return out; -} - -__inline -float4 operator*(float a, const float4& b) -{ - return make_float4(a*b.s[0], a*b.s[1], a*b.s[2], a*b.s[3]); -} - -__inline -float4 operator*(const float4& b, float a) -{ - CHECK_ALIGNMENT(b); - - return make_float4(a*b.s[0], a*b.s[1], a*b.s[2], a*b.s[3]); -} - -__inline -void operator*=(float4& a, const float4& b) -{ - CHECK_ALIGNMENT(a); - - a.s[0]*=b.s[0]; - a.s[1]*=b.s[1]; - a.s[2]*=b.s[2]; - a.s[3]*=b.s[3]; -} - -__inline -void operator*=(float4& a, float b) -{ - CHECK_ALIGNMENT(a); - - a.s[0]*=b; - a.s[1]*=b; - a.s[2]*=b; - a.s[3]*=b; -} - -// -__inline -float4 operator/(const float4& a, const float4& b) -{ - CHECK_ALIGNMENT(a); - - float4 out; - out.s[0] = a.s[0]/b.s[0]; - out.s[1] = a.s[1]/b.s[1]; - out.s[2] = a.s[2]/b.s[2]; - out.s[3] = a.s[3]/b.s[3]; - return out; -} - -__inline -float4 operator/(const float4& b, float a) -{ - CHECK_ALIGNMENT(b); - - return make_float4(b.s[0]/a, b.s[1]/a, b.s[2]/a, b.s[3]/a); -} - -__inline -void operator/=(float4& a, const float4& b) -{ - a.s[0]/=b.s[0]; - a.s[1]/=b.s[1]; - a.s[2]/=b.s[2]; - a.s[3]/=b.s[3]; -} - -__inline -void operator/=(float4& a, float b) -{ - CLASSERT((u32(&a) & 0xf) == 0); - - a.s[0]/=b; - a.s[1]/=b; - a.s[2]/=b; - a.s[3]/=b; -} -// - -__inline -float4 operator+(const float4& a, const float4& b) -{ - CHECK_ALIGNMENT(a); - - float4 out; - out.s[0] = a.s[0]+b.s[0]; - out.s[1] = a.s[1]+b.s[1]; - out.s[2] = a.s[2]+b.s[2]; - out.s[3] = a.s[3]+b.s[3]; - return out; -} - -__inline -float4 operator+(const float4& a, float b) -{ - CHECK_ALIGNMENT(a); - - float4 out; - out.s[0] = a.s[0]+b; - out.s[1] = a.s[1]+b; - out.s[2] = a.s[2]+b; - out.s[3] = a.s[3]+b; - return out; -} - -__inline -float4 operator-(const float4& a, const float4& b) -{ - CHECK_ALIGNMENT(a); - - float4 out; - out.s[0] = a.s[0]-b.s[0]; - out.s[1] = a.s[1]-b.s[1]; - out.s[2] = a.s[2]-b.s[2]; - out.s[3] = a.s[3]-b.s[3]; - return out; -} - -__inline -float4 operator-(const float4& a, float b) -{ - CHECK_ALIGNMENT(a); - - float4 out; - out.s[0] = a.s[0]-b; - out.s[1] = a.s[1]-b; - out.s[2] = a.s[2]-b; - out.s[3] = a.s[3]-b; - return out; -} - -__inline -void operator+=(float4& a, const float4& b) -{ - CHECK_ALIGNMENT(a); - - a.s[0]+=b.s[0]; - a.s[1]+=b.s[1]; - a.s[2]+=b.s[2]; - a.s[3]+=b.s[3]; -} - -__inline -void operator+=(float4& a, float b) -{ - CHECK_ALIGNMENT(a); - - a.s[0]+=b; - a.s[1]+=b; - a.s[2]+=b; - a.s[3]+=b; -} - -__inline -void operator-=(float4& a, const float4& b) -{ - CHECK_ALIGNMENT(a); - - a.s[0]-=b.s[0]; - a.s[1]-=b.s[1]; - a.s[2]-=b.s[2]; - a.s[3]-=b.s[3]; -} - -__inline -void operator-=(float4& a, float b) -{ - CHECK_ALIGNMENT(a); - - a.s[0]-=b; - a.s[1]-=b; - a.s[2]-=b; - a.s[3]-=b; -} - - - - - -__inline -float4 cross3(const float4& a, const float4& b) -{ - return make_float4(a.s[1]*b.s[2]-a.s[2]*b.s[1], - a.s[2]*b.s[0]-a.s[0]*b.s[2], - a.s[0]*b.s[1]-a.s[1]*b.s[0], - 0); -} - -__inline -float dot3F4(const float4& a, const float4& b) -{ - return a.x*b.x+a.y*b.y+a.z*b.z; -} - -__inline -float length3(const float4& a) -{ - return sqrtf(dot3F4(a,a)); -} - -__inline -float dot4(const float4& a, const float4& b) -{ - return a.x*b.x+a.y*b.y+a.z*b.z+a.w*b.w; -} - -// for height -__inline -float dot3w1(const float4& point, const float4& eqn) -{ - return point.x*eqn.x+point.y*eqn.y+point.z*eqn.z+eqn.w; -} - -__inline -float4 normalize3(const float4& a) -{ - float length = sqrtf(dot3F4(a, a)); - return 1.f/length * a; -} - -__inline -float4 normalize4(const float4& a) -{ - float length = sqrtf(dot4(a, a)); - return 1.f/length * a; -} - -__inline -float4 createEquation(const float4& a, const float4& b, const float4& c) -{ - float4 eqn; - float4 ab = b-a; - float4 ac = c-a; - eqn = normalize3( cross3(ab, ac) ); - eqn.w = -dot3F4(eqn,a); - return eqn; -} - - -template -__inline -T max2(const T& a, const T& b) -{ - return (a>b)? a:b; -} - -template -__inline -T min2(const T& a, const T& b) -{ - return (a -__inline -float4 max2(const float4& a, const float4& b) -{ - return make_float4( max2(a.x,b.x), max2(a.y,b.y), max2(a.z,b.z), max2(a.w,b.w) ); -} - -template<> -__inline -float4 min2(const float4& a, const float4& b) -{ - return make_float4( min2(a.x,b.x), min2(a.y,b.y), min2(a.z,b.z), min2(a.w,b.w) ); -} - diff --git a/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/Adlfloat4SSE.inl b/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/Adlfloat4SSE.inl deleted file mode 100644 index a10211e06..000000000 --- a/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/Adlfloat4SSE.inl +++ /dev/null @@ -1,381 +0,0 @@ -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Takahiro Harada - - -//#define CHECK_ALIGNMENT(a) CLASSERT((u32(&(a)) & 0xf) == 0); -#define CHECK_ALIGNMENT(a) a; - - -__inline -float4 make_float4(float x, float y, float z, float w = 0.f) -{ - float4 v; - v.m_quad = _mm_set_ps(w,z,y,x); - - return v; -} - -__inline -float4 make_float4(float x) -{ - return make_float4(x,x,x,x); -} - -__inline -float4 make_float4(const int4& x) -{ - return make_float4((float)x.s[0], (float)x.s[1], (float)x.s[2], (float)x.s[3]); -} - -__inline -float2 make_float2(float x, float y) -{ - float2 v; - v.s[0] = x; v.s[1] = y; - return v; -} - -__inline -float2 make_float2(float x) -{ - return make_float2(x,x); -} - -__inline -float2 make_float2(const int2& x) -{ - return make_float2((float)x.s[0], (float)x.s[1]); -} - -__inline -int4 make_int4(int x, int y, int z, int w = 0) -{ - int4 v; - v.s[0] = x; v.s[1] = y; v.s[2] = z; v.s[3] = w; - return v; -} - -__inline -int4 make_int4(int x) -{ - return make_int4(x,x,x,x); -} - -__inline -int4 make_int4(const float4& x) -{ - return make_int4((int)x.x, (int)x.y, (int)x.z, (int)x.w); -} - -__inline -int2 make_int2(int a, int b) -{ - int2 ans; ans.x = a; ans.y = b; - return ans; -} - -__inline -float4 operator-(const float4& a) -{ - float4 zero; zero.m_quad = _mm_setzero_ps(); - float4 ans; ans.m_quad = _mm_sub_ps( zero.m_quad, a.m_quad ); - return ans; -} - -__inline -float4 operator*(const float4& a, const float4& b) -{ - CHECK_ALIGNMENT(a); - - float4 out; - out.m_quad = _mm_mul_ps( a.m_quad, b.m_quad ); - return out; -} - -__inline -float4 operator*(float a, const float4& b) -{ - float4 av; av.m_quad = _mm_set1_ps( a ); - return av*b; -} - -__inline -float4 operator*(const float4& b, float a) -{ - CHECK_ALIGNMENT(b); - - float4 av; av.m_quad = _mm_set1_ps( a ); - return av*b; -} - -__inline -void operator*=(float4& a, const float4& b) -{ - CHECK_ALIGNMENT(a); - - a = a*b; -} - -__inline -void operator*=(float4& a, float b) -{ - CHECK_ALIGNMENT(a); - - float4 bv; bv.m_quad = _mm_set1_ps( b ); - a = a*bv; -} - -// -__inline -float4 operator/(const float4& a, const float4& b) -{ - CHECK_ALIGNMENT(a); - - float4 out; - out.m_quad = _mm_div_ps( a.m_quad, b.m_quad ); - return out; -} - -__inline -float4 operator/(const float4& b, float a) -{ - CHECK_ALIGNMENT(b); - - float4 av; av.m_quad = _mm_set1_ps( a ); - float4 out; - out = b/av; - return out; -} - -__inline -void operator/=(float4& a, const float4& b) -{ - a = a/b; -} - -__inline -void operator/=(float4& a, float b) -{ - CLASSERT((u32(&a) & 0xf) == 0); - - float4 bv; bv.m_quad = _mm_set1_ps( b ); - a = a/bv; -} -// - -__inline -float4 operator+(const float4& a, const float4& b) -{ - CHECK_ALIGNMENT(a); - - float4 out; - out.m_quad = _mm_add_ps( a.m_quad, b.m_quad ); - return out; -} - -__inline -float4 operator+(const float4& a, float b) -{ - CHECK_ALIGNMENT(a); - - float4 bv; bv.m_quad = _mm_set1_ps( b ); - return a+bv; -} - -__inline -float4 operator-(const float4& a, const float4& b) -{ - CHECK_ALIGNMENT(a); - - float4 out; - out.m_quad = _mm_sub_ps( a.m_quad, b.m_quad ); - return out; -} - -__inline -float4 operator-(const float4& a, float b) -{ - CHECK_ALIGNMENT(a); - - float4 bv; bv.m_quad = _mm_set1_ps( b ); - return a-bv; -} - -__inline -void operator+=(float4& a, const float4& b) -{ - CHECK_ALIGNMENT(a); - - a = a + b; -} - -__inline -void operator+=(float4& a, float b) -{ - CHECK_ALIGNMENT(a); - - float4 bv; bv.m_quad = _mm_set1_ps( b ); - - a = a + bv; -} - -__inline -void operator-=(float4& a, const float4& b) -{ - CHECK_ALIGNMENT(a); - - a = a - b; -} - -__inline -void operator-=(float4& a, float b) -{ - CHECK_ALIGNMENT(a); - - float4 bv; bv.m_quad = _mm_set1_ps( b ); - - a = a - bv; -} - - - - - -__inline -float4 cross3(const float4& a, const float4& b) -{ // xnamathvector.inl - union IntVec - { - unsigned int m_i[4]; - __m128 m_v; - }; - - IntVec mask3 = {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000}; - __m128 V1 = a.m_quad; - __m128 V2 = b.m_quad; - - __m128 vTemp1 = _mm_shuffle_ps(V1,V1,_MM_SHUFFLE(3,0,2,1)); - // z2,x2,y2,w2 - __m128 vTemp2 = _mm_shuffle_ps(V2,V2,_MM_SHUFFLE(3,1,0,2)); - // Perform the left operation - __m128 vResult = _mm_mul_ps(vTemp1,vTemp2); - // z1,x1,y1,w1 - vTemp1 = _mm_shuffle_ps(vTemp1,vTemp1,_MM_SHUFFLE(3,0,2,1)); - // y2,z2,x2,w2 - vTemp2 = _mm_shuffle_ps(vTemp2,vTemp2,_MM_SHUFFLE(3,1,0,2)); - // Perform the right operation - vTemp1 = _mm_mul_ps(vTemp1,vTemp2); - // Subract the right from left, and return answer - vResult = _mm_sub_ps(vResult,vTemp1); - // Set w to zero - float4 ans; ans.m_quad = _mm_and_ps(vResult,mask3.m_v); - return ans; -} - -__inline -float dot3F4(const float4& a, const float4& b) -{ -// return a.x*b.x+a.y*b.y+a.z*b.z; - // Perform the dot product - __m128 V1 = a.m_quad; - __m128 V2 = b.m_quad; - - __m128 vDot = _mm_mul_ps(V1,V2); - // x=Dot.vector4_f32[1], y=Dot.vector4_f32[2] - __m128 vTemp = _mm_shuffle_ps(vDot,vDot,_MM_SHUFFLE(2,1,2,1)); - // Result.vector4_f32[0] = x+y - vDot = _mm_add_ss(vDot,vTemp); - // x=Dot.vector4_f32[2] - vTemp = _mm_shuffle_ps(vTemp,vTemp,_MM_SHUFFLE(1,1,1,1)); - // Result.vector4_f32[0] = (x+y)+z - vDot = _mm_add_ss(vDot,vTemp); - // Splat x - float4 ans; ans.m_quad = _mm_shuffle_ps(vDot,vDot,_MM_SHUFFLE(0,0,0,0)); - return ans.x; -} - -__inline -float length3(const float4& a) -{ - return sqrtf(dot3F4(a,a)); -} - -__inline -float dot4(const float4& a, const float4& b) -{ - return a.x*b.x+a.y*b.y+a.z*b.z+a.w*b.w; -} - -// for height -__inline -float dot3w1(const float4& point, const float4& eqn) -{ - return point.x*eqn.x+point.y*eqn.y+point.z*eqn.z+eqn.w; -} - -__inline -float4 normalize3(const float4& a) -{ - float length = sqrtf(dot3F4(a, a)); - return 1.f/length * a; -} - -__inline -float4 normalize4(const float4& a) -{ - float length = sqrtf(dot4(a, a)); - return 1.f/length * a; -} - -__inline -float4 createEquation(const float4& a, const float4& b, const float4& c) -{ - float4 eqn; - float4 ab = b-a; - float4 ac = c-a; - eqn = normalize3( cross3(ab, ac) ); - eqn.w = -dot3F4(eqn,a); - return eqn; -} - - -template -__inline -T max2(const T& a, const T& b) -{ - return (a>b)? a:b; -} - -template -__inline -T min2(const T& a, const T& b) -{ - return (a -__inline -float4 max2(const float4& a, const float4& b) -{ - return make_float4( max2(a.x,b.x), max2(a.y,b.y), max2(a.z,b.z), max2(a.w,b.w) ); -} - -template<> -__inline -float4 min2(const float4& a, const float4& b) -{ - return make_float4( min2(a.x,b.x), min2(a.y,b.y), min2(a.z,b.z), min2(a.w,b.w) ); -} - diff --git a/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/ChNarrowPhase.h b/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/ChNarrowPhase.h deleted file mode 100644 index 4ad551f51..000000000 --- a/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/ChNarrowPhase.h +++ /dev/null @@ -1,154 +0,0 @@ -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Takahiro Harada - - -#pragma once - -#include -//#include - -#include "AdlMath.h" -#include "AdlContact4.h" -#include "AdlRigidBody.h" - -#include "../ConvexHeightFieldShape.h" - -//#include "TypeDefinition.h" -//#include "RigidBody.h" -//#include "ConvexHeightFieldShape.h" - -namespace adl -{ -class ShapeBase; - -class ChNarrowphaseBase -{ - public: - struct Config - { - float m_collisionMargin; - }; -/* - typedef struct - { - // m_normal.w == height in u8 - float4 m_normal[HEIGHT_RES*HEIGHT_RES*6]; - u32 m_height4[HEIGHT_RES*HEIGHT_RES*6]; - - float m_scale; - float m_padding0; - float m_padding1; - float m_padding2; - } ShapeData; -*/ -}; - -template -class ChNarrowphase : public ChNarrowphaseBase -{ - public: - typedef Launcher::BufferInfo BufferInfo; - - struct Data - { - const Device* m_device; - Kernel* m_supportCullingKernel; - Kernel* m_narrowphaseKernel; - Kernel* m_narrowphaseWithPlaneKernel; - - Buffer* m_counterBuffer; - }; - - enum - { - N_TASKS = 4, - HEIGHT_RES = ConvexHeightField::HEIGHT_RES, - }; - - struct ShapeData - { - float4 m_normal[HEIGHT_RES*HEIGHT_RES*6]; - u32 m_height4[HEIGHT_RES*HEIGHT_RES*6]; - u32 m_supportHeight4[HEIGHT_RES*HEIGHT_RES*6]; - - float m_scale; - float m_padding0; - float m_padding1; - float m_padding2; - }; - - struct ConstData - { - int m_nPairs; - float m_collisionMargin; - int m_capacity; - int m_paddings[1]; - }; - - static - Data* allocate( const Device* device ); - - static - void deallocate( Data* data ); -/* - static - Buffer* allocateShapeBuffer( const Device* device, int capacity ); - - static - void deallocateShapeBuffer( Buffer* shapeBuf ); - - static - void setShape( Buffer* shapeBuf, ShapeBase* shape, int idx, float collisionMargin ); -*/ - static - ShapeDataType allocateShapeBuffer( const Device* device, int capacity ); - - static - void deallocateShapeBuffer( ShapeDataType shapeBuf ); - - static - void setShape( ShapeDataType shapeBuf, ShapeBase* shape, int idx, float collisionMargin = 0.f ); - - static - void setShape( ShapeDataType shapeBuf, ConvexHeightField* cvxShape, int idx, float collisionMargin = 0.f ); - - // Run NarrowphaseKernel - //template - static - void execute( Data* data, const Buffer* pairs, int nPairs, - const Buffer* bodyBuf, const ShapeDataType shapeBuf, - Buffer* contactOut, int& nContacts, const Config& cfg ); - - // Run NarrowphaseWithPlaneKernel - //template - static - void execute( Data* data, const Buffer* pairs, int nPairs, - const Buffer* bodyBuf, const ShapeDataType shapeBuf, - const Buffer* vtxBuf, const Buffer* idxBuf, - Buffer* contactOut, int& nContacts, const Config& cfg ); - - // Run SupportCullingKernel - //template - static - int culling( Data* data, const Buffer* pairs, int nPairs, const Buffer* bodyBuf, - const ShapeDataType shapeBuf, const Buffer* pairsOut, const Config& cfg ); -}; - -//#include -//#include - -#include "ChNarrowphase.inl" - -}; diff --git a/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/ChNarrowphase.inl b/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/ChNarrowphase.inl deleted file mode 100644 index 00ffbda24..000000000 --- a/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/ChNarrowphase.inl +++ /dev/null @@ -1,303 +0,0 @@ -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Takahiro Harada - - -//#define PATH "..\\..\\dynamics\\basic_demo\\Stubs\\ChNarrowphaseKernels" -#define PATH "..\\..\\dynamics\\basic_demo\\Stubs\\ChNarrowphaseKernels" -#define KERNEL0 "SupportCullingKernel" -#define KERNEL1 "NarrowphaseKernel" - -#include "ChNarrowphaseKernels.h" - -class ChNarrowphaseImp -{ -public: - static - __inline - u32 u32Pack(u8 x, u8 y, u8 z, u8 w) - { - return (x) | (y<<8) | (z<<16) | (w<<24); - } - -}; - -template -typename ChNarrowphase::Data* ChNarrowphase::allocate( const Device* device ) -{ - char options[100]; - - const char* src[] = -#if defined(ADL_LOAD_KERNEL_FROM_STRING) - {narrowphaseKernelsCL, 0}; -#else - {0,0}; -#endif - - - - - //sprintf(options, "-I ..\\..\\ -Wf,--c++"); - sprintf(options, "-I .\\NarrowPhaseCL\\"); - - Data* data = new Data; - data->m_device = device; - data->m_supportCullingKernel = device->getKernel( PATH, KERNEL0, options,src[TYPE] ); - data->m_narrowphaseKernel = device->getKernel( PATH, KERNEL1, options, src[TYPE]); - data->m_narrowphaseWithPlaneKernel = device->getKernel( PATH, "NarrowphaseWithPlaneKernel", options,src[TYPE]); - data->m_counterBuffer = new Buffer( device, 1 ); - - return data; -} - - -template -void ChNarrowphase::deallocate( Data* data ) -{ - delete data->m_counterBuffer; - - delete data; -} - -template -ShapeDataType ChNarrowphase::allocateShapeBuffer( const Device* device, int capacity ) -{ - ADLASSERT( device->m_type == TYPE ); - - return new Buffer( device, capacity ); -} - -template -void ChNarrowphase::deallocateShapeBuffer( ShapeDataType shapeBuf ) -{ - Buffer* s = (Buffer*)shapeBuf; - delete s; -} - -template -void ChNarrowphase::setShape( ShapeDataType shapeBuf, ShapeBase* shape, int idx, float collisionMargin ) -{ - ConvexHeightField* cvxShape = new ConvexHeightField( shape ); - Buffer* dst = (Buffer*)shapeBuf; - cvxShape->m_aabb.expandBy( make_float4( collisionMargin ) ); - { - ShapeData s; - { - for(int j=0; jm_normal[j]; - } - for(int j=0; jm_data[4*j], cvxShape->m_data[4*j+1], cvxShape->m_data[4*j+2], cvxShape->m_data[4*j+3] ); - s.m_supportHeight4[j] = ChNarrowphaseImp::u32Pack( cvxShape->m_supportHeight[4*j], cvxShape->m_supportHeight[4*j+1], cvxShape->m_supportHeight[4*j+2], cvxShape->m_supportHeight[4*j+3] ); - } - s.m_scale = cvxShape->m_scale; - } - dst->write( &s, 1, idx ); - DeviceUtils::waitForCompletion( dst->m_device ); - } - delete cvxShape; -} - -template -void ChNarrowphase::setShape( ShapeDataType shapeBuf, ConvexHeightField* cvxShape, int idx, float collisionMargin ) -{ - Buffer* dst = (Buffer*)shapeBuf; - cvxShape->m_aabb.expandBy( make_float4( collisionMargin ) ); - { - ShapeData s; - { - for(int j=0; jm_normal[j]; - } - for(int j=0; jm_data[4*j], cvxShape->m_data[4*j+1], cvxShape->m_data[4*j+2], cvxShape->m_data[4*j+3] ); - s.m_supportHeight4[j] = ChNarrowphaseImp::u32Pack( cvxShape->m_supportHeight[4*j], cvxShape->m_supportHeight[4*j+1], cvxShape->m_supportHeight[4*j+2], cvxShape->m_supportHeight[4*j+3] ); - } - s.m_scale = cvxShape->m_scale; - } - dst->write( &s, 1, idx ); - DeviceUtils::waitForCompletion( dst->m_device ); - } -} - -// Run NarrowphaseKernel -template -//template -void ChNarrowphase::execute( Data* data, const Buffer* pairs, int nPairs, const Buffer* bodyBuf, - const ShapeDataType shapeBuf, - Buffer* contactOut, int& nContacts, const Config& cfg ) -{ - if( nPairs == 0 ) return; - - Buffer* shapeBuffer = (Buffer*)shapeBuf; - ADLASSERT( shapeBuffer->getType() == TYPE ); - - const Device* device = data->m_device; - - Buffer* gPairsInNative - = BufferUtils::map( data->m_device, pairs ); - Buffer* gBodyInNative - = BufferUtils::map( data->m_device, bodyBuf ); - Buffer* gContactOutNative - = BufferUtils::map( data->m_device, contactOut ); // this might not be empty - - Buffer constBuffer( device, 1, BufferBase::BUFFER_CONST ); - - ConstData cdata; - cdata.m_nPairs = nPairs; - cdata.m_collisionMargin = cfg.m_collisionMargin; - cdata.m_capacity = contactOut->getSize() - nContacts; - - u32 n = nContacts; - data->m_counterBuffer->write( &n, 1 ); -// DeviceUtils::waitForCompletion( device ); - - { - BufferInfo bInfo[] = { BufferInfo( gPairsInNative, true ), BufferInfo( shapeBuffer ), BufferInfo( gBodyInNative ), - BufferInfo( gContactOutNative ), - BufferInfo( data->m_counterBuffer ) }; - Launcher launcher( data->m_device, data->m_narrowphaseKernel ); - launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(Launcher::BufferInfo) ); - launcher.setConst( constBuffer, cdata ); - launcher.launch1D( nPairs*64, 64 ); - } - - data->m_counterBuffer->read( &n, 1 ); - DeviceUtils::waitForCompletion( device ); - - BufferUtils::unmap( gPairsInNative, pairs ); - BufferUtils::unmap( gBodyInNative, bodyBuf ); - BufferUtils::unmap( gContactOutNative, contactOut ); - - nContacts = min2((int)n, contactOut->getSize() ); -} - -// Run NarrowphaseWithPlaneKernel -template -//template -void ChNarrowphase::execute( Data* data, const Buffer* pairs, int nPairs, - const Buffer* bodyBuf, const ShapeDataType shapeBuf, - const Buffer* vtxBuf, const Buffer* idxBuf, - Buffer* contactOut, int& nContacts, const Config& cfg ) -{ - if( nPairs == 0 ) return; - - Buffer* shapeBuffer = (Buffer*)shapeBuf; - ADLASSERT( shapeBuffer->getType() == TYPE ); - - const Device* device = data->m_device; - - Buffer* gPairsInNative - = BufferUtils::map( data->m_device, pairs ); - Buffer* gBodyInNative - = BufferUtils::map( data->m_device, bodyBuf ); - Buffer* gContactOutNative - = BufferUtils::map( data->m_device, contactOut ); // this might not be empty - - Buffer constBuffer( device, 1, BufferBase::BUFFER_CONST ); - - ConstData cdata; - cdata.m_nPairs = nPairs; - cdata.m_collisionMargin = cfg.m_collisionMargin; - cdata.m_capacity = contactOut->getSize() - nContacts; - - u32 n = nContacts; - data->m_counterBuffer->write( &n, 1 ); -// DeviceUtils::waitForCompletion( device ); - - { - BufferInfo bInfo[] = { BufferInfo( gPairsInNative, true ), BufferInfo( shapeBuffer ), BufferInfo( gBodyInNative ), - BufferInfo( gContactOutNative ), - BufferInfo( data->m_counterBuffer ) }; - Launcher launcher( data->m_device, data->m_narrowphaseWithPlaneKernel ); - launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(Launcher::BufferInfo) ); - launcher.setConst( constBuffer, cdata ); - launcher.launch1D( nPairs*64, 64 ); - } - - data->m_counterBuffer->read( &n, 1 ); - DeviceUtils::waitForCompletion( device ); - - BufferUtils::unmap( gPairsInNative, pairs ); - BufferUtils::unmap( gBodyInNative, bodyBuf ); - BufferUtils::unmap( gContactOutNative, contactOut ); - - nContacts = min2((int)n, contactOut->getSize() ); -} - -// Run SupportCullingKernel -template -//template -int ChNarrowphase::culling( Data* data, const Buffer* pairs, int nPairs, const Buffer* bodyBuf, - const ShapeDataType shapeBuf, const Buffer* pairsOut, const Config& cfg ) -{ - if( nPairs == 0 ) return 0; - - Buffer* shapeBuffer = (Buffer*)shapeBuf; - ADLASSERT( shapeBuffer->getType() == TYPE ); - - const Device* device = data->m_device; - - Buffer* gPairsInNative - = BufferUtils::map( data->m_device, pairs ); - Buffer* gBodyInNative - = BufferUtils::map( data->m_device, bodyBuf ); - Buffer* gPairsOutNative - = BufferUtils::map( data->m_device, pairsOut ); - - // - Buffer constBuffer( device, 1, BufferBase::BUFFER_CONST ); - - ConstData cdata; - cdata.m_nPairs = nPairs; - cdata.m_collisionMargin = cfg.m_collisionMargin; - cdata.m_capacity = pairsOut->getSize(); - - u32 n = 0; - data->m_counterBuffer->write( &n, 1 ); -// DeviceUtils::waitForCompletion( device ); - { - BufferInfo bInfo[] = { BufferInfo( gPairsInNative, true ), BufferInfo( shapeBuffer ), BufferInfo( gBodyInNative ), - BufferInfo( gPairsOutNative ), BufferInfo( data->m_counterBuffer ) }; - Launcher launcher( data->m_device, data->m_supportCullingKernel ); - launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(Launcher::BufferInfo) ); - launcher.setConst( constBuffer, cdata ); - launcher.launch1D( nPairs, 64 ); - } - data->m_counterBuffer->read( &n, 1 ); - DeviceUtils::waitForCompletion( device ); -/* - if( gPairsInNative != pairs ) delete gPairsInNative; - if( gBodyInNative != bodyBuf ) delete gBodyInNative; - if( gPairsOutNative != pairsOut ) - { - gPairsOutNative->read( pairsOut->m_ptr, n ); - DeviceUtils::waitForCompletion( device ); - delete gPairsOutNative; - } -*/ - BufferUtils::unmap( gPairsInNative, pairs ); - BufferUtils::unmap( gBodyInNative, bodyBuf ); - BufferUtils::unmap( gPairsOutNative, pairsOut ); - - return min2((int)n, pairsOut->getSize() ); -} - -#undef PATH -#undef KERNEL0 -#undef KERNEL1 \ No newline at end of file diff --git a/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/ChNarrowphaseKernels.cl b/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/ChNarrowphaseKernels.cl deleted file mode 100644 index af177a836..000000000 --- a/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/ChNarrowphaseKernels.cl +++ /dev/null @@ -1,1629 +0,0 @@ -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Takahiro Harada - - -#pragma OPENCL EXTENSION cl_amd_printf : enable -#pragma OPENCL EXTENSION cl_khr_local_int32_base_atomics : enable -#pragma OPENCL EXTENSION cl_khr_global_int32_base_atomics : enable -#pragma OPENCL EXTENSION cl_khr_local_int32_extended_atomics : enable -#pragma OPENCL EXTENSION cl_khr_global_int32_extended_atomics : enable - -#ifdef cl_ext_atomic_counters_32 -#pragma OPENCL EXTENSION cl_ext_atomic_counters_32 : enable -#else -#define counter32_t volatile global int* -#endif - - -typedef unsigned int u32; -typedef unsigned short u16; -typedef unsigned char u8; - -#define GET_GROUP_IDX get_group_id(0) -#define GET_LOCAL_IDX get_local_id(0) -#define GET_GLOBAL_IDX get_global_id(0) -#define GET_GROUP_SIZE get_local_size(0) -#define GET_NUM_GROUPS get_num_groups(0) -#define GROUP_LDS_BARRIER barrier(CLK_LOCAL_MEM_FENCE) -#define GROUP_MEM_FENCE mem_fence(CLK_LOCAL_MEM_FENCE) -#define AtomInc(x) atom_inc(&(x)) -#define AtomInc1(x, out) out = atom_inc(&(x)) -#define AppendInc(x, out) out = atomic_inc(x) -#define AtomAdd(x, value) atom_add(&(x), value) -#define AtomCmpxhg(x, cmp, value) atom_cmpxchg( &(x), cmp, value ) -#define AtomXhg(x, value) atom_xchg ( &(x), value ) - - -#define SELECT_UINT4( b, a, condition ) select( b,a,condition ) - -#define make_float4 (float4) -#define make_float2 (float2) -#define make_uint4 (uint4) -#define make_int4 (int4) -#define make_uint2 (uint2) -#define make_int2 (int2) - - -#define max2 max -#define min2 min - - -/////////////////////////////////////// -// Vector -/////////////////////////////////////// -__inline -float fastDiv(float numerator, float denominator) -{ - return native_divide(numerator, denominator); -// return numerator/denominator; -} - -__inline -float4 fastDiv4(float4 numerator, float4 denominator) -{ - return native_divide(numerator, denominator); -} - -__inline -float fastSqrtf(float f2) -{ - return native_sqrt(f2); -// return sqrt(f2); -} - -__inline -float fastRSqrt(float f2) -{ - return native_rsqrt(f2); -} - -__inline -float fastLength4(float4 v) -{ - return fast_length(v); -} - -__inline -float4 fastNormalize4(float4 v) -{ - return fast_normalize(v); -} - - -__inline -float sqrtf(float a) -{ -// return sqrt(a); - return native_sqrt(a); -} - -__inline -float4 cross3(float4 a, float4 b) -{ - return cross(a,b); -} - -__inline -float dot3F4(float4 a, float4 b) -{ - float4 a1 = make_float4(a.xyz,0.f); - float4 b1 = make_float4(b.xyz,0.f); - return dot(a1, b1); -} - -__inline -float length3(const float4 a) -{ - return sqrtf(dot3F4(a,a)); -} - -__inline -float dot4(const float4 a, const float4 b) -{ - return dot( a, b ); -} - -// for height -__inline -float dot3w1(const float4 point, const float4 eqn) -{ - return dot3F4(point,eqn) + eqn.w; -} - -__inline -float4 normalize3(const float4 a) -{ - float4 n = make_float4(a.x, a.y, a.z, 0.f); - return fastNormalize4( n ); -// float length = sqrtf(dot3F4(a, a)); -// return 1.f/length * a; -} - -__inline -float4 normalize4(const float4 a) -{ - float length = sqrtf(dot4(a, a)); - return 1.f/length * a; -} - -__inline -float4 createEquation(const float4 a, const float4 b, const float4 c) -{ - float4 eqn; - float4 ab = b-a; - float4 ac = c-a; - eqn = normalize3( cross3(ab, ac) ); - eqn.w = -dot3F4(eqn,a); - return eqn; -} - -/////////////////////////////////////// -// Matrix3x3 -/////////////////////////////////////// - -typedef struct -{ - float4 m_row[3]; -}Matrix3x3; - -__inline -Matrix3x3 mtZero(); - -__inline -Matrix3x3 mtIdentity(); - -__inline -Matrix3x3 mtTranspose(Matrix3x3 m); - -__inline -Matrix3x3 mtMul(Matrix3x3 a, Matrix3x3 b); - -__inline -float4 mtMul1(Matrix3x3 a, float4 b); - -__inline -float4 mtMul3(float4 a, Matrix3x3 b); - -__inline -Matrix3x3 mtZero() -{ - Matrix3x3 m; - m.m_row[0] = (float4)(0.f); - m.m_row[1] = (float4)(0.f); - m.m_row[2] = (float4)(0.f); - return m; -} - -__inline -Matrix3x3 mtIdentity() -{ - Matrix3x3 m; - m.m_row[0] = (float4)(1,0,0,0); - m.m_row[1] = (float4)(0,1,0,0); - m.m_row[2] = (float4)(0,0,1,0); - return m; -} - -__inline -Matrix3x3 mtTranspose(Matrix3x3 m) -{ - Matrix3x3 out; - out.m_row[0] = (float4)(m.m_row[0].x, m.m_row[1].x, m.m_row[2].x, 0.f); - out.m_row[1] = (float4)(m.m_row[0].y, m.m_row[1].y, m.m_row[2].y, 0.f); - out.m_row[2] = (float4)(m.m_row[0].z, m.m_row[1].z, m.m_row[2].z, 0.f); - return out; -} - -__inline -Matrix3x3 mtMul(Matrix3x3 a, Matrix3x3 b) -{ - Matrix3x3 transB; - transB = mtTranspose( b ); - Matrix3x3 ans; - // why this doesn't run when 0ing in the for{} - a.m_row[0].w = 0.f; - a.m_row[1].w = 0.f; - a.m_row[2].w = 0.f; - for(int i=0; i<3; i++) - { -// a.m_row[i].w = 0.f; - ans.m_row[i].x = dot3F4(a.m_row[i],transB.m_row[0]); - ans.m_row[i].y = dot3F4(a.m_row[i],transB.m_row[1]); - ans.m_row[i].z = dot3F4(a.m_row[i],transB.m_row[2]); - ans.m_row[i].w = 0.f; - } - return ans; -} - -__inline -float4 mtMul1(Matrix3x3 a, float4 b) -{ - float4 ans; - ans.x = dot3F4( a.m_row[0], b ); - ans.y = dot3F4( a.m_row[1], b ); - ans.z = dot3F4( a.m_row[2], b ); - ans.w = 0.f; - return ans; -} - -__inline -float4 mtMul3(float4 a, Matrix3x3 b) -{ - float4 colx = make_float4(b.m_row[0].x, b.m_row[1].x, b.m_row[2].x, 0); - float4 coly = make_float4(b.m_row[0].y, b.m_row[1].y, b.m_row[2].y, 0); - float4 colz = make_float4(b.m_row[0].z, b.m_row[1].z, b.m_row[2].z, 0); - - float4 ans; - ans.x = dot3F4( a, colx ); - ans.y = dot3F4( a, coly ); - ans.z = dot3F4( a, colz ); - return ans; -} - -/////////////////////////////////////// -// Quaternion -/////////////////////////////////////// - -typedef float4 Quaternion; - -__inline -Quaternion qtMul(Quaternion a, Quaternion b); - -__inline -Quaternion qtNormalize(Quaternion in); - -__inline -float4 qtRotate(Quaternion q, float4 vec); - -__inline -Quaternion qtInvert(Quaternion q); - -__inline -Matrix3x3 qtGetRotationMatrix(Quaternion q); - - - -__inline -Quaternion qtMul(Quaternion a, Quaternion b) -{ - Quaternion ans; - ans = cross3( a, b ); - ans += a.w*b+b.w*a; -// ans.w = a.w*b.w - (a.x*b.x+a.y*b.y+a.z*b.z); - ans.w = a.w*b.w - dot3F4(a, b); - return ans; -} - -__inline -Quaternion qtNormalize(Quaternion in) -{ - return fastNormalize4(in); -// in /= length( in ); -// return in; -} -__inline -float4 qtRotate(Quaternion q, float4 vec) -{ - Quaternion qInv = qtInvert( q ); - float4 vcpy = vec; - vcpy.w = 0.f; - float4 out = qtMul(qtMul(q,vcpy),qInv); - return out; -} - -__inline -Quaternion qtInvert(Quaternion q) -{ - return (Quaternion)(-q.xyz, q.w); -} - -__inline -float4 qtInvRotate(const Quaternion q, float4 vec) -{ - return qtRotate( qtInvert( q ), vec ); -} - -__inline -Matrix3x3 qtGetRotationMatrix(Quaternion quat) -{ - float4 quat2 = (float4)(quat.x*quat.x, quat.y*quat.y, quat.z*quat.z, 0.f); - Matrix3x3 out; - - out.m_row[0].x=1-2*quat2.y-2*quat2.z; - out.m_row[0].y=2*quat.x*quat.y-2*quat.w*quat.z; - out.m_row[0].z=2*quat.x*quat.z+2*quat.w*quat.y; - out.m_row[0].w = 0.f; - - out.m_row[1].x=2*quat.x*quat.y+2*quat.w*quat.z; - out.m_row[1].y=1-2*quat2.x-2*quat2.z; - out.m_row[1].z=2*quat.y*quat.z-2*quat.w*quat.x; - out.m_row[1].w = 0.f; - - out.m_row[2].x=2*quat.x*quat.z-2*quat.w*quat.y; - out.m_row[2].y=2*quat.y*quat.z+2*quat.w*quat.x; - out.m_row[2].z=1-2*quat2.x-2*quat2.y; - out.m_row[2].w = 0.f; - - return out; -} - - -#define WG_SIZE 64 -#define HEIGHT_RES 4 -#define SHAPE_CONVEX_HEIGHT_FIELD 1//keep this in sync with AdlCollisionShape.h! - -typedef struct -{ - float4 m_normal[HEIGHT_RES*HEIGHT_RES*6]; - u32 m_height4[HEIGHT_RES*HEIGHT_RES*6]; - u32 m_supportHeight4[HEIGHT_RES*HEIGHT_RES*6]; - - float m_scale; - float m_padding0; - float m_padding1; - float m_padding2; -} ShapeData; - -typedef struct -{ - u32 m_height4[HEIGHT_RES*HEIGHT_RES*6/4]; - - float m_scale; -} ShapeDeviceData; - -typedef struct -{ - float4 m_pos; - float4 m_quat; - float4 m_linVel; - float4 m_angVel; - - u32 m_shapeIdx; - u32 m_shapeType; - - float m_invMass; - float m_restituitionCoeff; - float m_frictionCoeff; -} BodyData; - -typedef struct -{ - float4 m_worldPos[4]; - float4 m_worldNormal; // w: m_nPoints -// float m_restituitionCoeff; -// float m_frictionCoeff; - u32 m_coeffs; - u32 m_batchIdx; -// int m_nPoints; -// int m_padding0; - - u32 m_bodyAPtr;//x:m_bodyAPtr, y:m_bodyBPtr - u32 m_bodyBPtr; -} Contact4; - -#define GET_NPOINTS(x) (x).m_worldNormal.w - - -typedef struct -{ - int m_nPairs; - float m_collisionMargin; - int m_capacity; - int m_paddings[1]; -} ConstBuffer; - -__inline -float4 transform(const float4* p, const float4* translation, const Quaternion* orientation) -{ - return qtRotate( *orientation, *p ) + (*translation); -} - -__inline -float4 invTransform(const float4* p, const float4* translation, const Quaternion* orientation) -{ - return qtRotate( qtInvert( *orientation ), (*p)-(*translation) ); // use qtInvRotate -} - -void CubeMapUtilsCalcCrd(const float4 p, int* faceIdxOut, float* x, float* y) -{ - { - int idx; - float r2[] = {p.x*p.x, p.y*p.y, p.z*p.z}; - - if (r2[1]>r2[0]) - { - if (r2[2]>r2[1]) - { - idx = 2; - - } else - { - idx = 1; - } - - } else - { - if (r2[2]>r2[0]) - { - idx = 2; - } else - { - idx = 0; - } - } - - *faceIdxOut = (idx*2); -//== - float4 abs = make_float4( fabs(p.x), fabs(p.y), fabs(p.z), 0.f ); - - float d; - if( idx == 0 ) - { - *x = p.y; - *y = p.z; - d = abs.x; - *faceIdxOut += (p.x < 0.f)? 0: 1.f; - } - else if( idx == 1 ) - { - *x = p.z; - *y = p.x; - d = abs.y; - *faceIdxOut += (p.y < 0.f)? 0: 1.f; - } - else - { - *x = p.x; - *y = p.y; - d = abs.z; - *faceIdxOut += (p.z < 0.f)? 0: 1.f; - } - - float dInv = (d==0.f)? 0.f: fastDiv(1.f,d); - *x = (*x*dInv+1.f)*0.5f; - *y = (*y*dInv+1.f)*0.5f; - } -} - -float4 CubeMapUtilsCalcVector(int faceIdx, float x, float y) -{ - int dir = faceIdx/2; - float z = (faceIdx%2 == 0)? -1.f:1.f; - - x = x*2.f-1.f; - y = y*2.f-1.f; - - if( dir == 0 ) - { - return make_float4(z, x, y, 0.f); - } - else if( dir == 1 ) - { - return make_float4(y,z,x, 0.f); - } - else - { - return make_float4(x,y,z, 0.f); - } -} - -typedef int Face; - -u32 sample(__local ShapeDeviceData* shape, int face, int x, int y) -{ - - int idx = HEIGHT_RES*HEIGHT_RES*face + x + y*HEIGHT_RES; - __local u8* height = (__local u8*)shape->m_height4; - return height[idx]; -} - -u32 sampleSupportGlobal(__global ShapeData* shape, int face, int x, int y) -{ - - int idx = HEIGHT_RES*HEIGHT_RES*face + x + y*HEIGHT_RES; - __global u8* height = (__global u8*)shape->m_supportHeight4; - return height[idx]; -} - -float4 sampleNormal(__local ShapeData* shape, int face, int x, int y) -{ - return shape->m_normal[HEIGHT_RES*HEIGHT_RES*face + x + y*HEIGHT_RES]; -} - -float4 sampleNormalGlobal(const __global ShapeData* shape, int face, int x, int y) -{ - return shape->m_normal[HEIGHT_RES*HEIGHT_RES*face + x + y*HEIGHT_RES]; -} - -float4 ShapeDataCalcSamplePoint( __local const ShapeDeviceData* shape, int sIdx )//u8 height, int sIdx, float scale ) -{ - const float oneOver255 = 1.f/255.f; - - int faceIdx = fastDiv(sIdx,(HEIGHT_RES*HEIGHT_RES)); - int r = (sIdx%(HEIGHT_RES*HEIGHT_RES)); - int i = r/HEIGHT_RES; - int j = r%HEIGHT_RES; - - float4 v; - float x = fastDiv((i+0.5f),(float)HEIGHT_RES); - float y = fastDiv((j+0.5f),(float)HEIGHT_RES); - v = CubeMapUtilsCalcVector(faceIdx, x, y); - v = normalize3( v ); - - int quantizedHeight = sample( shape, faceIdx, i, j ); - float rheight = quantizedHeight*oneOver255*shape->m_scale; - return rheight*v; -} - -float ShapeDataQueryDistance(__local const ShapeDeviceData* shape, float4 p ) -{ - if( dot3F4( p, p ) >= shape->m_scale*shape->m_scale ) return FLT_MAX; - - const float oneOver255 = 1.f/255.f; - - int faceIdx; - float x, y; - CubeMapUtilsCalcCrd( p, &faceIdx, &x, &y ); - x = (x*HEIGHT_RES) - 0.5f; - y = (y*HEIGHT_RES) - 0.5f; - - float height; - { - int xi = (int)(x); - int yi = (int)(y); - float dx = x-xi; - float dy = y-yi; - - { - int xip = min2((int)(HEIGHT_RES-1), xi+1); - int yip = min2((int)(HEIGHT_RES-1), yi+1); - - u32 xy = sample( shape, faceIdx, xi, yi ); - u32 xpy = sample( shape, faceIdx, xip, yi ); - u32 xpyp = sample( shape, faceIdx, xip, yip ); - u32 xyp = sample( shape, faceIdx, xi, yip ); - - height = (xy*(1.f-dx)+xpy*dx)*(1.f-dy) + (xyp*(1.f-dx)+xpyp*dx)*dy; - height = height*oneOver255*shape->m_scale; - - p.w = 0.f; - - height = fastLength4( p ) - height; - } - } - - return height; -} - -float ShapeDataQuerySupportHeight(__global ShapeData* shape, float4 p ) -{ - int faceIdx; - float x, y; - CubeMapUtilsCalcCrd( p, &faceIdx, &x, &y ); - x = (x*HEIGHT_RES) - 0.5f; - y = (y*HEIGHT_RES) - 0.5f; - - float height; - { - int xi = (int)(x); - int yi = (int)(y); - - { - int xip = min2((int)(HEIGHT_RES-1), xi+1); - int yip = min2((int)(HEIGHT_RES-1), yi+1); - - u32 xy = sampleSupportGlobal( shape, faceIdx, xi, yi ); - u32 xpy = sampleSupportGlobal( shape, faceIdx, xip, yi ); - u32 xpyp = sampleSupportGlobal( shape, faceIdx, xip, yip ); - u32 xyp = sampleSupportGlobal( shape, faceIdx, xi, yip ); - - height = max2( xy, max2( xpy, max2( xpyp, xyp ) ) ); - height = height/255.f*shape->m_scale; - } - } - - return height; - -} - -float4 ShapeDataQueryNormal(__global const ShapeData* shape, float4 p ) -{ - int faceIdx; - float x, y; - CubeMapUtilsCalcCrd( p, &faceIdx, &x, &y ); - x = (x*HEIGHT_RES) - 0.5f; - y = (y*HEIGHT_RES) - 0.5f; - - float4 normalOut; - { - int xi = (int)(x); - int yi = (int)(y); - - normalOut = sampleNormalGlobal( shape, faceIdx, xi, yi ); - } - return normalOut; -} - - - -// kernels - - -__kernel -__attribute__((reqd_work_group_size(WG_SIZE,1,1))) -void SupportCullingKernel( __global int2* restrict gPairsIn, __global ShapeData* gShapes, - __global BodyData* gBodies, - __global int2* gPairsOut, - counter32_t gNPairs, - ConstBuffer cb ) -{ - int gIdx = GET_GLOBAL_IDX; - if( gIdx >= cb.m_nPairs ) return; - - const float collisionMargin = cb.m_collisionMargin; - const int capacity = cb.m_capacity; - - int2 pair = gPairsIn[gIdx]; - BodyData bodyA = gBodies[pair.x]; - BodyData bodyB = gBodies[pair.y]; - int shapeAIdx = bodyA.m_shapeIdx; - int shapeBIdx = bodyB.m_shapeIdx; - - - bool collide = false; - - //only collide if one of the two bodies has a non-zero mass - if (bodyA.m_invMass==0.f && bodyB.m_invMass==0.f) - return; - - - if (bodyA.m_shapeType == SHAPE_CONVEX_HEIGHT_FIELD && bodyB.m_shapeType==SHAPE_CONVEX_HEIGHT_FIELD) - { - float4 abInA, baInB; - float4 ab = bodyB.m_pos - bodyA.m_pos; - { - abInA = qtInvRotate( bodyA.m_quat, ab ); - baInB = qtInvRotate( bodyB.m_quat, -ab ); - } - float hA = ShapeDataQuerySupportHeight( gShapes+shapeAIdx, abInA ); - float hB = ShapeDataQuerySupportHeight( gShapes+shapeBIdx, baInB ); - - float h2 = dot3F4( ab, ab ); - - collide = ( hA + hB + collisionMargin > sqrtf(h2) ); - } - - if( collide ) - { - int dstIdx; - AppendInc( gNPairs, dstIdx ); - if( dstIdx < capacity ) - gPairsOut[dstIdx] = pair; - } -} - - -#define PARALLEL_DO(execution, n) for(int ie=0; ie h[lIdx+1].y)? h[lIdx]: h[lIdx+1];\ - mem_fence( CLK_LOCAL_MEM_FENCE );\ - h[lIdx] = (h[lIdx].y > h[lIdx+2].y)? h[lIdx]: h[lIdx+2];\ - mem_fence( CLK_LOCAL_MEM_FENCE );\ - h[lIdx] = (h[lIdx].y > h[lIdx+4].y)? h[lIdx]: h[lIdx+4];\ - mem_fence( CLK_LOCAL_MEM_FENCE );\ - h[lIdx] = (h[lIdx].y > h[lIdx+8].y)? h[lIdx]: h[lIdx+8];\ - mem_fence( CLK_LOCAL_MEM_FENCE );\ - h[lIdx] = (h[lIdx].y > h[lIdx+16].y)? h[lIdx]: h[lIdx+16];\ - }} - -#define PARALLEL_REDUCE32(h) \ - {int lIdx = GET_LOCAL_IDX;\ - if( lIdx < 32 )\ - {\ - h[lIdx] += h[lIdx+1];\ - mem_fence( CLK_LOCAL_MEM_FENCE );\ - h[lIdx] += h[lIdx+2];\ - mem_fence( CLK_LOCAL_MEM_FENCE );\ - h[lIdx] += h[lIdx+4];\ - mem_fence( CLK_LOCAL_MEM_FENCE );\ - h[lIdx] += h[lIdx+8];\ - mem_fence( CLK_LOCAL_MEM_FENCE );\ - h[lIdx] += h[lIdx+16];\ - }} - - -float4 extractManifold(__local float4* p, __local float4* h, __local int* nPointsPtr, float4 nearNormal) -{ - int nPoints = *nPointsPtr; - float4 center = make_float4(0,0,0,0); - { // calculate center - nPoints = min2( nPoints, 32 ); - { - int lIdx = GET_LOCAL_IDX; - h[lIdx] = p[lIdx]; - h[lIdx] = (lIdx= nPoints ) a[ie] = make_int4(-0xfffffff, -0xfffffff, -0xfffffff, -0xfffffff); - } - } - - GROUP_LDS_BARRIER; - - { // vector reduce, h[64] - int lIdx = GET_LOCAL_IDX; - if( lIdx < 32 ) - { - h[lIdx] = max2( h[lIdx], h[lIdx+1] ); - mem_fence( CLK_LOCAL_MEM_FENCE ); - h[lIdx] = max2( h[lIdx], h[lIdx+2] ); - mem_fence( CLK_LOCAL_MEM_FENCE ); - h[lIdx] = max2( h[lIdx], h[lIdx+4] ); - mem_fence( CLK_LOCAL_MEM_FENCE ); - h[lIdx] = max2( h[lIdx], h[lIdx+8] ); - mem_fence( CLK_LOCAL_MEM_FENCE ); - h[lIdx] = max2( h[lIdx], h[lIdx+16] ); - } - } - - GROUP_LDS_BARRIER; - } - { - { // set to idx - idx[0] = (int)a[0].x & 0xff; - idx[1] = (int)a[0].y & 0xff; - idx[2] = (int)a[0].z & 0xff; - idx[3] = (int)a[0].w & 0xff; - } - - GROUP_LDS_BARRIER; - float4 selection; - if( GET_LOCAL_IDX < 4 ) selection = p[idx[GET_LOCAL_IDX]]; - - GROUP_LDS_BARRIER; - if( GET_LOCAL_IDX < 4 ) p[GET_LOCAL_IDX] = selection; - } - - - return center; -} - -void extractManifold1(__local float4* p, __local float4* h, __local int* nPointsPtr, float4 center) -{ - __local int* a = (__local int*)h; - { - GROUP_LDS_BARRIER; - float4 selection; - if( GET_LOCAL_IDX < 4 ) - { - int idx = (int)a[GET_LOCAL_IDX] & 0xff; - selection = p[idx]; - } - - GROUP_LDS_BARRIER; - if( GET_LOCAL_IDX < 4 ) p[GET_LOCAL_IDX] = selection; - } - -} - -void extractManifold2( __local float4* p0, __local int* nPointsPtr0, float4 nearNormal0, - __local float4* p1, __local int* nPointsPtr1, float4 nearNormal1, - __local float4* h, float4 centerOut[2]) -{ - - int nPoints[2]; - nPoints[0] = *nPointsPtr0; - nPoints[1] = *nPointsPtr1; - float4 center[2]; - center[0] = make_float4(0,0,0,0); - center[1] = make_float4(0,0,0,0); - { // calculate center - nPoints[0] = min2( nPoints[0], 32 ); - nPoints[1] = min2( nPoints[1], 32 ); - { - int lIdx = GET_LOCAL_IDX; - h[lIdx] = (lIdx= nPoints[setIdx] ) a[ie + setIdx*64] = make_int4(-0xfffffff, -0xfffffff, -0xfffffff, -0xfffffff); - - a[ie + 32] = make_int4(-0xfffffff, -0xfffffff, -0xfffffff, -0xfffffff); - } - } - } - GROUP_LDS_BARRIER; - - { // vector reduce, h[64] - int bIdx = GET_LOCAL_IDX/32; - int eIdx = GET_LOCAL_IDX%32; - int lIdx = eIdx + bIdx*64; - { - h[lIdx] = max2( h[lIdx], h[lIdx+1] ); - mem_fence( CLK_LOCAL_MEM_FENCE ); - h[lIdx] = max2( h[lIdx], h[lIdx+2] ); - mem_fence( CLK_LOCAL_MEM_FENCE ); - h[lIdx] = max2( h[lIdx], h[lIdx+4] ); - mem_fence( CLK_LOCAL_MEM_FENCE ); - h[lIdx] = max2( h[lIdx], h[lIdx+8] ); - mem_fence( CLK_LOCAL_MEM_FENCE ); - h[lIdx] = max2( h[lIdx], h[lIdx+16] ); - } - } - - GROUP_LDS_BARRIER; - } - __local int* a = (__local int*)h; - { - GROUP_LDS_BARRIER; - - float4 selection; - - int bIdx = GET_LOCAL_IDX/32; - int eIdx = GET_LOCAL_IDX%32; - - if( eIdx < 4 ) - { - int idx = (int)a[eIdx+64*4*bIdx] & 0xff; - selection = p0[idx+32*bIdx]; - } - - GROUP_LDS_BARRIER; - if( eIdx < 4 ) p0[eIdx+32*bIdx] = selection; - } -} - -/* -1. Query Normal -2. Fill Normal -3. A->B, B->A -*/ - -void testVtx(__local BodyData* bodyAPtr, __local BodyData* bodyBPtr, - __local ShapeDeviceData* shapeAPtr, __local ShapeDeviceData* shapeBPtr, - __local int* lNContacts, __local float4* lCPoints) -{ - int pIdx = GET_LOCAL_IDX; - float4 bodyAPos = bodyAPtr->m_pos; - float4 bodyBPos = bodyBPtr->m_pos; - Quaternion bodyAQuat = bodyAPtr->m_quat; - Quaternion bodyBQuat = bodyBPtr->m_quat; - while( pIdx < HEIGHT_RES*HEIGHT_RES*6 ) - { - float4 pInB = ShapeDataCalcSamplePoint( shapeBPtr, pIdx ); - - float4 pInW = transform( &pInB, &bodyBPos, &bodyBQuat ); -// Aabb bodyAAabb = bodyAPtr->m_aabb; -// if( AabbOverlapsPoint( &bodyAAabb, pInW ) ) - { - float4 pInA = invTransform( &pInW, &bodyAPos, &bodyAQuat ); - - float dist = ShapeDataQueryDistance( shapeAPtr, pInA ); - if( dist < 0.010f ) - { - int dstIdx = atom_add( lNContacts, 1 ); - if( dstIdx < 32 ) - { - lCPoints[ dstIdx ] = make_float4( pInA.x, pInA.y, pInA.z, dist ); - } - } - } - - pIdx += GET_GROUP_SIZE; - } -} - -void testVtx2(__local const BodyData* bodyA, __local const BodyData* bodyB, - __local const ShapeDeviceData* shapeA, __local const ShapeDeviceData* shapeB, - __local int* lNContactsA, __local float4* lCPointsA, - __local int* lNContactsB, __local float4* lCPointsB, float collisionMargin ) -{ - int pIdx = GET_LOCAL_IDX; - - while( pIdx < HEIGHT_RES*HEIGHT_RES*6*2 ) - { - __local const BodyData* bodyAPtr =( pIdx < HEIGHT_RES*HEIGHT_RES*6 )?bodyA:bodyB; - __local const BodyData* bodyBPtr =( pIdx < HEIGHT_RES*HEIGHT_RES*6 )?bodyB:bodyA; - __local const ShapeDeviceData* shapeAPtr =( pIdx < HEIGHT_RES*HEIGHT_RES*6 )?shapeA:shapeB; - __local const ShapeDeviceData* shapeBPtr =( pIdx < HEIGHT_RES*HEIGHT_RES*6 )?shapeB:shapeA; - __local int* lNContacts =( pIdx < HEIGHT_RES*HEIGHT_RES*6 )?lNContactsA:lNContactsB; - __local float4* lCPoints =( pIdx < HEIGHT_RES*HEIGHT_RES*6 )?lCPointsA:lCPointsB; - - float4 bodyAPos = bodyAPtr->m_pos; - float4 bodyBPos = bodyBPtr->m_pos; - Quaternion bodyAQuat = bodyAPtr->m_quat; - Quaternion bodyBQuat = bodyBPtr->m_quat; - - float4 pInB = ShapeDataCalcSamplePoint( shapeBPtr, pIdx%(HEIGHT_RES*HEIGHT_RES*6) ); - - float4 pInW = transform( &pInB, &bodyBPos, &bodyBQuat ); -// Aabb bodyAAabb = bodyAPtr->m_aabb; -// if( AabbOverlapsPoint( &bodyAAabb, pInW ) ) - { - float4 pInA = invTransform( &pInW, &bodyAPos, &bodyAQuat ); - - float dist = ShapeDataQueryDistance( shapeAPtr, pInA ); - if( dist < collisionMargin ) - { - int dstIdx = atom_add( lNContacts, 1 ); - if( dstIdx < 32 ) - { - lCPoints[ dstIdx ] = make_float4( pInA.x, pInA.y, pInA.z, dist ); - } - } - } - - pIdx += GET_GROUP_SIZE; - } -} - -void testVtxWithPlane(__local BodyData* bodyA, __local BodyData* bodyB, - float4 nA, __local ShapeDeviceData* shapeB, - __local int* lNContactsA, __local float4* lCPointsA, float collisionMargin) -{ - int pIdx = GET_LOCAL_IDX; - - while( pIdx < HEIGHT_RES*HEIGHT_RES*6 ) - { - __local BodyData* bodyAPtr =bodyA; - __local BodyData* bodyBPtr =bodyB; - __local ShapeDeviceData* shapeBPtr =shapeB; - __local int* lNContacts =lNContactsA; - __local float4* lCPoints =lCPointsA; - - float4 bodyAPos = bodyAPtr->m_pos; - float4 bodyBPos = bodyBPtr->m_pos; - Quaternion bodyAQuat = bodyAPtr->m_quat; - Quaternion bodyBQuat = bodyBPtr->m_quat; - - float4 pInB = ShapeDataCalcSamplePoint( shapeBPtr, pIdx%(HEIGHT_RES*HEIGHT_RES*6) ); - - float4 pInW = transform( &pInB, &bodyBPos, &bodyBQuat ); - { - float4 pInA = invTransform( &pInW, &bodyAPos, &bodyAQuat ); - - float dist = dot3w1( pInA, nA );//ShapeDataQueryDistance( shapeAPtr, pInA ); - if( dist < collisionMargin ) - { - int dstIdx = atom_add( lNContacts, 1 ); - if( dstIdx < 32 ) - { - lCPoints[ dstIdx ] = make_float4( pInA.x, pInA.y, pInA.z, dist ); - } - } - } - - pIdx += GET_GROUP_SIZE; - } -} - -#define GET_SHAPE_IDX(x) (int)((x).m_shapeIdx) - -void output(__local BodyData* bodyAPtr, __local BodyData* bodyBPtr, - __local int2* iPair, - __local int* lNContacts, __local float4* lCPoints, - float4 center, - __global ShapeData* shapeData, __global Contact4* contactsOut, float collisionMargin) -{ - if( *lNContacts != 0 ) - { - int nContacts = min2( *lNContacts, 4 ); - - __global Contact4* c = contactsOut; - - if( GET_LOCAL_IDX < nContacts ) - { - int i = GET_LOCAL_IDX; - float4 p = lCPoints[i]; - float4 bodyAPos = bodyAPtr->m_pos; - Quaternion bodyAQuat = bodyAPtr->m_quat; - - c->m_worldPos[i] = transform( &p, &bodyAPos, &bodyAQuat ); - c->m_worldPos[i].w = lCPoints[i].w - collisionMargin; - } - - if( GET_LOCAL_IDX == 0 ) - { - float4 contactNormal; - contactNormal = ShapeDataQueryNormal( &shapeData[GET_SHAPE_IDX(*bodyAPtr)], center ); - contactNormal = normalize3( qtRotate( bodyAPtr->m_quat, contactNormal ) ); - - c->m_worldNormal = contactNormal; -// c->m_restituitionCoeff = 0.f; -// c->m_frictionCoeff = 0.7f; - c->m_coeffs = (u32)(0.f*0xffff) | ((u32)(0.7f*0xffff)<<16); - GET_NPOINTS(*c) = nContacts; - c->m_bodyAPtr = iPair[0].x; - c->m_bodyBPtr = iPair[0].y; - } - } - else - { - if( GET_LOCAL_IDX == 0 ) - GET_NPOINTS(contactsOut[0]) = 0; - } -} - -// todo. make it better -void output2(__local BodyData* bodyAPtr, __local BodyData* bodyBPtr, - int pair0, int pair1, - __local int* lNContacts, __local float4* lCPoints, - float4 center, - const __global ShapeData* shapeData, __global Contact4* contactsOut, counter32_t nContactsOut, int capacity, - float collisionMargin ) -{ - int lIdx = GET_LOCAL_IDX%32; - int nContacts = min2( *lNContacts, 4 ); - - GROUP_LDS_BARRIER; - - if( lIdx == 0 && nContacts) - { - int dstIdx; - AppendInc( nContactsOut, dstIdx ); - *lNContacts = dstIdx; - - if( dstIdx >= capacity ) - *lNContacts = -1; - } - - GROUP_LDS_BARRIER; - - bool canWrite = (*lNContacts!=-1); - - if( nContacts && canWrite ) - { - __global Contact4* c = contactsOut + (*lNContacts); - - if( lIdx < nContacts ) - { - int i = lIdx; - float4 p = lCPoints[i]; - float4 bodyAPos = bodyAPtr->m_pos; - Quaternion bodyAQuat = bodyAPtr->m_quat; - - p = transform( &p, &bodyAPos, &bodyAQuat ); - p.w = lCPoints[i].w - collisionMargin; - c->m_worldPos[i] = p; - } - - if( lIdx == 0 ) - { - if( nContacts ) - { - float4 contactNormal; - contactNormal = ShapeDataQueryNormal( &shapeData[GET_SHAPE_IDX(*bodyAPtr)], center ); - contactNormal = normalize3( qtRotate( bodyAPtr->m_quat, contactNormal ) ); - - c->m_worldNormal = contactNormal; -// c->m_restituitionCoeff = 0.f; -// c->m_frictionCoeff = 0.7f; - c->m_coeffs = (u32)(0.f*0xffff) | ((u32)(0.7f*0xffff)<<16); - c->m_bodyAPtr = pair0; - c->m_bodyBPtr = pair1; - } - GET_NPOINTS(*c) = nContacts; - } - } -} - -__inline -void output2LDS(__local BodyData* bodyAPtr, __local BodyData* bodyBPtr, - int pair0, int pair1, - int lNContacts, __local float4* lCPoints, - float4 center, - const __global ShapeData* shapeData, __local Contact4* contactsOut, - float collisionMargin ) -{ - int lIdx = GET_LOCAL_IDX%32; -// int lIdx = GET_LOCAL_IDX; -// int groupIdx = 0; - - int nContacts = min2( lNContacts, 4 ); - - GROUP_LDS_BARRIER; - - if( nContacts != 0 ) - { - if( lIdx < nContacts ) - { - int i = lIdx; - float4 p = lCPoints[i]; - float4 bodyAPos = bodyAPtr->m_pos; - Quaternion bodyAQuat = bodyAPtr->m_quat; - - p = transform( &p, &bodyAPos, &bodyAQuat ); - p.w = lCPoints[i].w - collisionMargin; - contactsOut->m_worldPos[i] = p; - } - } - - if( lIdx == 0 ) - { - if( nContacts != 0 ) - { - float4 contactNormal; - contactNormal = ShapeDataQueryNormal( &shapeData[GET_SHAPE_IDX(*bodyAPtr)], center ); - contactNormal = normalize3( qtRotate( bodyAPtr->m_quat, contactNormal ) ); - - contactsOut->m_worldNormal = contactNormal; -// contactsOut->m_worldNormal = make_float4(1.5f,1.4f,1.3f,0.f); -// contactsOut->m_restituitionCoeff = 0.f; -// contactsOut->m_frictionCoeff = 0.7f; - contactsOut->m_coeffs = (u32)(0.f*0xffff) | ((u32)(0.7f*0xffff)<<16); - contactsOut->m_bodyAPtr = pair0; - contactsOut->m_bodyBPtr = pair1; - } - GET_NPOINTS(*contactsOut) = nContacts;//nContacts; - } - -// contactsOut[groupIdx].m_worldNormal = make_float4(1.5f,1.4f,1.3f,0.f); -} - -void output2_1(__local BodyData* bodyAPtr, __local BodyData* bodyBPtr, - int pair0, int pair1, - __local int* lNContacts, __local float4* lCPoints, - float4 center, float4 nA, - const __global ShapeData* shapeData, __global Contact4* contactsOut, counter32_t nContactsOut, int capacity, float collisionMargin ) -{ - int lIdx = GET_LOCAL_IDX; - int nContacts = min2( *lNContacts, 4 ); - - GROUP_LDS_BARRIER; - - if( lIdx == 0 && nContacts) - { - int dstIdx; - AppendInc( nContactsOut, dstIdx ); - *lNContacts = dstIdx; - - if( dstIdx >= capacity ) - *lNContacts = -1; - } - - GROUP_LDS_BARRIER; - - bool canWrite = (*lNContacts!=-1); - - if( nContacts && canWrite ) - { - __global Contact4* c = contactsOut + (*lNContacts); - - if( lIdx < nContacts ) - { - int i = lIdx; - float4 p = lCPoints[i]; - float4 bodyAPos = bodyAPtr->m_pos; - Quaternion bodyAQuat = bodyAPtr->m_quat; - - p = transform( &p, &bodyAPos, &bodyAQuat ); - p.w = lCPoints[i].w - collisionMargin; - c->m_worldPos[i] = p; - } - - if( lIdx == 0 ) - { - if( nContacts ) - { - float4 contactNormal; - contactNormal = nA;//ShapeDataQueryNormal( &shapeData[GET_SHAPE_IDX(*bodyAPtr)], center ); - contactNormal = normalize3( qtRotate( bodyAPtr->m_quat, contactNormal ) ); - - c->m_worldNormal = contactNormal; -// c->m_restituitionCoeff = 0.f; -// c->m_frictionCoeff = 0.7f; - c->m_coeffs = (u32)(0.f*0xffff) | ((u32)(0.7f*0xffff)<<16); - c->m_bodyAPtr = pair0; - c->m_bodyBPtr = pair1; - } - GET_NPOINTS(*c) = nContacts; - } - } -} - -__kernel -void manifold(__global float4* vIn, __global float4* vOut) -{ - __local float4 lCPoints[32]; - __local float4 lManifoldBuffer[64]; - __local int lNContacts; - __local float4 ab; - - if( GET_LOCAL_IDX<32 ) - { - lCPoints[GET_LOCAL_IDX] = vIn[GET_GLOBAL_IDX]; - } - - if( GET_LOCAL_IDX == 0 ) - { - lNContacts = 32; - ab = vIn[GET_GLOBAL_IDX]; - } - - GROUP_LDS_BARRIER; - - float4 center = extractManifold( lCPoints, lManifoldBuffer, &lNContacts, ab ); - - if( GET_LOCAL_IDX < lNContacts ) - { - vOut[4*GET_GROUP_IDX+GET_LOCAL_IDX] = lCPoints[GET_LOCAL_IDX]; - } - -} - -//#define COMBINE_REDUCTION - -__kernel -__attribute__((reqd_work_group_size(64, 1, 1))) -void NarrowphaseKernel( const __global int2* restrict pairs, const __global ShapeData* shapeData, const __global BodyData* restrict bodyDatas, - __global Contact4* restrict contactsOut, - counter32_t nContactsOut, ConstBuffer cb ) -{ - // 2.5K LDS - __local Contact4 ldsContacts[2]; - __local BodyData bodyA; - __local BodyData bodyB; - __local ShapeDeviceData shapeA; - __local ShapeDeviceData shapeB; - __local float4 lCPointsA[32*2]; - __local int lNContactsA; - __local float4* lCPointsB = lCPointsA+32; - __local int lNContactsB; -#ifdef COMBINE_REDUCTION - __local float4 lManifoldBuffer[64*2]; -#else - __local float4 lManifoldBuffer[64]; -#endif - __local int2 iPairAB; - - const int capacity = cb.m_capacity; - const float collisionMargin = cb.m_collisionMargin; - - - int pairIdx = GET_GROUP_IDX; -// for(int pairIdx = GET_GROUP_IDX; pairIdxm_height4[idx] = shapeData[ myShapeIdx ].m_height4[idx]; - - idx+=32; - } - } - - GROUP_LDS_BARRIER; - - testVtx2( &bodyA, &bodyB, &shapeA, &shapeB, &lNContactsA, lCPointsA, &lNContactsB, lCPointsB, collisionMargin ); - - GROUP_LDS_BARRIER; - - float4 ab = bodyB.m_pos - bodyA.m_pos; - float4 center[2]; - - if( lNContactsA != 0 || lNContactsB != 0 ) - { - float4 abInA; - abInA = qtInvRotate( bodyA.m_quat, ab ); - - float4 abInB; - abInB = qtInvRotate( bodyB.m_quat, ab ); - -#ifdef COMBINE_REDUCTION - extractManifold2( lCPointsA, &lNContactsA, abInA, - lCPointsB, &lNContactsB, abInB, - lManifoldBuffer, center ); -#else - if( lNContactsA != 0 ) - center[0] = extractManifold( lCPointsA, lManifoldBuffer, &lNContactsA, abInA ); - if( lNContactsB != 0 ) - center[1] = extractManifold( lCPointsB, lManifoldBuffer, &lNContactsB, abInB ); -#endif - } - - int firstSet = GET_LOCAL_IDX/32; - -/* - if( GET_LOCAL_IDX == 0 ) // for debug - { - ldsContacts[0].m_worldNormal = make_float4(-1,-1,-1,0); - ldsContacts[0].m_bodyAPtr = 0; - ldsContacts[0].m_bodyBPtr = 0; - ldsContacts[0].m_batchIdx = 111; - ldsContacts[1].m_worldNormal = make_float4(-1,-1,-1,0); - ldsContacts[1].m_bodyAPtr = 0; - ldsContacts[1].m_bodyBPtr = 0; - ldsContacts[1].m_batchIdx = 111; - } -*/ - bool doReduction = true; - if( doReduction ) - { - GROUP_LDS_BARRIER; - - output2LDS( (firstSet)?&bodyA: &bodyB, (firstSet)?&bodyB : &bodyA, - (firstSet)?iPairAB.x : iPairAB.y, (firstSet)?iPairAB.y : iPairAB.x, - (firstSet)?lNContactsA : lNContactsB, (firstSet)?lCPointsA:lCPointsB, - (firstSet)?center[0] : center[1], shapeData, (firstSet)?&ldsContacts[0]: &ldsContacts[1], collisionMargin ); - - GROUP_LDS_BARRIER; - - if( GET_LOCAL_IDX == 0 ) - { - if( lNContactsA && lNContactsB ) - { - float nDotn = dot3F4( ldsContacts[0].m_worldNormal, ldsContacts[1].m_worldNormal ); - if( nDotn < -(1.f-0.01f) ) - { - if( ldsContacts[0].m_bodyAPtr > ldsContacts[1].m_bodyAPtr ) - lNContactsA = 0; - else - lNContactsB = 0; - } - } - } - - if( GET_LOCAL_IDX == 0 ) - { - int n = lNContactsA; - if( n != 0 ) - { - int dstIdx; - AppendInc( nContactsOut, dstIdx ); - if( dstIdx < capacity ) - { int idx = 0; - contactsOut[ dstIdx ] = ldsContacts[idx]; - contactsOut[ dstIdx].m_batchIdx = pairIdx; - } - } - - n = lNContactsB; - if( n != 0 ) - { - int dstIdx; - AppendInc( nContactsOut, dstIdx ); - if( dstIdx < capacity ) - { int idx = 1; - contactsOut[ dstIdx ] = ldsContacts[idx]; - contactsOut[ dstIdx].m_batchIdx = pairIdx; - } - } - } - - GROUP_LDS_BARRIER; - } - else - { - //output2( (firstSet)?&bodyA: &bodyB, (firstSet)?&bodyB : &bodyA, - // (firstSet)?iPairAB.x : iPairAB.y, (firstSet)?iPairAB.y : iPairAB.x, - // (firstSet)?&lNContactsA : &lNContactsB, (firstSet)?lCPointsA:lCPointsB, - // (firstSet)?center[0] : center[1], shapeData, contactsOut, nContactsOut, capacity, collisionMargin ); - } - } -} - - -__kernel -__attribute__((reqd_work_group_size(64, 1, 1))) -void NarrowphaseWithPlaneKernel( const __global int2* restrict pairs, const __global ShapeData* shapeData, const __global BodyData* restrict bodyDatas, - __global Contact4* restrict contactsOut, - counter32_t nContactsOut, ConstBuffer cb ) -{ - // 2.5K LDS - __local BodyData bodyA; - __local BodyData bodyB; - __local ShapeDeviceData shapeA; - __local ShapeDeviceData shapeB; - __local float4 lCPointsA[32*2]; - __local int lNContactsA; -// __local float4* lCPointsB = lCPointsA+32; -// __local int lNContactsB; - __local float4 lManifoldBuffer[64]; - __local int2 iPairAB; - - const int capacity = cb.m_capacity; - const float collisionMargin = cb.m_collisionMargin; - - int pairIdx = GET_GROUP_IDX; - { - if( GET_LOCAL_IDX == 0 ) // load Bodies - { - int2 pair = pairs[pairIdx]; - iPairAB = make_int2(pair.x, pair.y); - bodyA = bodyDatas[ pair.x ]; - bodyB = bodyDatas[ pair.y ]; - shapeA.m_scale = shapeData[ GET_SHAPE_IDX(bodyA) ].m_scale; - shapeB.m_scale = shapeData[ GET_SHAPE_IDX(bodyB) ].m_scale; - lNContactsA = 0; -// lNContactsB = 0; - } - - GROUP_LDS_BARRIER; - - if (bodyB.m_invMass == 0.f) - return; - - // todo. can check if the shape is the same to previous one. If same, dont read - { // load shape data - int idx = GET_LOCAL_IDX%32; - int bIdx = GET_LOCAL_IDX/32; - __local ShapeDeviceData* myShape = (bIdx==0)?&shapeA: &shapeB; - int myShapeIdx = (bIdx==0)?GET_SHAPE_IDX(bodyA): GET_SHAPE_IDX(bodyB); - - while( idx < HEIGHT_RES*HEIGHT_RES*6/4 ) - { - myShape->m_height4[idx] = shapeData[ myShapeIdx ].m_height4[idx]; - - idx+=32; - } - } - - GROUP_LDS_BARRIER; - - float4 nA = make_float4(0,1,0,0); - - -// testVtx2( &bodyA, &bodyB, &shapeA, &shapeB, &lNContactsA, lCPointsA, &lNContactsB, lCPointsB ); - testVtxWithPlane( &bodyA, &bodyB, nA, &shapeB, &lNContactsA, lCPointsA, collisionMargin ); - - GROUP_LDS_BARRIER; - -// float4 ab = bodyB.m_pos - bodyA.m_pos; - float4 center[2]; - - if( lNContactsA != 0 ) - { - float4 abInA; - abInA = nA;//qtInvRotate( bodyA.m_quat, ab ); - - if( lNContactsA != 0 ) - center[0] = extractManifold( lCPointsA, lManifoldBuffer, &lNContactsA, abInA ); - } - -// int firstSet = GET_LOCAL_IDX/32; - - output2_1( &bodyA, &bodyB, - iPairAB.x, iPairAB.y, - &lNContactsA, lCPointsA, - center[0], nA, shapeData, contactsOut, nContactsOut, capacity, collisionMargin ); - } -} \ No newline at end of file diff --git a/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/ChNarrowphaseKernels.h b/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/ChNarrowphaseKernels.h deleted file mode 100644 index ff846cb60..000000000 --- a/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/ChNarrowphaseKernels.h +++ /dev/null @@ -1,1616 +0,0 @@ -static const char* narrowphaseKernelsCL= \ -"\n" -"#pragma OPENCL EXTENSION cl_amd_printf : enable\n" -"#pragma OPENCL EXTENSION cl_khr_local_int32_base_atomics : enable\n" -"#pragma OPENCL EXTENSION cl_khr_global_int32_base_atomics : enable\n" -"#pragma OPENCL EXTENSION cl_khr_local_int32_extended_atomics : enable\n" -"#pragma OPENCL EXTENSION cl_khr_global_int32_extended_atomics : enable\n" -"\n" -"#ifdef cl_ext_atomic_counters_32\n" -"#pragma OPENCL EXTENSION cl_ext_atomic_counters_32 : enable\n" -"#else\n" -"#define counter32_t volatile global int*\n" -"#endif\n" -"\n" -"\n" -"typedef unsigned int u32;\n" -"typedef unsigned short u16;\n" -"typedef unsigned char u8;\n" -"\n" -"#define GET_GROUP_IDX get_group_id(0)\n" -"#define GET_LOCAL_IDX get_local_id(0)\n" -"#define GET_GLOBAL_IDX get_global_id(0)\n" -"#define GET_GROUP_SIZE get_local_size(0)\n" -"#define GET_NUM_GROUPS get_num_groups(0)\n" -"#define GROUP_LDS_BARRIER barrier(CLK_LOCAL_MEM_FENCE)\n" -"#define GROUP_MEM_FENCE mem_fence(CLK_LOCAL_MEM_FENCE)\n" -"#define AtomInc(x) atom_inc(&(x))\n" -"#define AtomInc1(x, out) out = atom_inc(&(x))\n" -"#define AppendInc(x, out) out = atomic_inc(x)\n" -"#define AtomAdd(x, value) atom_add(&(x), value)\n" -"#define AtomCmpxhg(x, cmp, value) atom_cmpxchg( &(x), cmp, value )\n" -"#define AtomXhg(x, value) atom_xchg ( &(x), value )\n" -"\n" -"\n" -"#define SELECT_UINT4( b, a, condition ) select( b,a,condition )\n" -"\n" -"#define make_float4 (float4)\n" -"#define make_float2 (float2)\n" -"#define make_uint4 (uint4)\n" -"#define make_int4 (int4)\n" -"#define make_uint2 (uint2)\n" -"#define make_int2 (int2)\n" -"\n" -"\n" -"#define max2 max\n" -"#define min2 min\n" -"\n" -"\n" -"///////////////////////////////////////\n" -"// Vector\n" -"///////////////////////////////////////\n" -"__inline\n" -"float fastDiv(float numerator, float denominator)\n" -"{\n" -" return native_divide(numerator, denominator); \n" -"// return numerator/denominator; \n" -"}\n" -"\n" -"__inline\n" -"float4 fastDiv4(float4 numerator, float4 denominator)\n" -"{\n" -" return native_divide(numerator, denominator); \n" -"}\n" -"\n" -"__inline\n" -"float fastSqrtf(float f2)\n" -"{\n" -" return native_sqrt(f2);\n" -"// return sqrt(f2);\n" -"}\n" -"\n" -"__inline\n" -"float fastRSqrt(float f2)\n" -"{\n" -" return native_rsqrt(f2);\n" -"}\n" -"\n" -"__inline\n" -"float fastLength4(float4 v)\n" -"{\n" -" return fast_length(v);\n" -"}\n" -"\n" -"__inline\n" -"float4 fastNormalize4(float4 v)\n" -"{\n" -" return fast_normalize(v);\n" -"}\n" -"\n" -"\n" -"__inline\n" -"float sqrtf(float a)\n" -"{\n" -"// return sqrt(a);\n" -" return native_sqrt(a);\n" -"}\n" -"\n" -"__inline\n" -"float4 cross3(float4 a, float4 b)\n" -"{\n" -" return cross(a,b);\n" -"}\n" -"\n" -"__inline\n" -"float dot3F4(float4 a, float4 b)\n" -"{\n" -" float4 a1 = make_float4(a.xyz,0.f);\n" -" float4 b1 = make_float4(b.xyz,0.f);\n" -" return dot(a1, b1);\n" -"}\n" -"\n" -"__inline\n" -"float length3(const float4 a)\n" -"{\n" -" return sqrtf(dot3F4(a,a));\n" -"}\n" -"\n" -"__inline\n" -"float dot4(const float4 a, const float4 b)\n" -"{\n" -" return dot( a, b );\n" -"}\n" -"\n" -"// for height\n" -"__inline\n" -"float dot3w1(const float4 point, const float4 eqn)\n" -"{\n" -" return dot3F4(point,eqn) + eqn.w;\n" -"}\n" -"\n" -"__inline\n" -"float4 normalize3(const float4 a)\n" -"{\n" -" float4 n = make_float4(a.x, a.y, a.z, 0.f);\n" -" return fastNormalize4( n );\n" -"// float length = sqrtf(dot3F4(a, a));\n" -"// return 1.f/length * a;\n" -"}\n" -"\n" -"__inline\n" -"float4 normalize4(const float4 a)\n" -"{\n" -" float length = sqrtf(dot4(a, a));\n" -" return 1.f/length * a;\n" -"}\n" -"\n" -"__inline\n" -"float4 createEquation(const float4 a, const float4 b, const float4 c)\n" -"{\n" -" float4 eqn;\n" -" float4 ab = b-a;\n" -" float4 ac = c-a;\n" -" eqn = normalize3( cross3(ab, ac) );\n" -" eqn.w = -dot3F4(eqn,a);\n" -" return eqn;\n" -"}\n" -"\n" -"///////////////////////////////////////\n" -"// Matrix3x3\n" -"///////////////////////////////////////\n" -"\n" -"typedef struct\n" -"{\n" -" float4 m_row[3];\n" -"}Matrix3x3;\n" -"\n" -"__inline\n" -"Matrix3x3 mtZero();\n" -"\n" -"__inline\n" -"Matrix3x3 mtIdentity();\n" -"\n" -"__inline\n" -"Matrix3x3 mtTranspose(Matrix3x3 m);\n" -"\n" -"__inline\n" -"Matrix3x3 mtMul(Matrix3x3 a, Matrix3x3 b);\n" -"\n" -"__inline\n" -"float4 mtMul1(Matrix3x3 a, float4 b);\n" -"\n" -"__inline\n" -"float4 mtMul3(float4 a, Matrix3x3 b);\n" -"\n" -"__inline\n" -"Matrix3x3 mtZero()\n" -"{\n" -" Matrix3x3 m;\n" -" m.m_row[0] = (float4)(0.f);\n" -" m.m_row[1] = (float4)(0.f);\n" -" m.m_row[2] = (float4)(0.f);\n" -" return m;\n" -"}\n" -"\n" -"__inline\n" -"Matrix3x3 mtIdentity()\n" -"{\n" -" Matrix3x3 m;\n" -" m.m_row[0] = (float4)(1,0,0,0);\n" -" m.m_row[1] = (float4)(0,1,0,0);\n" -" m.m_row[2] = (float4)(0,0,1,0);\n" -" return m;\n" -"}\n" -"\n" -"__inline\n" -"Matrix3x3 mtTranspose(Matrix3x3 m)\n" -"{\n" -" Matrix3x3 out;\n" -" out.m_row[0] = (float4)(m.m_row[0].x, m.m_row[1].x, m.m_row[2].x, 0.f);\n" -" out.m_row[1] = (float4)(m.m_row[0].y, m.m_row[1].y, m.m_row[2].y, 0.f);\n" -" out.m_row[2] = (float4)(m.m_row[0].z, m.m_row[1].z, m.m_row[2].z, 0.f);\n" -" return out;\n" -"}\n" -"\n" -"__inline\n" -"Matrix3x3 mtMul(Matrix3x3 a, Matrix3x3 b)\n" -"{\n" -" Matrix3x3 transB;\n" -" transB = mtTranspose( b );\n" -" Matrix3x3 ans;\n" -" // why this doesn't run when 0ing in the for{}\n" -" a.m_row[0].w = 0.f;\n" -" a.m_row[1].w = 0.f;\n" -" a.m_row[2].w = 0.f;\n" -" for(int i=0; i<3; i++)\n" -" {\n" -"// a.m_row[i].w = 0.f;\n" -" ans.m_row[i].x = dot3F4(a.m_row[i],transB.m_row[0]);\n" -" ans.m_row[i].y = dot3F4(a.m_row[i],transB.m_row[1]);\n" -" ans.m_row[i].z = dot3F4(a.m_row[i],transB.m_row[2]);\n" -" ans.m_row[i].w = 0.f;\n" -" }\n" -" return ans;\n" -"}\n" -"\n" -"__inline\n" -"float4 mtMul1(Matrix3x3 a, float4 b)\n" -"{\n" -" float4 ans;\n" -" ans.x = dot3F4( a.m_row[0], b );\n" -" ans.y = dot3F4( a.m_row[1], b );\n" -" ans.z = dot3F4( a.m_row[2], b );\n" -" ans.w = 0.f;\n" -" return ans;\n" -"}\n" -"\n" -"__inline\n" -"float4 mtMul3(float4 a, Matrix3x3 b)\n" -"{\n" -" float4 colx = make_float4(b.m_row[0].x, b.m_row[1].x, b.m_row[2].x, 0);\n" -" float4 coly = make_float4(b.m_row[0].y, b.m_row[1].y, b.m_row[2].y, 0);\n" -" float4 colz = make_float4(b.m_row[0].z, b.m_row[1].z, b.m_row[2].z, 0);\n" -"\n" -" float4 ans;\n" -" ans.x = dot3F4( a, colx );\n" -" ans.y = dot3F4( a, coly );\n" -" ans.z = dot3F4( a, colz );\n" -" return ans;\n" -"}\n" -"\n" -"///////////////////////////////////////\n" -"// Quaternion\n" -"///////////////////////////////////////\n" -"\n" -"typedef float4 Quaternion;\n" -"\n" -"__inline\n" -"Quaternion qtMul(Quaternion a, Quaternion b);\n" -"\n" -"__inline\n" -"Quaternion qtNormalize(Quaternion in);\n" -"\n" -"__inline\n" -"float4 qtRotate(Quaternion q, float4 vec);\n" -"\n" -"__inline\n" -"Quaternion qtInvert(Quaternion q);\n" -"\n" -"__inline\n" -"Matrix3x3 qtGetRotationMatrix(Quaternion q);\n" -"\n" -"\n" -"\n" -"__inline\n" -"Quaternion qtMul(Quaternion a, Quaternion b)\n" -"{\n" -" Quaternion ans;\n" -" ans = cross3( a, b );\n" -" ans += a.w*b+b.w*a;\n" -"// ans.w = a.w*b.w - (a.x*b.x+a.y*b.y+a.z*b.z);\n" -" ans.w = a.w*b.w - dot3F4(a, b);\n" -" return ans;\n" -"}\n" -"\n" -"__inline\n" -"Quaternion qtNormalize(Quaternion in)\n" -"{\n" -" return fastNormalize4(in);\n" -"// in /= length( in );\n" -"// return in;\n" -"}\n" -"__inline\n" -"float4 qtRotate(Quaternion q, float4 vec)\n" -"{\n" -" Quaternion qInv = qtInvert( q );\n" -" float4 vcpy = vec;\n" -" vcpy.w = 0.f;\n" -" float4 out = qtMul(qtMul(q,vcpy),qInv);\n" -" return out;\n" -"}\n" -"\n" -"__inline\n" -"Quaternion qtInvert(Quaternion q)\n" -"{\n" -" return (Quaternion)(-q.xyz, q.w);\n" -"}\n" -"\n" -"__inline\n" -"float4 qtInvRotate(const Quaternion q, float4 vec)\n" -"{\n" -" return qtRotate( qtInvert( q ), vec );\n" -"}\n" -"\n" -"__inline\n" -"Matrix3x3 qtGetRotationMatrix(Quaternion quat)\n" -"{\n" -" float4 quat2 = (float4)(quat.x*quat.x, quat.y*quat.y, quat.z*quat.z, 0.f);\n" -" Matrix3x3 out;\n" -"\n" -" out.m_row[0].x=1-2*quat2.y-2*quat2.z;\n" -" out.m_row[0].y=2*quat.x*quat.y-2*quat.w*quat.z;\n" -" out.m_row[0].z=2*quat.x*quat.z+2*quat.w*quat.y;\n" -" out.m_row[0].w = 0.f;\n" -"\n" -" out.m_row[1].x=2*quat.x*quat.y+2*quat.w*quat.z;\n" -" out.m_row[1].y=1-2*quat2.x-2*quat2.z;\n" -" out.m_row[1].z=2*quat.y*quat.z-2*quat.w*quat.x;\n" -" out.m_row[1].w = 0.f;\n" -"\n" -" out.m_row[2].x=2*quat.x*quat.z-2*quat.w*quat.y;\n" -" out.m_row[2].y=2*quat.y*quat.z+2*quat.w*quat.x;\n" -" out.m_row[2].z=1-2*quat2.x-2*quat2.y;\n" -" out.m_row[2].w = 0.f;\n" -"\n" -" return out;\n" -"}\n" -"\n" -"\n" -"#define WG_SIZE 64\n" -"#define HEIGHT_RES 4\n" -"#define SHAPE_CONVEX_HEIGHT_FIELD 1//keep this in sync with AdlCollisionShape.h!\n" -"\n" -"typedef struct\n" -"{\n" -" float4 m_normal[HEIGHT_RES*HEIGHT_RES*6];\n" -" u32 m_height4[HEIGHT_RES*HEIGHT_RES*6];\n" -" u32 m_supportHeight4[HEIGHT_RES*HEIGHT_RES*6];\n" -"\n" -" float m_scale;\n" -" float m_padding0;\n" -" float m_padding1;\n" -" float m_padding2;\n" -"} ShapeData;\n" -"\n" -"typedef struct\n" -"{\n" -" u32 m_height4[HEIGHT_RES*HEIGHT_RES*6/4];\n" -"\n" -" float m_scale;\n" -"} ShapeDeviceData;\n" -"\n" -"typedef struct\n" -"{\n" -" float4 m_pos;\n" -" float4 m_quat;\n" -" float4 m_linVel;\n" -" float4 m_angVel;\n" -"\n" -" u32 m_shapeIdx;\n" -" u32 m_shapeType;\n" -" \n" -" float m_invMass;\n" -" float m_restituitionCoeff;\n" -" float m_frictionCoeff;\n" -"} BodyData;\n" -"\n" -"typedef struct\n" -"{\n" -" float4 m_worldPos[4];\n" -" float4 m_worldNormal; // w: m_nPoints\n" -"// float m_restituitionCoeff;\n" -"// float m_frictionCoeff;\n" -" u32 m_coeffs;\n" -" u32 m_batchIdx;\n" -"// int m_nPoints;\n" -"// int m_padding0;\n" -"\n" -" u32 m_bodyAPtr;//x:m_bodyAPtr, y:m_bodyBPtr\n" -" u32 m_bodyBPtr;\n" -"} Contact4;\n" -"\n" -"#define GET_NPOINTS(x) (x).m_worldNormal.w\n" -"\n" -"\n" -"typedef struct\n" -"{\n" -" int m_nPairs;\n" -" float m_collisionMargin;\n" -" int m_capacity;\n" -" int m_paddings[1];\n" -"} ConstBuffer;\n" -"\n" -"__inline\n" -"float4 transform(const float4* p, const float4* translation, const Quaternion* orientation)\n" -"{\n" -" return qtRotate( *orientation, *p ) + (*translation);\n" -"}\n" -"\n" -"__inline\n" -"float4 invTransform(const float4* p, const float4* translation, const Quaternion* orientation)\n" -"{\n" -" return qtRotate( qtInvert( *orientation ), (*p)-(*translation) ); // use qtInvRotate\n" -"}\n" -"\n" -"void CubeMapUtilsCalcCrd(const float4 p, int* faceIdxOut, float* x, float* y)\n" -"{\n" -" {\n" -" int idx;\n" -" float r2[] = {p.x*p.x, p.y*p.y, p.z*p.z};\n" -"\n" -" if (r2[1]>r2[0])\n" -" {\n" -" if (r2[2]>r2[1])\n" -" {\n" -" idx = 2;\n" -" \n" -" } else\n" -" {\n" -" idx = 1;\n" -" }\n" -" \n" -" } else\n" -" {\n" -" if (r2[2]>r2[0])\n" -" {\n" -" idx = 2;\n" -" } else\n" -" {\n" -" idx = 0;\n" -" }\n" -" }\n" -"\n" -" *faceIdxOut = (idx*2);\n" -"//==\n" -" float4 abs = make_float4( fabs(p.x), fabs(p.y), fabs(p.z), 0.f );\n" -"\n" -" float d;\n" -" if( idx == 0 )\n" -" {\n" -" *x = p.y;\n" -" *y = p.z;\n" -" d = abs.x;\n" -" *faceIdxOut += (p.x < 0.f)? 0: 1.f;\n" -" }\n" -" else if( idx == 1 )\n" -" {\n" -" *x = p.z;\n" -" *y = p.x;\n" -" d = abs.y;\n" -" *faceIdxOut += (p.y < 0.f)? 0: 1.f;\n" -" }\n" -" else\n" -" {\n" -" *x = p.x;\n" -" *y = p.y;\n" -" d = abs.z;\n" -" *faceIdxOut += (p.z < 0.f)? 0: 1.f;\n" -" }\n" -"\n" -" float dInv = (d==0.f)? 0.f: fastDiv(1.f,d);\n" -" *x = (*x*dInv+1.f)*0.5f;\n" -" *y = (*y*dInv+1.f)*0.5f;\n" -" }\n" -"}\n" -"\n" -"float4 CubeMapUtilsCalcVector(int faceIdx, float x, float y)\n" -"{\n" -" int dir = faceIdx/2;\n" -" float z = (faceIdx%2 == 0)? -1.f:1.f;\n" -"\n" -" x = x*2.f-1.f;\n" -" y = y*2.f-1.f;\n" -" \n" -" if( dir == 0 )\n" -" {\n" -" return make_float4(z, x, y, 0.f);\n" -" }\n" -" else if( dir == 1 )\n" -" {\n" -" return make_float4(y,z,x, 0.f);\n" -" }\n" -" else\n" -" {\n" -" return make_float4(x,y,z, 0.f);\n" -" }\n" -"}\n" -"\n" -"typedef int Face;\n" -"\n" -"u32 sample(__local ShapeDeviceData* shape, int face, int x, int y)\n" -"{\n" -"\n" -" int idx = HEIGHT_RES*HEIGHT_RES*face + x + y*HEIGHT_RES;\n" -" __local u8* height = (__local u8*)shape->m_height4;\n" -" return height[idx];\n" -"}\n" -"\n" -"u32 sampleSupportGlobal(__global ShapeData* shape, int face, int x, int y)\n" -"{\n" -"\n" -" int idx = HEIGHT_RES*HEIGHT_RES*face + x + y*HEIGHT_RES;\n" -" __global u8* height = (__global u8*)shape->m_supportHeight4;\n" -" return height[idx];\n" -"}\n" -"\n" -"float4 sampleNormal(__local ShapeData* shape, int face, int x, int y)\n" -"{\n" -" return shape->m_normal[HEIGHT_RES*HEIGHT_RES*face + x + y*HEIGHT_RES];\n" -"}\n" -"\n" -"float4 sampleNormalGlobal(const __global ShapeData* shape, int face, int x, int y)\n" -"{\n" -" return shape->m_normal[HEIGHT_RES*HEIGHT_RES*face + x + y*HEIGHT_RES];\n" -"}\n" -"\n" -"float4 ShapeDataCalcSamplePoint( __local const ShapeDeviceData* shape, int sIdx )//u8 height, int sIdx, float scale )\n" -"{\n" -" const float oneOver255 = 1.f/255.f;\n" -"\n" -" int faceIdx = fastDiv(sIdx,(HEIGHT_RES*HEIGHT_RES));\n" -" int r = (sIdx%(HEIGHT_RES*HEIGHT_RES));\n" -" int i = r/HEIGHT_RES;\n" -" int j = r%HEIGHT_RES;\n" -"\n" -" float4 v;\n" -" float x = fastDiv((i+0.5f),(float)HEIGHT_RES);\n" -" float y = fastDiv((j+0.5f),(float)HEIGHT_RES);\n" -" v = CubeMapUtilsCalcVector(faceIdx, x, y);\n" -" v = normalize3( v );\n" -"\n" -" int quantizedHeight = sample( shape, faceIdx, i, j );\n" -" float rheight = quantizedHeight*oneOver255*shape->m_scale;\n" -" return rheight*v;\n" -"}\n" -"\n" -"float ShapeDataQueryDistance(__local const ShapeDeviceData* shape, float4 p )\n" -"{\n" -" if( dot3F4( p, p ) >= shape->m_scale*shape->m_scale ) return FLT_MAX;\n" -"\n" -" const float oneOver255 = 1.f/255.f;\n" -"\n" -" int faceIdx;\n" -" float x, y;\n" -" CubeMapUtilsCalcCrd( p, &faceIdx, &x, &y );\n" -" x = (x*HEIGHT_RES) - 0.5f;\n" -" y = (y*HEIGHT_RES) - 0.5f;\n" -"\n" -" float height;\n" -" {\n" -" int xi = (int)(x);\n" -" int yi = (int)(y);\n" -" float dx = x-xi;\n" -" float dy = y-yi;\n" -"\n" -" {\n" -" int xip = min2((int)(HEIGHT_RES-1), xi+1);\n" -" int yip = min2((int)(HEIGHT_RES-1), yi+1);\n" -"\n" -" u32 xy = sample( shape, faceIdx, xi, yi );\n" -" u32 xpy = sample( shape, faceIdx, xip, yi );\n" -" u32 xpyp = sample( shape, faceIdx, xip, yip );\n" -" u32 xyp = sample( shape, faceIdx, xi, yip );\n" -"\n" -" height = (xy*(1.f-dx)+xpy*dx)*(1.f-dy) + (xyp*(1.f-dx)+xpyp*dx)*dy;\n" -" height = height*oneOver255*shape->m_scale;\n" -"\n" -" p.w = 0.f;\n" -"\n" -" height = fastLength4( p ) - height;\n" -" }\n" -" }\n" -"\n" -" return height;\n" -"}\n" -"\n" -"float ShapeDataQuerySupportHeight(__global ShapeData* shape, float4 p )\n" -"{\n" -" int faceIdx;\n" -" float x, y;\n" -" CubeMapUtilsCalcCrd( p, &faceIdx, &x, &y );\n" -" x = (x*HEIGHT_RES) - 0.5f;\n" -" y = (y*HEIGHT_RES) - 0.5f;\n" -"\n" -" float height;\n" -" {\n" -" int xi = (int)(x);\n" -" int yi = (int)(y);\n" -"\n" -" {\n" -" int xip = min2((int)(HEIGHT_RES-1), xi+1);\n" -" int yip = min2((int)(HEIGHT_RES-1), yi+1);\n" -"\n" -" u32 xy = sampleSupportGlobal( shape, faceIdx, xi, yi );\n" -" u32 xpy = sampleSupportGlobal( shape, faceIdx, xip, yi );\n" -" u32 xpyp = sampleSupportGlobal( shape, faceIdx, xip, yip );\n" -" u32 xyp = sampleSupportGlobal( shape, faceIdx, xi, yip );\n" -"\n" -" height = max2( xy, max2( xpy, max2( xpyp, xyp ) ) );\n" -" height = height/255.f*shape->m_scale;\n" -" }\n" -" }\n" -"\n" -" return height;\n" -"\n" -"}\n" -"\n" -"float4 ShapeDataQueryNormal(__global const ShapeData* shape, float4 p )\n" -"{\n" -" int faceIdx;\n" -" float x, y;\n" -" CubeMapUtilsCalcCrd( p, &faceIdx, &x, &y );\n" -" x = (x*HEIGHT_RES) - 0.5f;\n" -" y = (y*HEIGHT_RES) - 0.5f;\n" -"\n" -" float4 normalOut;\n" -" {\n" -" int xi = (int)(x);\n" -" int yi = (int)(y);\n" -"\n" -" normalOut = sampleNormalGlobal( shape, faceIdx, xi, yi );\n" -" }\n" -" return normalOut;\n" -"}\n" -"\n" -"\n" -"\n" -"// kernels\n" -"\n" -"\n" -"__kernel\n" -"__attribute__((reqd_work_group_size(WG_SIZE,1,1)))\n" -"void SupportCullingKernel( __global int2* restrict gPairsIn, __global ShapeData* gShapes, \n" -" __global BodyData* gBodies, \n" -" __global int2* gPairsOut, \n" -" counter32_t gNPairs,\n" -" ConstBuffer cb )\n" -"{\n" -" int gIdx = GET_GLOBAL_IDX;\n" -" if( gIdx >= cb.m_nPairs ) return;\n" -"\n" -" const float collisionMargin = cb.m_collisionMargin;\n" -" const int capacity = cb.m_capacity;\n" -"\n" -" int2 pair = gPairsIn[gIdx];\n" -" BodyData bodyA = gBodies[pair.x];\n" -" BodyData bodyB = gBodies[pair.y];\n" -" int shapeAIdx = bodyA.m_shapeIdx;\n" -" int shapeBIdx = bodyB.m_shapeIdx;\n" -"\n" -"\n" -" bool collide = false;\n" -" \n" -" //only collide if one of the two bodies has a non-zero mass\n" -" if (bodyA.m_invMass==0.f && bodyB.m_invMass==0.f)\n" -" return;\n" -" \n" -" \n" -" if (bodyA.m_shapeType == SHAPE_CONVEX_HEIGHT_FIELD && bodyB.m_shapeType==SHAPE_CONVEX_HEIGHT_FIELD)\n" -" {\n" -" float4 abInA, baInB;\n" -" float4 ab = bodyB.m_pos - bodyA.m_pos;\n" -" {\n" -" abInA = qtInvRotate( bodyA.m_quat, ab );\n" -" baInB = qtInvRotate( bodyB.m_quat, -ab );\n" -" }\n" -" float hA = ShapeDataQuerySupportHeight( gShapes+shapeAIdx, abInA );\n" -" float hB = ShapeDataQuerySupportHeight( gShapes+shapeBIdx, baInB );\n" -"\n" -" float h2 = dot3F4( ab, ab );\n" -"\n" -" collide = ( hA + hB + collisionMargin > sqrtf(h2) );\n" -" }\n" -"\n" -" if( collide )\n" -" {\n" -" int dstIdx;\n" -" AppendInc( gNPairs, dstIdx );\n" -" if( dstIdx < capacity )\n" -" gPairsOut[dstIdx] = pair;\n" -" }\n" -"}\n" -"\n" -"\n" -"#define PARALLEL_DO(execution, n) for(int ie=0; ie h[lIdx+1].y)? h[lIdx]: h[lIdx+1];" -" mem_fence( CLK_LOCAL_MEM_FENCE );" -" h[lIdx] = (h[lIdx].y > h[lIdx+2].y)? h[lIdx]: h[lIdx+2];" -" mem_fence( CLK_LOCAL_MEM_FENCE );" -" h[lIdx] = (h[lIdx].y > h[lIdx+4].y)? h[lIdx]: h[lIdx+4];" -" mem_fence( CLK_LOCAL_MEM_FENCE );" -" h[lIdx] = (h[lIdx].y > h[lIdx+8].y)? h[lIdx]: h[lIdx+8];" -" mem_fence( CLK_LOCAL_MEM_FENCE );" -" h[lIdx] = (h[lIdx].y > h[lIdx+16].y)? h[lIdx]: h[lIdx+16];" -" }}\n" -"\n" -"#define PARALLEL_REDUCE32(h) " -" {int lIdx = GET_LOCAL_IDX;" -" if( lIdx < 32 )" -" {" -" h[lIdx] += h[lIdx+1];" -" mem_fence( CLK_LOCAL_MEM_FENCE );" -" h[lIdx] += h[lIdx+2];" -" mem_fence( CLK_LOCAL_MEM_FENCE );" -" h[lIdx] += h[lIdx+4];" -" mem_fence( CLK_LOCAL_MEM_FENCE );" -" h[lIdx] += h[lIdx+8];" -" mem_fence( CLK_LOCAL_MEM_FENCE );" -" h[lIdx] += h[lIdx+16];" -" }}\n" -"\n" -"\n" -"float4 extractManifold(__local float4* p, __local float4* h, __local int* nPointsPtr, float4 nearNormal)\n" -"{\n" -" int nPoints = *nPointsPtr;\n" -" float4 center = make_float4(0,0,0,0);\n" -" { // calculate center\n" -" nPoints = min2( nPoints, 32 );\n" -" {\n" -" int lIdx = GET_LOCAL_IDX;\n" -" h[lIdx] = p[lIdx];\n" -" h[lIdx] = (lIdx= nPoints ) a[ie] = make_int4(-0xfffffff, -0xfffffff, -0xfffffff, -0xfffffff);\n" -" }\n" -" }\n" -"\n" -" GROUP_LDS_BARRIER;\n" -"\n" -" { // vector reduce, h[64]\n" -" int lIdx = GET_LOCAL_IDX;\n" -" if( lIdx < 32 )\n" -" {\n" -" h[lIdx] = max2( h[lIdx], h[lIdx+1] );\n" -" mem_fence( CLK_LOCAL_MEM_FENCE );\n" -" h[lIdx] = max2( h[lIdx], h[lIdx+2] );\n" -" mem_fence( CLK_LOCAL_MEM_FENCE );\n" -" h[lIdx] = max2( h[lIdx], h[lIdx+4] );\n" -" mem_fence( CLK_LOCAL_MEM_FENCE );\n" -" h[lIdx] = max2( h[lIdx], h[lIdx+8] );\n" -" mem_fence( CLK_LOCAL_MEM_FENCE );\n" -" h[lIdx] = max2( h[lIdx], h[lIdx+16] );\n" -" }\n" -" }\n" -"\n" -" GROUP_LDS_BARRIER;\n" -" }\n" -" {\n" -" { // set to idx\n" -" idx[0] = (int)a[0].x & 0xff;\n" -" idx[1] = (int)a[0].y & 0xff;\n" -" idx[2] = (int)a[0].z & 0xff;\n" -" idx[3] = (int)a[0].w & 0xff;\n" -" }\n" -"\n" -" GROUP_LDS_BARRIER;\n" -" float4 selection;\n" -" if( GET_LOCAL_IDX < 4 ) selection = p[idx[GET_LOCAL_IDX]];\n" -"\n" -" GROUP_LDS_BARRIER;\n" -" if( GET_LOCAL_IDX < 4 ) p[GET_LOCAL_IDX] = selection;\n" -" }\n" -"\n" -"\n" -" return center;\n" -"}\n" -"\n" -"void extractManifold1(__local float4* p, __local float4* h, __local int* nPointsPtr, float4 center)\n" -"{\n" -" __local int* a = (__local int*)h;\n" -" {\n" -" GROUP_LDS_BARRIER;\n" -" float4 selection;\n" -" if( GET_LOCAL_IDX < 4 )\n" -" {\n" -" int idx = (int)a[GET_LOCAL_IDX] & 0xff;\n" -" selection = p[idx];\n" -" }\n" -"\n" -" GROUP_LDS_BARRIER;\n" -" if( GET_LOCAL_IDX < 4 ) p[GET_LOCAL_IDX] = selection;\n" -" }\n" -"\n" -"}\n" -"\n" -"void extractManifold2( __local float4* p0, __local int* nPointsPtr0, float4 nearNormal0,\n" -" __local float4* p1, __local int* nPointsPtr1, float4 nearNormal1,\n" -" __local float4* h, float4 centerOut[2])\n" -"{\n" -"\n" -" int nPoints[2];\n" -" nPoints[0] = *nPointsPtr0;\n" -" nPoints[1] = *nPointsPtr1;\n" -" float4 center[2];\n" -" center[0] = make_float4(0,0,0,0);\n" -" center[1] = make_float4(0,0,0,0);\n" -" { // calculate center\n" -" nPoints[0] = min2( nPoints[0], 32 );\n" -" nPoints[1] = min2( nPoints[1], 32 );\n" -" {\n" -" int lIdx = GET_LOCAL_IDX;\n" -" h[lIdx] = (lIdx= nPoints[setIdx] ) a[ie + setIdx*64] = make_int4(-0xfffffff, -0xfffffff, -0xfffffff, -0xfffffff);\n" -"\n" -" a[ie + 32] = make_int4(-0xfffffff, -0xfffffff, -0xfffffff, -0xfffffff);\n" -" }\n" -" }\n" -" }\n" -" GROUP_LDS_BARRIER;\n" -"\n" -" { // vector reduce, h[64]\n" -" int bIdx = GET_LOCAL_IDX/32;\n" -" int eIdx = GET_LOCAL_IDX%32;\n" -" int lIdx = eIdx + bIdx*64;\n" -" {\n" -" h[lIdx] = max2( h[lIdx], h[lIdx+1] );\n" -" mem_fence( CLK_LOCAL_MEM_FENCE );\n" -" h[lIdx] = max2( h[lIdx], h[lIdx+2] );\n" -" mem_fence( CLK_LOCAL_MEM_FENCE );\n" -" h[lIdx] = max2( h[lIdx], h[lIdx+4] );\n" -" mem_fence( CLK_LOCAL_MEM_FENCE );\n" -" h[lIdx] = max2( h[lIdx], h[lIdx+8] );\n" -" mem_fence( CLK_LOCAL_MEM_FENCE );\n" -" h[lIdx] = max2( h[lIdx], h[lIdx+16] );\n" -" }\n" -" }\n" -"\n" -" GROUP_LDS_BARRIER;\n" -" }\n" -" __local int* a = (__local int*)h;\n" -" {\n" -" GROUP_LDS_BARRIER;\n" -" \n" -" float4 selection;\n" -"\n" -" int bIdx = GET_LOCAL_IDX/32;\n" -" int eIdx = GET_LOCAL_IDX%32;\n" -"\n" -" if( eIdx < 4 )\n" -" {\n" -" int idx = (int)a[eIdx+64*4*bIdx] & 0xff;\n" -" selection = p0[idx+32*bIdx];\n" -" }\n" -"\n" -" GROUP_LDS_BARRIER;\n" -" if( eIdx < 4 ) p0[eIdx+32*bIdx] = selection;\n" -" }\n" -"}\n" -"\n" -"/*\n" -"1. Query Normal\n" -"2. Fill Normal\n" -"3. A->B, B->A\n" -"*/\n" -"\n" -"void testVtx(__local BodyData* bodyAPtr, __local BodyData* bodyBPtr,\n" -" __local ShapeDeviceData* shapeAPtr, __local ShapeDeviceData* shapeBPtr,\n" -" __local int* lNContacts, __local float4* lCPoints)\n" -"{\n" -" int pIdx = GET_LOCAL_IDX;\n" -" float4 bodyAPos = bodyAPtr->m_pos;\n" -" float4 bodyBPos = bodyBPtr->m_pos;\n" -" Quaternion bodyAQuat = bodyAPtr->m_quat;\n" -" Quaternion bodyBQuat = bodyBPtr->m_quat;\n" -" while( pIdx < HEIGHT_RES*HEIGHT_RES*6 )\n" -" {\n" -" float4 pInB = ShapeDataCalcSamplePoint( shapeBPtr, pIdx );\n" -"\n" -" float4 pInW = transform( &pInB, &bodyBPos, &bodyBQuat );\n" -"// Aabb bodyAAabb = bodyAPtr->m_aabb;\n" -"// if( AabbOverlapsPoint( &bodyAAabb, pInW ) )\n" -" {\n" -" float4 pInA = invTransform( &pInW, &bodyAPos, &bodyAQuat );\n" -"\n" -" float dist = ShapeDataQueryDistance( shapeAPtr, pInA );\n" -" if( dist < 0.010f )\n" -" {\n" -" int dstIdx = atom_add( lNContacts, 1 );\n" -" if( dstIdx < 32 )\n" -" {\n" -" lCPoints[ dstIdx ] = make_float4( pInA.x, pInA.y, pInA.z, dist );\n" -" }\n" -" }\n" -" }\n" -"\n" -" pIdx += GET_GROUP_SIZE;\n" -" }\n" -"}\n" -"\n" -"void testVtx2(__local const BodyData* bodyA, __local const BodyData* bodyB,\n" -" __local const ShapeDeviceData* shapeA, __local const ShapeDeviceData* shapeB,\n" -" __local int* lNContactsA, __local float4* lCPointsA,\n" -" __local int* lNContactsB, __local float4* lCPointsB, float collisionMargin )\n" -"{\n" -" int pIdx = GET_LOCAL_IDX;\n" -"\n" -" while( pIdx < HEIGHT_RES*HEIGHT_RES*6*2 )\n" -" {\n" -" __local const BodyData* bodyAPtr =( pIdx < HEIGHT_RES*HEIGHT_RES*6 )?bodyA:bodyB;\n" -" __local const BodyData* bodyBPtr =( pIdx < HEIGHT_RES*HEIGHT_RES*6 )?bodyB:bodyA;\n" -" __local const ShapeDeviceData* shapeAPtr =( pIdx < HEIGHT_RES*HEIGHT_RES*6 )?shapeA:shapeB;\n" -" __local const ShapeDeviceData* shapeBPtr =( pIdx < HEIGHT_RES*HEIGHT_RES*6 )?shapeB:shapeA;\n" -" __local int* lNContacts =( pIdx < HEIGHT_RES*HEIGHT_RES*6 )?lNContactsA:lNContactsB;\n" -" __local float4* lCPoints =( pIdx < HEIGHT_RES*HEIGHT_RES*6 )?lCPointsA:lCPointsB;\n" -"\n" -" float4 bodyAPos = bodyAPtr->m_pos;\n" -" float4 bodyBPos = bodyBPtr->m_pos;\n" -" Quaternion bodyAQuat = bodyAPtr->m_quat;\n" -" Quaternion bodyBQuat = bodyBPtr->m_quat;\n" -"\n" -" float4 pInB = ShapeDataCalcSamplePoint( shapeBPtr, pIdx%(HEIGHT_RES*HEIGHT_RES*6) );\n" -"\n" -" float4 pInW = transform( &pInB, &bodyBPos, &bodyBQuat );\n" -"// Aabb bodyAAabb = bodyAPtr->m_aabb;\n" -"// if( AabbOverlapsPoint( &bodyAAabb, pInW ) )\n" -" {\n" -" float4 pInA = invTransform( &pInW, &bodyAPos, &bodyAQuat );\n" -"\n" -" float dist = ShapeDataQueryDistance( shapeAPtr, pInA );\n" -" if( dist < collisionMargin )\n" -" {\n" -" int dstIdx = atom_add( lNContacts, 1 );\n" -" if( dstIdx < 32 )\n" -" {\n" -" lCPoints[ dstIdx ] = make_float4( pInA.x, pInA.y, pInA.z, dist );\n" -" }\n" -" }\n" -" }\n" -"\n" -" pIdx += GET_GROUP_SIZE;\n" -" }\n" -"}\n" -"\n" -"void testVtxWithPlane(__local BodyData* bodyA, __local BodyData* bodyB,\n" -" float4 nA, __local ShapeDeviceData* shapeB,\n" -" __local int* lNContactsA, __local float4* lCPointsA, float collisionMargin)\n" -"{\n" -" int pIdx = GET_LOCAL_IDX;\n" -"\n" -" while( pIdx < HEIGHT_RES*HEIGHT_RES*6 )\n" -" {\n" -" __local BodyData* bodyAPtr =bodyA;\n" -" __local BodyData* bodyBPtr =bodyB;\n" -" __local ShapeDeviceData* shapeBPtr =shapeB;\n" -" __local int* lNContacts =lNContactsA;\n" -" __local float4* lCPoints =lCPointsA;\n" -"\n" -" float4 bodyAPos = bodyAPtr->m_pos;\n" -" float4 bodyBPos = bodyBPtr->m_pos;\n" -" Quaternion bodyAQuat = bodyAPtr->m_quat;\n" -" Quaternion bodyBQuat = bodyBPtr->m_quat;\n" -"\n" -" float4 pInB = ShapeDataCalcSamplePoint( shapeBPtr, pIdx%(HEIGHT_RES*HEIGHT_RES*6) );\n" -"\n" -" float4 pInW = transform( &pInB, &bodyBPos, &bodyBQuat );\n" -" {\n" -" float4 pInA = invTransform( &pInW, &bodyAPos, &bodyAQuat );\n" -"\n" -" float dist = dot3w1( pInA, nA );//ShapeDataQueryDistance( shapeAPtr, pInA );\n" -" if( dist < collisionMargin )\n" -" {\n" -" int dstIdx = atom_add( lNContacts, 1 );\n" -" if( dstIdx < 32 )\n" -" {\n" -" lCPoints[ dstIdx ] = make_float4( pInA.x, pInA.y, pInA.z, dist );\n" -" }\n" -" }\n" -" }\n" -"\n" -" pIdx += GET_GROUP_SIZE;\n" -" }\n" -"}\n" -"\n" -"#define GET_SHAPE_IDX(x) (int)((x).m_shapeIdx)\n" -"\n" -"void output(__local BodyData* bodyAPtr, __local BodyData* bodyBPtr,\n" -" __local int2* iPair,\n" -" __local int* lNContacts, __local float4* lCPoints,\n" -" float4 center, \n" -" __global ShapeData* shapeData, __global Contact4* contactsOut, float collisionMargin)\n" -"{\n" -" if( *lNContacts != 0 )\n" -" {\n" -" int nContacts = min2( *lNContacts, 4 );\n" -"\n" -" __global Contact4* c = contactsOut;\n" -"\n" -" if( GET_LOCAL_IDX < nContacts )\n" -" {\n" -" int i = GET_LOCAL_IDX;\n" -" float4 p = lCPoints[i];\n" -" float4 bodyAPos = bodyAPtr->m_pos;\n" -" Quaternion bodyAQuat = bodyAPtr->m_quat;\n" -"\n" -" c->m_worldPos[i] = transform( &p, &bodyAPos, &bodyAQuat );\n" -" c->m_worldPos[i].w = lCPoints[i].w - collisionMargin;\n" -" }\n" -"\n" -" if( GET_LOCAL_IDX == 0 )\n" -" {\n" -" float4 contactNormal;\n" -" contactNormal = ShapeDataQueryNormal( &shapeData[GET_SHAPE_IDX(*bodyAPtr)], center );\n" -" contactNormal = normalize3( qtRotate( bodyAPtr->m_quat, contactNormal ) );\n" -"\n" -" c->m_worldNormal = contactNormal;\n" -"// c->m_restituitionCoeff = 0.f;\n" -"// c->m_frictionCoeff = 0.7f;\n" -" c->m_coeffs = (u32)(0.f*0xffff) | ((u32)(0.7f*0xffff)<<16);\n" -" GET_NPOINTS(*c) = nContacts;\n" -" c->m_bodyAPtr = iPair[0].x;\n" -" c->m_bodyBPtr = iPair[0].y;\n" -" }\n" -" }\n" -" else\n" -" {\n" -" if( GET_LOCAL_IDX == 0 )\n" -" GET_NPOINTS(contactsOut[0]) = 0;\n" -" }\n" -"}\n" -"\n" -"// todo. make it better\n" -"void output2(__local BodyData* bodyAPtr, __local BodyData* bodyBPtr,\n" -" int pair0, int pair1,\n" -" __local int* lNContacts, __local float4* lCPoints,\n" -" float4 center, \n" -" const __global ShapeData* shapeData, __global Contact4* contactsOut, counter32_t nContactsOut, int capacity,\n" -" float collisionMargin )\n" -"{\n" -" int lIdx = GET_LOCAL_IDX%32;\n" -" int nContacts = min2( *lNContacts, 4 );\n" -" \n" -" GROUP_LDS_BARRIER;\n" -"\n" -" if( lIdx == 0 && nContacts)\n" -" {\n" -" int dstIdx;\n" -" AppendInc( nContactsOut, dstIdx );\n" -" *lNContacts = dstIdx;\n" -"\n" -" if( dstIdx >= capacity )\n" -" *lNContacts = -1;\n" -" }\n" -"\n" -" GROUP_LDS_BARRIER;\n" -"\n" -" bool canWrite = (*lNContacts!=-1);\n" -"\n" -" if( nContacts && canWrite )\n" -" {\n" -" __global Contact4* c = contactsOut + (*lNContacts);\n" -"\n" -" if( lIdx < nContacts )\n" -" {\n" -" int i = lIdx;\n" -" float4 p = lCPoints[i];\n" -" float4 bodyAPos = bodyAPtr->m_pos;\n" -" Quaternion bodyAQuat = bodyAPtr->m_quat;\n" -"\n" -" p = transform( &p, &bodyAPos, &bodyAQuat );\n" -" p.w = lCPoints[i].w - collisionMargin;\n" -" c->m_worldPos[i] = p;\n" -" }\n" -"\n" -" if( lIdx == 0 )\n" -" {\n" -" if( nContacts )\n" -" {\n" -" float4 contactNormal;\n" -" contactNormal = ShapeDataQueryNormal( &shapeData[GET_SHAPE_IDX(*bodyAPtr)], center );\n" -" contactNormal = normalize3( qtRotate( bodyAPtr->m_quat, contactNormal ) );\n" -"\n" -" c->m_worldNormal = contactNormal;\n" -"// c->m_restituitionCoeff = 0.f;\n" -"// c->m_frictionCoeff = 0.7f;\n" -" c->m_coeffs = (u32)(0.f*0xffff) | ((u32)(0.7f*0xffff)<<16);\n" -" c->m_bodyAPtr = pair0;\n" -" c->m_bodyBPtr = pair1;\n" -" }\n" -" GET_NPOINTS(*c) = nContacts;\n" -" }\n" -" }\n" -"}\n" -"\n" -"__inline\n" -"void output2LDS(__local BodyData* bodyAPtr, __local BodyData* bodyBPtr,\n" -" int pair0, int pair1,\n" -" int lNContacts, __local float4* lCPoints,\n" -" float4 center, \n" -" const __global ShapeData* shapeData, __local Contact4* contactsOut,\n" -" float collisionMargin )\n" -"{\n" -" int lIdx = GET_LOCAL_IDX%32;\n" -"// int lIdx = GET_LOCAL_IDX;\n" -"// int groupIdx = 0;\n" -"\n" -" int nContacts = min2( lNContacts, 4 );\n" -" \n" -" GROUP_LDS_BARRIER;\n" -"\n" -" if( nContacts != 0 )\n" -" {\n" -" if( lIdx < nContacts )\n" -" {\n" -" int i = lIdx;\n" -" float4 p = lCPoints[i];\n" -" float4 bodyAPos = bodyAPtr->m_pos;\n" -" Quaternion bodyAQuat = bodyAPtr->m_quat;\n" -"\n" -" p = transform( &p, &bodyAPos, &bodyAQuat );\n" -" p.w = lCPoints[i].w - collisionMargin;\n" -" contactsOut->m_worldPos[i] = p;\n" -" }\n" -" }\n" -"\n" -" if( lIdx == 0 )\n" -" {\n" -" if( nContacts != 0 )\n" -" {\n" -" float4 contactNormal;\n" -" contactNormal = ShapeDataQueryNormal( &shapeData[GET_SHAPE_IDX(*bodyAPtr)], center );\n" -" contactNormal = normalize3( qtRotate( bodyAPtr->m_quat, contactNormal ) );\n" -"\n" -" contactsOut->m_worldNormal = contactNormal;\n" -"// contactsOut->m_worldNormal = make_float4(1.5f,1.4f,1.3f,0.f);\n" -"// contactsOut->m_restituitionCoeff = 0.f;\n" -"// contactsOut->m_frictionCoeff = 0.7f;\n" -" contactsOut->m_coeffs = (u32)(0.f*0xffff) | ((u32)(0.7f*0xffff)<<16);\n" -" contactsOut->m_bodyAPtr = pair0;\n" -" contactsOut->m_bodyBPtr = pair1;\n" -" }\n" -" GET_NPOINTS(*contactsOut) = nContacts;//nContacts;\n" -" }\n" -"\n" -"// contactsOut[groupIdx].m_worldNormal = make_float4(1.5f,1.4f,1.3f,0.f);\n" -"}\n" -"\n" -"void output2_1(__local BodyData* bodyAPtr, __local BodyData* bodyBPtr,\n" -" int pair0, int pair1,\n" -" __local int* lNContacts, __local float4* lCPoints,\n" -" float4 center, float4 nA, \n" -" const __global ShapeData* shapeData, __global Contact4* contactsOut, counter32_t nContactsOut, int capacity, float collisionMargin )\n" -"{\n" -" int lIdx = GET_LOCAL_IDX;\n" -" int nContacts = min2( *lNContacts, 4 );\n" -" \n" -" GROUP_LDS_BARRIER;\n" -"\n" -" if( lIdx == 0 && nContacts)\n" -" {\n" -" int dstIdx;\n" -" AppendInc( nContactsOut, dstIdx );\n" -" *lNContacts = dstIdx;\n" -"\n" -" if( dstIdx >= capacity )\n" -" *lNContacts = -1;\n" -" }\n" -"\n" -" GROUP_LDS_BARRIER;\n" -"\n" -" bool canWrite = (*lNContacts!=-1);\n" -"\n" -" if( nContacts && canWrite )\n" -" {\n" -" __global Contact4* c = contactsOut + (*lNContacts);\n" -"\n" -" if( lIdx < nContacts )\n" -" {\n" -" int i = lIdx;\n" -" float4 p = lCPoints[i];\n" -" float4 bodyAPos = bodyAPtr->m_pos;\n" -" Quaternion bodyAQuat = bodyAPtr->m_quat;\n" -"\n" -" p = transform( &p, &bodyAPos, &bodyAQuat );\n" -" p.w = lCPoints[i].w - collisionMargin;\n" -" c->m_worldPos[i] = p;\n" -" }\n" -"\n" -" if( lIdx == 0 )\n" -" {\n" -" if( nContacts )\n" -" {\n" -" float4 contactNormal;\n" -" contactNormal = nA;//ShapeDataQueryNormal( &shapeData[GET_SHAPE_IDX(*bodyAPtr)], center );\n" -" contactNormal = normalize3( qtRotate( bodyAPtr->m_quat, contactNormal ) );\n" -"\n" -" c->m_worldNormal = contactNormal;\n" -"// c->m_restituitionCoeff = 0.f;\n" -"// c->m_frictionCoeff = 0.7f;\n" -" c->m_coeffs = (u32)(0.f*0xffff) | ((u32)(0.7f*0xffff)<<16);\n" -" c->m_bodyAPtr = pair0;\n" -" c->m_bodyBPtr = pair1;\n" -" }\n" -" GET_NPOINTS(*c) = nContacts;\n" -" }\n" -" }\n" -"}\n" -"\n" -"__kernel\n" -"void manifold(__global float4* vIn, __global float4* vOut)\n" -"{\n" -" __local float4 lCPoints[32];\n" -" __local float4 lManifoldBuffer[64];\n" -" __local int lNContacts;\n" -" __local float4 ab;\n" -"\n" -" if( GET_LOCAL_IDX<32 )\n" -" {\n" -" lCPoints[GET_LOCAL_IDX] = vIn[GET_GLOBAL_IDX];\n" -" }\n" -"\n" -" if( GET_LOCAL_IDX == 0 ) \n" -" {\n" -" lNContacts = 32;\n" -" ab = vIn[GET_GLOBAL_IDX];\n" -" }\n" -"\n" -" GROUP_LDS_BARRIER;\n" -"\n" -" float4 center = extractManifold( lCPoints, lManifoldBuffer, &lNContacts, ab );\n" -"\n" -" if( GET_LOCAL_IDX < lNContacts )\n" -" {\n" -" vOut[4*GET_GROUP_IDX+GET_LOCAL_IDX] = lCPoints[GET_LOCAL_IDX];\n" -" }\n" -"\n" -"}\n" -"\n" -"//#define COMBINE_REDUCTION \n" -"\n" -"__kernel\n" -"__attribute__((reqd_work_group_size(64, 1, 1)))\n" -"void NarrowphaseKernel( const __global int2* restrict pairs, const __global ShapeData* shapeData, const __global BodyData* restrict bodyDatas, \n" -" __global Contact4* restrict contactsOut,\n" -" counter32_t nContactsOut, ConstBuffer cb ) \n" -"{\n" -" // 2.5K LDS\n" -" __local Contact4 ldsContacts[2];\n" -" __local BodyData bodyA;\n" -" __local BodyData bodyB;\n" -" __local ShapeDeviceData shapeA;\n" -" __local ShapeDeviceData shapeB;\n" -" __local float4 lCPointsA[32*2];\n" -" __local int lNContactsA;\n" -" __local float4* lCPointsB = lCPointsA+32;\n" -" __local int lNContactsB;\n" -"#ifdef COMBINE_REDUCTION\n" -" __local float4 lManifoldBuffer[64*2];\n" -"#else\n" -" __local float4 lManifoldBuffer[64];\n" -"#endif\n" -" __local int2 iPairAB;\n" -"\n" -" const int capacity = cb.m_capacity;\n" -" const float collisionMargin = cb.m_collisionMargin;\n" -"\n" -"\n" -" int pairIdx = GET_GROUP_IDX;\n" -"// for(int pairIdx = GET_GROUP_IDX; pairIdxm_height4[idx] = shapeData[ myShapeIdx ].m_height4[idx];\n" -"\n" -" idx+=32;\n" -" }\n" -" }\n" -"\n" -" GROUP_LDS_BARRIER;\n" -"\n" -" testVtx2( &bodyA, &bodyB, &shapeA, &shapeB, &lNContactsA, lCPointsA, &lNContactsB, lCPointsB, collisionMargin );\n" -"\n" -" GROUP_LDS_BARRIER;\n" -"\n" -" float4 ab = bodyB.m_pos - bodyA.m_pos;\n" -" float4 center[2];\n" -"\n" -" if( lNContactsA != 0 || lNContactsB != 0 )\n" -" {\n" -" float4 abInA;\n" -" abInA = qtInvRotate( bodyA.m_quat, ab );\n" -"\n" -" float4 abInB;\n" -" abInB = qtInvRotate( bodyB.m_quat, ab );\n" -"\n" -"#ifdef COMBINE_REDUCTION\n" -" extractManifold2( lCPointsA, &lNContactsA, abInA,\n" -" lCPointsB, &lNContactsB, abInB,\n" -" lManifoldBuffer, center );\n" -"#else\n" -" if( lNContactsA != 0 )\n" -" center[0] = extractManifold( lCPointsA, lManifoldBuffer, &lNContactsA, abInA );\n" -" if( lNContactsB != 0 )\n" -" center[1] = extractManifold( lCPointsB, lManifoldBuffer, &lNContactsB, abInB );\n" -"#endif\n" -" }\n" -"\n" -" int firstSet = GET_LOCAL_IDX/32;\n" -"\n" -"/*\n" -" if( GET_LOCAL_IDX == 0 ) // for debug\n" -" {\n" -" ldsContacts[0].m_worldNormal = make_float4(-1,-1,-1,0);\n" -" ldsContacts[0].m_bodyAPtr = 0;\n" -" ldsContacts[0].m_bodyBPtr = 0;\n" -" ldsContacts[0].m_batchIdx = 111;\n" -" ldsContacts[1].m_worldNormal = make_float4(-1,-1,-1,0);\n" -" ldsContacts[1].m_bodyAPtr = 0;\n" -" ldsContacts[1].m_bodyBPtr = 0;\n" -" ldsContacts[1].m_batchIdx = 111;\n" -" }\n" -"*/\n" -" bool doReduction = true;\n" -" if( doReduction )\n" -" {\n" -" GROUP_LDS_BARRIER;\n" -"\n" -" output2LDS( (firstSet)?&bodyA: &bodyB, (firstSet)?&bodyB : &bodyA, \n" -" (firstSet)?iPairAB.x : iPairAB.y, (firstSet)?iPairAB.y : iPairAB.x, \n" -" (firstSet)?lNContactsA : lNContactsB, (firstSet)?lCPointsA:lCPointsB, \n" -" (firstSet)?center[0] : center[1], shapeData, (firstSet)?&ldsContacts[0]: &ldsContacts[1], collisionMargin );\n" -"\n" -" GROUP_LDS_BARRIER;\n" -" \n" -" if( GET_LOCAL_IDX == 0 )\n" -" {\n" -" if( lNContactsA && lNContactsB )\n" -" {\n" -" float nDotn = dot3F4( ldsContacts[0].m_worldNormal, ldsContacts[1].m_worldNormal );\n" -" if( nDotn < -(1.f-0.01f) )\n" -" {\n" -" if( ldsContacts[0].m_bodyAPtr > ldsContacts[1].m_bodyAPtr )\n" -" lNContactsA = 0;\n" -" else\n" -" lNContactsB = 0;\n" -" }\n" -" }\n" -" }\n" -" \n" -" if( GET_LOCAL_IDX == 0 )\n" -" {\n" -" int n = lNContactsA;\n" -" if( n != 0 )\n" -" {\n" -" int dstIdx;\n" -" AppendInc( nContactsOut, dstIdx );\n" -" if( dstIdx < capacity )\n" -" { int idx = 0;\n" -" contactsOut[ dstIdx ] = ldsContacts[idx];\n" -" contactsOut[ dstIdx].m_batchIdx = pairIdx;\n" -" }\n" -" }\n" -"\n" -" n = lNContactsB;\n" -" if( n != 0 )\n" -" {\n" -" int dstIdx;\n" -" AppendInc( nContactsOut, dstIdx );\n" -" if( dstIdx < capacity )\n" -" { int idx = 1;\n" -" contactsOut[ dstIdx ] = ldsContacts[idx];\n" -" contactsOut[ dstIdx].m_batchIdx = pairIdx;\n" -" }\n" -" }\n" -" }\n" -"\n" -" GROUP_LDS_BARRIER;\n" -" }\n" -" else\n" -" {\n" -" //output2( (firstSet)?&bodyA: &bodyB, (firstSet)?&bodyB : &bodyA, \n" -" // (firstSet)?iPairAB.x : iPairAB.y, (firstSet)?iPairAB.y : iPairAB.x, \n" -" // (firstSet)?&lNContactsA : &lNContactsB, (firstSet)?lCPointsA:lCPointsB, \n" -" // (firstSet)?center[0] : center[1], shapeData, contactsOut, nContactsOut, capacity, collisionMargin );\n" -" }\n" -" }\n" -"}\n" -"\n" -"\n" -"__kernel\n" -"__attribute__((reqd_work_group_size(64, 1, 1)))\n" -"void NarrowphaseWithPlaneKernel( const __global int2* restrict pairs, const __global ShapeData* shapeData, const __global BodyData* restrict bodyDatas, \n" -" __global Contact4* restrict contactsOut,\n" -" counter32_t nContactsOut, ConstBuffer cb ) \n" -"{\n" -" // 2.5K LDS\n" -" __local BodyData bodyA;\n" -" __local BodyData bodyB;\n" -" __local ShapeDeviceData shapeA;\n" -" __local ShapeDeviceData shapeB;\n" -" __local float4 lCPointsA[32*2];\n" -" __local int lNContactsA;\n" -"// __local float4* lCPointsB = lCPointsA+32;\n" -"// __local int lNContactsB;\n" -" __local float4 lManifoldBuffer[64];\n" -" __local int2 iPairAB;\n" -"\n" -" const int capacity = cb.m_capacity;\n" -" const float collisionMargin = cb.m_collisionMargin;\n" -"\n" -" int pairIdx = GET_GROUP_IDX;\n" -" {\n" -" if( GET_LOCAL_IDX == 0 ) // load Bodies\n" -" {\n" -" int2 pair = pairs[pairIdx];\n" -" iPairAB = make_int2(pair.x, pair.y);\n" -" bodyA = bodyDatas[ pair.x ];\n" -" bodyB = bodyDatas[ pair.y ];\n" -" shapeA.m_scale = shapeData[ GET_SHAPE_IDX(bodyA) ].m_scale;\n" -" shapeB.m_scale = shapeData[ GET_SHAPE_IDX(bodyB) ].m_scale;\n" -" lNContactsA = 0;\n" -"// lNContactsB = 0;\n" -" }\n" -"\n" -" GROUP_LDS_BARRIER;\n" -"\n" -" if (bodyB.m_invMass == 0.f)\n" -" return;\n" -" \n" -" // todo. can check if the shape is the same to previous one. If same, dont read\n" -" { // load shape data\n" -" int idx = GET_LOCAL_IDX%32;\n" -" int bIdx = GET_LOCAL_IDX/32;\n" -" __local ShapeDeviceData* myShape = (bIdx==0)?&shapeA: &shapeB;\n" -" int myShapeIdx = (bIdx==0)?GET_SHAPE_IDX(bodyA): GET_SHAPE_IDX(bodyB);\n" -"\n" -" while( idx < HEIGHT_RES*HEIGHT_RES*6/4 )\n" -" {\n" -" myShape->m_height4[idx] = shapeData[ myShapeIdx ].m_height4[idx];\n" -"\n" -" idx+=32;\n" -" }\n" -" }\n" -"\n" -" GROUP_LDS_BARRIER;\n" -"\n" -" float4 nA = make_float4(0,1,0,0);\n" -"\n" -"\n" -"// testVtx2( &bodyA, &bodyB, &shapeA, &shapeB, &lNContactsA, lCPointsA, &lNContactsB, lCPointsB );\n" -" testVtxWithPlane( &bodyA, &bodyB, nA, &shapeB, &lNContactsA, lCPointsA, collisionMargin );\n" -"\n" -" GROUP_LDS_BARRIER;\n" -"\n" -"// float4 ab = bodyB.m_pos - bodyA.m_pos;\n" -" float4 center[2];\n" -"\n" -" if( lNContactsA != 0 )\n" -" {\n" -" float4 abInA;\n" -" abInA = nA;//qtInvRotate( bodyA.m_quat, ab );\n" -"\n" -" if( lNContactsA != 0 )\n" -" center[0] = extractManifold( lCPointsA, lManifoldBuffer, &lNContactsA, abInA );\n" -" }\n" -"\n" -"// int firstSet = GET_LOCAL_IDX/32;\n" -"\n" -" output2_1( &bodyA, &bodyB, \n" -" iPairAB.x, iPairAB.y, \n" -" &lNContactsA, lCPointsA, \n" -" center[0], nA, shapeData, contactsOut, nContactsOut, capacity, collisionMargin );\n" -" }\n" -"}\n" -; diff --git a/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/Solver.h b/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/Solver.h deleted file mode 100644 index 2a2382ac1..000000000 --- a/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/Solver.h +++ /dev/null @@ -1,203 +0,0 @@ -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Takahiro Harada - - -#pragma once -#ifndef __ADL_SOLVER_H -#define __ADL_SOLVER_H - - -#include -#include -#include -#include -#include -#include - -//#include -#include "AdlRigidBody.h" -#include "AdlContact4.h" - -//#include "AdlPhysics/Batching/Batching.h> - - -#define MYF4 float4 -#define MAKE_MYF4 make_float4 - -//#define MYF4 float4sse -//#define MAKE_MYF4 make_float4sse - -#include "AdlConstraint4.h" - -namespace adl -{ -class SolverBase -{ - public: - - - struct ConstraintData - { - ConstraintData(): m_b(0.f), m_appliedRambdaDt(0.f) {} - - float4 m_linear; // have to be normalized - float4 m_angular0; - float4 m_angular1; - float m_jacCoeffInv; - float m_b; - float m_appliedRambdaDt; - - u32 m_bodyAPtr; - u32 m_bodyBPtr; - - bool isInvalid() const { return ((u32)m_bodyAPtr+(u32)m_bodyBPtr) == 0; } - float getFrictionCoeff() const { return m_linear.w; } - void setFrictionCoeff(float coeff) { m_linear.w = coeff; } - }; - - struct ConstraintCfg - { - ConstraintCfg( float dt = 0.f ): m_positionDrift( 0.005f ), m_positionConstraintCoeff( 0.2f ), m_dt(dt), m_staticIdx(-1) {} - - float m_positionDrift; - float m_positionConstraintCoeff; - float m_dt; - bool m_enableParallelSolve; - float m_averageExtent; - int m_staticIdx; - }; - - static - __inline - Buffer* allocateContact4( const Device* device, int capacity ) - { - return new Buffer( device, capacity ); - } - - static - __inline - void deallocateContact4( Buffer* data ) { delete data; } - - static - __inline - SolverData allocateConstraint4( const Device* device, int capacity ) - { - return new Buffer( device, capacity ); - } - - static - __inline - void deallocateConstraint4( SolverData data ) { delete (Buffer*)data; } - - static - __inline - void* allocateFrictionConstraint( const Device* device, int capacity, u32 type = 0 ) - { - return 0; - } - - static - __inline - void deallocateFrictionConstraint( void* data ) - { - } - - enum - { - N_SPLIT = 16, - N_BATCHES = 4, - N_OBJ_PER_SPLIT = 10, - N_TASKS_PER_BATCH = N_SPLIT*N_SPLIT, - }; -}; - -template -class Solver : public SolverBase -{ - public: - typedef Launcher::BufferInfo BufferInfo; - - struct Data - { - Data() : m_nIterations(4){} - - const Device* m_device; - void* m_parallelSolveData; - int m_nIterations; - Kernel* m_batchingKernel; - Kernel* m_batchSolveKernel; - Kernel* m_contactToConstraintKernel; - Kernel* m_setSortDataKernel; - Kernel* m_reorderContactKernel; - Kernel* m_copyConstraintKernel; - //typename RadixSort::Data* m_sort; - typename RadixSort32::Data* m_sort32; - typename BoundSearch::Data* m_search; - typename PrefixScan::Data* m_scan; - Buffer* m_sortDataBuffer; - Buffer* m_contactBuffer; - }; - - enum - { - DYNAMIC_CONTACT_ALLOCATION_THRESHOLD = 2000000, - }; - - static - Data* allocate( const Device* device, int pairCapacity ); - - static - void deallocate( Data* data ); - - static - void reorderConvertToConstraints( Data* data, const Buffer* bodyBuf, - const Buffer* shapeBuf, - Buffer* contactsIn, SolverData contactCOut, void* additionalData, - int nContacts, const ConstraintCfg& cfg ); - - static - void solveContactConstraint( Data* data, const Buffer* bodyBuf, const Buffer* inertiaBuf, - SolverData constraint, void* additionalData, int n ); - -// static -// int createSolveTasks( int batchIdx, Data* data, const Buffer* bodyBuf, const Buffer* shapeBuf, -// SolverData constraint, int n, ThreadPool::Task* tasksOut[], int taskCapacity ); - - - //private: - static - void convertToConstraints( Data* data, const Buffer* bodyBuf, - const Buffer* shapeBuf, - Buffer* contactsIn, SolverData contactCOut, void* additionalData, - int nContacts, const ConstraintCfg& cfg ); - - static - void sortContacts( Data* data, const Buffer* bodyBuf, - Buffer* contactsIn, void* additionalData, - int nContacts, const ConstraintCfg& cfg ); - - static - void batchContacts( Data* data, Buffer* contacts, int nContacts, Buffer* n, Buffer* offsets, int staticIdx ); - -}; - -#include "Solver.inl" -#include "SolverHost.inl" -}; - -#undef MYF4 -#undef MAKE_MYF4 - -#endif //__ADL_SOLVER_H diff --git a/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/Solver.inl b/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/Solver.inl deleted file mode 100644 index 3fc5a2f9f..000000000 --- a/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/Solver.inl +++ /dev/null @@ -1,762 +0,0 @@ -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Takahiro Harada - - -#define PATH "..\\..\\dynamics\\basic_demo\\Stubs\\SolverKernels" -#define BATCHING_PATH "..\\..\\dynamics\\basic_demo\\Stubs\\batchingKernels" - -#define KERNEL1 "SingleBatchSolveKernel" -#define KERNEL2 "BatchSolveKernel" - -#define KERNEL3 "ContactToConstraintKernel" -#define KERNEL4 "SetSortDataKernel" -#define KERNEL5 "ReorderContactKernel" -#include "SolverKernels.h" - -#include "batchingKernels.h" - - -struct SolverDebugInfo -{ - int m_valInt0; - int m_valInt1; - int m_valInt2; - int m_valInt3; - - int m_valInt4; - int m_valInt5; - int m_valInt6; - int m_valInt7; - - int m_valInt8; - int m_valInt9; - int m_valInt10; - int m_valInt11; - - int m_valInt12; - int m_valInt13; - int m_valInt14; - int m_valInt15; - - - float m_val0; - float m_val1; - float m_val2; - float m_val3; -}; - - - - -class SolverDeviceInl -{ -public: - struct ParallelSolveData - { - Buffer* m_numConstraints; - Buffer* m_offsets; - }; -}; - -template -typename Solver::Data* Solver::allocate( const Device* device, int pairCapacity ) -{ - const char* src[] = -#if defined(ADL_LOAD_KERNEL_FROM_STRING) - {solverKernelsCL, 0}; -#else - {0,0}; -#endif - - const char* src2[] = -#if defined(ADL_LOAD_KERNEL_FROM_STRING) - {batchingKernelsCL, 0}; -#else - {0,0}; -#endif - - - - - Data* data = new Data; - data->m_device = device; - bool cacheBatchingKernel = true; - data->m_batchingKernel = device->getKernel( BATCHING_PATH, "CreateBatches", "-I ..\\..\\ ", src2[TYPE],cacheBatchingKernel); - //data->m_batchingKernel = device->getKernel( BATCHING_PATH, "CreateBatches", "-I ..\\..\\ ", 0,cacheBatchingKernel); - bool cacheSolverKernel = true; - - data->m_batchSolveKernel = device->getKernel( PATH, KERNEL2, "-I ..\\..\\ ", src[TYPE],cacheSolverKernel ); - data->m_contactToConstraintKernel = device->getKernel( PATH, KERNEL3, - "-I ..\\..\\ ", src[TYPE] ); - data->m_setSortDataKernel = device->getKernel( PATH, KERNEL4, - "-I ..\\..\\ ", src[TYPE] ); - data->m_reorderContactKernel = device->getKernel( PATH, KERNEL5, - "-I ..\\..\\ ", src[TYPE] ); - - data->m_copyConstraintKernel = device->getKernel( PATH, "CopyConstraintKernel", - "-I ..\\..\\ ", src[TYPE] ); - - data->m_parallelSolveData = new SolverDeviceInl::ParallelSolveData; - { - SolverDeviceInl::ParallelSolveData* solveData = (SolverDeviceInl::ParallelSolveData*)data->m_parallelSolveData; - solveData->m_numConstraints = new Buffer( device, N_SPLIT*N_SPLIT ); - solveData->m_offsets = new Buffer( device, N_SPLIT*N_SPLIT ); - } - const int sortSize = NEXTMULTIPLEOF( pairCapacity, 512 ); - - - //data->m_sort = RadixSort::allocate( data->m_device, sortSize );//todo. remove hardcode this - data->m_sort32 = RadixSort32::allocate( data->m_device, sortSize );//todo. remove hardcode this - - data->m_search = BoundSearch::allocate( data->m_device, N_SPLIT*N_SPLIT ); - data->m_scan = PrefixScan::allocate( data->m_device, N_SPLIT*N_SPLIT ); - - data->m_sortDataBuffer = new Buffer( data->m_device, sortSize ); - - if( pairCapacity < DYNAMIC_CONTACT_ALLOCATION_THRESHOLD ) - data->m_contactBuffer = new Buffer( data->m_device, pairCapacity ); - else - data->m_contactBuffer = 0; - - return data; -} - -template -void Solver::deallocate( Data* data ) -{ - { - SolverDeviceInl::ParallelSolveData* solveData = (SolverDeviceInl::ParallelSolveData*)data->m_parallelSolveData; - delete solveData->m_numConstraints; - delete solveData->m_offsets; - delete solveData; - } - -// RadixSort::deallocate( data->m_sort ); - RadixSort32::deallocate(data->m_sort32); - BoundSearch::deallocate( data->m_search ); - PrefixScan::deallocate( data->m_scan ); - - delete data->m_sortDataBuffer; - if( data->m_contactBuffer ) delete data->m_contactBuffer; - - delete data; -} - -template -void Solver::reorderConvertToConstraints( typename Solver::Data* data, const Buffer* bodyBuf, - const Buffer* shapeBuf, - Buffer* contactsIn, SolverData contactCOut, void* additionalData, - int nContacts, const typename Solver::ConstraintCfg& cfg ) -{ - if( data->m_contactBuffer ) - { - if( data->m_contactBuffer->getSize() < nContacts ) - { - BT_PROFILE("delete data->m_contactBuffer;"); - delete data->m_contactBuffer; - data->m_contactBuffer = 0; - } - } - if( data->m_contactBuffer == 0 ) - { - BT_PROFILE("new data->m_contactBuffer;"); - - data->m_contactBuffer = new Buffer( data->m_device, nContacts ); - } - Stopwatch sw; - - Buffer* contactNative = BufferUtils::map( data->m_device, contactsIn, nContacts ); - - //DeviceUtils::Config dhCfg; - //Device* deviceHost = DeviceUtils::allocate( TYPE_HOST, dhCfg ); - if( cfg.m_enableParallelSolve ) - { - SolverDeviceInl::ParallelSolveData* nativeSolveData = (SolverDeviceInl::ParallelSolveData*)data->m_parallelSolveData; - - DeviceUtils::waitForCompletion( data->m_device ); - sw.start(); - // contactsIn -> data->m_contactBuffer - { - BT_PROFILE("sortContacts"); - Solver::sortContacts( data, bodyBuf, contactNative, additionalData, nContacts, cfg ); - DeviceUtils::waitForCompletion( data->m_device ); - } - sw.split(); - if(0) - { - Contact4* tmp = new Contact4[nContacts]; - data->m_contactBuffer->read( tmp, nContacts ); - DeviceUtils::waitForCompletion( data->m_contactBuffer->m_device ); - contactNative->write( tmp, nContacts ); - DeviceUtils::waitForCompletion( contactNative->m_device ); - delete [] tmp; - } - else - { - BT_PROFILE("m_copyConstraintKernel"); - - Buffer constBuffer( data->m_device, 1, BufferBase::BUFFER_CONST ); - - int4 cdata; cdata.x = nContacts; - BufferInfo bInfo[] = { BufferInfo( data->m_contactBuffer ), BufferInfo( contactNative ) }; -// Launcher launcher( data->m_device, data->m_device->getKernel( PATH, "CopyConstraintKernel", "-I ..\\..\\ -Wf,--c++", 0 ) ); - Launcher launcher( data->m_device, data->m_copyConstraintKernel ); - launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(Launcher::BufferInfo) ); - launcher.setConst( constBuffer, cdata ); - launcher.launch1D( nContacts, 64 ); - DeviceUtils::waitForCompletion( data->m_device ); - } - { - BT_PROFILE("batchContacts"); - Solver::batchContacts( data, contactNative, nContacts, nativeSolveData->m_numConstraints, nativeSolveData->m_offsets, cfg.m_staticIdx ); - - } - } - { - BT_PROFILE("waitForCompletion (batchContacts)"); - DeviceUtils::waitForCompletion( data->m_device ); - } - sw.split(); - //================ - if(0) - { -// Solver::Data* solverHost = Solver::allocate( deviceHost, nContacts ); -// Solver::convertToConstraints( solverHost, bodyBuf, shapeBuf, contactNative, contactCOut, additionalData, nContacts, cfg ); -// Solver::deallocate( solverHost ); - } - else - { - BT_PROFILE("convertToConstraints"); - Solver::convertToConstraints( data, bodyBuf, shapeBuf, contactNative, contactCOut, additionalData, nContacts, cfg ); - } - { - BT_PROFILE("convertToConstraints waitForCompletion"); - DeviceUtils::waitForCompletion( data->m_device ); - } - sw.stop(); - - { - BT_PROFILE("printf"); - - float t[5]; - sw.getMs( t, 3 ); -// printf("%3.2f, %3.2f, %3.2f, ", t[0], t[1], t[2]); - } - - { - BT_PROFILE("deallocate and unmap"); - - //DeviceUtils::deallocate( deviceHost ); - - BufferUtils::unmap( contactNative, contactsIn, nContacts ); - } -} - - -template -void Solver::solveContactConstraint( typename Solver::Data* data, const Buffer* bodyBuf, const Buffer* shapeBuf, - SolverData constraint, void* additionalData, int n ) -{ - if(0) - { - DeviceUtils::Config dhCfg; - Device* deviceHost = DeviceUtils::allocate( TYPE_HOST, dhCfg ); - { - Solver::Data* hostData = Solver::allocate( deviceHost, 0 ); - Solver::solveContactConstraint( hostData, bodyBuf, shapeBuf, constraint, additionalData, n ); - Solver::deallocate( hostData ); - } - DeviceUtils::deallocate( deviceHost ); - return; - } - - ADLASSERT( data ); - - Buffer* cBuffer =0; - - Buffer* gBodyNative=0; - Buffer* gShapeNative =0; - Buffer* gConstraintNative =0; - - - { - BT_PROFILE("map"); - cBuffer = (Buffer*)constraint; - - gBodyNative= BufferUtils::map( data->m_device, bodyBuf ); - gShapeNative= BufferUtils::map( data->m_device, shapeBuf ); - gConstraintNative = BufferUtils::map( data->m_device, cBuffer ); - DeviceUtils::waitForCompletion( data->m_device ); - } - - Buffer constBuffer; - int4 cdata = make_int4( n, 0, 0, 0 ); - { - SolverDeviceInl::ParallelSolveData* solveData = (SolverDeviceInl::ParallelSolveData*)data->m_parallelSolveData; - const int nn = N_SPLIT*N_SPLIT; - - cdata.x = 0; - cdata.y = 250; - -#if 0 -//check how the cells are filled - unsigned int* hostCounts = new unsigned int[N_SPLIT*N_SPLIT]; - solveData->m_numConstraints->read(hostCounts,N_SPLIT*N_SPLIT); - DeviceUtils::waitForCompletion( data->m_device ); - for (int i=0;i gpuDebugInfo(data->m_device,numWorkItems); -#endif - - - - { - - BT_PROFILE("m_batchSolveKernel iterations"); - for(int iter=0; iterm_nIterations; iter++) - { - for(int ib=0; ibm_numConstraints ), - BufferInfo( solveData->m_offsets ) -#ifdef DEBUG_ME - , BufferInfo(&gpuDebugInfo) -#endif - }; - - Launcher launcher( data->m_device, data->m_batchSolveKernel ); - launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(Launcher::BufferInfo) ); - launcher.setConst( constBuffer, cdata ); - - launcher.launch1D( numWorkItems, 64 ); - -#ifdef DEBUG_ME - DeviceUtils::waitForCompletion( data->m_device ); - gpuDebugInfo.read(debugInfo,numWorkItems); - DeviceUtils::waitForCompletion( data->m_device ); - for (int i=0;i0) - { - printf("debugInfo[i].m_valInt2 = %d\n",i,debugInfo[i].m_valInt2); - } - - if (debugInfo[i].m_valInt3>0) - { - printf("debugInfo[i].m_valInt3 = %d\n",i,debugInfo[i].m_valInt3); - } - } -#endif //DEBUG_ME - - - } - } - - DeviceUtils::waitForCompletion( data->m_device ); - - - } - - cdata.x = 1; - { - BT_PROFILE("m_batchSolveKernel iterations2"); - for(int iter=0; iterm_nIterations; iter++) - { - for(int ib=0; ibm_numConstraints ), - BufferInfo( solveData->m_offsets ) -#ifdef DEBUG_ME - ,BufferInfo(&gpuDebugInfo) -#endif //DEBUG_ME - }; - Launcher launcher( data->m_device, data->m_batchSolveKernel ); - launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(Launcher::BufferInfo) ); - launcher.setConst( constBuffer, cdata ); - launcher.launch1D( 64*nn/N_BATCHES, 64 ); - } - } - DeviceUtils::waitForCompletion( data->m_device ); - - } -#ifdef DEBUG_ME - delete[] debugInfo; -#endif //DEBUG_ME - } - - { - BT_PROFILE("unmap"); - BufferUtils::unmap( gBodyNative, bodyBuf ); - BufferUtils::unmap( gShapeNative, shapeBuf ); - BufferUtils::unmap( gConstraintNative, cBuffer ); - DeviceUtils::waitForCompletion( data->m_device ); - } -} - -template -void Solver::convertToConstraints( typename Solver::Data* data, const Buffer* bodyBuf, - const Buffer* shapeBuf, - Buffer* contactsIn, SolverData contactCOut, void* additionalData, - int nContacts, const ConstraintCfg& cfg ) -{ - ADLASSERT( data->m_device->m_type == TYPE_CL ); - - Buffer* bodyNative =0; - Buffer* shapeNative =0; - Buffer* contactNative =0; - Buffer* constraintNative =0; - - { - BT_PROFILE("map buffers"); - - bodyNative = BufferUtils::map( data->m_device, bodyBuf ); - shapeNative = BufferUtils::map( data->m_device, shapeBuf ); - contactNative= BufferUtils::map( data->m_device, contactsIn ); - constraintNative = BufferUtils::map( data->m_device, (Buffer*)contactCOut ); - } - struct CB - { - int m_nContacts; - float m_dt; - float m_positionDrift; - float m_positionConstraintCoeff; - }; - - { - BT_PROFILE("m_contactToConstraintKernel"); - CB cdata; - cdata.m_nContacts = nContacts; - cdata.m_dt = cfg.m_dt; - cdata.m_positionDrift = cfg.m_positionDrift; - cdata.m_positionConstraintCoeff = cfg.m_positionConstraintCoeff; - - Buffer constBuffer( data->m_device, 1, BufferBase::BUFFER_CONST ); - BufferInfo bInfo[] = { BufferInfo( contactNative ), BufferInfo( bodyNative ), BufferInfo( shapeNative ), - BufferInfo( constraintNative )}; - Launcher launcher( data->m_device, data->m_contactToConstraintKernel ); - launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(Launcher::BufferInfo) ); - launcher.setConst( constBuffer, cdata ); - launcher.launch1D( nContacts, 64 ); - DeviceUtils::waitForCompletion( data->m_device ); - - } - - { - BT_PROFILE("unmap"); - BufferUtils::unmap( bodyNative, bodyBuf ); - BufferUtils::unmap( shapeNative, shapeBuf ); - BufferUtils::unmap( contactNative, contactsIn ); - BufferUtils::unmap( constraintNative, (Buffer*)contactCOut ); - } -} - -template -void Solver::sortContacts( typename Solver::Data* data, const Buffer* bodyBuf, - Buffer* contactsIn, void* additionalData, - int nContacts, const typename Solver::ConstraintCfg& cfg ) -{ - ADLASSERT( data->m_device->m_type == TYPE_CL ); - Buffer* bodyNative - = BufferUtils::map( data->m_device, bodyBuf ); - Buffer* contactNative - = BufferUtils::map( data->m_device, contactsIn ); - - const int sortAlignment = 512; // todo. get this out of sort - if( cfg.m_enableParallelSolve ) - { - SolverDeviceInl::ParallelSolveData* nativeSolveData = (SolverDeviceInl::ParallelSolveData*)data->m_parallelSolveData; - - int sortSize = NEXTMULTIPLEOF( nContacts, sortAlignment ); - - Buffer* countsNative = nativeSolveData->m_numConstraints;//BufferUtils::map( data->m_device, &countsHost ); - Buffer* offsetsNative = nativeSolveData->m_offsets;//BufferUtils::map( data->m_device, &offsetsHost ); - - { // 2. set cell idx - struct CB - { - int m_nContacts; - int m_staticIdx; - float m_scale; - int m_nSplit; - }; - - ADLASSERT( sortSize%64 == 0 ); - CB cdata; - cdata.m_nContacts = nContacts; - cdata.m_staticIdx = cfg.m_staticIdx; - cdata.m_scale = 1.f/(N_OBJ_PER_SPLIT*cfg.m_averageExtent); - cdata.m_nSplit = N_SPLIT; - - Buffer constBuffer( data->m_device, 1, BufferBase::BUFFER_CONST ); - BufferInfo bInfo[] = { BufferInfo( contactNative ), BufferInfo( bodyNative ), BufferInfo( data->m_sortDataBuffer ) }; - Launcher launcher( data->m_device, data->m_setSortDataKernel ); - launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(Launcher::BufferInfo) ); - launcher.setConst( constBuffer, cdata ); - launcher.launch1D( sortSize, 64 ); - } - - { // 3. sort by cell idx - int n = N_SPLIT*N_SPLIT; - int sortBit = 32; - //if( n <= 0xffff ) sortBit = 16; - //if( n <= 0xff ) sortBit = 8; - RadixSort32::execute( data->m_sort32, *data->m_sortDataBuffer,sortSize); - } - { // 4. find entries - BoundSearch::execute( data->m_search, *data->m_sortDataBuffer, nContacts, *countsNative, N_SPLIT*N_SPLIT, BoundSearchBase::COUNT ); - - PrefixScan::execute( data->m_scan, *countsNative, *offsetsNative, N_SPLIT*N_SPLIT ); - } - - { // 5. sort constraints by cellIdx - // todo. preallocate this -// ADLASSERT( contactsIn->getType() == TYPE_HOST ); -// Buffer* out = BufferUtils::map( data->m_device, contactsIn ); // copying contacts to this buffer - - { - Buffer constBuffer( data->m_device, 1, BufferBase::BUFFER_CONST ); - - int4 cdata; cdata.x = nContacts; - BufferInfo bInfo[] = { BufferInfo( contactNative ), BufferInfo( data->m_contactBuffer ), BufferInfo( data->m_sortDataBuffer ) }; - Launcher launcher( data->m_device, data->m_reorderContactKernel ); - launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(Launcher::BufferInfo) ); - launcher.setConst( constBuffer, cdata ); - launcher.launch1D( nContacts, 64 ); - } -// BufferUtils::unmap( out, contactsIn, nContacts ); - } - } - - BufferUtils::unmap( bodyNative, bodyBuf ); - BufferUtils::unmap( contactNative, contactsIn ); -} - -template -void Solver::batchContacts( typename Solver::Data* data, Buffer* contacts, int nContacts, Buffer* n, Buffer* offsets, int staticIdx ) -{ - ADLASSERT( data->m_device->m_type == TYPE_CL ); - - if(0) - { - BT_PROFILE("CPU classTestKernel/Kernel (batch generation?)"); - - DeviceUtils::Config dhCfg; - Device* deviceHost = DeviceUtils::allocate( TYPE_HOST, dhCfg ); - { - Solver::Data* hostData = Solver::allocate( deviceHost, 0 ); - Solver::batchContacts( hostData, contacts, nContacts, n, offsets, staticIdx ); - Solver::deallocate( hostData ); - } - DeviceUtils::deallocate( deviceHost ); - return; - } - - Buffer* contactNative - = BufferUtils::map( data->m_device, contacts, nContacts ); - Buffer* nNative - = BufferUtils::map( data->m_device, n ); - Buffer* offsetsNative - = BufferUtils::map( data->m_device, offsets ); - - { - BT_PROFILE("GPU classTestKernel/Kernel (batch generation?)"); - Buffer constBuffer( data->m_device, 1, BufferBase::BUFFER_CONST ); - int4 cdata; - cdata.x = nContacts; - cdata.y = 0; - cdata.z = staticIdx; - - int numWorkItems = 64*N_SPLIT*N_SPLIT; -#ifdef BATCH_DEBUG - SolverDebugInfo* debugInfo = new SolverDebugInfo[numWorkItems]; - adl::Buffer gpuDebugInfo(data->m_device,numWorkItems); - memset(debugInfo,0,sizeof(SolverDebugInfo)*numWorkItems); - gpuDebugInfo.write(debugInfo,numWorkItems); -#endif - - - BufferInfo bInfo[] = { - BufferInfo( contactNative ), - BufferInfo( data->m_contactBuffer ), - BufferInfo( nNative ), - BufferInfo( offsetsNative ) -#ifdef BATCH_DEBUG - , BufferInfo(&gpuDebugInfo) -#endif - }; - - - - Launcher launcher( data->m_device, data->m_batchingKernel); - launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(Launcher::BufferInfo) ); - launcher.setConst( constBuffer, cdata ); - launcher.launch1D( numWorkItems, 64 ); - DeviceUtils::waitForCompletion( data->m_device ); - -#ifdef BATCH_DEBUG - aaaa - Contact4* hostContacts = new Contact4[nContacts]; - data->m_contactBuffer->read(hostContacts,nContacts); - DeviceUtils::waitForCompletion( data->m_device ); - - gpuDebugInfo.read(debugInfo,numWorkItems); - DeviceUtils::waitForCompletion( data->m_device ); - - for (int i=0;i0) - { - printf("catch\n"); - } - if (debugInfo[i].m_valInt2>0) - { - printf("catch22\n"); - } - - if (debugInfo[i].m_valInt3>0) - { - printf("catch666\n"); - } - - if (debugInfo[i].m_valInt4>0) - { - printf("catch777\n"); - } - } - delete[] debugInfo; -#endif //BATCH_DEBUG - - } - - if(0) - { - u32* nhost = new u32[N_SPLIT*N_SPLIT]; - - nNative->read( nhost, N_SPLIT*N_SPLIT ); - - Contact4* chost = new Contact4[nContacts]; - data->m_contactBuffer->read( chost, nContacts ); - DeviceUtils::waitForCompletion( data->m_device ); - printf(">>"); - int nonzero = 0; - u32 maxn = 0; - for(int i=0; iwrite( *data->m_contactBuffer, nContacts ); - DeviceUtils::waitForCompletion( data->m_device ); - - if(0) - { - DeviceUtils::Config dhCfg; - Device* deviceHost = DeviceUtils::allocate( TYPE_HOST, dhCfg ); - { - HostBuffer host( deviceHost, nContacts ); - contactNative->read( host.m_ptr, nContacts ); - DeviceUtils::waitForCompletion( data->m_device ); - - for(int i=0; i( contactNative, contacts ); - BufferUtils::unmap( nNative, n ); - BufferUtils::unmap( offsetsNative, offsets ); -} - -#undef PATH -#undef KERNEL1 -#undef KERNEL2 - -#undef KERNEL3 -#undef KERNEL4 -#undef KERNEL5 diff --git a/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/SolverHost.inl b/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/SolverHost.inl deleted file mode 100644 index a79205d8c..000000000 --- a/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/SolverHost.inl +++ /dev/null @@ -1,848 +0,0 @@ -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Takahiro Harada - - -class SolverInl -{ -public: - typedef SolverBase::ConstraintData ConstraintData; - - - static - __forceinline - void setLinearAndAngular(const MYF4& n, const MYF4& r0, const MYF4& r1, - MYF4& linear, MYF4& angular0, MYF4& angular1) - { - linear = -n; - angular0 = -cross3(r0, n); - angular1 = cross3(r1, n); - } - - static - __forceinline - float calcJacCoeff(const MYF4& linear0, const MYF4& linear1, const MYF4& angular0, const MYF4& angular1, - float invMass0, const Matrix3x3& invInertia0, float invMass1, const Matrix3x3& invInertia1) - { - // linear0,1 are normlized - float jmj0 = invMass0;//dot3F4(linear0, linear0)*invMass0; - float jmj1 = dot3F4(mtMul3(angular0,invInertia0), angular0); - float jmj2 = invMass1;//dot3F4(linear1, linear1)*invMass1; - float jmj3 = dot3F4(mtMul3(angular1,invInertia1), angular1); - return -1.f/(jmj0+jmj1+jmj2+jmj3); - } - static - __forceinline - float calcRelVel(const MYF4& l0, const MYF4& l1, const MYF4& a0, const MYF4& a1, - const MYF4& linVel0, const MYF4& angVel0, const MYF4& linVel1, const MYF4& angVel1) - { - return dot3F4(l0, linVel0) + dot3F4(a0, angVel0) + dot3F4(l1, linVel1) + dot3F4(a1, angVel1); - } - - static - __forceinline - void setConstraint4( const MYF4& posA, const MYF4& linVelA, const MYF4& angVelA, float invMassA, const Matrix3x3& invInertiaA, - const MYF4& posB, const MYF4& linVelB, const MYF4& angVelB, float invMassB, const Matrix3x3& invInertiaB, - const Contact4& src, const SolverBase::ConstraintCfg& cfg, - Constraint4& dstC ) - { - dstC.m_bodyA = (u32)src.m_bodyAPtr; - dstC.m_bodyB = (u32)src.m_bodyBPtr; - - float dtInv = 1.f/cfg.m_dt; - for(int ic=0; ic<4; ic++) - { - dstC.m_appliedRambdaDt[ic] = 0.f; - } - dstC.m_fJacCoeffInv[0] = dstC.m_fJacCoeffInv[1] = 0.f; - - - const MYF4& n = src.m_worldNormal; - dstC.m_linear = -n; - dstC.setFrictionCoeff( src.getFrictionCoeff() ); - for(int ic=0; ic<4; ic++) - { - MYF4 r0 = src.m_worldPos[ic] - posA; - MYF4 r1 = src.m_worldPos[ic] - posB; - - if( ic >= src.getNPoints() ) - { - dstC.m_jacCoeffInv[ic] = 0.f; - continue; - } - - float relVelN; - { - MYF4 linear, angular0, angular1; - setLinearAndAngular(n, r0, r1, linear, angular0, angular1); - - dstC.m_jacCoeffInv[ic] = calcJacCoeff(linear, -linear, angular0, angular1, - invMassA, invInertiaA, invMassB, invInertiaB ); - - relVelN = calcRelVel(linear, -linear, angular0, angular1, - linVelA, angVelA, linVelB, angVelB); - - float e = src.getRestituitionCoeff(); - if( relVelN*relVelN < 0.004f ) e = 0.f; - - dstC.m_b[ic] = e*relVelN; - dstC.m_b[ic] += (src.getPenetration(ic) + cfg.m_positionDrift)*cfg.m_positionConstraintCoeff*dtInv; - dstC.m_appliedRambdaDt[ic] = 0.f; - } - } - - if( src.getNPoints() > 1 ) - { // prepare friction - MYF4 center = MAKE_MYF4(0.f); - for(int i=0; i 0.95f || (invMassA == 0.f || invMassB == 0.f)) - { - float angNA = dot3F4( n, angVelA ); - float angNB = dot3F4( n, angVelB ); - - angVelA -= (angNA*0.1f)*n; - angVelB -= (angNB*0.1f)*n; - } - } - } - - template - static - __inline - void solveContact(Constraint4& cs, - const MYF4& posA, MYF4& linVelA, MYF4& angVelA, float invMassA, const Matrix3x3& invInertiaA, - const MYF4& posB, MYF4& linVelB, MYF4& angVelB, float invMassB, const Matrix3x3& invInertiaB, - float maxRambdaDt[4], float minRambdaDt[4]) - { - MYF4 dLinVelA = MAKE_MYF4(0.f); - MYF4 dAngVelA = MAKE_MYF4(0.f); - MYF4 dLinVelB = MAKE_MYF4(0.f); - MYF4 dAngVelB = MAKE_MYF4(0.f); - - for(int ic=0; ic<4; ic++) - { - // dont necessary because this makes change to 0 - if( cs.m_jacCoeffInv[ic] == 0.f ) continue; - - { - MYF4 angular0, angular1, linear; - MYF4 r0 = cs.m_worldPos[ic] - posA; - MYF4 r1 = cs.m_worldPos[ic] - posB; - setLinearAndAngular( -cs.m_linear, r0, r1, linear, angular0, angular1 ); - - float rambdaDt = calcRelVel(cs.m_linear, -cs.m_linear, angular0, angular1, - linVelA, angVelA, linVelB, angVelB ) + cs.m_b[ic]; - rambdaDt *= cs.m_jacCoeffInv[ic]; - - { - float prevSum = cs.m_appliedRambdaDt[ic]; - float updated = prevSum; - updated += rambdaDt; - updated = max2( updated, minRambdaDt[ic] ); - updated = min2( updated, maxRambdaDt[ic] ); - rambdaDt = updated - prevSum; - cs.m_appliedRambdaDt[ic] = updated; - } - - MYF4 linImp0 = invMassA*linear*rambdaDt; - MYF4 linImp1 = invMassB*(-linear)*rambdaDt; - MYF4 angImp0 = mtMul1(invInertiaA, angular0)*rambdaDt; - MYF4 angImp1 = mtMul1(invInertiaB, angular1)*rambdaDt; - - if( JACOBI ) - { - dLinVelA += linImp0; - dAngVelA += angImp0; - dLinVelB += linImp1; - dAngVelB += angImp1; - } - else - { - linVelA += linImp0; - angVelA += angImp0; - linVelB += linImp1; - angVelB += angImp1; - } - } - } - - if( JACOBI ) - { - linVelA += dLinVelA; - angVelA += dAngVelA; - linVelB += dLinVelB; - angVelB += dAngVelB; - } - } - - enum - { - N_SPLIT = SolverBase::N_SPLIT, - }; - - // for parallel solve - struct ParallelSolveData - { - u32 m_n[N_SPLIT*N_SPLIT]; - u32 m_offset[N_SPLIT*N_SPLIT]; - }; - - static - __inline - int sortConstraintByBatch(Contact4* cs, int n, int ignoreIdx, int simdWidth = -1) - { - SortData* sortData; - { - BT_PROFILE("new"); - sortData = new SortData[n]; - } - - u32* idxBuffer = new u32[n]; - u32* idxSrc = idxBuffer; - u32* idxDst = idxBuffer; - int nIdxSrc, nIdxDst; - - const int N_FLG = 256; - const int FLG_MASK = N_FLG-1; - u32 flg[N_FLG/32]; -#if defined(_DEBUG) - for(int i=0; i sortBuffer; sortBuffer.setRawPtr( deviceHost, sortData, n ); - RadixSort::Data* sort = RadixSort::allocate( deviceHost, n ); - - RadixSort::execute( sort, sortBuffer, n ); - - RadixSort::deallocate( sort ); - } - DeviceUtils::deallocate( deviceHost ); - } - - { - BT_PROFILE("reorder"); - // reorder - Contact4* old = new Contact4[n]; - memcpy( old, cs, sizeof(Contact4)*n); - for(int i=0; i* bodies, const Buffer* shapes, const Buffer* constraints, - int start, int nConstraints) - : m_bodies( bodies ), m_shapes( shapes ), m_constraints( constraints ), m_start( start ), m_nConstraints( nConstraints ), - m_solveFriction( true ){} - - u16 getType(){ return 0; } - - void run(int tIdx) - { - HostBuffer& hBody = *(HostBuffer*)m_bodies; - HostBuffer& hShape = *(HostBuffer*)m_shapes; - HostBuffer& hc = *(HostBuffer*)m_constraints; - - for(int ic=0; ic( hc[i], bodyA.m_pos, (MYF4&)bodyA.m_linVel, (MYF4&)bodyA.m_angVel, bodyA.m_invMass, hShape[aIdx].m_invInertia, - bodyB.m_pos, (MYF4&)bodyB.m_linVel, (MYF4&)bodyB.m_angVel, bodyB.m_invMass, hShape[bIdx].m_invInertia, - maxRambdaDt, minRambdaDt ); - } - else - { - float maxRambdaDt[4] = {FLT_MAX,FLT_MAX,FLT_MAX,FLT_MAX}; - float minRambdaDt[4] = {0.f,0.f,0.f,0.f}; - - float sum = 0; - for(int j=0; j<4; j++) - { - sum +=hc[i].m_appliedRambdaDt[j]; - } - frictionCoeff = 0.7f; - for(int j=0; j<4; j++) - { - maxRambdaDt[j] = frictionCoeff*sum; - minRambdaDt[j] = -maxRambdaDt[j]; - } - - SolverInl::solveFriction( hc[i], bodyA.m_pos, (MYF4&)bodyA.m_linVel, (MYF4&)bodyA.m_angVel, bodyA.m_invMass, hShape[aIdx].m_invInertia, - bodyB.m_pos, (MYF4&)bodyB.m_linVel, (MYF4&)bodyB.m_angVel, bodyB.m_invMass, hShape[bIdx].m_invInertia, - maxRambdaDt, minRambdaDt ); - } - } - } - - const Buffer* m_bodies; - const Buffer* m_shapes; - const Buffer* m_constraints; - int m_start; - int m_nConstraints; - bool m_solveFriction; -}; - - -template<> -static Solver::Data* Solver::allocate( const Device* device, int pairCapacity ) -{ - Solver::Data* data = new Data; - data->m_device = device; - data->m_parallelSolveData = 0; - - return data; -} - -template<> -static void Solver::deallocate( Solver::Data* data ) -{ - if( data->m_parallelSolveData ) delete (SolverInl::ParallelSolveData*)data->m_parallelSolveData; - delete data; -} - - -void sortContacts2( Solver::Data* data, const Buffer* bodyBuf, - Buffer* contactsIn, void* additionalData, - int nContacts, const Solver::ConstraintCfg& cfg ) -{ - ADLASSERT( data->m_device->m_type == TYPE_HOST ); - HostBuffer* bodyNative - = (HostBuffer*)BufferUtils::map( data->m_device, bodyBuf ); - HostBuffer* contactNative - = (HostBuffer*)BufferUtils::map( data->m_device, contactsIn); - - if( cfg.m_enableParallelSolve ) - { - ADLASSERT( data->m_parallelSolveData == 0 ); - data->m_parallelSolveData = new SolverInl::ParallelSolveData; - SolverInl::ParallelSolveData* solveData = (SolverInl::ParallelSolveData*)data->m_parallelSolveData; - - HostBuffer sortData( data->m_device, nContacts ); - { // 2. set cell idx - float spacing = adl::SolverBase::N_OBJ_PER_SPLIT*cfg.m_averageExtent; - float xScale = 1.f/spacing; - for(int i=0; i= 0 && xIdx < adl::SolverBase::N_SPLIT ); - ADLASSERT( zIdx >= 0 && zIdx < adl::SolverBase::N_SPLIT ); - sortData[i].m_key = (xIdx+zIdx*adl::SolverBase::N_SPLIT); - sortData[i].m_value = i; - } - } - - { // 3. sort by cell idx - RadixSort::Data* sData = RadixSort::allocate( data->m_device, nContacts ); - - RadixSort::execute( sData, sortData, nContacts ); - - RadixSort::deallocate( sData ); - } - - { // 4. find entries - HostBuffer counts; counts.setRawPtr( data->m_device, solveData->m_n, adl::SolverBase::N_SPLIT*adl::SolverBase::N_SPLIT ); - HostBuffer offsets; offsets.setRawPtr( data->m_device, solveData->m_offset, adl::SolverBase::N_SPLIT*adl::SolverBase::N_SPLIT ); - { - BoundSearch::Data* sData = BoundSearch::allocate( data->m_device ); - PrefixScan::Data* pData = PrefixScan::allocate( data->m_device, adl::SolverBase::N_SPLIT*adl::SolverBase::N_SPLIT ); - - BoundSearch::execute( sData, sortData, nContacts, counts, adl::SolverBase::N_SPLIT*adl::SolverBase::N_SPLIT, BoundSearchBase::COUNT ); - - PrefixScan::execute( pData, counts, offsets, adl::SolverBase::N_SPLIT*adl::SolverBase::N_SPLIT ); - - BoundSearch::deallocate( sData ); - PrefixScan::deallocate( pData ); - } -#if defined(_DEBUG) - { - HostBuffer n0( data->m_device, adl::SolverBase::N_SPLIT*adl::SolverBase::N_SPLIT ); - HostBuffer offset0( data->m_device, adl::SolverBase::N_SPLIT*adl::SolverBase::N_SPLIT ); - for(int i=0; im_ptr, sizeof(Contact4)*nContacts ); - for(int i=0; i( bodyNative, bodyBuf ); - BufferUtils::unmap( contactNative, contactsIn ); -} - -static void reorderConvertToConstraints2( Solver::Data* data, const Buffer* bodyBuf, - const Buffer* shapeBuf, - adl::Buffer* contactsIn, SolverData contactCOut, void* additionalData, - int nContacts, const Solver::ConstraintCfg& cfg ) -{ - - - sortContacts2( data, bodyBuf, contactsIn, additionalData, nContacts, cfg ); - - { - SolverInl::ParallelSolveData* solveData = (SolverInl::ParallelSolveData*)data->m_parallelSolveData; - Buffer n; n.setRawPtr( data->m_device, solveData->m_n, adl::SolverBase::N_SPLIT*adl::SolverBase::N_SPLIT ); - Buffer offsets; offsets.setRawPtr( data->m_device, solveData->m_offset, adl::SolverBase::N_SPLIT*adl::SolverBase::N_SPLIT ); - Solver::batchContacts( data, contactsIn, nContacts, &n, &offsets, cfg.m_staticIdx ); - printf("hello\n"); - } - - Solver::convertToConstraints( data, bodyBuf, shapeBuf, contactsIn, contactCOut, additionalData, nContacts, cfg ); -} - -template -static void solveContactConstraint( Solver::Data* data, const Buffer* bodyBuf, const Buffer* shapeBuf, - SolverData constraint, void* additionalData, int n ) -{ - - Buffer* bodyNative - = BufferUtils::map( data->m_device, bodyBuf ); - Buffer* shapeNative - = BufferUtils::map( data->m_device, shapeBuf ); - Buffer* constraintNative - = BufferUtils::map( data->m_device, (const Buffer*)constraint ); - - for(int iter=0; iterm_nIterations; iter++) - { - SolveTask task( bodyNative, shapeNative, constraintNative, 0, n ); - task.m_solveFriction = false; - task.run(0); - } - - for(int iter=0; iterm_nIterations; iter++) - { - SolveTask task( bodyNative, shapeNative, constraintNative, 0, n ); - task.m_solveFriction = true; - task.run(0); - } - - BufferUtils::unmap( bodyNative, bodyBuf ); - BufferUtils::unmap( shapeNative, shapeBuf ); - BufferUtils::unmap( constraintNative, (const Buffer*)constraint ); -} - -#if 0 -static -int createSolveTasks( int batchIdx, Data* data, const Buffer* bodyBuf, const Buffer* shapeBuf, - SolverData constraint, int n, ThreadPool::Task* tasksOut[], int taskCapacity ) -{ -/* - ADLASSERT( (N_SPLIT&1) == 0 ); - ADLASSERT( batchIdx < N_BATCHES ); - ADLASSERT( data->m_device->m_type == TYPE_HOST ); - ADLASSERT( data->m_parallelSolveData ); - - SolverInl::ParallelSolveData* solveData = (SolverInl::ParallelSolveData*)data->m_parallelSolveData; - data->m_batchIdx = 0; - - const int nx = N_SPLIT/2; - - int nTasksCreated = 0; - -// for(int ii=0; ii<2; ii++) - for(batchIdx=0; batchIdx<4; batchIdx++) - { - int2 offset = make_int2( batchIdx&1, batchIdx>>1 ); - for(int ix=0; ixm_n[cellIdx]; - int start = solveData->m_offset[cellIdx]; - - if( n == 0 ) continue; - - SolveTask* task = new SolveTask( bodyBuf, shapeBuf, (const Buffer*)constraint, start, n ); -// task->m_solveFriction = (ii==0)? false:true; - tasksOut[nTasksCreated++] = task; - } - } - - return nTasksCreated; -*/ - ADLASSERT(0); - return 0; -} -#endif - - - -static void convertToConstraints2( Solver::Data* data, const Buffer* bodyBuf, - const Buffer* shapeBuf, - Buffer* contactsIn, SolverData contactCOut, void* additionalData, - int nContacts, const Solver::ConstraintCfg& cfg ) -{ - ADLASSERT( data->m_device->m_type == TYPE_HOST ); - - HostBuffer* bodyNative - = (HostBuffer*)BufferUtils::map( data->m_device, bodyBuf ); - HostBuffer* shapeNative - = (HostBuffer*)BufferUtils::map( data->m_device, shapeBuf ); - HostBuffer* contactNative - = (HostBuffer*)BufferUtils::map( data->m_device, contactsIn ); - HostBuffer* constraintNative - = (HostBuffer*)BufferUtils::map( data->m_device, (Buffer*)contactCOut ); - - { -#if !defined(_DEBUG) -#pragma omp parallel for -#endif - for(int i=0; i( bodyNative, bodyBuf ); - BufferUtils::unmap( shapeNative, shapeBuf ); - BufferUtils::unmap( contactNative, contactsIn ); - BufferUtils::unmap( constraintNative, (Buffer*)contactCOut ); -} - - - - - -static void batchContacts2( Solver::Data* data, Buffer* contacts, int nContacts, Buffer* n, Buffer* offsets, int staticIdx ) -{ - ADLASSERT( data->m_device->m_type == TYPE_HOST ); - - HostBuffer* contactNative =0; - HostBuffer* nNative =0; - HostBuffer* offsetsNative =0; - - int sz = sizeof(Contact4); - int sz2 = sizeof(int2); - { - BT_PROFILE("BufferUtils::map"); - contactNative = (HostBuffer*)BufferUtils::map( data->m_device, contacts, nContacts ); - } - { - BT_PROFILE("BufferUtils::map2"); - nNative = (HostBuffer*)BufferUtils::map( data->m_device, n ); - offsetsNative= (HostBuffer*)BufferUtils::map( data->m_device, offsets ); - } - - - { - BT_PROFILE("sortConstraintByBatch"); - int numNonzeroGrid=0; - int maxNumBatches = 0; - - for(int i=0; im_ptr+offset, n, staticIdx,-1 ); // on GPU - maxNumBatches = max(numBatches,maxNumBatches); - - // SolverInl::sortConstraintByBatch( contactNative->m_ptr+offset, n, staticIdx ); // on CPU - } - } - - printf("maxNumBatches = %d\n", maxNumBatches); - } - - { - BT_PROFILE("BufferUtils::unmap"); - BufferUtils::unmap( contactNative, contacts, nContacts ); - } - { - BT_PROFILE("BufferUtils::unmap2"); - BufferUtils::unmap( nNative, n ); - BufferUtils::unmap( offsetsNative, offsets ); - } - - -} - - diff --git a/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/SolverKernels.cl b/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/SolverKernels.cl deleted file mode 100644 index e46194391..000000000 --- a/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/SolverKernels.cl +++ /dev/null @@ -1,1051 +0,0 @@ -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Takahiro Harada - - -#pragma OPENCL EXTENSION cl_amd_printf : enable -#pragma OPENCL EXTENSION cl_khr_local_int32_base_atomics : enable -#pragma OPENCL EXTENSION cl_khr_global_int32_base_atomics : enable -#pragma OPENCL EXTENSION cl_khr_local_int32_extended_atomics : enable -#pragma OPENCL EXTENSION cl_khr_global_int32_extended_atomics : enable - - -#ifdef cl_ext_atomic_counters_32 -#pragma OPENCL EXTENSION cl_ext_atomic_counters_32 : enable -#else -#define counter32_t volatile global int* -#endif - -typedef unsigned int u32; -typedef unsigned short u16; -typedef unsigned char u8; - -#define GET_GROUP_IDX get_group_id(0) -#define GET_LOCAL_IDX get_local_id(0) -#define GET_GLOBAL_IDX get_global_id(0) -#define GET_GROUP_SIZE get_local_size(0) -#define GET_NUM_GROUPS get_num_groups(0) -#define GROUP_LDS_BARRIER barrier(CLK_LOCAL_MEM_FENCE) -#define GROUP_MEM_FENCE mem_fence(CLK_LOCAL_MEM_FENCE) -#define AtomInc(x) atom_inc(&(x)) -#define AtomInc1(x, out) out = atom_inc(&(x)) -#define AppendInc(x, out) out = atomic_inc(x) -#define AtomAdd(x, value) atom_add(&(x), value) -#define AtomCmpxhg(x, cmp, value) atom_cmpxchg( &(x), cmp, value ) -#define AtomXhg(x, value) atom_xchg ( &(x), value ) - - -#define SELECT_UINT4( b, a, condition ) select( b,a,condition ) - -#define make_float4 (float4) -#define make_float2 (float2) -#define make_uint4 (uint4) -#define make_int4 (int4) -#define make_uint2 (uint2) -#define make_int2 (int2) - - -#define max2 max -#define min2 min - - -/////////////////////////////////////// -// Vector -/////////////////////////////////////// -__inline -float fastDiv(float numerator, float denominator) -{ - return native_divide(numerator, denominator); -// return numerator/denominator; -} - -__inline -float4 fastDiv4(float4 numerator, float4 denominator) -{ - return native_divide(numerator, denominator); -} - -__inline -float fastSqrtf(float f2) -{ - return native_sqrt(f2); -// return sqrt(f2); -} - -__inline -float fastRSqrt(float f2) -{ - return native_rsqrt(f2); -} - -__inline -float fastLength4(float4 v) -{ - return fast_length(v); -} - -__inline -float4 fastNormalize4(float4 v) -{ - return fast_normalize(v); -} - - -__inline -float sqrtf(float a) -{ -// return sqrt(a); - return native_sqrt(a); -} - -__inline -float4 cross3(float4 a, float4 b) -{ - return cross(a,b); -} - -__inline -float dot3F4(float4 a, float4 b) -{ - float4 a1 = make_float4(a.xyz,0.f); - float4 b1 = make_float4(b.xyz,0.f); - return dot(a1, b1); -} - -__inline -float length3(const float4 a) -{ - return sqrtf(dot3F4(a,a)); -} - -__inline -float dot4(const float4 a, const float4 b) -{ - return dot( a, b ); -} - -// for height -__inline -float dot3w1(const float4 point, const float4 eqn) -{ - return dot3F4(point,eqn) + eqn.w; -} - -__inline -float4 normalize3(const float4 a) -{ - float4 n = make_float4(a.x, a.y, a.z, 0.f); - return fastNormalize4( n ); -// float length = sqrtf(dot3F4(a, a)); -// return 1.f/length * a; -} - -__inline -float4 normalize4(const float4 a) -{ - float length = sqrtf(dot4(a, a)); - return 1.f/length * a; -} - -__inline -float4 createEquation(const float4 a, const float4 b, const float4 c) -{ - float4 eqn; - float4 ab = b-a; - float4 ac = c-a; - eqn = normalize3( cross3(ab, ac) ); - eqn.w = -dot3F4(eqn,a); - return eqn; -} - -/////////////////////////////////////// -// Matrix3x3 -/////////////////////////////////////// - -typedef struct -{ - float4 m_row[3]; -}Matrix3x3; - -__inline -Matrix3x3 mtZero(); - -__inline -Matrix3x3 mtIdentity(); - -__inline -Matrix3x3 mtTranspose(Matrix3x3 m); - -__inline -Matrix3x3 mtMul(Matrix3x3 a, Matrix3x3 b); - -__inline -float4 mtMul1(Matrix3x3 a, float4 b); - -__inline -float4 mtMul3(float4 a, Matrix3x3 b); - -__inline -Matrix3x3 mtZero() -{ - Matrix3x3 m; - m.m_row[0] = (float4)(0.f); - m.m_row[1] = (float4)(0.f); - m.m_row[2] = (float4)(0.f); - return m; -} - -__inline -Matrix3x3 mtIdentity() -{ - Matrix3x3 m; - m.m_row[0] = (float4)(1,0,0,0); - m.m_row[1] = (float4)(0,1,0,0); - m.m_row[2] = (float4)(0,0,1,0); - return m; -} - -__inline -Matrix3x3 mtTranspose(Matrix3x3 m) -{ - Matrix3x3 out; - out.m_row[0] = (float4)(m.m_row[0].x, m.m_row[1].x, m.m_row[2].x, 0.f); - out.m_row[1] = (float4)(m.m_row[0].y, m.m_row[1].y, m.m_row[2].y, 0.f); - out.m_row[2] = (float4)(m.m_row[0].z, m.m_row[1].z, m.m_row[2].z, 0.f); - return out; -} - -__inline -Matrix3x3 mtMul(Matrix3x3 a, Matrix3x3 b) -{ - Matrix3x3 transB; - transB = mtTranspose( b ); - Matrix3x3 ans; - // why this doesn't run when 0ing in the for{} - a.m_row[0].w = 0.f; - a.m_row[1].w = 0.f; - a.m_row[2].w = 0.f; - for(int i=0; i<3; i++) - { -// a.m_row[i].w = 0.f; - ans.m_row[i].x = dot3F4(a.m_row[i],transB.m_row[0]); - ans.m_row[i].y = dot3F4(a.m_row[i],transB.m_row[1]); - ans.m_row[i].z = dot3F4(a.m_row[i],transB.m_row[2]); - ans.m_row[i].w = 0.f; - } - return ans; -} - -__inline -float4 mtMul1(Matrix3x3 a, float4 b) -{ - float4 ans; - ans.x = dot3F4( a.m_row[0], b ); - ans.y = dot3F4( a.m_row[1], b ); - ans.z = dot3F4( a.m_row[2], b ); - ans.w = 0.f; - return ans; -} - -__inline -float4 mtMul3(float4 a, Matrix3x3 b) -{ - float4 colx = make_float4(b.m_row[0].x, b.m_row[1].x, b.m_row[2].x, 0); - float4 coly = make_float4(b.m_row[0].y, b.m_row[1].y, b.m_row[2].y, 0); - float4 colz = make_float4(b.m_row[0].z, b.m_row[1].z, b.m_row[2].z, 0); - - float4 ans; - ans.x = dot3F4( a, colx ); - ans.y = dot3F4( a, coly ); - ans.z = dot3F4( a, colz ); - return ans; -} - -/////////////////////////////////////// -// Quaternion -/////////////////////////////////////// - -typedef float4 Quaternion; - -__inline -Quaternion qtMul(Quaternion a, Quaternion b); - -__inline -Quaternion qtNormalize(Quaternion in); - -__inline -float4 qtRotate(Quaternion q, float4 vec); - -__inline -Quaternion qtInvert(Quaternion q); - -__inline -Matrix3x3 qtGetRotationMatrix(Quaternion q); - - - -__inline -Quaternion qtMul(Quaternion a, Quaternion b) -{ - Quaternion ans; - ans = cross3( a, b ); - ans += a.w*b+b.w*a; -// ans.w = a.w*b.w - (a.x*b.x+a.y*b.y+a.z*b.z); - ans.w = a.w*b.w - dot3F4(a, b); - return ans; -} - -__inline -Quaternion qtNormalize(Quaternion in) -{ - return fastNormalize4(in); -// in /= length( in ); -// return in; -} -__inline -float4 qtRotate(Quaternion q, float4 vec) -{ - Quaternion qInv = qtInvert( q ); - float4 vcpy = vec; - vcpy.w = 0.f; - float4 out = qtMul(qtMul(q,vcpy),qInv); - return out; -} - -__inline -Quaternion qtInvert(Quaternion q) -{ - return (Quaternion)(-q.xyz, q.w); -} - -__inline -float4 qtInvRotate(const Quaternion q, float4 vec) -{ - return qtRotate( qtInvert( q ), vec ); -} - -__inline -Matrix3x3 qtGetRotationMatrix(Quaternion quat) -{ - float4 quat2 = (float4)(quat.x*quat.x, quat.y*quat.y, quat.z*quat.z, 0.f); - Matrix3x3 out; - - out.m_row[0].x=1-2*quat2.y-2*quat2.z; - out.m_row[0].y=2*quat.x*quat.y-2*quat.w*quat.z; - out.m_row[0].z=2*quat.x*quat.z+2*quat.w*quat.y; - out.m_row[0].w = 0.f; - - out.m_row[1].x=2*quat.x*quat.y+2*quat.w*quat.z; - out.m_row[1].y=1-2*quat2.x-2*quat2.z; - out.m_row[1].z=2*quat.y*quat.z-2*quat.w*quat.x; - out.m_row[1].w = 0.f; - - out.m_row[2].x=2*quat.x*quat.z-2*quat.w*quat.y; - out.m_row[2].y=2*quat.y*quat.z+2*quat.w*quat.x; - out.m_row[2].z=1-2*quat2.x-2*quat2.y; - out.m_row[2].w = 0.f; - - return out; -} - - - - -#define WG_SIZE 64 - -typedef struct -{ - float4 m_pos; - Quaternion m_quat; - float4 m_linVel; - float4 m_angVel; - - u32 m_shapeIdx; - u32 m_shapeType; - float m_invMass; - float m_restituitionCoeff; - float m_frictionCoeff; -} Body; - -typedef struct -{ - Matrix3x3 m_invInertia; - Matrix3x3 m_initInvInertia; -} Shape; - -typedef struct -{ - float4 m_linear; - float4 m_worldPos[4]; - float4 m_center; - float m_jacCoeffInv[4]; - float m_b[4]; - float m_appliedRambdaDt[4]; - - float m_fJacCoeffInv[2]; - float m_fAppliedRambdaDt[2]; - - u32 m_bodyA; - u32 m_bodyB; - - int m_batchIdx; - u32 m_paddings[1]; -} Constraint4; - -typedef struct -{ - float4 m_worldPos[4]; - float4 m_worldNormal; - u32 m_coeffs; - int m_batchIdx; - - u32 m_bodyAPtr; - u32 m_bodyBPtr; -} Contact4; - -typedef struct -{ - int m_nConstraints; - int m_start; - int m_batchIdx; - int m_nSplit; -// int m_paddings[1]; -} ConstBuffer; - -typedef struct -{ - int m_solveFriction; - int m_maxBatch; // long batch really kills the performance - int m_batchIdx; - int m_nSplit; -// int m_paddings[1]; -} ConstBufferBatchSolve; - - -void setLinearAndAngular( float4 n, float4 r0, float4 r1, float4* linear, float4* angular0, float4* angular1) -{ - *linear = -n; - *angular0 = -cross3(r0, n); - *angular1 = cross3(r1, n); -} - - -float calcRelVel( float4 l0, float4 l1, float4 a0, float4 a1, float4 linVel0, float4 angVel0, float4 linVel1, float4 angVel1 ) -{ - return dot3F4(l0, linVel0) + dot3F4(a0, angVel0) + dot3F4(l1, linVel1) + dot3F4(a1, angVel1); -} - - -float calcJacCoeff(const float4 linear0, const float4 linear1, const float4 angular0, const float4 angular1, - float invMass0, const Matrix3x3* invInertia0, float invMass1, const Matrix3x3* invInertia1) -{ - // linear0,1 are normlized - float jmj0 = invMass0;//dot3F4(linear0, linear0)*invMass0; - float jmj1 = dot3F4(mtMul3(angular0,*invInertia0), angular0); - float jmj2 = invMass1;//dot3F4(linear1, linear1)*invMass1; - float jmj3 = dot3F4(mtMul3(angular1,*invInertia1), angular1); - return -1.f/(jmj0+jmj1+jmj2+jmj3); -} - - - -void solveContact(__global Constraint4* cs, - float4 posA, float4* linVelA, float4* angVelA, float invMassA, Matrix3x3 invInertiaA, - float4 posB, float4* linVelB, float4* angVelB, float invMassB, Matrix3x3 invInertiaB) -{ - float minRambdaDt = 0; - float maxRambdaDt = FLT_MAX; - - for(int ic=0; ic<4; ic++) - { - if( cs->m_jacCoeffInv[ic] == 0.f ) continue; - - float4 angular0, angular1, linear; - float4 r0 = cs->m_worldPos[ic] - posA; - float4 r1 = cs->m_worldPos[ic] - posB; - setLinearAndAngular( -cs->m_linear, r0, r1, &linear, &angular0, &angular1 ); - - float rambdaDt = calcRelVel( cs->m_linear, -cs->m_linear, angular0, angular1, - *linVelA, *angVelA, *linVelB, *angVelB ) + cs->m_b[ic]; - rambdaDt *= cs->m_jacCoeffInv[ic]; - - { - float prevSum = cs->m_appliedRambdaDt[ic]; - float updated = prevSum; - updated += rambdaDt; - updated = max2( updated, minRambdaDt ); - updated = min2( updated, maxRambdaDt ); - rambdaDt = updated - prevSum; - cs->m_appliedRambdaDt[ic] = updated; - } - - float4 linImp0 = invMassA*linear*rambdaDt; - float4 linImp1 = invMassB*(-linear)*rambdaDt; - float4 angImp0 = mtMul1(invInertiaA, angular0)*rambdaDt; - float4 angImp1 = mtMul1(invInertiaB, angular1)*rambdaDt; - - *linVelA += linImp0; - *angVelA += angImp0; - *linVelB += linImp1; - *angVelB += angImp1; - } -} - - -void solveFriction(__global Constraint4* cs, - float4 posA, float4* linVelA, float4* angVelA, float invMassA, Matrix3x3 invInertiaA, - float4 posB, float4* linVelB, float4* angVelB, float invMassB, Matrix3x3 invInertiaB, - float maxRambdaDt[4], float minRambdaDt[4]) -{ - if( cs->m_fJacCoeffInv[0] == 0 && cs->m_fJacCoeffInv[0] == 0 ) return; - const float4 center = cs->m_center; - - float4 n = -cs->m_linear; - - float4 tangent[2]; - tangent[0] = cross3( n, cs->m_worldPos[0]-center ); - tangent[1] = cross3( tangent[0], n ); - tangent[0] = normalize3( tangent[0] ); - tangent[1] = normalize3( tangent[1] ); - - float4 angular0, angular1, linear; - float4 r0 = center - posA; - float4 r1 = center - posB; - for(int i=0; i<2; i++) - { - setLinearAndAngular( tangent[i], r0, r1, &linear, &angular0, &angular1 ); - float rambdaDt = calcRelVel(linear, -linear, angular0, angular1, - *linVelA, *angVelA, *linVelB, *angVelB ); - rambdaDt *= cs->m_fJacCoeffInv[i]; - - { - float prevSum = cs->m_fAppliedRambdaDt[i]; - float updated = prevSum; - updated += rambdaDt; - updated = max2( updated, minRambdaDt[i] ); - updated = min2( updated, maxRambdaDt[i] ); - rambdaDt = updated - prevSum; - cs->m_fAppliedRambdaDt[i] = updated; - } - - float4 linImp0 = invMassA*linear*rambdaDt; - float4 linImp1 = invMassB*(-linear)*rambdaDt; - float4 angImp0 = mtMul1(invInertiaA, angular0)*rambdaDt; - float4 angImp1 = mtMul1(invInertiaB, angular1)*rambdaDt; - - *linVelA += linImp0; - *angVelA += angImp0; - *linVelB += linImp1; - *angVelB += angImp1; - } - { // angular damping for point constraint - float4 ab = normalize3( posB - posA ); - float4 ac = normalize3( center - posA ); - if( dot3F4( ab, ac ) > 0.95f || (invMassA == 0.f || invMassB == 0.f)) - { - float angNA = dot3F4( n, *angVelA ); - float angNB = dot3F4( n, *angVelB ); - - *angVelA -= (angNA*0.1f)*n; - *angVelB -= (angNB*0.1f)*n; - } - } -} - -void solveAConstraint(__global Body* gBodies, __global Shape* gShapes, __global Constraint4* ldsCs) -{ - float frictionCoeff = ldsCs[0].m_linear.w; - int aIdx = ldsCs[0].m_bodyA; - int bIdx = ldsCs[0].m_bodyB; - - float4 posA = gBodies[aIdx].m_pos; - float4 linVelA = gBodies[aIdx].m_linVel; - float4 angVelA = gBodies[aIdx].m_angVel; - float invMassA = gBodies[aIdx].m_invMass; - Matrix3x3 invInertiaA = gShapes[aIdx].m_invInertia; - - float4 posB = gBodies[bIdx].m_pos; - float4 linVelB = gBodies[bIdx].m_linVel; - float4 angVelB = gBodies[bIdx].m_angVel; - float invMassB = gBodies[bIdx].m_invMass; - Matrix3x3 invInertiaB = gShapes[bIdx].m_invInertia; - - - { - solveContact( ldsCs, posA, &linVelA, &angVelA, invMassA, invInertiaA, - posB, &linVelB, &angVelB, invMassB, invInertiaB ); - } - - { - float maxRambdaDt[4] = {FLT_MAX,FLT_MAX,FLT_MAX,FLT_MAX}; - float minRambdaDt[4] = {0.f,0.f,0.f,0.f}; - - float sum = 0; - for(int j=0; j<4; j++) - { - sum +=ldsCs[0].m_appliedRambdaDt[j]; - } - frictionCoeff = 0.7f; - for(int j=0; j<4; j++) - { - maxRambdaDt[j] = frictionCoeff*sum; - minRambdaDt[j] = -maxRambdaDt[j]; - } - - solveFriction( ldsCs, posA, &linVelA, &angVelA, invMassA, invInertiaA, - posB, &linVelB, &angVelB, invMassB, invInertiaB, maxRambdaDt, minRambdaDt ); - } - - gBodies[aIdx].m_linVel = linVelA; - gBodies[aIdx].m_angVel = angVelA; - gBodies[bIdx].m_linVel = linVelB; - gBodies[bIdx].m_angVel = angVelB; -} - -void solveContactConstraint(__global Body* gBodies, __global Shape* gShapes, __global Constraint4* ldsCs) -{ - float frictionCoeff = ldsCs[0].m_linear.w; - int aIdx = ldsCs[0].m_bodyA; - int bIdx = ldsCs[0].m_bodyB; - - float4 posA = gBodies[aIdx].m_pos; - float4 linVelA = gBodies[aIdx].m_linVel; - float4 angVelA = gBodies[aIdx].m_angVel; - float invMassA = gBodies[aIdx].m_invMass; - Matrix3x3 invInertiaA = gShapes[aIdx].m_invInertia; - - float4 posB = gBodies[bIdx].m_pos; - float4 linVelB = gBodies[bIdx].m_linVel; - float4 angVelB = gBodies[bIdx].m_angVel; - float invMassB = gBodies[bIdx].m_invMass; - Matrix3x3 invInertiaB = gShapes[bIdx].m_invInertia; - - solveContact( ldsCs, posA, &linVelA, &angVelA, invMassA, invInertiaA, - posB, &linVelB, &angVelB, invMassB, invInertiaB ); - - gBodies[aIdx].m_linVel = linVelA; - gBodies[aIdx].m_angVel = angVelA; - gBodies[bIdx].m_linVel = linVelB; - gBodies[bIdx].m_angVel = angVelB; -} - -void solveFrictionConstraint(__global Body* gBodies, __global Shape* gShapes, __global Constraint4* ldsCs) -{ - float frictionCoeff = ldsCs[0].m_linear.w; - int aIdx = ldsCs[0].m_bodyA; - int bIdx = ldsCs[0].m_bodyB; - - float4 posA = gBodies[aIdx].m_pos; - float4 linVelA = gBodies[aIdx].m_linVel; - float4 angVelA = gBodies[aIdx].m_angVel; - float invMassA = gBodies[aIdx].m_invMass; - Matrix3x3 invInertiaA = gShapes[aIdx].m_invInertia; - - float4 posB = gBodies[bIdx].m_pos; - float4 linVelB = gBodies[bIdx].m_linVel; - float4 angVelB = gBodies[bIdx].m_angVel; - float invMassB = gBodies[bIdx].m_invMass; - Matrix3x3 invInertiaB = gShapes[bIdx].m_invInertia; - - { - float maxRambdaDt[4] = {FLT_MAX,FLT_MAX,FLT_MAX,FLT_MAX}; - float minRambdaDt[4] = {0.f,0.f,0.f,0.f}; - - float sum = 0; - for(int j=0; j<4; j++) - { - sum +=ldsCs[0].m_appliedRambdaDt[j]; - } - frictionCoeff = 0.7f; - for(int j=0; j<4; j++) - { - maxRambdaDt[j] = frictionCoeff*sum; - minRambdaDt[j] = -maxRambdaDt[j]; - } - - solveFriction( ldsCs, posA, &linVelA, &angVelA, invMassA, invInertiaA, - posB, &linVelB, &angVelB, invMassB, invInertiaB, maxRambdaDt, minRambdaDt ); - } - - gBodies[aIdx].m_linVel = linVelA; - gBodies[aIdx].m_angVel = angVelA; - gBodies[bIdx].m_linVel = linVelB; - gBodies[bIdx].m_angVel = angVelB; -} - -typedef struct -{ - int m_valInt0; - int m_valInt1; - int m_valInt2; - int m_valInt3; - - float m_val0; - float m_val1; - float m_val2; - float m_val3; -} SolverDebugInfo; - - -__kernel -__attribute__((reqd_work_group_size(WG_SIZE,1,1))) -//void BatchSolveKernel(__global Body* gBodies, __global Shape* gShapes, __global Constraint4* gConstraints, __global int* gN, __global int* gOffsets, __global SolverDebugInfo* debugInfo, ConstBufferBatchSolve cb) -void BatchSolveKernel(__global Body* gBodies, -__global Shape* gShapes, -__global Constraint4* gConstraints, -__global int* gN, -__global int* gOffsets, -ConstBufferBatchSolve cb) -{ - __local int ldsBatchIdx[WG_SIZE+1]; - - __local int ldsCurBatch; - __local int ldsNextBatch; - __local int ldsStart; - - int lIdx = GET_LOCAL_IDX; - int wgIdx = GET_GROUP_IDX; - - int gIdx = GET_GLOBAL_IDX; -// debugInfo[gIdx].m_valInt0 = gIdx; - //debugInfo[gIdx].m_valInt1 = GET_GROUP_SIZE; - - const int solveFriction = cb.m_solveFriction; - const int maxBatch = cb.m_maxBatch; - const int bIdx = cb.m_batchIdx; - const int nSplit = cb.m_nSplit; - - int xIdx = (wgIdx/(nSplit/2))*2 + (bIdx&1); - int yIdx = (wgIdx%(nSplit/2))*2 + (bIdx>>1); - int cellIdx = xIdx+yIdx*nSplit; - - if( gN[cellIdx] == 0 ) - return; - - const int start = gOffsets[cellIdx]; - const int end = start + gN[cellIdx]; - - - if( lIdx == 0 ) - { - ldsCurBatch = 0; - ldsNextBatch = 0; - ldsStart = start; - } - - - GROUP_LDS_BARRIER; - - int idx=ldsStart+lIdx; - while (ldsCurBatch < maxBatch) - { - for(; idxm_bodyA = src.m_bodyAPtr; - dstC->m_bodyB = src.m_bodyBPtr; - - float dtInv = 1.f/dt; - for(int ic=0; ic<4; ic++) - { - dstC->m_appliedRambdaDt[ic] = 0.f; - } - dstC->m_fJacCoeffInv[0] = dstC->m_fJacCoeffInv[1] = 0.f; - - - dstC->m_linear = -src.m_worldNormal; - dstC->m_linear.w = 0.7f ;//src.getFrictionCoeff() ); - for(int ic=0; ic<4; ic++) - { - float4 r0 = src.m_worldPos[ic] - posA; - float4 r1 = src.m_worldPos[ic] - posB; - - if( ic >= src.m_worldNormal.w )//npoints - { - dstC->m_jacCoeffInv[ic] = 0.f; - continue; - } - - float relVelN; - { - float4 linear, angular0, angular1; - setLinearAndAngular(src.m_worldNormal, r0, r1, &linear, &angular0, &angular1); - - dstC->m_jacCoeffInv[ic] = calcJacCoeff(linear, -linear, angular0, angular1, - invMassA, &invInertiaA, invMassB, &invInertiaB ); - - relVelN = calcRelVel(linear, -linear, angular0, angular1, - linVelA, angVelA, linVelB, angVelB); - - float e = 0.f;//src.getRestituitionCoeff(); - if( relVelN*relVelN < 0.004f ) e = 0.f; - - dstC->m_b[ic] = e*relVelN; - //float penetration = src.m_worldPos[ic].w; - dstC->m_b[ic] += (src.m_worldPos[ic].w + positionDrift)*positionConstraintCoeff*dtInv; - dstC->m_appliedRambdaDt[ic] = 0.f; - } - } - - if( src.m_worldNormal.w > 1 )//npoints - { // prepare friction - float4 center = make_float4(0.f); - for(int i=0; im_fJacCoeffInv[i] = calcJacCoeff(linear, -linear, angular0, angular1, - invMassA, &invInertiaA, invMassB, &invInertiaB ); - dstC->m_fAppliedRambdaDt[i] = 0.f; - } - dstC->m_center = center; - } - else - { - // single point constraint - } - - for(int i=0; i<4; i++) - { - if( im_worldPos[i] = src.m_worldPos[i]; - } - else - { - dstC->m_worldPos[i] = make_float4(0.f); - } - } -} - -typedef struct -{ - int m_nContacts; - float m_dt; - float m_positionDrift; - float m_positionConstraintCoeff; -} ConstBufferCTC; - -__kernel -__attribute__((reqd_work_group_size(WG_SIZE,1,1))) -void ContactToConstraintKernel(__global Contact4* gContact, __global Body* gBodies, __global Shape* gShapes, __global Constraint4* gConstraintOut, ConstBufferCTC cb) -{ - int gIdx = GET_GLOBAL_IDX; - int nContacts = cb.m_nContacts; - float dt = cb.m_dt; - float positionDrift = cb.m_positionDrift; - float positionConstraintCoeff = cb.m_positionConstraintCoeff; - - if( gIdx < nContacts ) - { - int aIdx = gContact[gIdx].m_bodyAPtr; - int bIdx = gContact[gIdx].m_bodyBPtr; - - float4 posA = gBodies[aIdx].m_pos; - float4 linVelA = gBodies[aIdx].m_linVel; - float4 angVelA = gBodies[aIdx].m_angVel; - float invMassA = gBodies[aIdx].m_invMass; - Matrix3x3 invInertiaA = gShapes[aIdx].m_invInertia; - - float4 posB = gBodies[bIdx].m_pos; - float4 linVelB = gBodies[bIdx].m_linVel; - float4 angVelB = gBodies[bIdx].m_angVel; - float invMassB = gBodies[bIdx].m_invMass; - Matrix3x3 invInertiaB = gShapes[bIdx].m_invInertia; - - Constraint4 cs; - - setConstraint4( posA, linVelA, angVelA, invMassA, invInertiaA, posB, linVelB, angVelB, invMassB, invInertiaB, - gContact[gIdx], dt, positionDrift, positionConstraintCoeff, - &cs ); - - cs.m_batchIdx = gContact[gIdx].m_batchIdx; - - gConstraintOut[gIdx] = cs; - } -} - -__kernel -__attribute__((reqd_work_group_size(WG_SIZE,1,1))) -void CopyConstraintKernel(__global Contact4* gIn, __global Contact4* gOut, int4 cb ) -{ - int gIdx = GET_GLOBAL_IDX; - if( gIdx < cb.x ) - { - gOut[gIdx] = gIn[gIdx]; - } -} \ No newline at end of file diff --git a/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/SolverKernels.h b/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/SolverKernels.h deleted file mode 100644 index c80a6ae05..000000000 --- a/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/SolverKernels.h +++ /dev/null @@ -1,1037 +0,0 @@ -static const char* solverKernelsCL= \ -"#pragma OPENCL EXTENSION cl_amd_printf : enable\n" -"#pragma OPENCL EXTENSION cl_khr_local_int32_base_atomics : enable\n" -"#pragma OPENCL EXTENSION cl_khr_global_int32_base_atomics : enable\n" -"#pragma OPENCL EXTENSION cl_khr_local_int32_extended_atomics : enable\n" -"#pragma OPENCL EXTENSION cl_khr_global_int32_extended_atomics : enable\n" -"\n" -"\n" -"#ifdef cl_ext_atomic_counters_32\n" -"#pragma OPENCL EXTENSION cl_ext_atomic_counters_32 : enable\n" -"#else\n" -"#define counter32_t volatile global int*\n" -"#endif\n" -"\n" -"typedef unsigned int u32;\n" -"typedef unsigned short u16;\n" -"typedef unsigned char u8;\n" -"\n" -"#define GET_GROUP_IDX get_group_id(0)\n" -"#define GET_LOCAL_IDX get_local_id(0)\n" -"#define GET_GLOBAL_IDX get_global_id(0)\n" -"#define GET_GROUP_SIZE get_local_size(0)\n" -"#define GET_NUM_GROUPS get_num_groups(0)\n" -"#define GROUP_LDS_BARRIER barrier(CLK_LOCAL_MEM_FENCE)\n" -"#define GROUP_MEM_FENCE mem_fence(CLK_LOCAL_MEM_FENCE)\n" -"#define AtomInc(x) atom_inc(&(x))\n" -"#define AtomInc1(x, out) out = atom_inc(&(x))\n" -"#define AppendInc(x, out) out = atomic_inc(x)\n" -"#define AtomAdd(x, value) atom_add(&(x), value)\n" -"#define AtomCmpxhg(x, cmp, value) atom_cmpxchg( &(x), cmp, value )\n" -"#define AtomXhg(x, value) atom_xchg ( &(x), value )\n" -"\n" -"\n" -"#define SELECT_UINT4( b, a, condition ) select( b,a,condition )\n" -"\n" -"#define make_float4 (float4)\n" -"#define make_float2 (float2)\n" -"#define make_uint4 (uint4)\n" -"#define make_int4 (int4)\n" -"#define make_uint2 (uint2)\n" -"#define make_int2 (int2)\n" -"\n" -"\n" -"#define max2 max\n" -"#define min2 min\n" -"\n" -"\n" -"///////////////////////////////////////\n" -"// Vector\n" -"///////////////////////////////////////\n" -"__inline\n" -"float fastDiv(float numerator, float denominator)\n" -"{\n" -" return native_divide(numerator, denominator); \n" -"// return numerator/denominator; \n" -"}\n" -"\n" -"__inline\n" -"float4 fastDiv4(float4 numerator, float4 denominator)\n" -"{\n" -" return native_divide(numerator, denominator); \n" -"}\n" -"\n" -"__inline\n" -"float fastSqrtf(float f2)\n" -"{\n" -" return native_sqrt(f2);\n" -"// return sqrt(f2);\n" -"}\n" -"\n" -"__inline\n" -"float fastRSqrt(float f2)\n" -"{\n" -" return native_rsqrt(f2);\n" -"}\n" -"\n" -"__inline\n" -"float fastLength4(float4 v)\n" -"{\n" -" return fast_length(v);\n" -"}\n" -"\n" -"__inline\n" -"float4 fastNormalize4(float4 v)\n" -"{\n" -" return fast_normalize(v);\n" -"}\n" -"\n" -"\n" -"__inline\n" -"float sqrtf(float a)\n" -"{\n" -"// return sqrt(a);\n" -" return native_sqrt(a);\n" -"}\n" -"\n" -"__inline\n" -"float4 cross3(float4 a, float4 b)\n" -"{\n" -" return cross(a,b);\n" -"}\n" -"\n" -"__inline\n" -"float dot3F4(float4 a, float4 b)\n" -"{\n" -" float4 a1 = make_float4(a.xyz,0.f);\n" -" float4 b1 = make_float4(b.xyz,0.f);\n" -" return dot(a1, b1);\n" -"}\n" -"\n" -"__inline\n" -"float length3(const float4 a)\n" -"{\n" -" return sqrtf(dot3F4(a,a));\n" -"}\n" -"\n" -"__inline\n" -"float dot4(const float4 a, const float4 b)\n" -"{\n" -" return dot( a, b );\n" -"}\n" -"\n" -"// for height\n" -"__inline\n" -"float dot3w1(const float4 point, const float4 eqn)\n" -"{\n" -" return dot3F4(point,eqn) + eqn.w;\n" -"}\n" -"\n" -"__inline\n" -"float4 normalize3(const float4 a)\n" -"{\n" -" float4 n = make_float4(a.x, a.y, a.z, 0.f);\n" -" return fastNormalize4( n );\n" -"// float length = sqrtf(dot3F4(a, a));\n" -"// return 1.f/length * a;\n" -"}\n" -"\n" -"__inline\n" -"float4 normalize4(const float4 a)\n" -"{\n" -" float length = sqrtf(dot4(a, a));\n" -" return 1.f/length * a;\n" -"}\n" -"\n" -"__inline\n" -"float4 createEquation(const float4 a, const float4 b, const float4 c)\n" -"{\n" -" float4 eqn;\n" -" float4 ab = b-a;\n" -" float4 ac = c-a;\n" -" eqn = normalize3( cross3(ab, ac) );\n" -" eqn.w = -dot3F4(eqn,a);\n" -" return eqn;\n" -"}\n" -"\n" -"///////////////////////////////////////\n" -"// Matrix3x3\n" -"///////////////////////////////////////\n" -"\n" -"typedef struct\n" -"{\n" -" float4 m_row[3];\n" -"}Matrix3x3;\n" -"\n" -"__inline\n" -"Matrix3x3 mtZero();\n" -"\n" -"__inline\n" -"Matrix3x3 mtIdentity();\n" -"\n" -"__inline\n" -"Matrix3x3 mtTranspose(Matrix3x3 m);\n" -"\n" -"__inline\n" -"Matrix3x3 mtMul(Matrix3x3 a, Matrix3x3 b);\n" -"\n" -"__inline\n" -"float4 mtMul1(Matrix3x3 a, float4 b);\n" -"\n" -"__inline\n" -"float4 mtMul3(float4 a, Matrix3x3 b);\n" -"\n" -"__inline\n" -"Matrix3x3 mtZero()\n" -"{\n" -" Matrix3x3 m;\n" -" m.m_row[0] = (float4)(0.f);\n" -" m.m_row[1] = (float4)(0.f);\n" -" m.m_row[2] = (float4)(0.f);\n" -" return m;\n" -"}\n" -"\n" -"__inline\n" -"Matrix3x3 mtIdentity()\n" -"{\n" -" Matrix3x3 m;\n" -" m.m_row[0] = (float4)(1,0,0,0);\n" -" m.m_row[1] = (float4)(0,1,0,0);\n" -" m.m_row[2] = (float4)(0,0,1,0);\n" -" return m;\n" -"}\n" -"\n" -"__inline\n" -"Matrix3x3 mtTranspose(Matrix3x3 m)\n" -"{\n" -" Matrix3x3 out;\n" -" out.m_row[0] = (float4)(m.m_row[0].x, m.m_row[1].x, m.m_row[2].x, 0.f);\n" -" out.m_row[1] = (float4)(m.m_row[0].y, m.m_row[1].y, m.m_row[2].y, 0.f);\n" -" out.m_row[2] = (float4)(m.m_row[0].z, m.m_row[1].z, m.m_row[2].z, 0.f);\n" -" return out;\n" -"}\n" -"\n" -"__inline\n" -"Matrix3x3 mtMul(Matrix3x3 a, Matrix3x3 b)\n" -"{\n" -" Matrix3x3 transB;\n" -" transB = mtTranspose( b );\n" -" Matrix3x3 ans;\n" -" // why this doesn't run when 0ing in the for{}\n" -" a.m_row[0].w = 0.f;\n" -" a.m_row[1].w = 0.f;\n" -" a.m_row[2].w = 0.f;\n" -" for(int i=0; i<3; i++)\n" -" {\n" -"// a.m_row[i].w = 0.f;\n" -" ans.m_row[i].x = dot3F4(a.m_row[i],transB.m_row[0]);\n" -" ans.m_row[i].y = dot3F4(a.m_row[i],transB.m_row[1]);\n" -" ans.m_row[i].z = dot3F4(a.m_row[i],transB.m_row[2]);\n" -" ans.m_row[i].w = 0.f;\n" -" }\n" -" return ans;\n" -"}\n" -"\n" -"__inline\n" -"float4 mtMul1(Matrix3x3 a, float4 b)\n" -"{\n" -" float4 ans;\n" -" ans.x = dot3F4( a.m_row[0], b );\n" -" ans.y = dot3F4( a.m_row[1], b );\n" -" ans.z = dot3F4( a.m_row[2], b );\n" -" ans.w = 0.f;\n" -" return ans;\n" -"}\n" -"\n" -"__inline\n" -"float4 mtMul3(float4 a, Matrix3x3 b)\n" -"{\n" -" float4 colx = make_float4(b.m_row[0].x, b.m_row[1].x, b.m_row[2].x, 0);\n" -" float4 coly = make_float4(b.m_row[0].y, b.m_row[1].y, b.m_row[2].y, 0);\n" -" float4 colz = make_float4(b.m_row[0].z, b.m_row[1].z, b.m_row[2].z, 0);\n" -"\n" -" float4 ans;\n" -" ans.x = dot3F4( a, colx );\n" -" ans.y = dot3F4( a, coly );\n" -" ans.z = dot3F4( a, colz );\n" -" return ans;\n" -"}\n" -"\n" -"///////////////////////////////////////\n" -"// Quaternion\n" -"///////////////////////////////////////\n" -"\n" -"typedef float4 Quaternion;\n" -"\n" -"__inline\n" -"Quaternion qtMul(Quaternion a, Quaternion b);\n" -"\n" -"__inline\n" -"Quaternion qtNormalize(Quaternion in);\n" -"\n" -"__inline\n" -"float4 qtRotate(Quaternion q, float4 vec);\n" -"\n" -"__inline\n" -"Quaternion qtInvert(Quaternion q);\n" -"\n" -"__inline\n" -"Matrix3x3 qtGetRotationMatrix(Quaternion q);\n" -"\n" -"\n" -"\n" -"__inline\n" -"Quaternion qtMul(Quaternion a, Quaternion b)\n" -"{\n" -" Quaternion ans;\n" -" ans = cross3( a, b );\n" -" ans += a.w*b+b.w*a;\n" -"// ans.w = a.w*b.w - (a.x*b.x+a.y*b.y+a.z*b.z);\n" -" ans.w = a.w*b.w - dot3F4(a, b);\n" -" return ans;\n" -"}\n" -"\n" -"__inline\n" -"Quaternion qtNormalize(Quaternion in)\n" -"{\n" -" return fastNormalize4(in);\n" -"// in /= length( in );\n" -"// return in;\n" -"}\n" -"__inline\n" -"float4 qtRotate(Quaternion q, float4 vec)\n" -"{\n" -" Quaternion qInv = qtInvert( q );\n" -" float4 vcpy = vec;\n" -" vcpy.w = 0.f;\n" -" float4 out = qtMul(qtMul(q,vcpy),qInv);\n" -" return out;\n" -"}\n" -"\n" -"__inline\n" -"Quaternion qtInvert(Quaternion q)\n" -"{\n" -" return (Quaternion)(-q.xyz, q.w);\n" -"}\n" -"\n" -"__inline\n" -"float4 qtInvRotate(const Quaternion q, float4 vec)\n" -"{\n" -" return qtRotate( qtInvert( q ), vec );\n" -"}\n" -"\n" -"__inline\n" -"Matrix3x3 qtGetRotationMatrix(Quaternion quat)\n" -"{\n" -" float4 quat2 = (float4)(quat.x*quat.x, quat.y*quat.y, quat.z*quat.z, 0.f);\n" -" Matrix3x3 out;\n" -"\n" -" out.m_row[0].x=1-2*quat2.y-2*quat2.z;\n" -" out.m_row[0].y=2*quat.x*quat.y-2*quat.w*quat.z;\n" -" out.m_row[0].z=2*quat.x*quat.z+2*quat.w*quat.y;\n" -" out.m_row[0].w = 0.f;\n" -"\n" -" out.m_row[1].x=2*quat.x*quat.y+2*quat.w*quat.z;\n" -" out.m_row[1].y=1-2*quat2.x-2*quat2.z;\n" -" out.m_row[1].z=2*quat.y*quat.z-2*quat.w*quat.x;\n" -" out.m_row[1].w = 0.f;\n" -"\n" -" out.m_row[2].x=2*quat.x*quat.z-2*quat.w*quat.y;\n" -" out.m_row[2].y=2*quat.y*quat.z+2*quat.w*quat.x;\n" -" out.m_row[2].z=1-2*quat2.x-2*quat2.y;\n" -" out.m_row[2].w = 0.f;\n" -"\n" -" return out;\n" -"}\n" -"\n" -"\n" -"\n" -"\n" -"#define WG_SIZE 64\n" -"\n" -"typedef struct\n" -"{\n" -" float4 m_pos;\n" -" Quaternion m_quat;\n" -" float4 m_linVel;\n" -" float4 m_angVel;\n" -"\n" -" u32 m_shapeIdx;\n" -" u32 m_shapeType;\n" -" float m_invMass;\n" -" float m_restituitionCoeff;\n" -" float m_frictionCoeff;\n" -"} Body;\n" -"\n" -"typedef struct\n" -"{\n" -" Matrix3x3 m_invInertia;\n" -" Matrix3x3 m_initInvInertia;\n" -"} Shape;\n" -"\n" -"typedef struct\n" -"{\n" -" float4 m_linear;\n" -" float4 m_worldPos[4];\n" -" float4 m_center; \n" -" float m_jacCoeffInv[4];\n" -" float m_b[4];\n" -" float m_appliedRambdaDt[4];\n" -"\n" -" float m_fJacCoeffInv[2]; \n" -" float m_fAppliedRambdaDt[2]; \n" -"\n" -" u32 m_bodyA;\n" -" u32 m_bodyB;\n" -"\n" -" int m_batchIdx;\n" -" u32 m_paddings[1];\n" -"} Constraint4;\n" -"\n" -"typedef struct\n" -"{\n" -" float4 m_worldPos[4];\n" -" float4 m_worldNormal;\n" -" u32 m_coeffs;\n" -" int m_batchIdx;\n" -"\n" -" u32 m_bodyAPtr;\n" -" u32 m_bodyBPtr;\n" -"} Contact4;\n" -"\n" -"typedef struct\n" -"{\n" -" int m_nConstraints;\n" -" int m_start;\n" -" int m_batchIdx;\n" -" int m_nSplit;\n" -"// int m_paddings[1];\n" -"} ConstBuffer;\n" -"\n" -"typedef struct\n" -"{\n" -" int m_solveFriction;\n" -" int m_maxBatch; // long batch really kills the performance\n" -" int m_batchIdx;\n" -" int m_nSplit;\n" -"// int m_paddings[1];\n" -"} ConstBufferBatchSolve;\n" -"\n" -"\n" -"void setLinearAndAngular( float4 n, float4 r0, float4 r1, float4* linear, float4* angular0, float4* angular1)\n" -"{\n" -" *linear = -n;\n" -" *angular0 = -cross3(r0, n);\n" -" *angular1 = cross3(r1, n);\n" -"}\n" -"\n" -"\n" -"float calcRelVel( float4 l0, float4 l1, float4 a0, float4 a1, float4 linVel0, float4 angVel0, float4 linVel1, float4 angVel1 )\n" -"{\n" -" return dot3F4(l0, linVel0) + dot3F4(a0, angVel0) + dot3F4(l1, linVel1) + dot3F4(a1, angVel1);\n" -"}\n" -"\n" -"\n" -"float calcJacCoeff(const float4 linear0, const float4 linear1, const float4 angular0, const float4 angular1,\n" -" float invMass0, const Matrix3x3* invInertia0, float invMass1, const Matrix3x3* invInertia1)\n" -"{\n" -" // linear0,1 are normlized\n" -" float jmj0 = invMass0;//dot3F4(linear0, linear0)*invMass0;\n" -" float jmj1 = dot3F4(mtMul3(angular0,*invInertia0), angular0);\n" -" float jmj2 = invMass1;//dot3F4(linear1, linear1)*invMass1;\n" -" float jmj3 = dot3F4(mtMul3(angular1,*invInertia1), angular1);\n" -" return -1.f/(jmj0+jmj1+jmj2+jmj3);\n" -"}\n" -"\n" -"\n" -"\n" -"void solveContact(__global Constraint4* cs,\n" -" float4 posA, float4* linVelA, float4* angVelA, float invMassA, Matrix3x3 invInertiaA,\n" -" float4 posB, float4* linVelB, float4* angVelB, float invMassB, Matrix3x3 invInertiaB)\n" -"{\n" -" float minRambdaDt = 0;\n" -" float maxRambdaDt = FLT_MAX;\n" -"\n" -" for(int ic=0; ic<4; ic++)\n" -" {\n" -" if( cs->m_jacCoeffInv[ic] == 0.f ) continue;\n" -"\n" -" float4 angular0, angular1, linear;\n" -" float4 r0 = cs->m_worldPos[ic] - posA;\n" -" float4 r1 = cs->m_worldPos[ic] - posB;\n" -" setLinearAndAngular( -cs->m_linear, r0, r1, &linear, &angular0, &angular1 );\n" -"\n" -" float rambdaDt = calcRelVel( cs->m_linear, -cs->m_linear, angular0, angular1, \n" -" *linVelA, *angVelA, *linVelB, *angVelB ) + cs->m_b[ic];\n" -" rambdaDt *= cs->m_jacCoeffInv[ic];\n" -"\n" -" {\n" -" float prevSum = cs->m_appliedRambdaDt[ic];\n" -" float updated = prevSum;\n" -" updated += rambdaDt;\n" -" updated = max2( updated, minRambdaDt );\n" -" updated = min2( updated, maxRambdaDt );\n" -" rambdaDt = updated - prevSum;\n" -" cs->m_appliedRambdaDt[ic] = updated;\n" -" }\n" -"\n" -" float4 linImp0 = invMassA*linear*rambdaDt;\n" -" float4 linImp1 = invMassB*(-linear)*rambdaDt;\n" -" float4 angImp0 = mtMul1(invInertiaA, angular0)*rambdaDt;\n" -" float4 angImp1 = mtMul1(invInertiaB, angular1)*rambdaDt;\n" -"\n" -" *linVelA += linImp0;\n" -" *angVelA += angImp0;\n" -" *linVelB += linImp1;\n" -" *angVelB += angImp1;\n" -" }\n" -"}\n" -"\n" -"\n" -"void solveFriction(__global Constraint4* cs,\n" -" float4 posA, float4* linVelA, float4* angVelA, float invMassA, Matrix3x3 invInertiaA,\n" -" float4 posB, float4* linVelB, float4* angVelB, float invMassB, Matrix3x3 invInertiaB,\n" -" float maxRambdaDt[4], float minRambdaDt[4])\n" -"{\n" -" if( cs->m_fJacCoeffInv[0] == 0 && cs->m_fJacCoeffInv[0] == 0 ) return;\n" -" const float4 center = cs->m_center;\n" -"\n" -" float4 n = -cs->m_linear;\n" -"\n" -" float4 tangent[2];\n" -" tangent[0] = cross3( n, cs->m_worldPos[0]-center );\n" -" tangent[1] = cross3( tangent[0], n );\n" -" tangent[0] = normalize3( tangent[0] );\n" -" tangent[1] = normalize3( tangent[1] );\n" -"\n" -" float4 angular0, angular1, linear;\n" -" float4 r0 = center - posA;\n" -" float4 r1 = center - posB;\n" -" for(int i=0; i<2; i++)\n" -" {\n" -" setLinearAndAngular( tangent[i], r0, r1, &linear, &angular0, &angular1 );\n" -" float rambdaDt = calcRelVel(linear, -linear, angular0, angular1,\n" -" *linVelA, *angVelA, *linVelB, *angVelB );\n" -" rambdaDt *= cs->m_fJacCoeffInv[i];\n" -"\n" -" {\n" -" float prevSum = cs->m_fAppliedRambdaDt[i];\n" -" float updated = prevSum;\n" -" updated += rambdaDt;\n" -" updated = max2( updated, minRambdaDt[i] );\n" -" updated = min2( updated, maxRambdaDt[i] );\n" -" rambdaDt = updated - prevSum;\n" -" cs->m_fAppliedRambdaDt[i] = updated;\n" -" }\n" -"\n" -" float4 linImp0 = invMassA*linear*rambdaDt;\n" -" float4 linImp1 = invMassB*(-linear)*rambdaDt;\n" -" float4 angImp0 = mtMul1(invInertiaA, angular0)*rambdaDt;\n" -" float4 angImp1 = mtMul1(invInertiaB, angular1)*rambdaDt;\n" -"\n" -" *linVelA += linImp0;\n" -" *angVelA += angImp0;\n" -" *linVelB += linImp1;\n" -" *angVelB += angImp1;\n" -" }\n" -" { // angular damping for point constraint\n" -" float4 ab = normalize3( posB - posA );\n" -" float4 ac = normalize3( center - posA );\n" -" if( dot3F4( ab, ac ) > 0.95f || (invMassA == 0.f || invMassB == 0.f))\n" -" {\n" -" float angNA = dot3F4( n, *angVelA );\n" -" float angNB = dot3F4( n, *angVelB );\n" -"\n" -" *angVelA -= (angNA*0.1f)*n;\n" -" *angVelB -= (angNB*0.1f)*n;\n" -" }\n" -" }\n" -"}\n" -"\n" -"void solveAConstraint(__global Body* gBodies, __global Shape* gShapes, __global Constraint4* ldsCs)\n" -"{\n" -" float frictionCoeff = ldsCs[0].m_linear.w;\n" -" int aIdx = ldsCs[0].m_bodyA;\n" -" int bIdx = ldsCs[0].m_bodyB;\n" -"\n" -" float4 posA = gBodies[aIdx].m_pos;\n" -" float4 linVelA = gBodies[aIdx].m_linVel;\n" -" float4 angVelA = gBodies[aIdx].m_angVel;\n" -" float invMassA = gBodies[aIdx].m_invMass;\n" -" Matrix3x3 invInertiaA = gShapes[aIdx].m_invInertia;\n" -"\n" -" float4 posB = gBodies[bIdx].m_pos;\n" -" float4 linVelB = gBodies[bIdx].m_linVel;\n" -" float4 angVelB = gBodies[bIdx].m_angVel;\n" -" float invMassB = gBodies[bIdx].m_invMass;\n" -" Matrix3x3 invInertiaB = gShapes[bIdx].m_invInertia;\n" -" \n" -" \n" -" {\n" -" solveContact( ldsCs, posA, &linVelA, &angVelA, invMassA, invInertiaA,\n" -" posB, &linVelB, &angVelB, invMassB, invInertiaB );\n" -" }\n" -"\n" -" {\n" -" float maxRambdaDt[4] = {FLT_MAX,FLT_MAX,FLT_MAX,FLT_MAX};\n" -" float minRambdaDt[4] = {0.f,0.f,0.f,0.f};\n" -"\n" -" float sum = 0;\n" -" for(int j=0; j<4; j++)\n" -" {\n" -" sum +=ldsCs[0].m_appliedRambdaDt[j];\n" -" }\n" -" frictionCoeff = 0.7f;\n" -" for(int j=0; j<4; j++)\n" -" {\n" -" maxRambdaDt[j] = frictionCoeff*sum;\n" -" minRambdaDt[j] = -maxRambdaDt[j];\n" -" }\n" -"\n" -" solveFriction( ldsCs, posA, &linVelA, &angVelA, invMassA, invInertiaA,\n" -" posB, &linVelB, &angVelB, invMassB, invInertiaB, maxRambdaDt, minRambdaDt );\n" -" }\n" -"\n" -" gBodies[aIdx].m_linVel = linVelA;\n" -" gBodies[aIdx].m_angVel = angVelA;\n" -" gBodies[bIdx].m_linVel = linVelB;\n" -" gBodies[bIdx].m_angVel = angVelB;\n" -"}\n" -"\n" -"void solveContactConstraint(__global Body* gBodies, __global Shape* gShapes, __global Constraint4* ldsCs)\n" -"{\n" -" float frictionCoeff = ldsCs[0].m_linear.w;\n" -" int aIdx = ldsCs[0].m_bodyA;\n" -" int bIdx = ldsCs[0].m_bodyB;\n" -"\n" -" float4 posA = gBodies[aIdx].m_pos;\n" -" float4 linVelA = gBodies[aIdx].m_linVel;\n" -" float4 angVelA = gBodies[aIdx].m_angVel;\n" -" float invMassA = gBodies[aIdx].m_invMass;\n" -" Matrix3x3 invInertiaA = gShapes[aIdx].m_invInertia;\n" -"\n" -" float4 posB = gBodies[bIdx].m_pos;\n" -" float4 linVelB = gBodies[bIdx].m_linVel;\n" -" float4 angVelB = gBodies[bIdx].m_angVel;\n" -" float invMassB = gBodies[bIdx].m_invMass;\n" -" Matrix3x3 invInertiaB = gShapes[bIdx].m_invInertia;\n" -"\n" -" solveContact( ldsCs, posA, &linVelA, &angVelA, invMassA, invInertiaA,\n" -" posB, &linVelB, &angVelB, invMassB, invInertiaB );\n" -"\n" -" gBodies[aIdx].m_linVel = linVelA;\n" -" gBodies[aIdx].m_angVel = angVelA;\n" -" gBodies[bIdx].m_linVel = linVelB;\n" -" gBodies[bIdx].m_angVel = angVelB;\n" -"}\n" -"\n" -"void solveFrictionConstraint(__global Body* gBodies, __global Shape* gShapes, __global Constraint4* ldsCs)\n" -"{\n" -" float frictionCoeff = ldsCs[0].m_linear.w;\n" -" int aIdx = ldsCs[0].m_bodyA;\n" -" int bIdx = ldsCs[0].m_bodyB;\n" -"\n" -" float4 posA = gBodies[aIdx].m_pos;\n" -" float4 linVelA = gBodies[aIdx].m_linVel;\n" -" float4 angVelA = gBodies[aIdx].m_angVel;\n" -" float invMassA = gBodies[aIdx].m_invMass;\n" -" Matrix3x3 invInertiaA = gShapes[aIdx].m_invInertia;\n" -"\n" -" float4 posB = gBodies[bIdx].m_pos;\n" -" float4 linVelB = gBodies[bIdx].m_linVel;\n" -" float4 angVelB = gBodies[bIdx].m_angVel;\n" -" float invMassB = gBodies[bIdx].m_invMass;\n" -" Matrix3x3 invInertiaB = gShapes[bIdx].m_invInertia;\n" -"\n" -" {\n" -" float maxRambdaDt[4] = {FLT_MAX,FLT_MAX,FLT_MAX,FLT_MAX};\n" -" float minRambdaDt[4] = {0.f,0.f,0.f,0.f};\n" -"\n" -" float sum = 0;\n" -" for(int j=0; j<4; j++)\n" -" {\n" -" sum +=ldsCs[0].m_appliedRambdaDt[j];\n" -" }\n" -" frictionCoeff = 0.7f;\n" -" for(int j=0; j<4; j++)\n" -" {\n" -" maxRambdaDt[j] = frictionCoeff*sum;\n" -" minRambdaDt[j] = -maxRambdaDt[j];\n" -" }\n" -"\n" -" solveFriction( ldsCs, posA, &linVelA, &angVelA, invMassA, invInertiaA,\n" -" posB, &linVelB, &angVelB, invMassB, invInertiaB, maxRambdaDt, minRambdaDt );\n" -" }\n" -"\n" -" gBodies[aIdx].m_linVel = linVelA;\n" -" gBodies[aIdx].m_angVel = angVelA;\n" -" gBodies[bIdx].m_linVel = linVelB;\n" -" gBodies[bIdx].m_angVel = angVelB;\n" -"}\n" -"\n" -"typedef struct \n" -"{\n" -" int m_valInt0;\n" -" int m_valInt1;\n" -" int m_valInt2;\n" -" int m_valInt3;\n" -"\n" -" float m_val0;\n" -" float m_val1;\n" -" float m_val2;\n" -" float m_val3;\n" -"} SolverDebugInfo;\n" -"\n" -"\n" -"__kernel\n" -"__attribute__((reqd_work_group_size(WG_SIZE,1,1)))\n" -"//void BatchSolveKernel(__global Body* gBodies, __global Shape* gShapes, __global Constraint4* gConstraints, __global int* gN, __global int* gOffsets, __global SolverDebugInfo* debugInfo, ConstBufferBatchSolve cb)\n" -"void BatchSolveKernel(__global Body* gBodies, \n" -"__global Shape* gShapes, \n" -"__global Constraint4* gConstraints, \n" -"__global int* gN, \n" -"__global int* gOffsets, \n" -"ConstBufferBatchSolve cb)\n" -"{\n" -" __local int ldsBatchIdx[WG_SIZE+1];\n" -"\n" -" __local int ldsCurBatch;\n" -" __local int ldsNextBatch;\n" -" __local int ldsStart;\n" -"\n" -" int lIdx = GET_LOCAL_IDX;\n" -" int wgIdx = GET_GROUP_IDX;\n" -"\n" -" int gIdx = GET_GLOBAL_IDX;\n" -"// debugInfo[gIdx].m_valInt0 = gIdx;\n" -" //debugInfo[gIdx].m_valInt1 = GET_GROUP_SIZE;\n" -"\n" -" const int solveFriction = cb.m_solveFriction;\n" -" const int maxBatch = cb.m_maxBatch;\n" -" const int bIdx = cb.m_batchIdx;\n" -" const int nSplit = cb.m_nSplit;\n" -"\n" -" int xIdx = (wgIdx/(nSplit/2))*2 + (bIdx&1);\n" -" int yIdx = (wgIdx%(nSplit/2))*2 + (bIdx>>1);\n" -" int cellIdx = xIdx+yIdx*nSplit;\n" -" \n" -" if( gN[cellIdx] == 0 ) \n" -" return;\n" -"\n" -" const int start = gOffsets[cellIdx];\n" -" const int end = start + gN[cellIdx];\n" -"\n" -" \n" -" if( lIdx == 0 )\n" -" {\n" -" ldsCurBatch = 0;\n" -" ldsNextBatch = 0;\n" -" ldsStart = start;\n" -" }\n" -"\n" -"\n" -" GROUP_LDS_BARRIER;\n" -"\n" -" int idx=ldsStart+lIdx;\n" -" while (ldsCurBatch < maxBatch)\n" -" {\n" -" for(; idxm_bodyA = src.m_bodyAPtr;\n" -" dstC->m_bodyB = src.m_bodyBPtr;\n" -"\n" -" float dtInv = 1.f/dt;\n" -" for(int ic=0; ic<4; ic++)\n" -" {\n" -" dstC->m_appliedRambdaDt[ic] = 0.f;\n" -" }\n" -" dstC->m_fJacCoeffInv[0] = dstC->m_fJacCoeffInv[1] = 0.f;\n" -"\n" -"\n" -" dstC->m_linear = -src.m_worldNormal;\n" -" dstC->m_linear.w = 0.7f ;//src.getFrictionCoeff() );\n" -" for(int ic=0; ic<4; ic++)\n" -" {\n" -" float4 r0 = src.m_worldPos[ic] - posA;\n" -" float4 r1 = src.m_worldPos[ic] - posB;\n" -"\n" -" if( ic >= src.m_worldNormal.w )//npoints\n" -" {\n" -" dstC->m_jacCoeffInv[ic] = 0.f;\n" -" continue;\n" -" }\n" -"\n" -" float relVelN;\n" -" {\n" -" float4 linear, angular0, angular1;\n" -" setLinearAndAngular(src.m_worldNormal, r0, r1, &linear, &angular0, &angular1);\n" -"\n" -" dstC->m_jacCoeffInv[ic] = calcJacCoeff(linear, -linear, angular0, angular1,\n" -" invMassA, &invInertiaA, invMassB, &invInertiaB );\n" -"\n" -" relVelN = calcRelVel(linear, -linear, angular0, angular1,\n" -" linVelA, angVelA, linVelB, angVelB);\n" -"\n" -" float e = 0.f;//src.getRestituitionCoeff();\n" -" if( relVelN*relVelN < 0.004f ) e = 0.f;\n" -"\n" -" dstC->m_b[ic] = e*relVelN;\n" -" //float penetration = src.m_worldPos[ic].w;\n" -" dstC->m_b[ic] += (src.m_worldPos[ic].w + positionDrift)*positionConstraintCoeff*dtInv;\n" -" dstC->m_appliedRambdaDt[ic] = 0.f;\n" -" }\n" -" }\n" -"\n" -" if( src.m_worldNormal.w > 1 )//npoints\n" -" { // prepare friction\n" -" float4 center = make_float4(0.f);\n" -" for(int i=0; im_fJacCoeffInv[i] = calcJacCoeff(linear, -linear, angular0, angular1,\n" -" invMassA, &invInertiaA, invMassB, &invInertiaB );\n" -" dstC->m_fAppliedRambdaDt[i] = 0.f;\n" -" }\n" -" dstC->m_center = center;\n" -" }\n" -" else\n" -" {\n" -" // single point constraint\n" -" }\n" -"\n" -" for(int i=0; i<4; i++)\n" -" {\n" -" if( im_worldPos[i] = src.m_worldPos[i];\n" -" }\n" -" else\n" -" {\n" -" dstC->m_worldPos[i] = make_float4(0.f);\n" -" }\n" -" }\n" -"}\n" -"\n" -"typedef struct\n" -"{\n" -" int m_nContacts;\n" -" float m_dt;\n" -" float m_positionDrift;\n" -" float m_positionConstraintCoeff;\n" -"} ConstBufferCTC;\n" -"\n" -"__kernel\n" -"__attribute__((reqd_work_group_size(WG_SIZE,1,1)))\n" -"void ContactToConstraintKernel(__global Contact4* gContact, __global Body* gBodies, __global Shape* gShapes, __global Constraint4* gConstraintOut, ConstBufferCTC cb)\n" -"{\n" -" int gIdx = GET_GLOBAL_IDX;\n" -" int nContacts = cb.m_nContacts;\n" -" float dt = cb.m_dt;\n" -" float positionDrift = cb.m_positionDrift;\n" -" float positionConstraintCoeff = cb.m_positionConstraintCoeff;\n" -"\n" -" if( gIdx < nContacts )\n" -" {\n" -" int aIdx = gContact[gIdx].m_bodyAPtr;\n" -" int bIdx = gContact[gIdx].m_bodyBPtr;\n" -"\n" -" float4 posA = gBodies[aIdx].m_pos;\n" -" float4 linVelA = gBodies[aIdx].m_linVel;\n" -" float4 angVelA = gBodies[aIdx].m_angVel;\n" -" float invMassA = gBodies[aIdx].m_invMass;\n" -" Matrix3x3 invInertiaA = gShapes[aIdx].m_invInertia;\n" -"\n" -" float4 posB = gBodies[bIdx].m_pos;\n" -" float4 linVelB = gBodies[bIdx].m_linVel;\n" -" float4 angVelB = gBodies[bIdx].m_angVel;\n" -" float invMassB = gBodies[bIdx].m_invMass;\n" -" Matrix3x3 invInertiaB = gShapes[bIdx].m_invInertia;\n" -"\n" -" Constraint4 cs;\n" -"\n" -" setConstraint4( posA, linVelA, angVelA, invMassA, invInertiaA, posB, linVelB, angVelB, invMassB, invInertiaB,\n" -" gContact[gIdx], dt, positionDrift, positionConstraintCoeff, \n" -" &cs );\n" -" \n" -" cs.m_batchIdx = gContact[gIdx].m_batchIdx;\n" -"\n" -" gConstraintOut[gIdx] = cs;\n" -" }\n" -"}\n" -"\n" -"__kernel\n" -"__attribute__((reqd_work_group_size(WG_SIZE,1,1)))\n" -"void CopyConstraintKernel(__global Contact4* gIn, __global Contact4* gOut, int4 cb )\n" -"{\n" -" int gIdx = GET_GLOBAL_IDX;\n" -" if( gIdx < cb.x )\n" -" {\n" -" gOut[gIdx] = gIn[gIdx];\n" -" }\n" -"}\n" -; diff --git a/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/batchingKernels.cl b/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/batchingKernels.cl deleted file mode 100644 index eee80c1a3..000000000 --- a/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/batchingKernels.cl +++ /dev/null @@ -1,338 +0,0 @@ -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Takahiro Harada - - -#pragma OPENCL EXTENSION cl_amd_printf : enable -#pragma OPENCL EXTENSION cl_khr_local_int32_base_atomics : enable -#pragma OPENCL EXTENSION cl_khr_global_int32_base_atomics : enable -#pragma OPENCL EXTENSION cl_khr_local_int32_extended_atomics : enable -#pragma OPENCL EXTENSION cl_khr_global_int32_extended_atomics : enable - -#ifdef cl_ext_atomic_counters_32 -#pragma OPENCL EXTENSION cl_ext_atomic_counters_32 : enable -#else -#define counter32_t volatile __global int* -#endif - - -typedef unsigned int u32; -typedef unsigned short u16; -typedef unsigned char u8; - -#define GET_GROUP_IDX get_group_id(0) -#define GET_LOCAL_IDX get_local_id(0) -#define GET_GLOBAL_IDX get_global_id(0) -#define GET_GROUP_SIZE get_local_size(0) -#define GET_NUM_GROUPS get_num_groups(0) -#define GROUP_LDS_BARRIER barrier(CLK_LOCAL_MEM_FENCE) -#define GROUP_MEM_FENCE mem_fence(CLK_LOCAL_MEM_FENCE) -#define AtomInc(x) atom_inc(&(x)) -#define AtomInc1(x, out) out = atom_inc(&(x)) -#define AppendInc(x, out) out = atomic_inc(x) -#define AtomAdd(x, value) atom_add(&(x), value) -#define AtomCmpxhg(x, cmp, value) atom_cmpxchg( &(x), cmp, value ) -#define AtomXhg(x, value) atom_xchg ( &(x), value ) - - -#define SELECT_UINT4( b, a, condition ) select( b,a,condition ) - -#define make_float4 (float4) -#define make_float2 (float2) -#define make_uint4 (uint4) -#define make_int4 (int4) -#define make_uint2 (uint2) -#define make_int2 (int2) - - -#define max2 max -#define min2 min - - -#define WG_SIZE 64 - - - -typedef struct -{ - float4 m_worldPos[4]; - float4 m_worldNormal; - u32 m_coeffs; - int m_batchIdx; - - u32 m_bodyA; - u32 m_bodyB; -}Contact4; - -typedef struct -{ - int m_n; - int m_start; - int m_staticIdx; - int m_paddings[1]; -} ConstBuffer; - -typedef struct -{ - u32 m_a; - u32 m_b; - u32 m_idx; -}Elem; - -#define STACK_SIZE (WG_SIZE*10) -//#define STACK_SIZE (WG_SIZE) -#define RING_SIZE 1024 -#define RING_SIZE_MASK (RING_SIZE-1) -#define CHECK_SIZE (WG_SIZE) - - -#define GET_RING_CAPACITY (RING_SIZE - ldsRingEnd) -#define RING_END ldsTmp - -u32 readBuf(__local u32* buff, int idx) -{ - idx = idx % (32*CHECK_SIZE); - int bitIdx = idx%32; - int bufIdx = idx/32; - return buff[bufIdx] & (1<> bitIdx)&1) == 0; -} - -// batching on the GPU -__kernel void CreateBatches( __global Contact4* gConstraints, __global Contact4* gConstraintsOut, - __global u32* gN, __global u32* gStart, - ConstBuffer cb ) -{ - __local u32 ldsStackIdx[STACK_SIZE]; - __local u32 ldsStackEnd; - __local Elem ldsRingElem[RING_SIZE]; - __local u32 ldsRingEnd; - __local u32 ldsTmp; - __local u32 ldsCheckBuffer[CHECK_SIZE]; - __local u32 ldsFixedBuffer[CHECK_SIZE]; - __local u32 ldsGEnd; - __local u32 ldsDstEnd; - - int wgIdx = GET_GROUP_IDX; - int lIdx = GET_LOCAL_IDX; - - const int m_n = gN[wgIdx]; - const int m_start = gStart[wgIdx]; - const int m_staticIdx = cb.m_staticIdx; - - if( lIdx == 0 ) - { - ldsRingEnd = 0; - ldsGEnd = 0; - ldsStackEnd = 0; - ldsDstEnd = m_start; - } - -// while(1) - for(int ie=0; ie<250; ie++) - { - ldsFixedBuffer[lIdx] = 0; - - for(int giter=0; giter<4; giter++) - { - int ringCap = GET_RING_CAPACITY; - - // 1. fill ring - if( ldsGEnd < m_n ) - { - while( ringCap > WG_SIZE ) - { - if( ldsGEnd >= m_n ) break; - if( lIdx < ringCap - WG_SIZE ) - { - int srcIdx; - AtomInc1( ldsGEnd, srcIdx ); - if( srcIdx < m_n ) - { - int dstIdx; - AtomInc1( ldsRingEnd, dstIdx ); - - int a = gConstraints[m_start+srcIdx].m_bodyA; - int b = gConstraints[m_start+srcIdx].m_bodyB; - ldsRingElem[dstIdx].m_a = (a>b)? b:a; - ldsRingElem[dstIdx].m_b = (a>b)? a:b; - ldsRingElem[dstIdx].m_idx = srcIdx; - } - } - ringCap = GET_RING_CAPACITY; - } - } - - GROUP_LDS_BARRIER; - - // 2. fill stack - __local Elem* dst = ldsRingElem; - if( lIdx == 0 ) RING_END = 0; - - int srcIdx=lIdx; - int end = ldsRingEnd; - - { - for(int ii=0; ii> bitIdx)&1) == 0;\n" -"}\n" -"\n" -"typedef struct \n" -"{\n" -" int m_valInt0;\n" -" int m_valInt1;\n" -" int m_valInt2;\n" -" int m_valInt3;\n" -"\n" -" int m_valInt4;\n" -" int m_valInt5;\n" -" int m_valInt6;\n" -" int m_valInt7;\n" -"\n" -" int m_valInt8;\n" -" int m_valInt9;\n" -" int m_valInt10;\n" -" int m_valInt11;\n" -" \n" -" int m_valInt12;\n" -" int m_valInt13;\n" -" int m_valInt14;\n" -" int m_valInt15;\n" -"\n" -"\n" -" float m_fval0;\n" -" float m_fval1;\n" -" float m_fval2;\n" -" float m_fval3;\n" -"} SolverDebugInfo;\n" -"\n" -"// batching on the GPU\n" -"__kernel void CreateBatches( __global Contact4* gConstraints, __global Contact4* gConstraintsOut, //__global u32* gRes, \n" -" __global u32* gN, __global u32* gStart, \n" -"// __global SolverDebugInfo* debugInfo, \n" -" ConstBuffer cb )\n" -"{\n" -" __local u32 ldsStackIdx[STACK_SIZE];\n" -" __local u32 ldsStackEnd;\n" -" __local Elem ldsRingElem[RING_SIZE];\n" -" __local u32 ldsRingEnd;\n" -" __local u32 ldsTmp;\n" -" __local u32 ldsCheckBuffer[CHECK_SIZE];\n" -" __local u32 ldsFixedBuffer[CHECK_SIZE];\n" -" __local u32 ldsGEnd;\n" -" __local u32 ldsDstEnd;\n" -"\n" -" int wgIdx = GET_GROUP_IDX;\n" -" int lIdx = GET_LOCAL_IDX;\n" -" \n" -" const int m_n = gN[wgIdx];\n" -" const int m_start = gStart[wgIdx];\n" -" const int m_staticIdx = cb.m_staticIdx;\n" -" \n" -" if( lIdx == 0 )\n" -" {\n" -" ldsRingEnd = 0;\n" -" ldsGEnd = 0;\n" -" ldsStackEnd = 0;\n" -" ldsDstEnd = m_start;\n" -" }\n" -" \n" -"// while(1)\n" -" for(int ie=0; ie<250; ie++)\n" -" {\n" -" ldsFixedBuffer[lIdx] = 0;\n" -"\n" -" for(int giter=0; giter<4; giter++)\n" -" {\n" -" int ringCap = GET_RING_CAPACITY;\n" -" \n" -" // 1. fill ring\n" -" if( ldsGEnd < m_n )\n" -" {\n" -" while( ringCap > WG_SIZE )\n" -" {\n" -" if( ldsGEnd >= m_n ) break;\n" -" if( lIdx < ringCap - WG_SIZE )\n" -" {\n" -" int srcIdx;\n" -" AtomInc1( ldsGEnd, srcIdx );\n" -" if( srcIdx < m_n )\n" -" {\n" -" int dstIdx;\n" -" AtomInc1( ldsRingEnd, dstIdx );\n" -" \n" -" int a = gConstraints[m_start+srcIdx].m_bodyA;\n" -" int b = gConstraints[m_start+srcIdx].m_bodyB;\n" -" ldsRingElem[dstIdx].m_a = (a>b)? b:a;\n" -" ldsRingElem[dstIdx].m_b = (a>b)? a:b;\n" -" ldsRingElem[dstIdx].m_idx = srcIdx;\n" -" }\n" -" }\n" -" ringCap = GET_RING_CAPACITY;\n" -" }\n" -" }\n" -"\n" -" GROUP_LDS_BARRIER;\n" -" \n" -" // 2. fill stack\n" -" __local Elem* dst = ldsRingElem;\n" -" if( lIdx == 0 ) RING_END = 0;\n" -"\n" -" int srcIdx=lIdx;\n" -" int end = ldsRingEnd;\n" -"\n" -" {\n" -" for(int ii=0; iiChNarrowphaseKernels.h - - -@echo Warning: -@echo You might still need to find/replace for \\n (due to macros) and replace #include statements by their content -pause diff --git a/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/stringifykernelsAll.bat b/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/stringifykernelsAll.bat deleted file mode 100644 index 9854d9352..000000000 --- a/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/stringifykernelsAll.bat +++ /dev/null @@ -1,10 +0,0 @@ -stringify.py ChNarrowphaseKernels.cl narrowphaseKernelsCL >ChNarrowphaseKernels.h -stringify.py SolverKernels.cl solverKernelsCL >SolverKernels.h -stringify.py batchingKernels.cl batchingKernelsCL >batchingKernels.h - - - - -@echo Warning: -@echo You might still need to find/replace for \\n (due to macros) and replace #include statements by their content -pause diff --git a/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/stringifykernelsBatching.bat b/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/stringifykernelsBatching.bat deleted file mode 100644 index 1282f7e28..000000000 --- a/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/stringifykernelsBatching.bat +++ /dev/null @@ -1,8 +0,0 @@ -stringify.py batchingKernels.cl batchingKernelsCL >batchingKernels.h - - - - -@echo Warning: -@echo You might still need to find/replace for \\n (due to macros) and replace #include statements by their content -pause diff --git a/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/stringifykernelsNarrowphase.bat b/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/stringifykernelsNarrowphase.bat deleted file mode 100644 index 20a0d3ea8..000000000 --- a/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/stringifykernelsNarrowphase.bat +++ /dev/null @@ -1,8 +0,0 @@ -stringify.py ChNarrowphaseKernels.cl narrowphaseKernelsCL >ChNarrowphaseKernels.h - - - - -@echo Warning: -@echo You might still need to find/replace for \\n (due to macros) and replace #include statements by their content -pause diff --git a/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/stringifykernelsSolver.bat b/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/stringifykernelsSolver.bat deleted file mode 100644 index ff483deb9..000000000 --- a/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/Stubs/stringifykernelsSolver.bat +++ /dev/null @@ -1,8 +0,0 @@ -stringify.py SolverKernels.cl solverKernelsCL >SolverKernels.h - - - - -@echo Warning: -@echo You might still need to find/replace for \\n (due to macros) and replace #include statements by their content -pause diff --git a/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/main.cpp b/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/main.cpp deleted file mode 100644 index 26846f90c..000000000 --- a/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/main.cpp +++ /dev/null @@ -1,77 +0,0 @@ -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Erwin Coumans - -#include "BasicDemo.h" -#include "GlutStuff.h" -#include "btBulletDynamicsCommon.h" -#include "LinearMath/btHashMap.h" - -#ifdef CL_PLATFORM_AMD -#include "../../opencl/basic_initialize/btOpenCLUtils.h" -extern cl_context g_cxMainContext; -extern cl_command_queue g_cqCommandQue; -extern cl_device_id g_clDevice; -#endif - - - -int main(int argc,char** argv) -{ - - #ifdef CL_PLATFORM_AMD - int ciErrNum = 0; - const char* vendorSDK = btOpenCLUtils::getSdkVendorName(); - printf("This program was compiled using the %s OpenCL SDK\n",vendorSDK); - - cl_device_type deviceType = CL_DEVICE_TYPE_GPU;//CPU;//GPU; - - - void* glCtx=0; - void* glDC = 0; - g_cxMainContext = btOpenCLUtils::createContextFromType(deviceType, &ciErrNum, glCtx, glDC); - oclCHECKERROR(ciErrNum, CL_SUCCESS); - - int numDev = btOpenCLUtils::getNumDevices(g_cxMainContext); - - if (numDev>0) - { - int deviceIndex =0; - g_clDevice = btOpenCLUtils::getDevice(g_cxMainContext,deviceIndex); - btOpenCLDeviceInfo clInfo; - btOpenCLUtils::getDeviceInfo(g_clDevice,clInfo); - btOpenCLUtils::printDeviceInfo(g_clDevice); - // create a command-queue - g_cqCommandQue = clCreateCommandQueue(g_cxMainContext, g_clDevice, 0, &ciErrNum); - oclCHECKERROR(ciErrNum, CL_SUCCESS); - } -#endif //#ifdef CL_PLATFORM_AMD - - - BasicDemo ccdDemo; - ccdDemo.initPhysics(); - - -#ifdef CHECK_MEMORY_LEAKS - ccdDemo.exitPhysics(); -#else - glutmain(argc, argv,1024,600,"Bullet Physics Demo. http://bulletphysics.org",&ccdDemo); -#endif - - //setupGUI(1024,768); - glutMainLoop(); - //default glut doesn't return from mainloop - return 0; -} - diff --git a/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/premake4.lua b/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/premake4.lua deleted file mode 100644 index c779ff987..000000000 --- a/Extras/RigidBodyGpuPipeline/dynamics/basic_demo/premake4.lua +++ /dev/null @@ -1,34 +0,0 @@ - --- include "AMD" - -if os.is("Windows") then - - project "basic_bullet2_demo" - - language "C++" - - kind "ConsoleApp" - targetdir "../../bin" - - includedirs { - ".", - "../../bullet2", - "../testbed", - "../../rendering/Gwen", - } - - - links { "testbed", - "bullet2", - "gwen" - } - - initOpenGL() - initGlut() - - files { - "**.cpp", - "**.h" - } - -end diff --git a/Extras/RigidBodyGpuPipeline/dynamics/testbed/DebugCastResult.h b/Extras/RigidBodyGpuPipeline/dynamics/testbed/DebugCastResult.h deleted file mode 100644 index ef3befe44..000000000 --- a/Extras/RigidBodyGpuPipeline/dynamics/testbed/DebugCastResult.h +++ /dev/null @@ -1,88 +0,0 @@ -/* -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 DEBUG_CAST_RESULT_H -#define DEBUG_CAST_RESULT_H - -#include "BulletCollision/NarrowPhaseCollision/btConvexCast.h" -#include "LinearMath/btTransform.h" -#include "GL_ShapeDrawer.h" -#include "GlutStuff.h" -#ifdef WIN32 -#include -#endif -//think different -#if defined(__APPLE__) && !defined (VMDMESA) -#include -#include -#else -#include -#endif -struct btDebugCastResult : public btConvexCast::CastResult -{ - - btTransform m_fromTrans; - const btPolyhedralConvexShape* m_shape; - btVector3 m_linVel; - btVector3 m_angVel; - GL_ShapeDrawer* m_shapeDrawer; - - btDebugCastResult(const btTransform& fromTrans,const btPolyhedralConvexShape* shape, - const btVector3& linVel,const btVector3& angVel,GL_ShapeDrawer* drawer) - :m_fromTrans(fromTrans), - m_shape(shape), - m_linVel(linVel), - m_angVel(angVel), - m_shapeDrawer(drawer) - { - } - - virtual void drawCoordSystem(const btTransform& tr) - { - btScalar m[16]; - tr.getOpenGLMatrix(m); - glPushMatrix(); - btglLoadMatrix(m); - glBegin(GL_LINES); - btglColor3(1, 0, 0); - btglVertex3(0, 0, 0); - btglVertex3(1, 0, 0); - btglColor3(0, 1, 0); - btglVertex3(0, 0, 0); - btglVertex3(0, 1, 0); - btglColor3(0, 0, 1); - btglVertex3(0, 0, 0); - btglVertex3(0, 0, 1); - glEnd(); - glPopMatrix(); - } - - virtual void DebugDraw(btScalar fraction) - { - btVector3 worldBoundsMin(-1000,-1000,-1000); - btVector3 worldBoundsMax(1000,1000,1000); - - - btScalar m[16]; - btTransform hitTrans; - btTransformUtil::integrateTransform(m_fromTrans,m_linVel,m_angVel,fraction,hitTrans); - hitTrans.getOpenGLMatrix(m); - if (m_shapeDrawer) - m_shapeDrawer->drawOpenGL(m,m_shape,btVector3(1,0,0),btIDebugDraw::DBG_NoDebug,worldBoundsMin,worldBoundsMax); - } -}; - - -#endif //DEBUG_CAST_RESULT_H diff --git a/Extras/RigidBodyGpuPipeline/dynamics/testbed/DemoApplication.cpp b/Extras/RigidBodyGpuPipeline/dynamics/testbed/DemoApplication.cpp deleted file mode 100644 index d582570e6..000000000 --- a/Extras/RigidBodyGpuPipeline/dynamics/testbed/DemoApplication.cpp +++ /dev/null @@ -1,1375 +0,0 @@ -/* -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 "DemoApplication.h" -#include "LinearMath/btIDebugDraw.h" -#include "BulletDynamics/Dynamics/btDynamicsWorld.h" - -#include "BulletDynamics/ConstraintSolver/btPoint2PointConstraint.h"//picking -#include "BulletDynamics/ConstraintSolver/btGeneric6DofConstraint.h"//picking - -#include "BulletCollision/CollisionShapes/btCollisionShape.h" -#include "BulletCollision/CollisionShapes/btBoxShape.h" -#include "BulletCollision/CollisionShapes/btSphereShape.h" -#include "BulletCollision/CollisionShapes/btCompoundShape.h" -#include "BulletCollision/CollisionShapes/btUniformScalingShape.h" -#include "BulletDynamics/ConstraintSolver/btConstraintSolver.h" -#include "GL_ShapeDrawer.h" -#include "LinearMath/btQuickprof.h" -#include "LinearMath/btDefaultMotionState.h" -#include "LinearMath/btSerializer.h" -#include "GLDebugFont.h" - -static bool use6Dof = false; -extern bool gDisableDeactivation; -int numObjects = 0; -const int maxNumObjects = 16384; -btTransform startTransforms[maxNumObjects]; -btCollisionShape* gShapePtr[maxNumObjects];//1 rigidbody has 1 shape (no re-use of shapes) -#define SHOW_NUM_DEEP_PENETRATIONS 1 - -extern int gNumClampedCcdMotions; - -#ifdef SHOW_NUM_DEEP_PENETRATIONS -extern int gNumDeepPenetrationChecks; - -extern int gNumSplitImpulseRecoveries; -extern int gNumGjkChecks; -extern int gNumAlignedAllocs; -extern int gNumAlignedFree; -extern int gTotalBytesAlignedAllocs; - -#endif // - - -DemoApplication::DemoApplication() -//see btIDebugDraw.h for modes -: -m_dynamicsWorld(0), -m_pickConstraint(0), -m_shootBoxShape(0), -m_cameraDistance(15.0), -m_debugMode(0), -m_ele(20.f), -m_azi(0.f), -m_cameraPosition(0.f,0.f,0.f), -m_cameraTargetPosition(0.f,0.f,0.f), -m_mouseOldX(0), -m_mouseOldY(0), -m_mouseButtons(0), -m_modifierKeys(0), -m_scaleBottom(0.5f), -m_scaleFactor(2.f), -m_cameraUp(0,1,0), -m_forwardAxis(2), -m_glutScreenWidth(0), -m_glutScreenHeight(0), -m_frustumZNear(1.f), -m_frustumZFar(10000.f), -m_ortho(0), -m_ShootBoxInitialSpeed(40.f), -m_stepping(true), -m_singleStep(false), -m_idle(false), - -m_enableshadows(false), -m_sundirection(btVector3(1,-2,1)*1000), -m_defaultContactProcessingThreshold(BT_LARGE_FLOAT) -{ -#ifndef BT_NO_PROFILE - m_profileIterator = CProfileManager::Get_Iterator(); -#endif //BT_NO_PROFILE - - m_shapeDrawer = new GL_ShapeDrawer (); - m_shapeDrawer->enableTexture(true); - m_enableshadows = false; -} - - - -DemoApplication::~DemoApplication() -{ -#ifndef BT_NO_PROFILE - CProfileManager::Release_Iterator(m_profileIterator); -#endif //BT_NO_PROFILE - - if (m_shootBoxShape) - delete m_shootBoxShape; - - if (m_shapeDrawer) - delete m_shapeDrawer; -} - - -void DemoApplication::overrideGLShapeDrawer (GL_ShapeDrawer* shapeDrawer) -{ - shapeDrawer->enableTexture (m_shapeDrawer->hasTextureEnabled()); - delete m_shapeDrawer; - m_shapeDrawer = shapeDrawer; -} - -void DemoApplication::myinit(void) -{ - - 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 )}; - /* light_position is NOT default value */ - GLfloat light_position0[] = { btScalar(1.0), btScalar(10.0), btScalar(1.0), btScalar(0.0 )}; - GLfloat light_position1[] = { btScalar(-1.0), btScalar(-10.0), btScalar(-1.0), btScalar(0.0) }; - - glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient); - glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse); - glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular); - glLightfv(GL_LIGHT0, GL_POSITION, light_position0); - - glLightfv(GL_LIGHT1, GL_AMBIENT, light_ambient); - glLightfv(GL_LIGHT1, GL_DIFFUSE, light_diffuse); - glLightfv(GL_LIGHT1, GL_SPECULAR, light_specular); - glLightfv(GL_LIGHT1, GL_POSITION, light_position1); - - glEnable(GL_LIGHTING); - glEnable(GL_LIGHT0); - glEnable(GL_LIGHT1); - - - glShadeModel(GL_SMOOTH); - glEnable(GL_DEPTH_TEST); - glDepthFunc(GL_LESS); - - glClearColor(btScalar(0.7),btScalar(0.7),btScalar(0.7),btScalar(0)); - - // glEnable(GL_CULL_FACE); - // glCullFace(GL_BACK); -} - - -void DemoApplication::setCameraDistance(float dist) -{ - m_cameraDistance = dist; -} - -float DemoApplication::getCameraDistance() -{ - return m_cameraDistance; -} - - - -void DemoApplication::toggleIdle() { - if (m_idle) { - m_idle = false; - } - else { - m_idle = true; - } -} - - - - -void DemoApplication::updateCamera() { - - - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - btScalar rele = m_ele * btScalar(0.01745329251994329547);// rads per deg - btScalar razi = m_azi * btScalar(0.01745329251994329547);// rads per deg - - - btQuaternion rot(m_cameraUp,razi); - - - btVector3 eyePos(0,0,0); - eyePos[m_forwardAxis] = -m_cameraDistance; - - btVector3 forward(eyePos[0],eyePos[1],eyePos[2]); - if (forward.length2() < SIMD_EPSILON) - { - forward.setValue(1.f,0.f,0.f); - } - btVector3 right = m_cameraUp.cross(forward); - btQuaternion roll(right,-rele); - - eyePos = btMatrix3x3(rot) * btMatrix3x3(roll) * eyePos; - - m_cameraPosition[0] = eyePos.getX(); - m_cameraPosition[1] = eyePos.getY(); - m_cameraPosition[2] = eyePos.getZ(); - m_cameraPosition += m_cameraTargetPosition; - - if (m_glutScreenWidth == 0 && m_glutScreenHeight == 0) - return; - - btScalar aspect; - btVector3 extents; - - aspect = m_glutScreenWidth / (btScalar)m_glutScreenHeight; - extents.setValue(aspect * 1.0f, 1.0f,0); - - - if (m_ortho) - { - // reset matrix - glLoadIdentity(); - - - extents *= m_cameraDistance; - btVector3 lower = m_cameraTargetPosition - extents; - btVector3 upper = m_cameraTargetPosition + extents; - //gluOrtho2D(lower.x, upper.x, lower.y, upper.y); - glOrtho(lower.getX(), upper.getX(), lower.getY(), upper.getY(),-1000,1000); - - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - //glTranslatef(100,210,0); - } else - { -// glFrustum (-aspect, aspect, -1.0, 1.0, 1.0, 10000.0); - glFrustum (-aspect * m_frustumZNear, aspect * m_frustumZNear, -m_frustumZNear, m_frustumZNear, m_frustumZNear, m_frustumZFar); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - gluLookAt(m_cameraPosition[0], m_cameraPosition[1], m_cameraPosition[2], - m_cameraTargetPosition[0], m_cameraTargetPosition[1], m_cameraTargetPosition[2], - m_cameraUp.getX(),m_cameraUp.getY(),m_cameraUp.getZ()); - } - -} - - - -const float STEPSIZE = 5; - -void DemoApplication::stepLeft() -{ - m_azi -= STEPSIZE; if (m_azi < 0) m_azi += 360; updateCamera(); -} -void DemoApplication::stepRight() -{ - m_azi += STEPSIZE; if (m_azi >= 360) m_azi -= 360; updateCamera(); -} -void DemoApplication::stepFront() -{ - m_ele += STEPSIZE; if (m_ele >= 360) m_ele -= 360; updateCamera(); -} -void DemoApplication::stepBack() -{ - m_ele -= STEPSIZE; if (m_ele < 0) m_ele += 360; updateCamera(); -} -void DemoApplication::zoomIn() -{ - m_cameraDistance -= btScalar(0.4); updateCamera(); - if (m_cameraDistance < btScalar(0.1)) - m_cameraDistance = btScalar(0.1); - -} -void DemoApplication::zoomOut() -{ - m_cameraDistance += btScalar(0.4); updateCamera(); - -} - - - - - - - - - - -void DemoApplication::reshape(int w, int h) -{ - GLDebugResetFont(w,h); - - m_glutScreenWidth = w; - m_glutScreenHeight = h; - - glViewport(0, 0, w, h); - updateCamera(); -} - - -void DemoApplication::keyboardCallback(unsigned char key, int x, int y) -{ - (void)x; - (void)y; - - m_lastKey = 0; - -#ifndef BT_NO_PROFILE - if (key >= 0x31 && key <= 0x39) - { - int child = key-0x31; - m_profileIterator->Enter_Child(child); - } - if (key==0x30) - { - m_profileIterator->Enter_Parent(); - } -#endif //BT_NO_PROFILE - - switch (key) - { - case 'q' : -#ifdef BT_USE_FREEGLUT - //return from glutMainLoop(), detect memory leaks etc. - glutLeaveMainLoop(); -#else - exit(0); -#endif - break; - - case 'l' : stepLeft(); break; - case 'r' : stepRight(); break; - case 'f' : stepFront(); break; - case 'b' : stepBack(); break; - case 'z' : zoomIn(); break; - case 'x' : zoomOut(); break; - case 'i' : toggleIdle(); break; - case 'g' : m_enableshadows=!m_enableshadows;break; - case 'u' : m_shapeDrawer->enableTexture(!m_shapeDrawer->enableTexture(false));break; - case 'h': - if (m_debugMode & btIDebugDraw::DBG_NoHelpText) - m_debugMode = m_debugMode & (~btIDebugDraw::DBG_NoHelpText); - else - m_debugMode |= btIDebugDraw::DBG_NoHelpText; - break; - - case 'w': - if (m_debugMode & btIDebugDraw::DBG_DrawWireframe) - m_debugMode = m_debugMode & (~btIDebugDraw::DBG_DrawWireframe); - else - m_debugMode |= btIDebugDraw::DBG_DrawWireframe; - break; - - case 'p': - if (m_debugMode & btIDebugDraw::DBG_ProfileTimings) - m_debugMode = m_debugMode & (~btIDebugDraw::DBG_ProfileTimings); - else - m_debugMode |= btIDebugDraw::DBG_ProfileTimings; - break; - - case '=': - { - int maxSerializeBufferSize = 1024*1024*5; - btDefaultSerializer* serializer = new btDefaultSerializer(maxSerializeBufferSize); - //serializer->setSerializationFlags(BT_SERIALIZE_NO_DUPLICATE_ASSERT); - m_dynamicsWorld->serialize(serializer); - FILE* f2 = fopen("testFile.bullet","wb"); - fwrite(serializer->getBufferPointer(),serializer->getCurrentBufferSize(),1,f2); - fclose(f2); - delete serializer; - break; - - } - - case 'm': - if (m_debugMode & btIDebugDraw::DBG_EnableSatComparison) - m_debugMode = m_debugMode & (~btIDebugDraw::DBG_EnableSatComparison); - else - m_debugMode |= btIDebugDraw::DBG_EnableSatComparison; - break; - - case 'n': - if (m_debugMode & btIDebugDraw::DBG_DisableBulletLCP) - m_debugMode = m_debugMode & (~btIDebugDraw::DBG_DisableBulletLCP); - else - m_debugMode |= btIDebugDraw::DBG_DisableBulletLCP; - break; - - case 't' : - if (m_debugMode & btIDebugDraw::DBG_DrawText) - m_debugMode = m_debugMode & (~btIDebugDraw::DBG_DrawText); - else - m_debugMode |= btIDebugDraw::DBG_DrawText; - break; - case 'y': - if (m_debugMode & btIDebugDraw::DBG_DrawFeaturesText) - m_debugMode = m_debugMode & (~btIDebugDraw::DBG_DrawFeaturesText); - else - m_debugMode |= btIDebugDraw::DBG_DrawFeaturesText; - break; - case 'a': - if (m_debugMode & btIDebugDraw::DBG_DrawAabb) - m_debugMode = m_debugMode & (~btIDebugDraw::DBG_DrawAabb); - else - m_debugMode |= btIDebugDraw::DBG_DrawAabb; - break; - case 'c' : - if (m_debugMode & btIDebugDraw::DBG_DrawContactPoints) - m_debugMode = m_debugMode & (~btIDebugDraw::DBG_DrawContactPoints); - else - m_debugMode |= btIDebugDraw::DBG_DrawContactPoints; - break; - case 'C' : - if (m_debugMode & btIDebugDraw::DBG_DrawConstraints) - m_debugMode = m_debugMode & (~btIDebugDraw::DBG_DrawConstraints); - else - m_debugMode |= btIDebugDraw::DBG_DrawConstraints; - break; - case 'L' : - if (m_debugMode & btIDebugDraw::DBG_DrawConstraintLimits) - m_debugMode = m_debugMode & (~btIDebugDraw::DBG_DrawConstraintLimits); - else - m_debugMode |= btIDebugDraw::DBG_DrawConstraintLimits; - break; - - case 'd' : - if (m_debugMode & btIDebugDraw::DBG_NoDeactivation) - m_debugMode = m_debugMode & (~btIDebugDraw::DBG_NoDeactivation); - else - m_debugMode |= btIDebugDraw::DBG_NoDeactivation; - if (m_debugMode & btIDebugDraw::DBG_NoDeactivation) - { - gDisableDeactivation = true; - } else - { - gDisableDeactivation = false; - } - break; - - - - - case 'o' : - { - m_ortho = !m_ortho;//m_stepping = !m_stepping; - break; - } - case 's' : clientMoveAndDisplay(); break; - // case ' ' : newRandom(); break; - case ' ': - clientResetScene(); - break; - case '1': - { - if (m_debugMode & btIDebugDraw::DBG_EnableCCD) - m_debugMode = m_debugMode & (~btIDebugDraw::DBG_EnableCCD); - else - m_debugMode |= btIDebugDraw::DBG_EnableCCD; - break; - } - - case '.': - { - shootBox(getRayTo(x,y));//getCameraTargetPosition()); - break; - } - - case '+': - { - m_ShootBoxInitialSpeed += 10.f; - break; - } - case '-': - { - m_ShootBoxInitialSpeed -= 10.f; - break; - } - - default: - // std::cout << "unused key : " << key << std::endl; - break; - } - - if (getDynamicsWorld() && getDynamicsWorld()->getDebugDrawer()) - getDynamicsWorld()->getDebugDrawer()->setDebugMode(m_debugMode); - - - -} - -void DemoApplication::setDebugMode(int mode) -{ - m_debugMode = mode; - if (getDynamicsWorld() && getDynamicsWorld()->getDebugDrawer()) - getDynamicsWorld()->getDebugDrawer()->setDebugMode(mode); -} - - - - - - -void DemoApplication::moveAndDisplay() -{ - if (!m_idle) - clientMoveAndDisplay(); - else - displayCallback(); -} - - - - -void DemoApplication::displayCallback() -{ -} - -#define NUM_SPHERES_ON_DIAGONAL 9 - -void DemoApplication::setShootBoxShape () -{ - if (!m_shootBoxShape) - { - btBoxShape* box = new btBoxShape(btVector3(.5f,.5f,.5f)); - box->initializePolyhedralFeatures(); - m_shootBoxShape = box; - } -} - -void DemoApplication::shootBox(const btVector3& destination) -{ - - if (m_dynamicsWorld) - { - float mass = 1.f; - btTransform startTransform; - startTransform.setIdentity(); - btVector3 camPos = getCameraPosition(); - startTransform.setOrigin(camPos); - - setShootBoxShape (); - - btRigidBody* body = this->localCreateRigidBody(mass, startTransform,m_shootBoxShape); - body->setLinearFactor(btVector3(1,1,1)); - //body->setRestitution(1); - - btVector3 linVel(destination[0]-camPos[0],destination[1]-camPos[1],destination[2]-camPos[2]); - linVel.normalize(); - linVel*=m_ShootBoxInitialSpeed; - - body->getWorldTransform().setOrigin(camPos); - body->getWorldTransform().setRotation(btQuaternion(0,0,0,1)); - body->setLinearVelocity(linVel); - body->setAngularVelocity(btVector3(0,0,0)); - body->setCcdMotionThreshold(0.5); - body->setCcdSweptSphereRadius(0.9f); -// printf("shootBox uid=%d\n", body->getBroadphaseHandle()->getUid()); -// printf("camPos=%f,%f,%f\n",camPos.getX(),camPos.getY(),camPos.getZ()); -// printf("destination=%f,%f,%f\n",destination.getX(),destination.getY(),destination.getZ()); - - } -} - - -int gPickingConstraintId = 0; -btVector3 gOldPickingPos; -btVector3 gHitPos(-1,-1,-1); -float gOldPickingDist = 0.f; -btRigidBody* pickedBody = 0;//for deactivation state - - -btVector3 DemoApplication::getRayTo(int x,int y) -{ - - - - if (m_ortho) - { - - btScalar aspect; - btVector3 extents; - aspect = m_glutScreenWidth / (btScalar)m_glutScreenHeight; - extents.setValue(aspect * 1.0f, 1.0f,0); - - extents *= m_cameraDistance; - btVector3 lower = m_cameraTargetPosition - extents; - btVector3 upper = m_cameraTargetPosition + extents; - - btScalar u = x / btScalar(m_glutScreenWidth); - btScalar v = (m_glutScreenHeight - y) / btScalar(m_glutScreenHeight); - - btVector3 p(0,0,0); - p.setValue((1.0f - u) * lower.getX() + u * upper.getX(),(1.0f - v) * lower.getY() + v * upper.getY(),m_cameraTargetPosition.getZ()); - return p; - } - - 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 rayFrom = getCameraPosition(); - btVector3 rayForward = (getCameraTargetPosition()-getCameraPosition()); - rayForward.normalize(); - float farPlane = 10000.f; - rayForward*= farPlane; - - btVector3 rightOffset; - btVector3 vertical = m_cameraUp; - - btVector3 hor; - hor = rayForward.cross(vertical); - hor.normalize(); - vertical = hor.cross(rayForward); - vertical.normalize(); - - float tanfov = tanf(0.5f*fov); - - - hor *= 2.f * farPlane * tanfov; - vertical *= 2.f * farPlane * tanfov; - - btScalar aspect; - - aspect = m_glutScreenWidth / (btScalar)m_glutScreenHeight; - - hor*=aspect; - - - btVector3 rayToCenter = rayFrom + rayForward; - btVector3 dHor = hor * 1.f/float(m_glutScreenWidth); - btVector3 dVert = vertical * 1.f/float(m_glutScreenHeight); - - - btVector3 rayTo = rayToCenter - 0.5f * hor + 0.5f * vertical; - rayTo += btScalar(x) * dHor; - rayTo -= btScalar(y) * dVert; - return rayTo; -} - -btScalar mousePickClamping = 30.f; - - -void DemoApplication::mouseFunc(int button, int state, int x, int y) -{ - if (state == 0) - { - m_mouseButtons |= 1<rayTest(m_cameraPosition,rayTo,rayCallback); - if (rayCallback.hasHit()) - { - - btRigidBody* body = btRigidBody::upcast(rayCallback.m_collisionObject); - if (body) - { - body->setActivationState(ACTIVE_TAG); - btVector3 impulse = rayTo; - impulse.normalize(); - float impulseStrength = 10.f; - impulse *= impulseStrength; - btVector3 relPos = rayCallback.m_hitPointWorld - body->getCenterOfMassPosition(); - body->applyImpulse(impulse,relPos); - } - } - } -#endif - - - - } else - { - - } - break; - } - case 0: - { - if (state==0) - { - - - //add a point to point constraint for picking - if (m_dynamicsWorld) - { - - btVector3 rayFrom; - if (m_ortho) - { - rayFrom = rayTo; - rayFrom.setZ(-100.f); - } else - { - rayFrom = m_cameraPosition; - } - - btCollisionWorld::ClosestRayResultCallback rayCallback(rayFrom,rayTo); - m_dynamicsWorld->rayTest(rayFrom,rayTo,rayCallback); - if (rayCallback.hasHit()) - { - - - btRigidBody* body = btRigidBody::upcast(rayCallback.m_collisionObject); - if (body) - { - //other exclusions? - if (!(body->isStaticObject() || body->isKinematicObject())) - { - pickedBody = body; - pickedBody->setActivationState(DISABLE_DEACTIVATION); - - - btVector3 pickPos = rayCallback.m_hitPointWorld; - //printf("pickPos=%f,%f,%f\n",pickPos.getX(),pickPos.getY(),pickPos.getZ()); - - - btVector3 localPivot = body->getCenterOfMassTransform().inverse() * pickPos; - - - - - - - if (use6Dof) - { - btTransform tr; - tr.setIdentity(); - tr.setOrigin(localPivot); - btGeneric6DofConstraint* dof6 = new btGeneric6DofConstraint(*body, tr,false); - dof6->setLinearLowerLimit(btVector3(0,0,0)); - dof6->setLinearUpperLimit(btVector3(0,0,0)); - dof6->setAngularLowerLimit(btVector3(0,0,0)); - dof6->setAngularUpperLimit(btVector3(0,0,0)); - - m_dynamicsWorld->addConstraint(dof6); - m_pickConstraint = dof6; - - dof6->setParam(BT_CONSTRAINT_STOP_CFM,0.8,0); - dof6->setParam(BT_CONSTRAINT_STOP_CFM,0.8,1); - dof6->setParam(BT_CONSTRAINT_STOP_CFM,0.8,2); - dof6->setParam(BT_CONSTRAINT_STOP_CFM,0.8,3); - dof6->setParam(BT_CONSTRAINT_STOP_CFM,0.8,4); - dof6->setParam(BT_CONSTRAINT_STOP_CFM,0.8,5); - - dof6->setParam(BT_CONSTRAINT_STOP_ERP,0.1,0); - dof6->setParam(BT_CONSTRAINT_STOP_ERP,0.1,1); - dof6->setParam(BT_CONSTRAINT_STOP_ERP,0.1,2); - dof6->setParam(BT_CONSTRAINT_STOP_ERP,0.1,3); - dof6->setParam(BT_CONSTRAINT_STOP_ERP,0.1,4); - dof6->setParam(BT_CONSTRAINT_STOP_ERP,0.1,5); - } else - { - btPoint2PointConstraint* p2p = new btPoint2PointConstraint(*body,localPivot); - m_dynamicsWorld->addConstraint(p2p); - m_pickConstraint = p2p; - p2p->m_setting.m_impulseClamp = mousePickClamping; - //very weak constraint for picking - p2p->m_setting.m_tau = 0.001f; -/* - p2p->setParam(BT_CONSTRAINT_CFM,0.8,0); - p2p->setParam(BT_CONSTRAINT_CFM,0.8,1); - p2p->setParam(BT_CONSTRAINT_CFM,0.8,2); - p2p->setParam(BT_CONSTRAINT_ERP,0.1,0); - p2p->setParam(BT_CONSTRAINT_ERP,0.1,1); - p2p->setParam(BT_CONSTRAINT_ERP,0.1,2); - */ - - - } - use6Dof = !use6Dof; - - //save mouse position for dragging - gOldPickingPos = rayTo; - gHitPos = pickPos; - - gOldPickingDist = (pickPos-rayFrom).length(); - } - } - } - } - - } else - { - removePickingConstraint(); - } - - break; - - } - default: - { - } - } - -} - -void DemoApplication::removePickingConstraint() -{ - if (m_pickConstraint && m_dynamicsWorld) - { - m_dynamicsWorld->removeConstraint(m_pickConstraint); - delete m_pickConstraint; - //printf("removed constraint %i",gPickingConstraintId); - m_pickConstraint = 0; - pickedBody->forceActivationState(ACTIVE_TAG); - pickedBody->setDeactivationTime( 0.f ); - pickedBody = 0; - } -} - -void DemoApplication::mouseMotionFunc(int x,int y) -{ - - if (m_pickConstraint) - { - //move the constraint pivot - - if (m_pickConstraint->getConstraintType() == D6_CONSTRAINT_TYPE) - { - btGeneric6DofConstraint* pickCon = static_cast(m_pickConstraint); - if (pickCon) - { - //keep it at the same picking distance - - btVector3 newRayTo = getRayTo(x,y); - btVector3 rayFrom; - btVector3 oldPivotInB = pickCon->getFrameOffsetA().getOrigin(); - - btVector3 newPivotB; - if (m_ortho) - { - newPivotB = oldPivotInB; - newPivotB.setX(newRayTo.getX()); - newPivotB.setY(newRayTo.getY()); - } else - { - rayFrom = m_cameraPosition; - btVector3 dir = newRayTo-rayFrom; - dir.normalize(); - dir *= gOldPickingDist; - - newPivotB = rayFrom + dir; - } - pickCon->getFrameOffsetA().setOrigin(newPivotB); - } - - } else - { - btPoint2PointConstraint* pickCon = static_cast(m_pickConstraint); - if (pickCon) - { - //keep it at the same picking distance - - btVector3 newRayTo = getRayTo(x,y); - btVector3 rayFrom; - btVector3 oldPivotInB = pickCon->getPivotInB(); - btVector3 newPivotB; - if (m_ortho) - { - newPivotB = oldPivotInB; - newPivotB.setX(newRayTo.getX()); - newPivotB.setY(newRayTo.getY()); - } else - { - rayFrom = m_cameraPosition; - btVector3 dir = newRayTo-rayFrom; - dir.normalize(); - dir *= gOldPickingDist; - - newPivotB = rayFrom + dir; - } - pickCon->setPivotB(newPivotB); - } - } - } - - float dx, dy; - dx = btScalar(x) - m_mouseOldX; - dy = btScalar(y) - m_mouseOldY; - - - ///only if ALT key is pressed (Maya style) - if (m_modifierKeys& BT_ACTIVE_ALT) - { - if(m_mouseButtons & 2) - { - btVector3 hor = getRayTo(0,0)-getRayTo(1,0); - btVector3 vert = getRayTo(0,0)-getRayTo(0,1); - btScalar multiplierX = btScalar(0.001); - btScalar multiplierY = btScalar(0.001); - if (m_ortho) - { - multiplierX = 1; - multiplierY = 1; - } - - - m_cameraTargetPosition += hor* dx * multiplierX; - m_cameraTargetPosition += vert* dy * multiplierY; - } - - if(m_mouseButtons & (2 << 2) && m_mouseButtons & 1) - { - } - else if(m_mouseButtons & 1) - { - m_azi += dx * btScalar(0.2); - m_azi = fmodf(m_azi, btScalar(360.f)); - m_ele += dy * btScalar(0.2); - m_ele = fmodf(m_ele, btScalar(180.f)); - } - else if(m_mouseButtons & 4) - { - m_cameraDistance -= dy * btScalar(0.02f); - if (m_cameraDistancegetShapeType() != 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// - - m_dynamicsWorld->addRigidBody(body); - - return body; -} - -//See http://www.lighthouse3d.com/opengl/glut/index.php?bmpfontortho -void DemoApplication::setOrthographicProjection() -{ - - // switch to projection mode - glMatrixMode(GL_PROJECTION); - - // save previous matrix which contains the - //settings for the perspective projection - glPushMatrix(); - // reset matrix - glLoadIdentity(); - // set a 2D orthographic projection - gluOrtho2D(0, m_glutScreenWidth, 0, m_glutScreenHeight); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - - // invert the y axis, down is positive - glScalef(1, -1, 1); - // mover the origin from the bottom left corner - // to the upper left corner - glTranslatef(btScalar(0), btScalar(-m_glutScreenHeight), btScalar(0)); - -} - -void DemoApplication::resetPerspectiveProjection() -{ - - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); - updateCamera(); -} - - - - -extern CProfileIterator * m_profileIterator; - -void DemoApplication::displayProfileString(int xOffset,int yStart,char* message) -{ - glRasterPos3f(btScalar(xOffset),btScalar(yStart),btScalar(0)); - GLDebugDrawString(xOffset,yStart,message); -} - - -float DemoApplication::showProfileInfo(int& xOffset,int& yStart, int yIncr) -{ -#ifndef BT_NO_PROFILE - - static double time_since_reset = 0.f; - if (!m_idle) - { - time_since_reset = CProfileManager::Get_Time_Since_Reset(); - } - - - { - //recompute profiling data, and store profile strings - - char blockTime[128]; - - double totalTime = 0; - - int frames_since_reset = CProfileManager::Get_Frame_Count_Since_Reset(); - - m_profileIterator->First(); - - double parent_time = m_profileIterator->Is_Root() ? time_since_reset : m_profileIterator->Get_Current_Parent_Total_Time(); - - { - sprintf(blockTime,"--- Profiling: %s (total running time: %.3f ms) ---", m_profileIterator->Get_Current_Parent_Name(), parent_time ); - displayProfileString(xOffset,yStart,blockTime); - yStart += yIncr; - sprintf(blockTime,"press (1,2...) to display child timings, or 0 for parent" ); - displayProfileString(xOffset,yStart,blockTime); - yStart += yIncr; - - } - - - double accumulated_time = 0.f; - - for (int i = 0; !m_profileIterator->Is_Done(); m_profileIterator->Next()) - { - double current_total_time = m_profileIterator->Get_Current_Total_Time(); - accumulated_time += current_total_time; - double fraction = parent_time > SIMD_EPSILON ? (current_total_time / parent_time) * 100 : 0.f; - - sprintf(blockTime,"%d -- %s (%.2f %%) :: %.3f ms / frame (%d calls)", - ++i, m_profileIterator->Get_Current_Name(), fraction, - (current_total_time / (double)frames_since_reset),m_profileIterator->Get_Current_Total_Calls()); - displayProfileString(xOffset,yStart,blockTime); - yStart += yIncr; - totalTime += current_total_time; - } - - sprintf(blockTime,"%s (%.3f %%) :: %.3f ms", "Unaccounted", - // (min(0, time_since_reset - totalTime) / time_since_reset) * 100); - parent_time > SIMD_EPSILON ? ((parent_time - accumulated_time) / parent_time) * 100 : 0.f, parent_time - accumulated_time); - - displayProfileString(xOffset,yStart,blockTime); - yStart += yIncr; - - - - sprintf(blockTime,"-------------------------------------------------"); - displayProfileString(xOffset,yStart,blockTime); - yStart += yIncr; - - } -#endif//BT_NO_PROFILE - - return time_since_reset; - - -} - - -// -void DemoApplication::renderscene(int pass) -{ - btScalar m[16]; - btMatrix3x3 rot;rot.setIdentity(); - const int numObjects=m_dynamicsWorld->getNumCollisionObjects(); - btVector3 wireColor(1,0,0); - for(int i=0;igetCollisionObjectArray()[i]; - btRigidBody* body=btRigidBody::upcast(colObj); - if(body&&body->getMotionState()) - { - btDefaultMotionState* myMotionState = (btDefaultMotionState*)body->getMotionState(); - myMotionState->m_graphicsWorldTrans.getOpenGLMatrix(m); - rot=myMotionState->m_graphicsWorldTrans.getBasis(); - } - else - { - colObj->getWorldTransform().getOpenGLMatrix(m); - rot=colObj->getWorldTransform().getBasis(); - } - btVector3 wireColor(1.f,1.0f,0.5f); //wants deactivation - if(i&1) wireColor=btVector3(0.f,0.0f,1.f); - ///color differently for active, sleeping, wantsdeactivation states - if (colObj->getActivationState() == 1) //active - { - if (i & 1) - { - wireColor += btVector3 (1.f,0.f,0.f); - } - else - { - wireColor += btVector3 (.5f,0.f,0.f); - } - } - if(colObj->getActivationState()==2) //ISLAND_SLEEPING - { - if(i&1) - { - wireColor += btVector3 (0.f,1.f, 0.f); - } - else - { - wireColor += btVector3 (0.f,0.5f,0.f); - } - } - - btVector3 aabbMin,aabbMax; - m_dynamicsWorld->getBroadphase()->getBroadphaseAabb(aabbMin,aabbMax); - - aabbMin-=btVector3(BT_LARGE_FLOAT,BT_LARGE_FLOAT,BT_LARGE_FLOAT); - aabbMax+=btVector3(BT_LARGE_FLOAT,BT_LARGE_FLOAT,BT_LARGE_FLOAT); -// printf("aabbMin=(%f,%f,%f)\n",aabbMin.getX(),aabbMin.getY(),aabbMin.getZ()); -// printf("aabbMax=(%f,%f,%f)\n",aabbMax.getX(),aabbMax.getY(),aabbMax.getZ()); -// m_dynamicsWorld->getDebugDrawer()->drawAabb(aabbMin,aabbMax,btVector3(1,1,1)); - - - if (!(getDebugMode()& btIDebugDraw::DBG_DrawWireframe)) - { - switch(pass) - { - case 0: m_shapeDrawer->drawOpenGL(m,colObj->getCollisionShape(),wireColor,getDebugMode(),aabbMin,aabbMax);break; - case 1: m_shapeDrawer->drawShadow(m,m_sundirection*rot,colObj->getCollisionShape(),aabbMin,aabbMax);break; - case 2: m_shapeDrawer->drawOpenGL(m,colObj->getCollisionShape(),wireColor*btScalar(0.3),0,aabbMin,aabbMax);break; - } - } - } -} - -// -void DemoApplication::renderme() -{ - myinit(); - - updateCamera(); - - if (m_dynamicsWorld) - { - if(m_enableshadows) - { - glClear(GL_STENCIL_BUFFER_BIT); - glEnable(GL_CULL_FACE); - renderscene(0); - - glDisable(GL_LIGHTING); - glDepthMask(GL_FALSE); - glDepthFunc(GL_LEQUAL); - glEnable(GL_STENCIL_TEST); - glColorMask(GL_FALSE,GL_FALSE,GL_FALSE,GL_FALSE); - glStencilFunc(GL_ALWAYS,1,0xFFFFFFFFL); - glFrontFace(GL_CCW); - glStencilOp(GL_KEEP,GL_KEEP,GL_INCR); - renderscene(1); - glFrontFace(GL_CW); - glStencilOp(GL_KEEP,GL_KEEP,GL_DECR); - renderscene(1); - glFrontFace(GL_CCW); - - glPolygonMode(GL_FRONT,GL_FILL); - glPolygonMode(GL_BACK,GL_FILL); - glShadeModel(GL_SMOOTH); - glEnable(GL_DEPTH_TEST); - glDepthFunc(GL_LESS); - glEnable(GL_LIGHTING); - glDepthMask(GL_TRUE); - glCullFace(GL_BACK); - glFrontFace(GL_CCW); - glEnable(GL_CULL_FACE); - glColorMask(GL_TRUE,GL_TRUE,GL_TRUE,GL_TRUE); - - glDepthFunc(GL_LEQUAL); - glStencilFunc( GL_NOTEQUAL, 0, 0xFFFFFFFFL ); - glStencilOp( GL_KEEP, GL_KEEP, GL_KEEP ); - glDisable(GL_LIGHTING); - renderscene(2); - glEnable(GL_LIGHTING); - glDepthFunc(GL_LESS); - glDisable(GL_STENCIL_TEST); - glDisable(GL_CULL_FACE); - } - else - { - glDisable(GL_CULL_FACE); - renderscene(0); - } - - int xOffset = 10; - int yStart = 20; - int yIncr = 20; - - - glDisable(GL_LIGHTING); - glColor3f(0, 0, 0); - - if ((m_debugMode & btIDebugDraw::DBG_NoHelpText)==0) - { - setOrthographicProjection(); - - showProfileInfo(xOffset,yStart,yIncr); - -#ifdef USE_QUICKPROF - - - if ( getDebugMode() & btIDebugDraw::DBG_ProfileTimings) - { - static int counter = 0; - counter++; - std::map::iterator iter; - for (iter = btProfiler::mProfileBlocks.begin(); iter != btProfiler::mProfileBlocks.end(); ++iter) - { - char blockTime[128]; - sprintf(blockTime, "%s: %lf",&((*iter).first[0]),btProfiler::getBlockTime((*iter).first, btProfiler::BLOCK_CYCLE_SECONDS));//BLOCK_TOTAL_PERCENT)); - glRasterPos3f(xOffset,yStart,0); - GLDebugDrawString(BMF_GetFont(BMF_kHelvetica10),blockTime); - yStart += yIncr; - - } - - } -#endif //USE_QUICKPROF - - - - - resetPerspectiveProjection(); - } - - glDisable(GL_LIGHTING); - - - } - - updateCamera(); - -} - -#include "BulletCollision/BroadphaseCollision/btAxisSweep3.h" - - -void DemoApplication::clientResetScene() -{ - removePickingConstraint(); - -#ifdef SHOW_NUM_DEEP_PENETRATIONS - gNumDeepPenetrationChecks = 0; - gNumGjkChecks = 0; -#endif //SHOW_NUM_DEEP_PENETRATIONS - - gNumClampedCcdMotions = 0; - int numObjects = 0; - int i; - - if (m_dynamicsWorld) - { - int numConstraints = m_dynamicsWorld->getNumConstraints(); - for (i=0;igetConstraint(0)->setEnabled(true); - } - numObjects = m_dynamicsWorld->getNumCollisionObjects(); - - ///create a copy of the array, not a reference! - btCollisionObjectArray copyArray = m_dynamicsWorld->getCollisionObjectArray(); - - - - - for (i=0;igetMotionState()) - { - btDefaultMotionState* myMotionState = (btDefaultMotionState*)body->getMotionState(); - myMotionState->m_graphicsWorldTrans = myMotionState->m_startWorldTrans; - body->setCenterOfMassTransform( myMotionState->m_graphicsWorldTrans ); - colObj->setInterpolationWorldTransform( myMotionState->m_startWorldTrans ); - colObj->forceActivationState(ACTIVE_TAG); - colObj->activate(); - colObj->setDeactivationTime(0); - //colObj->setActivationState(WANTS_DEACTIVATION); - } - //removed cached contact points (this is not necessary if all objects have been removed from the dynamics world) - if (m_dynamicsWorld->getBroadphase()->getOverlappingPairCache()) - m_dynamicsWorld->getBroadphase()->getOverlappingPairCache()->cleanProxyFromPairs(colObj->getBroadphaseHandle(),getDynamicsWorld()->getDispatcher()); - - btRigidBody* body = btRigidBody::upcast(colObj); - if (body && !body->isStaticObject()) - { - btRigidBody::upcast(colObj)->setLinearVelocity(btVector3(0,0,0)); - btRigidBody::upcast(colObj)->setAngularVelocity(btVector3(0,0,0)); - } - } - - } - - ///reset some internal cached data in the broadphase - m_dynamicsWorld->getBroadphase()->resetPool(getDynamicsWorld()->getDispatcher()); - m_dynamicsWorld->getConstraintSolver()->reset(); - - } - -} diff --git a/Extras/RigidBodyGpuPipeline/dynamics/testbed/DemoApplication.h b/Extras/RigidBodyGpuPipeline/dynamics/testbed/DemoApplication.h deleted file mode 100644 index 42903e3ec..000000000 --- a/Extras/RigidBodyGpuPipeline/dynamics/testbed/DemoApplication.h +++ /dev/null @@ -1,257 +0,0 @@ -/* -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 DEMO_APPLICATION_H -#define DEMO_APPLICATION_H - - -#include "GlutStuff.h" -#include "GL_ShapeDrawer.h" - -#include -#include -#include - - -#include "LinearMath/btVector3.h" -#include "LinearMath/btMatrix3x3.h" -#include "LinearMath/btTransform.h" -#include "LinearMath/btQuickprof.h" -#include "LinearMath/btAlignedObjectArray.h" - -class btCollisionShape; -class btDynamicsWorld; -class btRigidBody; -class btTypedConstraint; - - - -class DemoApplication -{ -protected: - void displayProfileString(int xOffset,int yStart,char* message); - class CProfileIterator* m_profileIterator; - - protected: -#ifdef USE_BT_CLOCK - btClock m_clock; -#endif //USE_BT_CLOCK - - ///this is the most important class - btDynamicsWorld* m_dynamicsWorld; - - ///constraint for mouse picking - btTypedConstraint* m_pickConstraint; - - virtual void removePickingConstraint(); - - btCollisionShape* m_shootBoxShape; - - float m_cameraDistance; - int m_debugMode; - - float m_ele; - float m_azi; - btVector3 m_cameraPosition; - btVector3 m_cameraTargetPosition;//look at - - int m_mouseOldX; - int m_mouseOldY; - int m_mouseButtons; -public: - int m_modifierKeys; -protected: - - float m_scaleBottom; - float m_scaleFactor; - btVector3 m_cameraUp; - int m_forwardAxis; - - int m_glutScreenWidth; - int m_glutScreenHeight; - - float m_frustumZNear; - float m_frustumZFar; - - int m_ortho; - - float m_ShootBoxInitialSpeed; - - bool m_stepping; - bool m_singleStep; - bool m_idle; - int m_lastKey; - - virtual float showProfileInfo(int& xOffset,int& yStart, int yIncr); - void renderscene(int pass); - - GL_ShapeDrawer* m_shapeDrawer; - bool m_enableshadows; - btVector3 m_sundirection; - btScalar m_defaultContactProcessingThreshold; - -public: - - DemoApplication(); - - virtual ~DemoApplication(); - - btDynamicsWorld* getDynamicsWorld() - { - return m_dynamicsWorld; - } - - virtual void initPhysics() = 0; - - virtual void setDrawClusters(bool drawClusters) - { - - } - - void overrideGLShapeDrawer (GL_ShapeDrawer* shapeDrawer); - - void setOrthographicProjection(); - void resetPerspectiveProjection(); - - bool setTexturing(bool enable) { return(m_shapeDrawer->enableTexture(enable)); } - bool setShadows(bool enable) { bool p=m_enableshadows;m_enableshadows=enable;return(p); } - bool getTexturing() const - { - return m_shapeDrawer->hasTextureEnabled(); - } - bool getShadows() const - { - return m_enableshadows; - } - - - int getDebugMode() - { - return m_debugMode ; - } - - void setDebugMode(int mode); - - void setAzi(float azi) - { - m_azi = azi; - } - - void setCameraUp(const btVector3& camUp) - { - m_cameraUp = camUp; - } - void setCameraForwardAxis(int axis) - { - m_forwardAxis = axis; - } - - virtual void myinit(); - - void toggleIdle(); - - virtual void updateCamera(); - - btVector3 getCameraPosition() - { - return m_cameraPosition; - } - btVector3 getCameraTargetPosition() - { - return m_cameraTargetPosition; - } - - btScalar getDeltaTimeMicroseconds() - { -#ifdef USE_BT_CLOCK - btScalar dt = (btScalar)m_clock.getTimeMicroseconds(); - m_clock.reset(); - return dt; -#else - return btScalar(16666.); -#endif - } - void setFrustumZPlanes(float zNear, float zFar) - { - m_frustumZNear = zNear; - m_frustumZFar = zFar; - } - - ///glut callbacks - - float getCameraDistance(); - void setCameraDistance(float dist); - void moveAndDisplay(); - - virtual void clientMoveAndDisplay() = 0; - - virtual void clientResetScene(); - - ///Demo functions - virtual void setShootBoxShape (); - virtual void shootBox(const btVector3& destination); - - - btVector3 getRayTo(int x,int y); - - btRigidBody* localCreateRigidBody(float mass, const btTransform& startTransform,btCollisionShape* shape); - - ///callback methods by glut - - virtual void keyboardCallback(unsigned char key, int x, int y); - - virtual void keyboardUpCallback(unsigned char key, int x, int y) {} - - virtual void specialKeyboard(int key, int x, int y){} - - virtual void specialKeyboardUp(int key, int x, int y){} - - virtual void reshape(int w, int h); - - virtual void mouseFunc(int button, int state, int x, int y); - - virtual void mouseMotionFunc(int x,int y); - - virtual void displayCallback(); - - virtual void renderme(); - - virtual void swapBuffers() = 0; - - virtual void updateModifierKeys() = 0; - - void stepLeft(); - void stepRight(); - void stepFront(); - void stepBack(); - void zoomIn(); - void zoomOut(); - - bool isIdle() const - { - return m_idle; - } - - void setIdle(bool idle) - { - m_idle = idle; - } - - -}; - -#endif //DEMO_APPLICATION_H - - diff --git a/Extras/RigidBodyGpuPipeline/dynamics/testbed/GLDebugDrawer.cpp b/Extras/RigidBodyGpuPipeline/dynamics/testbed/GLDebugDrawer.cpp deleted file mode 100644 index 79758df6c..000000000 --- a/Extras/RigidBodyGpuPipeline/dynamics/testbed/GLDebugDrawer.cpp +++ /dev/null @@ -1,139 +0,0 @@ - -#include "GLDebugDrawer.h" -#include "GLDebugFont.h" -#include "GlutStuff.h" - - - -#include //printf debugging -GLDebugDrawer::GLDebugDrawer() -:m_debugMode(0) -{ - -} - -void GLDebugDrawer::drawLine(const btVector3& from,const btVector3& to,const btVector3& fromColor, const btVector3& toColor) -{ - glBegin(GL_LINES); - glColor3f(fromColor.getX(), fromColor.getY(), fromColor.getZ()); - glVertex3d(from.getX(), from.getY(), from.getZ()); - glColor3f(toColor.getX(), toColor.getY(), toColor.getZ()); - glVertex3d(to.getX(), to.getY(), to.getZ()); - glEnd(); -} - -void GLDebugDrawer::drawLine(const btVector3& from,const btVector3& to,const btVector3& color) -{ - drawLine(from,to,color,color); -} - -void GLDebugDrawer::drawSphere (const btVector3& p, btScalar radius, const btVector3& color) -{ - glColor4f (color.getX(), color.getY(), color.getZ(), btScalar(1.0f)); - glPushMatrix (); - glTranslatef (p.getX(), p.getY(), p.getZ()); - - int lats = 5; - int longs = 5; - - int i, j; - for(i = 0; i <= lats; i++) { - btScalar lat0 = SIMD_PI * (-btScalar(0.5) + (btScalar) (i - 1) / lats); - btScalar z0 = radius*sin(lat0); - btScalar zr0 = radius*cos(lat0); - - btScalar lat1 = SIMD_PI * (-btScalar(0.5) + (btScalar) i / lats); - btScalar z1 = radius*sin(lat1); - btScalar zr1 = radius*cos(lat1); - - glBegin(GL_QUAD_STRIP); - for(j = 0; j <= longs; j++) { - btScalar lng = 2 * SIMD_PI * (btScalar) (j - 1) / longs; - btScalar x = cos(lng); - btScalar y = sin(lng); - - glNormal3f(x * zr0, y * zr0, z0); - glVertex3f(x * zr0, y * zr0, z0); - glNormal3f(x * zr1, y * zr1, z1); - glVertex3f(x * zr1, y * zr1, z1); - } - glEnd(); - } - - glPopMatrix(); -} - -void GLDebugDrawer::drawBox (const btVector3& boxMin, const btVector3& boxMax, const btVector3& color, btScalar alpha) -{ - btVector3 halfExtent = (boxMax - boxMin) * btScalar(0.5f); - btVector3 center = (boxMax + boxMin) * btScalar(0.5f); - //glEnable(GL_BLEND); // Turn blending On - //glBlendFunc(GL_SRC_ALPHA, GL_ONE); - glColor4f (color.getX(), color.getY(), color.getZ(), alpha); - glPushMatrix (); - glTranslatef (center.getX(), center.getY(), center.getZ()); - glScaled(2*halfExtent[0], 2*halfExtent[1], 2*halfExtent[2]); -// glutSolidCube(1.0); - glPopMatrix (); - //glDisable(GL_BLEND); -} - -void GLDebugDrawer::drawTriangle(const btVector3& a,const btVector3& b,const btVector3& c,const btVector3& color,btScalar alpha) -{ -// if (m_debugMode > 0) - { - const btVector3 n=btCross(b-a,c-a).normalized(); - glBegin(GL_TRIANGLES); - glColor4f(color.getX(), color.getY(), color.getZ(),alpha); - glNormal3d(n.getX(),n.getY(),n.getZ()); - glVertex3d(a.getX(),a.getY(),a.getZ()); - glVertex3d(b.getX(),b.getY(),b.getZ()); - glVertex3d(c.getX(),c.getY(),c.getZ()); - glEnd(); - } -} - -void GLDebugDrawer::setDebugMode(int debugMode) -{ - m_debugMode = debugMode; - -} - -void GLDebugDrawer::draw3dText(const btVector3& location,const char* textString) -{ - glRasterPos3f(location.x(), location.y(), location.z()); - //BMF_DrawString(BMF_GetFont(BMF_kHelvetica10),textString); -} - -void GLDebugDrawer::reportErrorWarning(const char* warningString) -{ - printf("%s\n",warningString); -} - -void GLDebugDrawer::drawContactPoint(const btVector3& pointOnB,const btVector3& normalOnB,btScalar distance,int lifeTime,const btVector3& color) -{ - - { - btVector3 to=pointOnB+normalOnB*1;//distance; - const btVector3&from = pointOnB; - glColor4f(color.getX(), color.getY(), color.getZ(),1.f); - //glColor4f(0,0,0,1.f); - glBegin(GL_LINES); - glVertex3d(from.getX(), from.getY(), from.getZ()); - glVertex3d(to.getX(), to.getY(), to.getZ()); - glEnd(); - - -// glRasterPos3f(from.x(), from.y(), from.z()); -// char buf[12]; -// sprintf(buf," %d",lifeTime); - //BMF_DrawString(BMF_GetFont(BMF_kHelvetica10),buf); - - - } -} - - - - - diff --git a/Extras/RigidBodyGpuPipeline/dynamics/testbed/GLDebugDrawer.h b/Extras/RigidBodyGpuPipeline/dynamics/testbed/GLDebugDrawer.h deleted file mode 100644 index 2a05405a7..000000000 --- a/Extras/RigidBodyGpuPipeline/dynamics/testbed/GLDebugDrawer.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef GL_DEBUG_DRAWER_H -#define GL_DEBUG_DRAWER_H - -#include "LinearMath/btIDebugDraw.h" - - - -class GLDebugDrawer : public btIDebugDraw -{ - int m_debugMode; - -public: - - GLDebugDrawer(); - - - virtual void drawLine(const btVector3& from,const btVector3& to,const btVector3& fromColor, const btVector3& toColor); - - virtual void drawLine(const btVector3& from,const btVector3& to,const btVector3& color); - - virtual void drawSphere (const btVector3& p, btScalar radius, const btVector3& color); - virtual void drawBox (const btVector3& boxMin, const btVector3& boxMax, const btVector3& color, btScalar alpha); - - virtual void drawTriangle(const btVector3& a,const btVector3& b,const btVector3& c,const btVector3& color,btScalar alpha); - - virtual void drawContactPoint(const btVector3& PointOnB,const btVector3& normalOnB,btScalar distance,int lifeTime,const btVector3& color); - - virtual void reportErrorWarning(const char* warningString); - - virtual void draw3dText(const btVector3& location,const char* textString); - - virtual void setDebugMode(int debugMode); - - virtual int getDebugMode() const { return m_debugMode;} - -}; - -#endif//GL_DEBUG_DRAWER_H diff --git a/Extras/RigidBodyGpuPipeline/dynamics/testbed/GLDebugFont.cpp b/Extras/RigidBodyGpuPipeline/dynamics/testbed/GLDebugFont.cpp deleted file mode 100644 index b62973182..000000000 --- a/Extras/RigidBodyGpuPipeline/dynamics/testbed/GLDebugFont.cpp +++ /dev/null @@ -1,1000 +0,0 @@ -/* -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 "GLDebugFont.h" - - -#ifdef _WIN32//for glut.h -#include -#endif - -//think different -#if defined(__APPLE__) && !defined (VMDMESA) -#include -#if (defined (TARGET_OS_IPHONE) && TARGET_OS_IPHONE) || (defined (TARGET_IPHONE_SIMULATOR) && TARGET_IPHONE_SIMULATOR) -#import -#define glOrtho glOrthof -#else -#include -#include -#include -#endif -#else - - - -#ifdef _WINDOWS -#include -#include -#include -#else -#include -#include -#endif -#endif - -#include -#include //for memset - -extern unsigned char sFontData[]; -static bool sTexturesInitialized = false; - -static GLuint sTexture = -1; -static int sScreenWidth = -1; -static int sScreenHeight = -1; - - -void GLDebugResetFont(int screenWidth,int screenHeight) -{ - - if ((sScreenWidth == screenWidth) && (sScreenHeight == screenHeight)) - return; - - sScreenWidth = screenWidth; - sScreenHeight = screenHeight; - - if (!sTexturesInitialized) - { - sTexturesInitialized = true; - glGenTextures(1, &sTexture); - glBindTexture(GL_TEXTURE_2D, sTexture); - glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); - glTexImage2D(GL_TEXTURE_2D, 0, 3, 256 , 256 , 0, GL_RGB, GL_UNSIGNED_BYTE, &sFontData[0]); - } - - printf("generating font at resolution %d,%d\n",screenWidth,screenHeight); - -} - -#define USE_ARRAYS 1 - -void GLDebugDrawStringInternal(int x,int y,const char* string, const btVector3& rgb) -{ - GLDebugDrawStringInternal(x,y,string,rgb,true,10); -} - -void GLDebugDrawStringInternal(int x,int y,const char* string, const btVector3& rgb, bool enableBlend, int spacing) -{ - - if (!sTexturesInitialized) - { - GLDebugResetFont(sScreenWidth,sScreenHeight); - } - if (strlen(string)) - { - - glColor4f(rgb.getX(),rgb.getY(),rgb.getZ(),1.f); - float cx; - float cy; - - glMatrixMode(GL_TEXTURE); - glLoadIdentity(); - - glDisable(GL_TEXTURE_GEN_S); - glDisable(GL_TEXTURE_GEN_T); - glDisable(GL_TEXTURE_GEN_R); - - glEnable(GL_TEXTURE_2D); - glBlendFunc(GL_SRC_ALPHA,GL_ONE); - glDepthFunc (GL_LEQUAL); - - if (enableBlend) - { - glEnable(GL_BLEND); - } else - { - glDisable(GL_BLEND); - } - glEnable (GL_DEPTH_TEST); - glBindTexture(GL_TEXTURE_2D, sTexture); - glDisable(GL_DEPTH_TEST); - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadIdentity(); - - glOrtho(0,sScreenWidth,0,sScreenHeight,-1,1); - - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glLoadIdentity(); - glTranslatef(btScalar(x),btScalar(sScreenHeight - y),btScalar(0)); - -#if USE_ARRAYS - - glDisableClientState(GL_COLOR_ARRAY); - glDisableClientState(GL_NORMAL_ARRAY); - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState (GL_TEXTURE_COORD_ARRAY); -#endif - - GLfloat verts[] ={ - 0.0f, 1.0f, 0.0f, - -1.0f, -1.0f, 0.0f, - 1.0f, -1.0f, 0.0f, - 0.f,0.f,0.f - }; - - GLfloat uv_texcoords[] = { - 0,0, - 0,0, - 0,0, - 0,0 - }; - verts[0] = 0; verts[1] = 0; verts[2] = 0; - verts[3] = 16-1; verts[4] = 0; verts[5] = 0; - verts[6] = 16-1; verts[7] = 16-1; verts[8] = 0; - verts[9] = 0; verts[10] = 16-1; verts[11] = 0; - - for (int i=0;i=0) - { - cx=float(ch%16) * btScalar(1./16.f); - cy=float(ch/16) * btScalar(1./16.f); - - uv_texcoords[0] = cx; uv_texcoords[1] = btScalar(1-cy-1./16.f); - uv_texcoords[2] = btScalar(cx+1./16.f); uv_texcoords[3] = btScalar(1-cy-1./16.f); - uv_texcoords[4] = btScalar(cx+1./16.f); uv_texcoords[5] = btScalar(1-cy); - uv_texcoords[6] = cx; uv_texcoords[7] = btScalar(1-cy); -#if USE_ARRAYS - glTexCoordPointer(2,GL_FLOAT,0,uv_texcoords); - glVertexPointer(3, GL_FLOAT, 0, verts); - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); -#else - glBegin(GL_QUADS); - glTexCoord2f(cx,1-cy-1./16.f); - - glVertex2i(0,0); - glTexCoord2f(cx+1./16.f,1-cy-1./16.f); - - glVertex2i(16 - 1,0); - glTexCoord2f(cx+1./16.f,1-cy); - - glVertex2i(16 - 1,16 -1); - glTexCoord2f(cx,1-cy); - - glVertex2i(0,16 -1); - glEnd(); -#endif - - glTranslatef(spacing,0,0); - } - } - - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); -#if 1 - glEnable(GL_DEPTH_TEST); - glBlendFunc(GL_SRC_ALPHA,GL_ONE); - glDepthFunc (GL_LEQUAL); - glDisable(GL_BLEND); - glDisable(GL_TEXTURE_2D); - - glMatrixMode(GL_TEXTURE); - glLoadIdentity(); - glScalef(btScalar(0.025),btScalar(0.025),btScalar(0.025)); -#endif - glMatrixMode(GL_MODELVIEW); -#if USE_ARRAYS - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState (GL_TEXTURE_COORD_ARRAY); -#endif - //glDisable(GL_TEXTURE_2D); - } -} - -void GLDebugDrawString(int x,int y,const char* string) -{ - - btVector3 rgb(1,1,1); - GLDebugDrawStringInternal(x,y,string,rgb); -} - - -unsigned char sFontData[] = -{ - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,103,103,103,145,145,145,255,255,255,255,255,255,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,103,103,103,213,213,213,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,103,103,103,2,2,2,255,255,255,255,255,255,255,255,255,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,0,0,0,103,103,103,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,255,255,255,255,255,255,246,246,246,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,255,255,255,255,255,255,246,246,246,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213, - 213,213,255,255,255,255,255,255,246,246,246,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,255,255,255,255,255,255,246,246,246,255,255,255,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,255,255,255,255,255,255,246,246,246,255,255,255,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,255,255,255,213,213,213,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,255,255,255,255,255,255,178,178,178,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,255,255,255,213,213,213,255,255,255,255,255,255,255,255,255,213,213,213,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,178,178,178,178,178,178,255,255,255,255,255,255,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,0,0,0,0,0,0,0,0,0,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,103,103,103,246,246,246,255,255,255,103,103,103,103,103,103,103,103,103,178,178,178,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,145,145,145,178,178,178,255,255,255,255,255,255,255,255,255,145,145,145,103,103,103,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,255,255,255,0,0,0,2,2,2,255,255,255,178,178,178,103,103,103,145,145,145,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,145,145,145,103,103,103,246,246,246,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,145,145,145,103,103,103,246,246,246,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255, - 255,255,145,145,145,103,103,103,246,246,246,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,213,213,213,178,178,178,255,255,255,255,255,255,178,178,178,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,213,213,213,178,178,178,255,255,255,255,255,255,178,178,178,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,255,255,255,178,178,178,103,103,103,255,255,255,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,103,103,103,145,145,145,255,255,255,255,255,255,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,103,103,103,103,103,103,255,255,255,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,103,103,103,145,145,145,178,178,178,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,103,103,103,145,145,145,255,255,255,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,255,255,255,255,255,255,0,0,0,213,213,213,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,70,70,70,0,0,0,0,0,0,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,255,255,255,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,70, - 70,70,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,255,255,255,70,70, - 70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,213,213,213,255,255,255,255,255,255,0,0,0,0,0,0,70,70,70,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,178,178,178,103,103,103,255,255,255,213,213,213,70,70,70,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,2,2,2,255,255,255,246,246,246,178,178,178,246,246,246,70,70,70,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,37, - 37,37,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,2,2,2,0,0,0,0,0,0,246,246,246,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,2,2,2,0,0,0,0,0,0,246,246,246,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,178,178,178,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,255,255,255,213,213, - 213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,37,37,37,0,0,0,255,255,255,255,255,255,103,103,103,0,0,0,255,255,255,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,103,103,103,255,255,255,103,103,103,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,178,178,178,255,255,255,37,37,37,0,0,0,0,0,0,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,103,103,103,255,255,255,255,255,255,145,145,145,103,103,103,246,246,246,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,2,2,2,145,145,145,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255, - 255,255,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,145,145,145,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,145,145,145,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,103,103,103,0,0,0,0,0,0,213,213,213,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,145,145,145,255,255, - 255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,103,103,103,255,255,255,255,255,255,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,70,70,70,255,255,255,70,70,70,0,0,0,145,145,145,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,213,213,213,255,255,255,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,213,213,213,0,0,0,70,70,70,255,255,255,37,37,37,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,103,103,103,103,103,103,246,246,246,255,255,255,255,255,255,103,103,103,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,246,246,246,70,70,70,255,255,255,0,0,0,255,255,255,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,145,145,145,103,103,103,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,145,145,145,103,103,103,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255, - 255,255,255,255,255,145,145,145,103,103,103,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,213,213,213,0,0,0,37,37,37,246,246,246,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,213,213,213,0,0,0,37,37,37,246,246,246,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,246,246,246,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,213,213,213,0,0,0,0,0,0,0,0,0,70,70,70,255,255, - 255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,178,178,178,103,103,103,213,213,213,255,255,255,255,255,255,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,0,0,0,0,0,0,37,37,37,255,255,255,178,178,178,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,70,70,70,0,0,0,70,70,70,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,255,255,255,255,255,255,255,255,255,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,255,255,255,255,255,255,145,145,145,213,213,213,255,255,255,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,70,70,70,255,255,255,37,37,37,0,0,0,145,145,145,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,178,178,178,255,255,255,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,255,255,255,255,255,255,0,0,0,103,103,103,255,255,255,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,255,255,255,255,255,255,0,0,0,103,103,103,255,255,255,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,246,246,246,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,255,255, - 255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,255,255,255,255,255,255,255,255,255,178,178,178,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,0,0,0,0,0,0,0,0,0,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,178,178,178,255,255,255,213,213,213,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,213,213,213,255,255,255,103,103,103,103,103,103,103,103,103,103,103,103,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,255,255,255,255,255,255,246,246,246,103,103,103,246,246,246,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,0,0,0,0,0,0,0,0,0,37,37,37,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,246,246,246,103,103,103,246,246,246,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,255,255,255,103,103,103,70,70,70,0,0,0,103,103,103,255,255, - 255,246,246,246,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,246,246,246,103,103,103,246,246,246,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,255,255,255,145,145,145,103,103,103,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,103,103,103,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,2,2,2,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,178,178,178,0,0,0,0,0,0,255,255,255,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,255,255,255,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,37,37,37,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,178,178,178,0,0,0,255,255,255,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,213,213,213,255,255,255,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,2,2,2,255,255,255,255,255, - 255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,255,255,255,255,255,255,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,255,255,255,255,255,255,255,255,255,178,178,178,178,178,178,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,0,0,0,0,0,0,246,246,246,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,0,0,0,246,246,246,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,255,255,255,0,0,0,0,0,0,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,255,255,255,0,0,0,255,255,255,246,246, - 246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,103,103,103,255,255, - 255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,103,103,103,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,255,255,255,255,255,255,246,246,246,255,255,255,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,213,213,213,255,255,255,255,255,255,255,255,255,178,178,178,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,255,255,255,255,255,255,213,213,213,213,213,213,255,255,255,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,255,255,255,255,255,255,213,213,213,213,213,213,255,255,255,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,255, - 255,255,255,255,255,213,213,213,213,213,213,255,255,255,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,255,255,255,255,255,255,178,178,178,213,213,213,255,255,255,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,255,255,255,255,255,255,255,255,255,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,213,213,213,255,255,255,255,255,255,255,255,255,178,178,178,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,213,213,213,255,255,255,255,255,255,255,255,255,178,178,178,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,213,213,213,255,255,255,255,255,255,255,255,255,178,178,178,2,2,2,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,255,255,255,255,255,255,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,255,255,255,255,255,255,103,103,103,145,145,145,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,213,213,213,178,178,178,255,255,255,255,255,255,178,178,178,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,246,246,246,103,103,103,103,103,103,103,103,103,178,178,178,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,178,178,178,103,103,103,255,255,255,255,255,255,255,255,255,178,178,178,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,178,178,178,103,103,103,255,255,255,255,255,255,255,255,255,178,178,178,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,178, - 178,178,103,103,103,255,255,255,255,255,255,255,255,255,178,178,178,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,145,145,145,145,145,145,255,255,255,255,255,255,255,255,255,178,178,178,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,145,145,145,145,145,145,255,255,255,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,246,246,246,103,103,103,103,103,103,103,103,103,178,178,178,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,103,103,103,103,103,103,103,103,103,178,178,178,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,246,246,246,103,103,103,103,103,103,103,103,103,178,178,178,255,255,255,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,103,103,103,178,178,178,255,255,255,178,178,178,103,103,103,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,103,103,103,178,178,178,255,255,255,178,178,178,103,103,103,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,103,103,103,178,178,178,255,255,255,178,178,178,103,103,103,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,246,246,246,255,255,255,145,145,145,0,0,0,37,37,37,246,246,246,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,246,246,246,255,255,255,145,145,145,0,0,0,37,37,37,246,246,246,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,2, - 2,2,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,2,2,2,0,0,0,0,0,0,2,2,2,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,103,103, - 103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,2,2,2,0,0,0,0,0,0,246,246,246,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,246,246,246,103,103,103,103,103,103,103,103,103,103,103,103,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255, - 255,255,255,255,255,255,255,255,255,255,255,255,255,255,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,246,246,246,103,103,103,103,103,103,103,103,103,103,103,103,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,246,246,246,103,103,103,103,103,103,103,103,103,103,103,103,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,246,246,246,103,103,103,103,103,103,103,103,103,103,103,103,255,255,255,178,178, - 178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,246,246,246,103,103,103,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,246,246,246,103,103,103,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,145,145,145,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,103,103,103,103,103,103,103,103,103,246,246,246,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,103,103,103,103,103,103,103,103,103,246,246,246,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37, - 37,37,103,103,103,103,103,103,103,103,103,246,246,246,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,103,103,103,103,103,103,103,103,103,246,246,246,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,246,246,246,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,246,246, - 246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,213,213,213,0,0,0,37,37,37,246,246,246,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,178,178,178,103,103,103,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,246,246,246,103,103,103,103,103,103,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,246,246,246,103,103,103,103,103,103,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255, - 255,255,246,246,246,103,103,103,103,103,103,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,178,178,178,103,103,103,145,145,145,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,103,103,103,145,145,145,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,178,178,178,103,103,103,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,178,178,178,103,103,103,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,178,178,178,103,103,103,255,255,255,255,255,255,103,103, - 103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,103,103,103,246,246,246,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,103,103,103,246,246,246,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,103,103,103,246,246,246,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,2,2,2,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,2,2,2,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,246,246,246,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,255,255,255,255,255,255,0,0,0,103,103,103,255,255,255,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,246,246,246,255,255,255,255,255,255,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,246,246,246,255,255,255,255,255,255,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103, - 103,103,246,246,246,255,255,255,255,255,255,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,255,255,255,255,255,255,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,255,255,255,255,255,255,246,246,246,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,255,255,255,255,255,255,103,103,103,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,255,255,255,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,255,255,255,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,255,255,255,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,255,255,255,103,103,103,145,145,145,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,255,255,255,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,255,255,255,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,0,0,0,0,0,0,0,0,0,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,213,213,213,255,255,255,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,213,213,213,255,255,255,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,213,213,213,255,255,255,255,255,255,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,246,246,246,0,0,0,0,0,0,255,255,255,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,70,70,70,70,70,70,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,178,178,178,0,0,0,0,0,0,255,255,255,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,0,0,0,37,37,37,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,37,37,37,70,70,70,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,178,178,178,0,0,0,0,0,0,255,255,255,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,145,145,145,178,178,178,255,255,255,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,246,246,246,0,0,0,178,178,178,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,0,0,0,0,0,0,246,246,246,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,0,0,0,0,0,0,246,246,246,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,0,0,0,0,0,0,246,246,246,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,255,255,255,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,255,255,255,0,0,0,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,37,37,37,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,103,103,103,255,255,255,255,255,255,255,255,255,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,246,246,246,103,103,103,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,103,103,103,246,246,246,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,103,103,103,145,145,145,255,255,255,255,255,255,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,213,213,213,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,213,213,213,213,213,213,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,255,255,255,255,255,255,213,213,213,213,213,213,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,246,246,246,255,255,255,255,255,255,255,255,255,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,213,213,213,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246, - 246,246,255,255,255,255,255,255,246,246,246,255,255,255,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,255,255,255,0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,178,178,178,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,255,255,255,145,145,145,178,178,178,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,103,103,103,178,178,178,255,255,255,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,178,178,178,255,255,255,178,178,178,103,103,103,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,246,246,246,103,103,103,103,103,103,246,246,246,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,213,213,213,103,103,103,255,255,255,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255, - 255,255,213,213,213,178,178,178,255,255,255,255,255,255,178,178,178,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,255,255,255,178,178,178,0,0,0,255,255,255,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,178,178,178,255,255,255,255,255,255,0,0,0,0,0,0,70,70,70,255,255,255,255,255,255,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,255,255,255,103,103,103,103,103,103,178,178,178,255,255,255,2,2, - 2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,70,70,70,0,0,0,0,0,0,37,37,37,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,70,70,70,0,0,0,0,0,0,37,37,37,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,246,246,246,0,0,0,2,2,2,37,37,37,145,145,145,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255, - 255,255,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,255,255,255,70,70,70,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,145,145,145,255,255,255,103,103,103,255,255,255,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,178,178,178,255,255,255,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,246,246,246,0,0,0,0,0,0,246,246,246,70,70, - 70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,0,0,0,2,2,2,255,255,255,255,255,255,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,255,255,255,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,246,246,246,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255, - 255,255,2,2,2,0,0,0,0,0,0,246,246,246,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,103,103,103,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,103,103,103,255,255,255,255,255,255,0,0,0,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,178,178,178,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,2,2,2,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,246,246,246,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,213,213,213,0,0,0,0,0,0,0,0,0,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,70,70,70,2,2,2,2,2,2,103,103,103,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255, - 255,255,103,103,103,0,0,0,0,0,0,145,145,145,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,178,178,178,0,0,0,0,0,0,213,213,213,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,255,255,255,255,255,255,0,0,0,178,178,178,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,103,103,103,178,178,178,255,255,255,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,103,103,103,0,0,0,0,0,0,213,213,213,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,2,2,2,0,0,0,145,145,145,255,255,255,103,103,103,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,178,178,178,0,0,0,0,0,0,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,255,255,255,255,255,255,103,103,103,213,213,213,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,103,103,103,246,246,246,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,246,246,246,255,255,255,255,255,255,246,246,246,246,246,246,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,145,145,145,103,103,103,178,178,178,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,255,255,255,103,103,103,103,103,103,103,103,103,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255, - 255,255,213,213,213,0,0,0,37,37,37,246,246,246,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,246,246,246,255,255,255,213,213,213,0,0,0,0,0,0,103,103,103,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,246,246,246,70,70,70,103,103,103,246,246,246,0,0,0,213,213,213,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,255,255,255,103,103,103,0,0,0,255,255,255,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,246,246,246,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,255,255,255,103,103,103,103,103,103,255,255,255,255,255,255,246,246, - 246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,255,255,255,255,255,255,213,213,213,255,255,255,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,255,255,255,255,255,255,145,145,145,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,70,70,70,178,178,178,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,255, - 255,255,255,255,255,0,0,0,103,103,103,255,255,255,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,255,255,255,255,255,255,70,70,70,0,0,0,178,178,178,255,255,255,255,255,255,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,255,255,255,255,255,255,0,0,0,255,255,255,255,255,255,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, - 255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,145,145,145,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,246,246,246,255,255,255,255,255,255,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,246,246,246,103,103,103,103,103,103,145,145,145,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,178,178,178,103,103,103,178,178,178,255,255,255,145,145,145,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,255,255,255,255,255,255,213,213,213,213,213,213,255,255,255,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,213,213,213,213,213,213,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,255,255,255,255,255,255,213,213,213,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,255,255,255,255,255,255,213,213,213,213,213,213,255,255,255,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,213, - 213,213,255,255,255,255,255,255,255,255,255,178,178,178,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,255,255,255,255,255,255,246,246,246,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,213,213,213,145,145,145,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,178,178,178,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,103,103,103,255,255,255,255,255,255,103,103,103,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,255,255,255,255,255,255,213,213,213,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,178,178,178,103,103,103,255,255,255,255,255,255,255,255,255,178,178,178,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,246,246,246,255,255,255,255,255,255,145,145,145,178,178,178,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,145,145,145,103,103,103,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,103,103,103,178,178,178,255,255,255,255,255,255,178,178,178,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,246, - 246,246,103,103,103,103,103,103,103,103,103,178,178,178,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,178,178,178,255,255,255,178,178,178,103,103,103,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,145,145,145,178,178,178,255,255,255,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,246,246,246,255,255,255,103,103,103,0,0,0,178,178,178,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,103,103,103,178,178,178,255,255,255,178,178,178,103,103,103,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,2,2,2,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,246,246,246,255,255,255,0,0,0,70,70,70,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,103,103,103,178,178,178,255,255,255,178,178,178,103,103,103,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,246,246,246,255,255,255,37,37,37,178,178,178,255,255,255,37,37,37,178,178,178,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,246,246,246,255,255,255,103,103,103,0,0,0,70,70,70,178,178,178,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,213,213,213,103,103,103,103,103,103,255,255,255,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,70,70,70,0,0,0,0,0,0,37,37,37,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,255, - 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,70,70,70,0,0,0,0,0,0,37,37,37,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,103,103,103,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,103,103,103,255,255,255,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,255,255,255,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,246,246,246,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,246, - 246,246,103,103,103,103,103,103,103,103,103,103,103,103,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,255,255,255,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,2,2,2,0,0,0,0,0,0,246,246,246,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,213,213,213,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,2,2,2,0,0,0,255,255,255,2,2,2,0,0,0,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,246,246,246,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,103,103,103,103,103,103,103,103,103,246,246,246,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,213,213,213,0,0,0,0,0,0,0,0,0,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,255, - 255,255,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,213,213,213,0,0,0,0,0,0,145,145,145,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,255,255,255,103,103,103,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,213,213,213,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,246,246,246,103,103,103,103,103,103,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,255,255,255,255,255,255,103,103,103,213,213,213,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,103,103,103,103,103,103,255,255,255,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,103,103,103,246,246,246,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255, - 255,255,255,255,255,178,178,178,103,103,103,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,246,246,246,255,255,255,103,103,103,103,103,103,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,255,255,255,103,103,103,213,213,213,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,255,255,255,255,255,255,103,103,103,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,103,103,103,246,246,246,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,103,103,103,103,103,103,246,246,246,255,255,255,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,213,213,213,213,213,213,255,255,255,246,246,246,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,255,255,255,37,37,37,255,255,255,255,255,255,70,70,70,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,255,255,255,255,255,255,178,178,178,103,103,103,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,178,178,178,103,103,103,145,145,145,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,246,246,246,255,255,255,255,255,255,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,178,178,178,255,255,255,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,255,255,255,213,213,213,255,255,255,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,255,255,255,255,255,255,145,145,145,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,145,145,145,255,255,255,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,213,213,213,255,255,255,255,255,255,178,178,178,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,178,178,178,255,255,255,255,255,255,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,255,255,255,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,37,37, - 37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,255,255,255,246,246,246,255,255,255,145,145,145,255,255,255,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,255,255,255,255,255,255,213,213,213,255,255,255,255,255,255,255,255,255,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,255,255,255,255,255,255,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,246,246,246,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,246,246,246,103,103,103,103,103,103,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,2,2, - 2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,246,246,246,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,246,246,246,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,246,246,246,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,246,246,246,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,246,246, - 246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,246,246,246,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,246,246,246,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255, - 255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,246,246,246,178,178,178,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,103,103,103,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,103,103,103,246,246,246,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,246,246,246,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,246,246,246,0,0,0,0,0,0,255,255,255,255,255,255,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,246,246,246,255,255,255,255,255,255,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255, - 255,255,255,255,255,255,255,255,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,103,103,103,0,0,0,0,0,0,2,2,2,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,145,145,145,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,103,103,103,246,246,246,255,255,255,103,103,103,103,103,103,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,246,246,246,255,255,255,103,103,103,0,0,0,103,103,103,255,255,255,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,255,255,255,255,255,255,103,103,103,145,145,145,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,178,178,178,255,255,255,178,178,178,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255, - 255,255,145,145,145,103,103,103,178,178,178,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,103,103,103,255,255,255,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,213,213,213,255,255,255,246,246,246,2,2,2,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,178,178,178,255,255,255,178,178,178,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,255,255,255,103,103,103,103,103,103,178,178,178,255,255,255,2,2, - 2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,37,37,37,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,37, - 37,37,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,255,255,255,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,178,178,178,0,0,0,145,145,145,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,255,255,255,2,2,2,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,145,145,145,0,0,0,0,0,0,255,255,255,103,103, - 103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,0,0,0,103,103,103,103,103,103,213,213,213,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,2, - 2,2,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,37,37,37,246,246,246,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,145,145,145,255,255,255,2,2,2,246,246,246,103,103,103,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,255,255,255,70,70,70,0,0,0,145,145,145,103,103, - 103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,246,246,246,103,103,103,103,103,103,213,213,213,255,255,255,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,246,246,246,103,103,103,103,103,103,246,246,246,255,255,255,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,0,0,0,0,0,0,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103, - 103,103,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,255,255,255,0,0,0,0,0,0,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,145,145,145,103,103,103,246,246,246,255,255,255,103,103,103,213,213,213,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,70,70,70,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,2,2,2,255,255,255,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,213,213,213,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,213,213,213,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,255,255,255,145,145,145,2,2,2,0,0,0,0,0,0,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,255,255,255,0,0,0,70,70,70,255,255,255,0,0,0,2,2,2,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,213, - 213,213,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,103,103,103,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,246,246,246,0,0,0,255,255,255,255,255,255,2,2,2,70,70,70,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,255,255,255,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,178,178,178,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,70,70,70,0,0,0,255,255,255,255,255,255,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,246,246,246,178,178,178,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,0,0,0,0,0,0,0,0,0,37,37,37,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,37,37,37,0,0,0,255,255,255,37,37,37,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255, - 255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,213,213,213,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,246,246,246,0,0,0,103,103,103,255,255,255,2,2,2,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,255,255,255,103,103,103,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,37,37,37,0,0,0,103,103,103,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,0,0,0,0,0,0,255,255,255,255,255,255,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,213,213,213,255,255,255,103,103,103,103,103,103,145,145,145,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,246,246,246,103,103,103,246,246,246,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,213,213,213,255,255,255,103,103,103,103,103,103,103,103,103,255,255,255,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,145,145,145,103,103,103,255,255,255,255,255,255,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,246,246,246,103,103,103,255,255,255,246,246,246,103,103,103,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,255, - 255,255,103,103,103,103,103,103,0,0,0,70,70,70,103,103,103,255,255,255,246,246,246,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,246,246,246,2,2,2,0,0,0,0,0,0,213,213,213,255,255,255,213,213,213,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,255,255,255,0,0,0,213,213,213,255,255,255,145,145,145,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,246,246,246,255,255,255,145,145,145,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,255,255,255,103,103,103,103,103,103,213,213,213,255,255,255,255,255, - 255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,246,246,246,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,103,103,103,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,246,246,246,255,255,255,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,255,255,255,255,255,255,255,255,255,246,246,246,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255, - 255,255,255,255,255,255,255,255,2,2,2,178,178,178,255,255,255,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,178,178,178,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,37,37,37,0,0,0,0,0,0,246,246,246,255,255,255,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,37,37,37,178,178,178,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,37,37,37,0,0,0,0,0,0,246,246,246,255,255,255,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, - 255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,255,255,255,255,255,255,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,255,255,255,255,255,255,255,255,255,246,246,246,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,255,255,255,255,255,255,213,213,213,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,213,213,213,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,255,255,255,255,255,255,255,255,255,246,246,246,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,213,213,213,103,103,103,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,255,255,255,255,255,255,213,213,213,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,178,178,178,0,0,0,0,0,0,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,255,255,255,255,255,255,255,255,255,0,0,0,246,246,246,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,255,255,255,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,145,145,145,103,103,103,103,103,103,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,246,246,246,255,255,255,145,145,145,0,0,0,0,0,0,37,37,37,246,246,246,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,246,246,246,255,255,255,103,103,103,103,103,103,103,103,103,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,255,255,255,178,178,178,103,103,103,246,246,246,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,246,246,246,255,255,255,103,103,103,103,103,103,145,145,145,255,255,255,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,246,246,246,255, - 255,255,103,103,103,103,103,103,103,103,103,178,178,178,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,246,246,246,255,255,255,103,103,103,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,178,178,178,103,103,103,103,103,103,213,213,213,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,246,246,246,255,255,255,103,103,103,0,0,0,178,178,178,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,103,103,103,178,178,178,255,255,255,178,178,178,103,103,103,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,255,255,255,145,145,145,103,103,103,255,255,255,255,255,255,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,246,246,246,255,255,255,103,103,103,70,70,70,0,0,0,37,37,37,255,255,255,246,246,246,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,246,246,246,255,255,255,103,103,103,103,103,103,103,103,103,178,178,178,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,246,246,246,255,255,255,103,103,103,0,0,0,2,2,2,178,178,178,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,246,246,246,255,255,255,103,103,103,0,0,0,70,70,70,255,255,255,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,255,255,255,103,103,103,145,145,145,255,255,255,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,103,103,103,103,103,103,255,255,255,255,255,255,178,178,178,255,255,255,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,145,145,145,0,0,0,0,0,0,0,0,0,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255, - 255,255,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,37,37,37,0,0,0,70,70,70,255,255,255,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,246,246,246,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,145,145,145,178,178,178,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,213,213,213,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,37,37,37,246,246,246,255,255,255,2,2,2,213,213,213,255,255,255,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,246,246,246,103,103,103,103,103,103,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,178,178,178,103,103,103,103,103,103,255,255,255,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255, - 255,255,178,178,178,103,103,103,255,255,255,213,213,213,70,70,70,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,178,178,178,103,103,103,255,255,255,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,2,2,2,0,0,0,0,0,0,103,103,103,103,103,103,103,103,103,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,178,178,178,103,103,103,103,103,103,255,255,255,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,255,255,255,213,213,213,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,213,213,213,2,2,2,178,178,178,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,246,246,246,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,2,2,2,246,246,246,255,255,255,0,0,0,246,246,246,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,2,2,2,0,0,0,255,255,255,213,213,213,246,246,246,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,37,37,37,255,255,255,178,178,178,37,37,37,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255, - 255,255,255,255,255,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,70,70,70,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,246,246,246,255,255,255,178,178,178,145,145,145,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,70,70,70,255,255,255,70,70,70,145,145,145,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,0,0,0,2,2,2,213,213,213,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,145,145,145,103,103,103,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,213,213,213,0,0,0,0,0,0,0,0,0,213,213,213,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246, - 246,246,213,213,213,0,0,0,70,70,70,255,255,255,37,37,37,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,213,213,213,0,0,0,70,70,70,255,255,255,37,37,37,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,213,213,213,0,0,0,0,0,0,70,70,70,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,246,246,246,145,145,145,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,213,213,213,246,246,246,103,103,103,255,255,255,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,213,213,213,213,213,213,255,255,255,0,0,0,70,70,70,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,255,255,255,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,70,70,70,0,0,0,0,0,0,37,37,37,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145, - 145,145,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,213,213,213,0,0,0,0,0,0,37,37,37,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,0,0,0,0,0,0,0,0,0,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,37,37, - 37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,0,0,0,2,2,2,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,246,246,246,2,2,2,103,103,103,246,246,246,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,255,255,255,213,213,213,0,0,0,0,0,0,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,246,246,246,103,103,103,103,103,103,246,246,246,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,213,213,213,255,255,255,255,255,255,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,213,213,213,255,255,255,103,103,103,103,103,103,103,103,103,255,255,255,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,178,178,178,103,103,103,255,255,255,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,213,213,213,255,255,255,103,103,103,103,103,103,103,103,103,246,246,246,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,213, - 213,213,255,255,255,103,103,103,103,103,103,103,103,103,103,103,103,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,213,213,213,255,255,255,103,103,103,103,103,103,103,103,103,103,103,103,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,255,255,255,103,103,103,255,255,255,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,255,255,255,103,103,103,0,0,0,103,103,103,255,255,255,246,246,246,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,103,103,103,103,103,103,255,255,255,246,246,246,103,103,103,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,103,103,103,103,103,103,255,255,255,246,246, - 246,103,103,103,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,213,213,213,255,255,255,103,103,103,103,103,103,0,0,0,255,255,255,255,255,255,145,145,145,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,213,213,213,255,255,255,103,103,103,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,255,255,255,255,255,255,2,2,2,0,0,0,255,255,255,255,255,255,246,246,246,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,255,255,255,255,255,255,70,70,70,0,0,0,103,103,103,255,255,255,246,246,246,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,255,255,255,145,145,145,103,103,103,255,255,255,255,255,255,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,246,246,246,255,255,255,255,255,255,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,255,255,255,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,255,255,255,255,255,255,255,255,255,246,246,246,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,255, - 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,255,255,255,255,255,255,255,255,255,246,246,246,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,70,70,70,246,246,246,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255, - 255,255,255,255,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,255,255,255,255,255,255,255,255,255,255,255,255,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,255,255,255,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,2,2,2,0,0,0,103,103,103,255,255,255,255,255,255,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,0,0,0,2,2,2,255,255,255,255,255,255,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,255,255,255,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,255,255,255,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,255,255,255,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,255,255,255,255,255,255,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255, - 255,255,255,255,255,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,246,246,246,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,145,145,145,255,255,255,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,103,103,103,178,178,178,255,255,255,178,178,178,103,103,103,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,255,255,255,255,255,255,103,103,103,178,178,178,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,255,255,255,103,103,103,103,103,103,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,178,178,178,255,255,255,178,178,178,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,213, - 213,213,103,103,103,145,145,145,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,103,103,103,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,255,255,255,103,103,103,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,103,103,103,145,145,145,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,255,255,255,103,103,103,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,37,37,37,0,0,0,2,2,2,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,255,255,255,246,246,246,0,0,0,103,103,103,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,37,37,37,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,213,213,213,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,37,37,37,0,0,0,0,0,0,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,255,255,255,103,103,103,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,255,255,255,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,103,103,103,103,103,103,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,246,246,246,37,37,37,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,246,246,246,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,145,145,145,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,213,213,213,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,0,0,0,145,145,145,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255, - 255,255,213,213,213,103,103,103,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,178,178,178,213,213,213,255,255,255,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,178,178,178,213,213,213,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,255,255,255,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,255,255,255,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,255,255,255,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246, - 246,246,255,255,255,255,255,255,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,246,246,246,255,255,255,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,255,255,255,0,0,0,0,0,0,178,178,178,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,255,255,255,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,246,246,246,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,178,178,178,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,103,103,103,0,0,0,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,246,246,246,0,0,0,0,0,0,2,2,2,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,246,246,246,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145, - 145,145,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,103,103,103,0,0,0,0,0,0,37,37,37,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,37,37,37,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,0,0,0,0,0,0,37,37,37,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,246,246,246,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,103,103,103,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,246,246,246,103,103,103,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,213,213,213,103,103,103,213,213,213,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37, - 37,37,255,255,255,103,103,103,103,103,103,103,103,103,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,255,255,255,103,103,103,103,103,103,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,255,255,255,103,103,103,103,103,103,103,103,103,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,246,246,246,103,103,103,213,213,213,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,103,103,103,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,255,255,255,213,213,213,103,103,103,103,103,103,255,255,255,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,213,213,213,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,213,213,213,255,255,255,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,213,213,213,255,255,255,255,255,255,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,255,255,255,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,255,255,255,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,246,246,246,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,70,70,70,0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,213,213,213,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,213,213,213,246,246,246,255,255,255,255,255,255,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,70,70,70,255,255,255,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,246,246,246,178,178,178,255,255,255,255,255,255,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,0,0,0,0,0,0,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,255,255,255,246,246,246,246,246,246,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,246,246,246,213,213,213,37,37,37,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,145,145,145,213,213,213,255,255,255,255,255,255,103,103,103,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,178, - 178,178,0,0,0,0,0,0,213,213,213,213,213,213,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,2,2,2,178,178,178,255,255,255,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,178,178,178,255,255,255,178,178,178,103,103,103,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,145,145,145,255,255,255,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103, - 103,103,255,255,255,178,178,178,0,0,0,246,246,246,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,0,0,0,0,0,0,103,103,103,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,246,246,246,246,246,246,255,255,255,255,255,255,246,246,246,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,178,178,178,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,255,255,255,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,2,2,2,178,178,178,255,255,255,103,103,103,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,255,255,255,213,213,213,37,37,37,255,255,255,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,213,213,213,255,255,255,37,37, - 37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,255,255,255,0,0,0,213,213,213,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,255,255,255,103,103,103,213,213,213,255,255,255,145,145,145,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255, - 255,255,255,255,255,145,145,145,0,0,0,213,213,213,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,37,37,37,103,103,103,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,145,145,145,70,70,70,2,2,2,213,213,213,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255, - 255,255,0,0,0,255,255,255,2,2,2,0,0,0,2,2,2,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,103,103,103,246,246,246,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,255,255,255,255,255,255,255,255,255,255,255,255,255,255, - 255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,145,145,145,103,103,103,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255, - 255,255,37,37,37,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,2,2,2,255,255,255,145,145,145,70,70, - 70,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,255,255,255,2,2,2,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,70,70,70,0,0,0,246,246,246,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70, - 70,70,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,255,255,255,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,213,213,213,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,0,0,0,0,0,0,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,145,145,145,145,145,145,255,255,255,255,255,255,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,178,178,178,0,0,0,0,0,0,103,103,103,255,255,255,255,255,255,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,255,255,255,255,255,255,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,255,255,255,255,255,255,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,37,37,37,255,255,255,255,255,255,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,178,178,178,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,178,178,178,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,246,246,246,255,255, - 255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,246,246,246,255,255,255,255,255,255,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,2,2,2,255,255,255,255,255,255,178,178,178,0,0,0,0,0,0,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,255,255,255,103,103,103,0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,255,255,255,103,103,103,0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37, - 37,37,255,255,255,103,103,103,0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,37,37,37,103,103,103,213,213,213,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,37,37,37,103,103,103,213,213,213,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,0,0,0,0,0,0,0,0, - 0,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,213,213,213,0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,37,37,37,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,178,178,178,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,2,2,2,178,178,178,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255, - 255,255,246,246,246,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,2,2,2,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,2,2,2,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,213,213,213,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0, - 0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,37,37,37,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,255,255,255,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,0,0,0,70,70,70,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,246,246,246,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,246,246,246,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255, - 255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,145,145,145,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0, - 0,246,246,246,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,2,2,2,255,255,255,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,213,213,213,246,246,246,103,103,103,0,0,0,0,0,0,178,178,178,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,255,255,255,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255, - 255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,0,0,0,0,0,0,246,246,246,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0, - 0,246,246,246,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,103,103,103,246,246,246,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,255,255,255,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,246,246,246,246,246,246,246,246,246,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,2,2,2,2,2,2,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,70,70,70,103,103,103,255,255,255,246,246,246,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255, - 255,255,246,246,246,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,246,246,246,0,0,0,0,0,0,37,37,37,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0, - 0,246,246,246,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,213,213,213,246,246,246,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,255,255,255,246,246,246,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,145,145,145,246,246,246,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,0,0,0,70,70,70,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,178,178,178,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,255,255,255,103,103,103,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,103,103,103,255,255,255,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,255,255,255,103,103,103,0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,255,255,255,103,103,103,0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37, - 37,37,255,255,255,103,103,103,0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0, - 0,246,246,246,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,255,255,255,103,103,103,0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,255,255,255,37,37,37,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,255,255,255,255,255,255,145,145,145,255,255,255,255,255,255,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,178,178,178,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,255,255,255,255,255,255,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,255,255,255,255,255,255,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,37,37,37,255,255,255,255,255,255,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0, - 0,246,246,246,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,255,255,255,255,255,255,255,255,255,213,213,213,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,213,213,213,0,0,0,0,0,0,37,37,37,255,255,255,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0, - 0,246,246,246,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,246,246,246,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,178,178,178,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,255,255,255,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,37,37,37,0,0,0,0,0,0,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,70,70,70,0,0,0,2,2,2,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,0,0,0,0,0,0,37,37,37,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,0,0,0,0,0,0,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,178,178,178,0,0,0,0,0,0,178,178,178,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0, - 0,246,246,246,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,178,178,178,0,0,0,0,0,0,178,178,178,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,246,246,246,246,246,246,246,246,246,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,145,145,145,0,0,0,70,70,70,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,178,178,178,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,255,255,255,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,0,0,0,0,0,0,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,255,255,255,255,255,255,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,70,70,70,0,0,0,0,0,0,0,0, - 0,145,145,145,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,255,255,255,255,255,255,213,213,213,145,145,145,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,70,70,70,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,0,0,0,0,0,0,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,0,0,0,0,0,0,2,2, - 2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,0,0,0,2,2,2,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,2,2,2,0,0,0,255,255, - 255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,159,159,159,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,246,246,246,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,246,246,246,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,255,255,255,255,255,255,246,246,246,255,255,255,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,178,178,178,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,246,246,246,255,255,255,255,255,255,255,255,255,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,37,37,37,213,213,213,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,37,37,37,213,213,213,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,255,255,255,255,255,255,255,255,255,37,37,37,213,213,213,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,37,37,37,213,213,213,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,255,255,255,255,255,255,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,246,246,246,255,255,255,255,255,255,255,255,255,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,246,246,246,255,255,255,255,255,255,255,255,255,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,246,246,246,255,255,255,255,255,255,255,255, - 255,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,255,255,255,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,37,37,37,103,103,103,213,213,213,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,246,246,246,0,0,0,0,0,0,213,213,213,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,246,246,246,0,0,0,0,0,0,213,213,213,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255, - 255,255,246,246,246,0,0,0,0,0,0,213,213,213,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,246,246,246,0,0,0,0,0,0,213,213,213,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,255,255,255,178,178,178,0,0,0,0,0,0,0,0, - 0,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,2,2,2,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,2,2,2,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,2,2,2,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255, - 255,255,103,103,103,0,0,0,0,0,0,2,2,2,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,2,2,2,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,178,178,178,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,37,37,37,0,0,0,2,2,2,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,37,37,37,0,0,0,2,2,2,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103, - 103,103,255,255,255,37,37,37,0,0,0,2,2,2,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,37,37,37,0,0,0,2,2,2,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,178,178,178,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,178,178,178,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,178,178,178,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,246,246,246,246,246,246,246,246,246,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,178,178,178,246,246,246,255,255,255,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,178,178,178,246,246,246,255,255,255,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,2,2,2,178,178,178,246,246,246,255,255,255,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,178,178,178,246,246,246,255,255,255,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,246,246,246,246,246,246,246,246,246,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,246,246,246,246,246,246,246,246,246,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,246,246,246,246,246,246,246,246,246,255,255, - 255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,178,178,178,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,178,178,178,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,178,178,178,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,178,178,178,0,0,0,0,0,0,0,0,0,145,145, - 145,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,0,0,0,0,0,0,145,145,145,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,0,0,0,0,0,0,145,145,145,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,70,70,70,0,0,0,0,0,0,145,145,145,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,0,0,0,0,0,0,145,145,145,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,255,255, - 255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,145,145,145,0,0,0,255,255,255,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,145,145,145,0,0,0,255,255,255,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,255,255,255,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,255,255,255,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,255,255,255,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,213,213,213,255,255,255,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,255,255,255,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,255,255,255,255,255,255,255,255,255,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,255,255,255,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,255,255,255,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,255,255,255,255,255,255,178,178, - 178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,0,0,0,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,0,0,0,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,70,70,70,0,0,0,0,0,0,2,2,2,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,0,0,0,0,0,0,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,37,37,37,0,0,0,0,0,0,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,70,70,70,0,0,0,2,2,2,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,37,37,37,0,0,0,0,0,0,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,0,0,0,0,0,0,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,2,2,2,0,0,0,70,70,70,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,0,0,0,0,0,0,37,37,37,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,255,255,255,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,255,255,255,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,246,246,246,255,255,255,255,255,255,255,255,255,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,0,0,0,0,0,0,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,145,145,145,0,0,0,70,70,70,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,0,0,0,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,0,0,0,0,0,0,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,246,246,246,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,70,70,70,0,0,0,145,145,145,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,255,255,255,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,246,246,246,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,145,145,145,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,246,246,246,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,0,0,0,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,103,103,103,0,0,0,246,246,246,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,103,103,103,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,246,246,246,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,246,246,246,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,145,145,145,213,213,213,255,255,255,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,255,255,255,70,70,70,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,255,255,255,255,255,255,255,255,255,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,255,255,255,255,255,255,178,178,178,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,0,0,0,0,0,0,0,0,0,255,255,255,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, - 255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,2,2,2,0,0,0,103,103,103,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,103,103,103,37,37,37,246,246,246,246,246,246,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,255,255,255,255,255,255,37,37,37,103,103,103,213,213,213,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,255,255,255,70,70,70,0,0,0,37,37,37,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,145,145,145,0,0,0,0,0,0,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,213,213,213,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,213,213,213,0,0,0,0,0,0,0,0,0,213,213,213,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,255,255,255,103,103,103,0,0,0,0,0,0,2,2,2,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,255,255,255,145,145,145,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,213,213,213,0,0,0,145,145,145,145,145,145,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,70,70,70,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,213,213,213,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,0,0,0,255,255,255,0,0,0,255,255,255,37,37,37,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,145,145,145,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,255,255,255,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,103,103,103,255,255,255,145,145,145,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,0,0,0,0,0,0,246,246,246,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,255,255,255,0,0,0,246,246,246,0,0,0,255,255,255,0,0,0,213,213,213,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,0,0,0,0,0,0,246,246,246,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,246,246,246,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,213,213,213,0,0,0,0,0,0,0,0,0,213,213,213,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,213,213,213,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,178,178,178,0,0,0,0,0,0,70,70,70,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,213,213,213,0,0,0,103,103,103,246,246,246,255,255,255,0,0,0,103,103,103,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,213,213,213,246,246,246,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,246,246,246,0,0,0,0,0,0,37,37,37,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,178,178, - 178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,246,246,246,255,255,255,37,37,37,103,103,103,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,255,255,255,103,103,103,0,0,0,2,2,2,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,246,246,246,255,255,255,70,70,70,103,103,103,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,0,0,0,0,0,0,0,0,0,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,103,103,103,0,0,0,0,0,0,255,255,255,145,145,145,0,0,0,2,2,2,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255, - 255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,70,70,70,255,255,255,255,255,255,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,255,255,255,255,255,255,246,246,246,70,70,70,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,37,37,37,255,255,255,255,255,255,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,37,37,37,0,0,0,0,0,0,2,2,2,0,0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,0,0,0,0,0,0,0,0,0,37,37,37,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,255,255,255,255,255,255,255,255,255,255,255,255,255,255, - 255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,103,103,103,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,103,103,103,255,255,255,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,103,103,103,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,103,103,103,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,255,255,255,255,255,255,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,255,255,255,255,255,255,255,255,255,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,0,0,0,0,0,0,103,103,103,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,0,0,0,0,0,0,213,213,213,255,255,255,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,2,2, - 2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,37,37,37,213,213,213,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,255,255,255,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,246,246,246,255,255,255,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,255,255,255,0,0,0,246,246,246,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,37,37,37,246,246,246,255,255,255,255,255,255,255,255,255,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,255,255,255,70,70,70,246,246,246,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,2,2, - 2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,2,2,2,0,0,0,246,246,246,103,103,103,0,0,0,103,103,103,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,255,255,255,255,255,255,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,246,246,246,0,0,0,0,0,0,213,213,213,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,37,37,37,0,0,0,2,2,2,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,103,103,103,37,37,37,246,246,246,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37, - 37,37,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,103,103,103,37,37,37,255,255,255,246,246,246,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,2,2, - 2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,2,2,2,0,0,0,246,246,246,103,103,103,0,0,0,103,103,103,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,255,255,255,103,103,103,0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,2,2,2,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,213,213,213,0,0,0,0,0,0,0,0,0,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255, - 255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,213,213,213,0,0,0,0,0,0,0,0,0,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,2,2, - 2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,2,2,2,0,0,0,246,246,246,103,103,103,0,0,0,103,103,103,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,37,37,37,0,0,0,2,2,2,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,246,246,246,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255, - 255,255,178,178,178,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,246,246,246,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,2,2, - 2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,145,145,145,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,2,2,2,0,0,0,246,246,246,103,103,103,0,0,0,103,103,103,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,178,178,178,246,246,246,255,255,255,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,246,246,246,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255, - 255,255,255,255,255,246,246,246,246,246,246,246,246,246,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,246,246,246,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,2,2, - 2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,213,213,213,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,2,2,2,0,0,0,246,246,246,103,103,103,0,0,0,103,103,103,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,213,213,213,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,213,213,213,0,0,0,0,0,0,0,0,0,246,246,246,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213, - 213,213,178,178,178,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,213,213,213,0,0,0,0,0,0,0,0,0,246,246,246,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,2,2, - 2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,37,37,37,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,246,246,246,246,246,246,0,0,0,103,103,103,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,0,0,0,0,0,0,145,145,145,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,246,246,246,255,255,255,37,37,37,70,70,70,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,255,255,255,70,70,70,0,0,0,103,103,103,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,255,255,255,103,103,103,0,0,0,0,0,0,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,255,255,255,2,2,2,0,0,0,103,103,103,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,246,246,246,246,246,246,2,2,2,145,145,145,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,2,2, - 2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,70,70,70,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,246,246,246,70,70,70,255,255,255,246,246,246,178,178,178,213,213,213,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,246,246,246,246,246,246,2,2,2,145,145,145,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,255,255,255,103,103,103,0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,255,255,255,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,37,37,37,255,255,255,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,255,255,255,255,255,255,255,255,255,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,255,255,255,145,145,145,246,246,246,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,2,2,2,255,255,255,255,255,255,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,255,255,255,178,178,178,145,145,145,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,37,37,37,255,255,255,255,255,255,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,255,255,255,255,255,255,255,255,255,2,2, - 2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,2,2,2,246,246,246,255,255,255,0,0,0,178,178,178,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,37,37,37,255,255,255,255,255,255,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,255,255,255,255,255,255,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,255,255,255,246,246,246,103,103,103,103,103,103,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,2,2, - 2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,103,103,103,103,103,103,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,103,103,103,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,246,246,246,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,103,103,103,103,103,103,103,103,103,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,246,246,246,246,246,246,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,246,246,246,246,246,246,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,37,37,37,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,246,246,246,246,246,246,255,255,255,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,255,255,255,255,255,255,246,246,246,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,37,37,37,0,0,0,145,145,145,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, - 255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,255,255,255,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,178,178,178,255,255,255,0,0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,255,255,255,103,103,103,0,0,0,246,246,246,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,255,255,255,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,246,246,246,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,178,178,178,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,213,213,213,246,246,246,0,0,0,255,255,255,213,213,213,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,0,0,0,0,0,0,178,178,178,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,246,246,246,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,37,37,37,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,246,246,246,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,37,37,37,255,255,255,0,0,0,255,255,255,2,2,2,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,255,255,255,2,2,2,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,255,255,255,103,103,103,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,246,246,246,103,103,103,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,178,178,178,2,2,2,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,246,246,246,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,246,246,246,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,0,0,0,255,255,255,103,103,103,255,255,255,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,255,255,255,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,70,70,70,0,0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,246,246,246,103,103,103,145,145,145,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,246,246,246,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,246,246,246,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,70,70,70,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,0,0,0,246,246,246,255,255,255,178,178,178,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,246,246,246,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,178,178,178,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,255,255,255,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,178,178,178,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,246,246,246,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,0,0,0,0,0,0,0,0,0,255,255,255,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,103,103,103,255,255,255,103,103,103,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,37,37,37,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,37,37, - 37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,70,70,70,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,246,246,246,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,213,213,213,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,246,246,246,0,0,0,2,2,2,246,246,246,0,0,0,0,0,0,246,246,246,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,255,255,255,0,0,0,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,246,246,246,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,255,255, - 255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,178,178,178,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,246,246,246,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,103,103,103,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,0,0,0,0,0,0,0,0,0,255,255,255,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255, - 255,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,178,178,178,2,2,2,2,2,2,103,103,103,255,255,255,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,178,178,178,0,0,0,0,0,0,178,178,178,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,178,178,178,2,2,2,37,37,37,213,213,213,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,213,213,213,0,0,0,0,0,0,0,0,0,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,178,178,178,255,255,255,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,246,246,246,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,255,255,255,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,178,178, - 178,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,246,246,246,246,246,246,246,246,246,213,213,213,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,255,255,255,255,255,255,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,246,246,246,246,246,246,246,246,246,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,255,255,255,255,255,255,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,246,246,246,70,70,70,0,0,0,0,0,0,0,0,0,145,145,145,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,246,246,246,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,246,246,246,246,246,246,246,246,246,246,246,246,246,246, - 246,246,246,246,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,246,246,246,103,103,103,103,103,103,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,103,103,103,103,103,103,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,103,103,103,103,103,103,103,103,103,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,103,103,103,103,103,103,103,103,103,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,255,255,255,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,255,255,255,246,246,246,255,255,255,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,255,255,255,246,246,246,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,37,37, - 37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,246,246,246,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,178,178,178,0,0,0,0,0,0,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,2,2,2,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,213,213,213,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,2,2,2,0,0,0,0,0,0,246,246,246,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255, - 255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,103,103,103,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,103,103,103,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,213,213,213,0,0,0,0,0,0,103,103,103,0,0,0,70,70,70,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,246,246,246,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,255,255,255,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255, - 255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,2,2,2,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,255,255,255,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,145,145,145,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,2,2,2,0,0,0,255,255,255,178,178,178,178,178,178,246,246,246,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255, - 255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,255,255,255,213,213,213,0,0,0,103,103,103,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,103,103,103,255,255,255,246,246,246,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,0,0,0,2,2,2,255,255,255,0,0,0,178,178,178,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,246,246,246,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,178,178,178,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255, - 255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,246,246,246,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,0,0,0,70,70,70,255,255,255,255,255,255,0,0,0,103,103,103,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,255,255,255,246,246,246,103,103,103,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,0,0,0,2,2,2,246,246,246,0,0,0,0,0,0,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,255,255,255,255,255,255,246,246,246,246,246,246,246,246,246,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,246,246,246,246,246,246,246,246,246,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255, - 255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,0,0,0,213,213,213,178,178,178,255,255,255,70,70,70,103,103,103,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,103,103,103,255,255,255,2,2,2,103,103,103,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,145,145,145,0,0,0,255,255,255,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,255,255,255,178,178,178,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255, - 255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,246,246,246,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,0,0,0,255,255,255,2,2,2,103,103,103,213,213,213,103,103,103,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,255,255,255,178,178,178,0,0,0,103,103,103,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,103,103,103,0,0,0,145,145,145,103,103,103,0,0,0,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,0,0,0,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255, - 255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,255,255,255,0,0,0,0,0,0,255,255,255,103,103,103,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,103,103,103,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,246,246,246,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,0,0,0,0,0,0,103,103,103,246,246,246,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,255,255,255,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255, - 255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,37,37,37,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,145,145,145,0,0,0,0,0,0,255,255,255,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,178,178,178,0,0,0,0,0,0,103,103,103,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,0,0,0,0,0,0,2,2,2,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,255,255,255,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,178,178,178,2,2,2,37,37,37,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,70,70,70,0,0,0,0,0,0,2,2,2,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,178,178,178,2,2,2,70,70,70,246,246,246,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,255,255,255,178,178,178,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,178,178,178,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,178,178,178,255,255,255,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,103,103,103,255,255, - 255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,178,178,178,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,103,103,103,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,178,178,178,0,0,0,0,0,0,178,178,178,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,255,255,255,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,246,246,246,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,246,246,246,246,246,246,246,246,246,213,213,213,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,246,246,246,255,255,255,255,255,255,255,255,255,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,246,246,246,246,246,246,246,246,246,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,246,246,246,255,255,255,255,255,255,255,255,255,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,70,70,70,0,0,0,0,0,0,0,0,0,246,246,246,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,246,246,246,246,246,246,246,246, - 246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,70,70,70,0,0,0,0,0,0,0,0,0,213,213,213,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,103,103,103,0,0,0,0,0,0,0,0,0,70,70,70,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,255,255,255,255,255,255,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,246,246,246,255,255,255,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,246,246,246,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,255,255,255,246,246,246,255,255,255,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,246,246,246,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,246,246,246,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,246,246,246,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,2,2, - 2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,2,2,2,0,0,0,0,0,0,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,255,255,255,0,0,0,0,0,0,0,0,0,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,2,2, - 2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,178,178,178,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,246,246,246,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,145,145,145,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,0,0,0,103,103,103,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,246,246,246,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,37,37,37,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,213,213,213,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,255,255,255,0,0,0,0,0,0,255,255,255,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,255,255,255,246,246,246,255,255,255,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,246,246,246,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,70,70,70,103,103,103,246,246,246,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,2,2,2,0,0,0,103,103,103,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,255,255,255,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,246,246,246,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,37,37,37,246,246,246,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,246,246,246,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,246,246,246,246,246,246,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,37,37,37,213,213,213,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,178,178,178,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,2,2, - 2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,178,178,178,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,103,103,103,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,246,246,246,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,103,103,103,0,0,0,0,0,0,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,2,2, - 2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,178,178,178,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,178,178,178,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,246,246,246,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,246,246,246,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,213,213,213,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,246,246,246,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,2,2,2,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,178,178,178,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,0,0,0,0,0,0,2,2,2,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,246,246,246,246,246,246,103,103,103,103,103,103,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,178,178,178,0,0,0,0,0,0,0,0,0,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,103,103,103,103,103,103,103,103,103,145,145,145,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,70,70,70,0,0,0,2,2,2,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,255,255,255,2,2,2,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,145,145,145,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,213,213,213,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,255,255,255,255,255,255,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,255,255,255,255,255,255,255,255,255,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,145,145,145,246,246,246,246,246,246,246,246,246,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,255,255,255,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,255,255,255,255,255,255,255,255,255,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,255,255,255,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,255,255,255,255,255,255,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,0,0,0,70,70,70,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,255,255,255,255,255,255,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,178, - 178,178,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,255,255,255,255,255,255,103,103,103,145,145,145,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,2,2,2,0,0,0,255,255,255,0,0,0,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246, - 246,246,37,37,37,0,0,0,37,37,37,246,246,246,0,0,0,2,2,2,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,103,103,103,0,0,0,0,0,0,246,246,246,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,103,103,103,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,0,0,0,246,246,246,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,255,255,255,0,0,0,103,103,103,103,103,103,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,246,246,246,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,255,255,255,255,255,255,246,246,246,255,255,255,255,255,255,246,246,246,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,0,0,0,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,70,70,70,246,246,246,37,37,37,246,246,246,0,0,0,2,2,2,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,246,246,246,255,255,255,0,0,0,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,246,246,246,246,246,246,255,255,255,255,255,255,246,246,246,246,246,246,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,2,2,2,103,103,103,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,213,213,213,103,103,103,145,145,145,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,246,246,246,0,0,0,70,70,70,255,255,255,2,2,2,0,0,0,246,246,246,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,255,255,255,103,103,103,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,37,37,37,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,2,2,2,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,213,213,213,255,255,255,246,246,246,0,0,0,0,0,0,145,145,145,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,70,70,70,0,0,0,255,255, - 255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,246,246,246,246,246,246,103,103,103,255,255,255,178,178,178,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255, - 255,255,145,145,145,255,255,255,37,37,37,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,255,255,255,145,145,145,178,178, - 178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,0,0,0,0,0,0,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,103,103,103,255,255,255,103,103,103,213,213,213,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,255,255,255,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,0, - 0,0,0,0,0,255,255,255,255,255,255,145,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,2,2,2,0,0,0,70,70, - 70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,2,2,2,0,0,0,103,103,103,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,255,255,255,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,0, - 0,0,0,0,0,103,103,103,103,103,103,0,0,0,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,103,103,103,2,2,2,70,70,70,70,70, - 70,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,70,70,70,0,0,0,178,178,178,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,70,70,70,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,255,255,255,103,103,103,255,255,255,2,2,2,103,103,103,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,213,213,103, - 103,103,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,213,213,213,0,0,0,255,255,255,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,178,178,178,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,103,103,103,0,0,0,246,246,246,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,103,103,103,0,0,0,103,103,103,37,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,213,213,213,255,255,255,246,246,246,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178, - 178,178,246,246,246,37,37,37,0,0,0,0,0,0,0,0,0,103,103,103,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,178,178,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,255,255,255,255,255,255,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,178,178,178,255,255,255,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,145,145,145,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,70,70,70,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,2,2,2,0,0,0,70,70,70,70,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,246,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,37,37,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,70,70,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -}; diff --git a/Extras/RigidBodyGpuPipeline/dynamics/testbed/GLDebugFont.h b/Extras/RigidBodyGpuPipeline/dynamics/testbed/GLDebugFont.h deleted file mode 100644 index bf2c2575d..000000000 --- a/Extras/RigidBodyGpuPipeline/dynamics/testbed/GLDebugFont.h +++ /dev/null @@ -1,29 +0,0 @@ -/* -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_DEBUG_FONT_H -#define BT_DEBUG_FONT_H - -#include "LinearMath/btVector3.h" - - -void GLDebugDrawStringInternal(int x,int y,const char* string,const btVector3& rgb, bool enableBlend, int spacing); -void GLDebugDrawStringInternal(int x,int y,const char* string,const btVector3& rgb); -void GLDebugDrawString(int x,int y,const char* string); -void GLDebugResetFont(int screenWidth,int screenHeight); - -#endif //BT_DEBUG_FONT_H - diff --git a/Extras/RigidBodyGpuPipeline/dynamics/testbed/GL_ShapeDrawer.cpp b/Extras/RigidBodyGpuPipeline/dynamics/testbed/GL_ShapeDrawer.cpp deleted file mode 100644 index 7beb19f05..000000000 --- a/Extras/RigidBodyGpuPipeline/dynamics/testbed/GL_ShapeDrawer.cpp +++ /dev/null @@ -1,1058 +0,0 @@ -/* -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. -*/ - -#ifdef _WIN32 //needed for glut.h -#include -#endif -#include "GLDebugFont.h" - - - -#include "GlutStuff.h" -#include "GL_ShapeDrawer.h" -#include "BulletCollision/CollisionShapes/btPolyhedralConvexShape.h" -#include "BulletCollision/CollisionShapes/btTriangleMeshShape.h" -#include "BulletCollision/CollisionShapes/btBoxShape.h" -#include "BulletCollision/CollisionShapes/btSphereShape.h" -#include "BulletCollision/CollisionShapes/btConeShape.h" -#include "BulletCollision/CollisionShapes/btCylinderShape.h" -#include "BulletCollision/CollisionShapes/btTetrahedronShape.h" -#include "BulletCollision/CollisionShapes/btCompoundShape.h" -#include "BulletCollision/CollisionShapes/btCapsuleShape.h" -#include "BulletCollision/CollisionShapes/btConvexTriangleMeshShape.h" -#include "BulletCollision/CollisionShapes/btUniformScalingShape.h" -#include "BulletCollision/CollisionShapes/btStaticPlaneShape.h" -#include "BulletCollision/CollisionShapes/btMultiSphereShape.h" -#include "BulletCollision/CollisionShapes/btConvexPolyhedron.h" - - -/// -#include "BulletCollision/CollisionShapes/btShapeHull.h" - -#include "LinearMath/btTransformUtil.h" - - -#include "LinearMath/btIDebugDraw.h" -//for debugmodes - -#include //printf debugging - -//#define USE_DISPLAY_LISTS 1 -#ifdef USE_DISPLAY_LISTS - -#include - -using namespace std; - -//Set for storing Display list per trimesh -struct TRIMESH_KEY -{ - btCollisionShape* m_shape; - GLuint m_dlist;//OpenGL display list -}; - -typedef map TRIMESH_KEY_MAP; - -typedef pair TRIMESH_KEY_PAIR; - -TRIMESH_KEY_MAP g_display_lists; - -class GlDisplaylistDrawcallback : public btTriangleCallback -{ -public: - - virtual void processTriangle(btVector3* triangle,int partId, int triangleIndex) - { - - btVector3 diff1 = triangle[1] - triangle[0]; - btVector3 diff2 = triangle[2] - triangle[0]; - btVector3 normal = diff1.cross(diff2); - - normal.normalize(); - - glBegin(GL_TRIANGLES); - glColor3f(1, 1, 1); - glNormal3d(normal.getX(),normal.getY(),normal.getZ()); - glVertex3d(triangle[0].getX(), triangle[0].getY(), triangle[0].getZ()); - - //glColor3f(0, 1, 0); - glNormal3d(normal.getX(),normal.getY(),normal.getZ()); - glVertex3d(triangle[1].getX(), triangle[1].getY(), triangle[1].getZ()); - - //glColor3f(0, 1, 0); - glNormal3d(normal.getX(),normal.getY(),normal.getZ()); - glVertex3d(triangle[2].getX(), triangle[2].getY(), triangle[2].getZ()); - glEnd(); - - /*glBegin(GL_LINES); - glColor3f(1, 1, 0); - glNormal3d(normal.getX(),normal.getY(),normal.getZ()); - glVertex3d(triangle[0].getX(), triangle[0].getY(), triangle[0].getZ()); - glNormal3d(normal.getX(),normal.getY(),normal.getZ()); - glVertex3d(triangle[1].getX(), triangle[1].getY(), triangle[1].getZ()); - glColor3f(1, 1, 0); - glNormal3d(normal.getX(),normal.getY(),normal.getZ()); - glVertex3d(triangle[2].getX(), triangle[2].getY(), triangle[2].getZ()); - glNormal3d(normal.getX(),normal.getY(),normal.getZ()); - glVertex3d(triangle[1].getX(), triangle[1].getY(), triangle[1].getZ()); - glColor3f(1, 1, 0); - glNormal3d(normal.getX(),normal.getY(),normal.getZ()); - glVertex3d(triangle[2].getX(), triangle[2].getY(), triangle[2].getZ()); - glNormal3d(normal.getX(),normal.getY(),normal.getZ()); - glVertex3d(triangle[0].getX(), triangle[0].getY(), triangle[0].getZ()); - glEnd();*/ - - - } -}; - -GLuint OGL_get_displaylist_for_shape(btCollisionShape * shape) -{ - TRIMESH_KEY_MAP::iterator map_iter; - - unsigned long key = (unsigned long)shape; - map_iter = g_display_lists.find(key); - if(map_iter!=g_display_lists.end()) - { - return map_iter->second.m_dlist; - } - - return 0; -} - -void OGL_displaylist_clean() -{ - TRIMESH_KEY_MAP::iterator map_iter,map_itend; - - map_iter = g_display_lists.begin(); - - while(map_iter!=map_itend) - { - glDeleteLists(map_iter->second.m_dlist,1); - map_iter++; - } - - g_display_lists.clear(); -} - - -void OGL_displaylist_register_shape(btCollisionShape * shape) -{ - btVector3 aabbMax(btScalar(BT_LARGE_FLOAT),btScalar(BT_LARGE_FLOAT),btScalar(BT_LARGE_FLOAT)); - btVector3 aabbMin(-btScalar(BT_LARGE_FLOAT),-btScalar(BT_LARGE_FLOAT),-btScalar(BT_LARGE_FLOAT)); - GlDisplaylistDrawcallback drawCallback; - TRIMESH_KEY dlist; - - dlist.m_dlist = glGenLists(1); - dlist.m_shape = shape; - - unsigned long key = (unsigned long)shape; - - g_display_lists.insert(TRIMESH_KEY_PAIR(key,dlist)); - - glNewList(dlist.m_dlist,GL_COMPILE); - -// glEnable(GL_CULL_FACE); - - glCullFace(GL_BACK); - - if (shape->isConcave()) - { - btConcaveShape* concaveMesh = (btConcaveShape*) shape; - //todo pass camera, for some culling - concaveMesh->processAllTriangles(&drawCallback,aabbMin,aabbMax); - } - -// glDisable(GL_CULL_FACE); - - glEndList(); -} -#endif //USE_DISPLAY_LISTS - -void GL_ShapeDrawer::drawCoordSystem() { - glBegin(GL_LINES); - glColor3f(1, 0, 0); - glVertex3d(0, 0, 0); - glVertex3d(1, 0, 0); - glColor3f(0, 1, 0); - glVertex3d(0, 0, 0); - glVertex3d(0, 1, 0); - glColor3f(0, 0, 1); - glVertex3d(0, 0, 0); - glVertex3d(0, 0, 1); - glEnd(); - -} - - - - - -class GlDrawcallback : public btTriangleCallback -{ - -public: - - bool m_wireframe; - - GlDrawcallback() - :m_wireframe(false) - { - } - - virtual void processTriangle(btVector3* triangle,int partId, int triangleIndex) - { - - (void)triangleIndex; - (void)partId; - - - if (m_wireframe) - { - glBegin(GL_LINES); - glColor3f(1, 0, 0); - glVertex3d(triangle[0].getX(), triangle[0].getY(), triangle[0].getZ()); - glVertex3d(triangle[1].getX(), triangle[1].getY(), triangle[1].getZ()); - glColor3f(0, 1, 0); - glVertex3d(triangle[2].getX(), triangle[2].getY(), triangle[2].getZ()); - glVertex3d(triangle[1].getX(), triangle[1].getY(), triangle[1].getZ()); - glColor3f(0, 0, 1); - glVertex3d(triangle[2].getX(), triangle[2].getY(), triangle[2].getZ()); - glVertex3d(triangle[0].getX(), triangle[0].getY(), triangle[0].getZ()); - glEnd(); - } else - { - glBegin(GL_TRIANGLES); - //glColor3f(1, 1, 1); - - - glVertex3d(triangle[0].getX(), triangle[0].getY(), triangle[0].getZ()); - glVertex3d(triangle[1].getX(), triangle[1].getY(), triangle[1].getZ()); - glVertex3d(triangle[2].getX(), triangle[2].getY(), triangle[2].getZ()); - - glVertex3d(triangle[2].getX(), triangle[2].getY(), triangle[2].getZ()); - glVertex3d(triangle[1].getX(), triangle[1].getY(), triangle[1].getZ()); - glVertex3d(triangle[0].getX(), triangle[0].getY(), triangle[0].getZ()); - glEnd(); - } - } -}; - -class TriangleGlDrawcallback : public btInternalTriangleIndexCallback -{ -public: - virtual void internalProcessTriangleIndex(btVector3* triangle,int partId,int triangleIndex) - { - (void)triangleIndex; - (void)partId; - - - glBegin(GL_TRIANGLES);//LINES); - glColor3f(1, 0, 0); - glVertex3d(triangle[0].getX(), triangle[0].getY(), triangle[0].getZ()); - glVertex3d(triangle[1].getX(), triangle[1].getY(), triangle[1].getZ()); - glColor3f(0, 1, 0); - glVertex3d(triangle[2].getX(), triangle[2].getY(), triangle[2].getZ()); - glVertex3d(triangle[1].getX(), triangle[1].getY(), triangle[1].getZ()); - glColor3f(0, 0, 1); - glVertex3d(triangle[2].getX(), triangle[2].getY(), triangle[2].getZ()); - glVertex3d(triangle[0].getX(), triangle[0].getY(), triangle[0].getZ()); - glEnd(); - } -}; - - -void GL_ShapeDrawer::drawSphere(btScalar radius, int lats, int longs) -{ - int i, j; - for(i = 0; i <= lats; i++) { - btScalar lat0 = SIMD_PI * (-btScalar(0.5) + (btScalar) (i - 1) / lats); - btScalar z0 = radius*sin(lat0); - btScalar zr0 = radius*cos(lat0); - - btScalar lat1 = SIMD_PI * (-btScalar(0.5) + (btScalar) i / lats); - btScalar z1 = radius*sin(lat1); - btScalar zr1 = radius*cos(lat1); - - glBegin(GL_QUAD_STRIP); - for(j = 0; j <= longs; j++) { - btScalar lng = 2 * SIMD_PI * (btScalar) (j - 1) / longs; - btScalar x = cos(lng); - btScalar y = sin(lng); - glNormal3f(x * zr1, y * zr1, z1); - glVertex3f(x * zr1, y * zr1, z1); - glNormal3f(x * zr0, y * zr0, z0); - glVertex3f(x * zr0, y * zr0, z0); - } - glEnd(); - } -} - -void GL_ShapeDrawer::drawCylinder(float radius,float halfHeight, int upAxis) -{ - - - glPushMatrix(); - switch (upAxis) - { - case 0: - glRotatef(-90.0, 0.0, 1.0, 0.0); - glTranslatef(0.0, 0.0, -halfHeight); - break; - case 1: - glRotatef(-90.0, 1.0, 0.0, 0.0); - glTranslatef(0.0, 0.0, -halfHeight); - break; - case 2: - - glTranslatef(0.0, 0.0, -halfHeight); - break; - default: - { - btAssert(0); - } - - } - - GLUquadricObj *quadObj = gluNewQuadric(); - - //The gluCylinder subroutine draws a cylinder that is oriented along the z axis. - //The base of the cylinder is placed at z = 0; the top of the cylinder is placed at z=height. - //Like a sphere, the cylinder is subdivided around the z axis into slices and along the z axis into stacks. - - gluQuadricDrawStyle(quadObj, (GLenum)GLU_FILL); - gluQuadricNormals(quadObj, (GLenum)GLU_SMOOTH); - - gluDisk(quadObj,0,radius,15, 10); - - gluCylinder(quadObj, radius, radius, 2.f*halfHeight, 15, 10); - glTranslatef(0.0f, 0.0f, 2.f*halfHeight); - glRotatef(-180.0f, 0.0f, 1.0f, 0.0f); - gluDisk(quadObj,0.f,radius,15, 10); - - glPopMatrix(); - gluDeleteQuadric(quadObj); -} - -GL_ShapeDrawer::ShapeCache* GL_ShapeDrawer::cache(btConvexShape* shape) -{ - ShapeCache* sc=(ShapeCache*)shape->getUserPointer(); - if(!sc) - { - sc=new(btAlignedAlloc(sizeof(ShapeCache),16)) ShapeCache(shape); - - m_shapecaches.push_back(sc); - shape->setUserPointer(sc); - - const btConvexPolyhedron* poly = shape->isPolyhedral() ? ((btPolyhedralConvexShape*) shape)->getConvexPolyhedron() : 0; - if (poly) - { - int i; - /* Build edges */ - const int nv= poly->m_vertices.size(); - if (nv) - { - const btVector3* pv=&poly->m_vertices[0]; - btAlignedObjectArray edges; - edges.resize(nv*nv,0); - - int maxIndices = 0; - for (i=0;im_faces.size();i++) - { - maxIndices += poly->m_faces[i].m_indices.size(); - } - sc->m_edges.reserve(maxIndices); - - for (i=0;im_faces.size();i++) - { - int numVerts = poly->m_faces[i].m_indices.size(); - if (numVerts>2) - { - int index0 = poly->m_faces[i].m_indices[0]; - int index1 = poly->m_faces[i].m_indices[1]; - int index2 = poly->m_faces[i].m_indices[2]; - int j = poly->m_faces[i].m_indices.size()-1; - const btVector3 nrm=btCross(pv[index1]-pv[index0],pv[index2]-pv[index0]).normalized(); - - for (int v=0;vm_faces[i].m_indices.size();j=v++) - { - { - const unsigned int a=poly->m_faces[i].m_indices[j]; - const unsigned int b=poly->m_faces[i].m_indices[v]; - int edgeIndex = btMin(a,b)*nv+btMax(a,b); - ShapeCache::Edge*& e=edges[edgeIndex]; - if(!e) - { - sc->m_edges.push_back(ShapeCache::Edge()); - e=&sc->m_edges[sc->m_edges.size()-1]; - e->n[0]=nrm;e->n[1]=-nrm; - e->v[0]=a;e->v[1]=b; - } - else - { - e->n[1]=nrm; - } - } - } - } - } - } - - } else - { - - sc->m_shapehull.buildHull(shape->getMargin()); - - - /* Build edges */ - const int ni=sc->m_shapehull.numIndices(); - const int nv=sc->m_shapehull.numVertices(); - const unsigned int* pi=sc->m_shapehull.getIndexPointer(); - const btVector3* pv=sc->m_shapehull.getVertexPointer(); - btAlignedObjectArray edges; - sc->m_edges.reserve(ni); - edges.resize(nv*nv,0); - for(int i=0;im_edges.push_back(ShapeCache::Edge()); - e=&sc->m_edges[sc->m_edges.size()-1]; - e->n[0]=nrm;e->n[1]=-nrm; - e->v[0]=a;e->v[1]=b; - } - else - { - e->n[1]=nrm; - } - } - } - } - } - return(sc); -} - -void renderSquareA(float x, float y, float z) -{ - glBegin(GL_LINE_LOOP); - glVertex3f(x, y, z); - glVertex3f(x + 10.f, y, z); - glVertex3f(x + 10.f, y + 10.f, z); - glVertex3f(x, y + 10.f, z); - glEnd(); -} - -inline void glDrawVector(const btVector3& v) { glVertex3d(v[0], v[1], v[2]); } - - -void GL_ShapeDrawer::drawOpenGL(btScalar* m, const btCollisionShape* shape, const btVector3& color,int debugMode,const btVector3& worldBoundsMin,const btVector3& worldBoundsMax) -{ - - if (shape->getShapeType() == CUSTOM_CONVEX_SHAPE_TYPE) - { - btVector3 org(m[12], m[13], m[14]); - btVector3 dx(m[0], m[1], m[2]); - btVector3 dy(m[4], m[5], m[6]); -// btVector3 dz(m[8], m[9], m[10]); - const btBoxShape* boxShape = static_cast(shape); - btVector3 halfExtent = boxShape->getHalfExtentsWithMargin(); - dx *= halfExtent[0]; - dy *= halfExtent[1]; -// dz *= halfExtent[2]; - glColor3f(1,1,1); - glDisable(GL_LIGHTING); - glLineWidth(2); - - glBegin(GL_LINE_LOOP); - glDrawVector(org - dx - dy); - glDrawVector(org - dx + dy); - glDrawVector(org + dx + dy); - glDrawVector(org + dx - dy); - glEnd(); - return; - } - else if((shape->getShapeType() == BOX_SHAPE_PROXYTYPE) && (debugMode & btIDebugDraw::DBG_FastWireframe)) - { - btVector3 org(m[12], m[13], m[14]); - btVector3 dx(m[0], m[1], m[2]); - btVector3 dy(m[4], m[5], m[6]); - btVector3 dz(m[8], m[9], m[10]); - const btBoxShape* boxShape = static_cast(shape); - btVector3 halfExtent = boxShape->getHalfExtentsWithMargin(); - dx *= halfExtent[0]; - dy *= halfExtent[1]; - dz *= halfExtent[2]; - glBegin(GL_LINE_LOOP); - glDrawVector(org - dx - dy - dz); - glDrawVector(org + dx - dy - dz); - glDrawVector(org + dx + dy - dz); - glDrawVector(org - dx + dy - dz); - glDrawVector(org - dx + dy + dz); - glDrawVector(org + dx + dy + dz); - glDrawVector(org + dx - dy + dz); - glDrawVector(org - dx - dy + dz); - glEnd(); - glBegin(GL_LINES); - glDrawVector(org + dx - dy - dz); - glDrawVector(org + dx - dy + dz); - glDrawVector(org + dx + dy - dz); - glDrawVector(org + dx + dy + dz); - glDrawVector(org - dx - dy - dz); - glDrawVector(org - dx + dy - dz); - glDrawVector(org - dx - dy + dz); - glDrawVector(org - dx + dy + dz); - glEnd(); - return; - } - - glPushMatrix(); - btglMultMatrix(m); - - - if (shape->getShapeType() == UNIFORM_SCALING_SHAPE_PROXYTYPE) - { - const btUniformScalingShape* scalingShape = static_cast(shape); - const btConvexShape* convexShape = scalingShape->getChildShape(); - float scalingFactor = (float)scalingShape->getUniformScalingFactor(); - { - btScalar tmpScaling[4][4]={{scalingFactor,0,0,0}, - {0,scalingFactor,0,0}, - {0,0,scalingFactor,0}, - {0,0,0,1}}; - - drawOpenGL( (btScalar*)tmpScaling,convexShape,color,debugMode,worldBoundsMin,worldBoundsMax); - } - glPopMatrix(); - return; - } - - if (shape->getShapeType() == COMPOUND_SHAPE_PROXYTYPE) - { - const btCompoundShape* compoundShape = static_cast(shape); - for (int i=compoundShape->getNumChildShapes()-1;i>=0;i--) - { - btTransform childTrans = compoundShape->getChildTransform(i); - const btCollisionShape* colShape = compoundShape->getChildShape(i); - btScalar childMat[16]; - childTrans.getOpenGLMatrix(childMat); - drawOpenGL(childMat,colShape,color,debugMode,worldBoundsMin,worldBoundsMax); - } - - } else - { - if(m_textureenabled&&(!m_textureinitialized)) - { - GLubyte* image=new GLubyte[256*256*3]; - for(int y=0;y<256;++y) - { - const int t=y>>4; - GLubyte* pi=image+y*256*3; - for(int x=0;x<256;++x) - { - const int s=x>>4; - const GLubyte b=180; - GLubyte c=b+((s+t&1)&1)*(255-b); - pi[0]=pi[1]=pi[2]=c;pi+=3; - } - } - - glGenTextures(1,(GLuint*)&m_texturehandle); - glBindTexture(GL_TEXTURE_2D,m_texturehandle); - glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE); - glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR); - glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR_MIPMAP_LINEAR); - glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT); - glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT); - gluBuild2DMipmaps(GL_TEXTURE_2D,3,256,256,GL_RGB,GL_UNSIGNED_BYTE,image); - delete[] image; - - - } - - glMatrixMode(GL_TEXTURE); - glLoadIdentity(); - glScalef(0.025f,0.025f,0.025f); - glMatrixMode(GL_MODELVIEW); - - static const GLfloat planex[]={1,0,0,0}; - // static const GLfloat planey[]={0,1,0,0}; - static const GLfloat planez[]={0,0,1,0}; - glTexGenfv(GL_S,GL_OBJECT_PLANE,planex); - glTexGenfv(GL_T,GL_OBJECT_PLANE,planez); - glTexGeni(GL_S,GL_TEXTURE_GEN_MODE,GL_OBJECT_LINEAR); - glTexGeni(GL_T,GL_TEXTURE_GEN_MODE,GL_OBJECT_LINEAR); - glEnable(GL_TEXTURE_GEN_S); - glEnable(GL_TEXTURE_GEN_T); - glEnable(GL_TEXTURE_GEN_R); - m_textureinitialized=true; - - - - - //drawCoordSystem(); - - //glPushMatrix(); - glEnable(GL_COLOR_MATERIAL); - if(m_textureenabled) - { - glEnable(GL_TEXTURE_2D); - glBindTexture(GL_TEXTURE_2D,m_texturehandle); - } else - { - glDisable(GL_TEXTURE_2D); - } - - - glColor3f(color.x(),color.y(), color.z()); - - bool useWireframeFallback = true; - - if (!(debugMode & btIDebugDraw::DBG_DrawWireframe)) - { - ///you can comment out any of the specific cases, and use the default - - ///the benefit of 'default' is that it approximates the actual collision shape including collision margin - //int shapetype=m_textureenabled?MAX_BROADPHASE_COLLISION_TYPES:shape->getShapeType(); - int shapetype=shape->getShapeType(); - switch (shapetype) - { - - case SPHERE_SHAPE_PROXYTYPE: - { - const btSphereShape* sphereShape = static_cast(shape); - float radius = sphereShape->getMargin();//radius doesn't include the margin, so draw with margin - drawSphere(radius,10,10); - useWireframeFallback = false; - break; - } - - case BOX_SHAPE_PROXYTYPE: - { - const btBoxShape* boxShape = static_cast(shape); - btVector3 halfExtent = boxShape->getHalfExtentsWithMargin(); - - static int indices[36] = { - 0,1,2, - 3,2,1, - 4,0,6, - 6,0,2, - 5,1,4, - 4,1,0, - 7,3,1, - 7,1,5, - 5,4,7, - 7,4,6, - 7,2,3, - 7,6,2}; - - btVector3 vertices[8]={ - btVector3(halfExtent[0],halfExtent[1],halfExtent[2]), - btVector3(-halfExtent[0],halfExtent[1],halfExtent[2]), - btVector3(halfExtent[0],-halfExtent[1],halfExtent[2]), - btVector3(-halfExtent[0],-halfExtent[1],halfExtent[2]), - btVector3(halfExtent[0],halfExtent[1],-halfExtent[2]), - btVector3(-halfExtent[0],halfExtent[1],-halfExtent[2]), - btVector3(halfExtent[0],-halfExtent[1],-halfExtent[2]), - btVector3(-halfExtent[0],-halfExtent[1],-halfExtent[2])}; -#if 1 - glBegin (GL_TRIANGLES); - int si=36; - for (int i=0;i(shape); - int upIndex = coneShape->getConeUpIndex(); - float radius = coneShape->getRadius();//+coneShape->getMargin(); - float height = coneShape->getHeight();//+coneShape->getMargin(); - switch (upIndex) - { - case 0: - glRotatef(90.0, 0.0, 1.0, 0.0); - break; - case 1: - glRotatef(-90.0, 1.0, 0.0, 0.0); - break; - case 2: - break; - default: - { - } - }; - - glTranslatef(0.0, 0.0, -0.5*height); - glutSolidCone(radius,height,10,10); - useWireframeFallback = false; - break; - - } -#endif - - case STATIC_PLANE_PROXYTYPE: - { - const btStaticPlaneShape* staticPlaneShape = static_cast(shape); - btScalar planeConst = staticPlaneShape->getPlaneConstant(); - const btVector3& planeNormal = staticPlaneShape->getPlaneNormal(); - btVector3 planeOrigin = planeNormal * planeConst; - btVector3 vec0,vec1; - btPlaneSpace1(planeNormal,vec0,vec1); - btScalar vecLen = 100.f; - btVector3 pt0 = planeOrigin + vec0*vecLen; - btVector3 pt1 = planeOrigin - vec0*vecLen; - btVector3 pt2 = planeOrigin + vec1*vecLen; - btVector3 pt3 = planeOrigin - vec1*vecLen; - glBegin(GL_LINES); - glVertex3f(pt0.getX(),pt0.getY(),pt0.getZ()); - glVertex3f(pt1.getX(),pt1.getY(),pt1.getZ()); - glVertex3f(pt2.getX(),pt2.getY(),pt2.getZ()); - glVertex3f(pt3.getX(),pt3.getY(),pt3.getZ()); - glEnd(); - - - break; - - } - -/* - case CYLINDER_SHAPE_PROXYTYPE: - { - const btCylinderShape* cylinder = static_cast(shape); - int upAxis = cylinder->getUpAxis(); - - - float radius = cylinder->getRadius(); - float halfHeight = cylinder->getHalfExtentsWithMargin()[upAxis]; - - drawCylinder(radius,halfHeight,upAxis); - - break; - } -*/ - - case MULTI_SPHERE_SHAPE_PROXYTYPE: - { - const btMultiSphereShape* multiSphereShape = static_cast(shape); - - btTransform childTransform; - childTransform.setIdentity(); - - - for (int i = multiSphereShape->getSphereCount()-1; i>=0;i--) - { - btSphereShape sc(multiSphereShape->getSphereRadius(i)); - childTransform.setOrigin(multiSphereShape->getSpherePosition(i)); - btScalar childMat[16]; - childTransform.getOpenGLMatrix(childMat); - drawOpenGL(childMat,&sc,color,debugMode,worldBoundsMin,worldBoundsMax); - } - - break; - } - - default: - { - if (shape->isConvex()) - { - const btConvexPolyhedron* poly = shape->isPolyhedral() ? ((btPolyhedralConvexShape*) shape)->getConvexPolyhedron() : 0; - if (poly) - { - int i; - glBegin (GL_TRIANGLES); - for (i=0;im_faces.size();i++) - { - btVector3 centroid(0,0,0); - int numVerts = poly->m_faces[i].m_indices.size(); - if (numVerts>2) - { - btVector3 v1 = poly->m_vertices[poly->m_faces[i].m_indices[0]]; - for (int v=0;vm_faces[i].m_indices.size()-2;v++) - { - - btVector3 v2 = poly->m_vertices[poly->m_faces[i].m_indices[v+1]]; - btVector3 v3 = poly->m_vertices[poly->m_faces[i].m_indices[v+2]]; - btVector3 normal = (v3-v1).cross(v2-v1); - normal.normalize (); - glNormal3f(normal.getX(),normal.getY(),normal.getZ()); - glVertex3f (v1.x(), v1.y(), v1.z()); - glVertex3f (v2.x(), v2.y(), v2.z()); - glVertex3f (v3.x(), v3.y(), v3.z()); - } - } - } - glEnd (); - } else - { - ShapeCache* sc=cache((btConvexShape*)shape); - //glutSolidCube(1.0); - btShapeHull* hull = &sc->m_shapehull/*(btShapeHull*)shape->getUserPointer()*/; - - if (hull && hull->numTriangles () > 0) - { - int index = 0; - const unsigned int* idx = hull->getIndexPointer(); - const btVector3* vtx = hull->getVertexPointer(); - - glBegin (GL_TRIANGLES); - - for (int i = 0; i < hull->numTriangles (); i++) - { - int i1 = index++; - int i2 = index++; - int i3 = index++; - btAssert(i1 < hull->numIndices () && - i2 < hull->numIndices () && - i3 < hull->numIndices ()); - - int index1 = idx[i1]; - int index2 = idx[i2]; - int index3 = idx[i3]; - btAssert(index1 < hull->numVertices () && - index2 < hull->numVertices () && - index3 < hull->numVertices ()); - - btVector3 v1 = vtx[index1]; - btVector3 v2 = vtx[index2]; - btVector3 v3 = vtx[index3]; - btVector3 normal = (v3-v1).cross(v2-v1); - normal.normalize (); - glNormal3f(normal.getX(),normal.getY(),normal.getZ()); - glVertex3f (v1.x(), v1.y(), v1.z()); - glVertex3f (v2.x(), v2.y(), v2.z()); - glVertex3f (v3.x(), v3.y(), v3.z()); - - } - glEnd (); - - } - } - } - } - } - - } - - - glNormal3f(0,1,0); - - - /// for polyhedral shapes - if (debugMode==btIDebugDraw::DBG_DrawFeaturesText && (shape->isPolyhedral())) - { - btPolyhedralConvexShape* polyshape = (btPolyhedralConvexShape*) shape; - - { - - glColor3f(1.f, 1.f, 1.f); - int i; - for (i=0;igetNumVertices();i++) - { - btVector3 vtx; - polyshape->getVertex(i,vtx); - char buf[12]; - sprintf(buf," %d",i); - //btDrawString(BMF_GetFont(BMF_kHelvetica10),buf); - } - - for (i=0;igetNumPlanes();i++) - { - btVector3 normal; - btVector3 vtx; - polyshape->getPlane(normal,vtx,i); - //btScalar d = vtx.dot(normal); - - //char buf[12]; - //sprintf(buf," plane %d",i); - //btDrawString(BMF_GetFont(BMF_kHelvetica10),buf); - - } - } - - } - - -#ifdef USE_DISPLAY_LISTS - - if (shape->getShapeType() == TRIANGLE_MESH_SHAPE_PROXYTYPE||shape->getShapeType() == GIMPACT_SHAPE_PROXYTYPE) - { - GLuint dlist = OGL_get_displaylist_for_shape((btCollisionShape * )shape); - if (dlist) - { - glCallList(dlist); - } - else - { -#else - if (shape->isConcave() && !shape->isInfinite()) - { - btConcaveShape* concaveMesh = (btConcaveShape*) shape; - - GlDrawcallback drawCallback; - drawCallback.m_wireframe = (debugMode & btIDebugDraw::DBG_DrawWireframe)!=0; - - concaveMesh->processAllTriangles(&drawCallback,worldBoundsMin,worldBoundsMax); - - } -#endif - -#ifdef USE_DISPLAY_LISTS - } -} -#endif - - - - - - } - glPopMatrix(); - -} - -// -void GL_ShapeDrawer::drawShadow(btScalar* m,const btVector3& extrusion,const btCollisionShape* shape,const btVector3& worldBoundsMin,const btVector3& worldBoundsMax) -{ - glPushMatrix(); - btglMultMatrix(m); - if(shape->getShapeType() == UNIFORM_SCALING_SHAPE_PROXYTYPE) - { - const btUniformScalingShape* scalingShape = static_cast(shape); - const btConvexShape* convexShape = scalingShape->getChildShape(); - float scalingFactor = (float)scalingShape->getUniformScalingFactor(); - btScalar tmpScaling[4][4]={ {scalingFactor,0,0,0}, - {0,scalingFactor,0,0}, - {0,0,scalingFactor,0}, - {0,0,0,1}}; - drawShadow((btScalar*)tmpScaling,extrusion,convexShape,worldBoundsMin,worldBoundsMax); - glPopMatrix(); - return; - } - else if(shape->getShapeType()==COMPOUND_SHAPE_PROXYTYPE) - { - const btCompoundShape* compoundShape = static_cast(shape); - for (int i=compoundShape->getNumChildShapes()-1;i>=0;i--) - { - btTransform childTrans = compoundShape->getChildTransform(i); - const btCollisionShape* colShape = compoundShape->getChildShape(i); - btScalar childMat[16]; - childTrans.getOpenGLMatrix(childMat); - drawShadow(childMat,extrusion*childTrans.getBasis(),colShape,worldBoundsMin,worldBoundsMax); - } - } - else - { - // bool useWireframeFallback = true; - if (shape->isConvex()) - { - - const btConvexPolyhedron* poly = shape->isPolyhedral() ? ((btPolyhedralConvexShape*) shape)->getConvexPolyhedron() : 0; - ShapeCache* sc=cache((btConvexShape*)shape); - btShapeHull* hull =&sc->m_shapehull; - const btVector3* vertexPointer = 0; - - vertexPointer = (poly && poly->m_vertices.size())? &poly->m_vertices[0] : 0; - if (!vertexPointer) - vertexPointer = hull->numVertices() ? hull->getVertexPointer():0; - - if (vertexPointer) - { - glBegin(GL_QUADS); - for(int i=0;im_edges.size();++i) - { - const btScalar d=btDot(sc->m_edges[i].n[0],extrusion); - if((d*btDot(sc->m_edges[i].n[1],extrusion))<0) - { - const int q= d<0?1:0; - const btVector3& a= vertexPointer[sc->m_edges[i].v[q]]; - const btVector3& b= vertexPointer[sc->m_edges[i].v[1-q]]; - glVertex3f(a[0],a[1],a[2]); - glVertex3f(b[0],b[1],b[2]); - glVertex3f(b[0]+extrusion[0],b[1]+extrusion[1],b[2]+extrusion[2]); - glVertex3f(a[0]+extrusion[0],a[1]+extrusion[1],a[2]+extrusion[2]); - } - } - glEnd(); - } - } - } - - - if (shape->isConcave())//>getShapeType() == TRIANGLE_MESH_SHAPE_PROXYTYPE||shape->getShapeType() == GIMPACT_SHAPE_PROXYTYPE) - // if (shape->getShapeType() == TRIANGLE_MESH_SHAPE_PROXYTYPE) - { - btConcaveShape* concaveMesh = (btConcaveShape*) shape; - - GlDrawcallback drawCallback; - drawCallback.m_wireframe = false; - - concaveMesh->processAllTriangles(&drawCallback,worldBoundsMin,worldBoundsMax); - - } - glPopMatrix(); - -} - -// -GL_ShapeDrawer::GL_ShapeDrawer() -{ - m_texturehandle = 0; - m_textureenabled = false; - m_textureinitialized = false; -} - -GL_ShapeDrawer::~GL_ShapeDrawer() -{ - int i; - for (i=0;i~ShapeCache(); - btAlignedFree(m_shapecaches[i]); - } - m_shapecaches.clear(); - if(m_textureinitialized) - { - glDeleteTextures(1,(const GLuint*) &m_texturehandle); - } -} - - diff --git a/Extras/RigidBodyGpuPipeline/dynamics/testbed/GL_ShapeDrawer.h b/Extras/RigidBodyGpuPipeline/dynamics/testbed/GL_ShapeDrawer.h deleted file mode 100644 index 65bf29de4..000000000 --- a/Extras/RigidBodyGpuPipeline/dynamics/testbed/GL_ShapeDrawer.h +++ /dev/null @@ -1,70 +0,0 @@ -/* -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 GL_SHAPE_DRAWER_H -#define GL_SHAPE_DRAWER_H - -class btCollisionShape; -class btShapeHull; -#include "LinearMath/btAlignedObjectArray.h" -#include "LinearMath/btVector3.h" - -#include "BulletCollision/CollisionShapes/btShapeHull.h" - -/// OpenGL shape drawing -class GL_ShapeDrawer -{ -protected: - struct ShapeCache - { - struct Edge { btVector3 n[2];int v[2]; }; - ShapeCache(btConvexShape* s) : m_shapehull(s) {} - btShapeHull m_shapehull; - btAlignedObjectArray m_edges; - }; - //clean-up memory of dynamically created shape hulls - btAlignedObjectArray m_shapecaches; - unsigned int m_texturehandle; - bool m_textureenabled; - bool m_textureinitialized; - - - ShapeCache* cache(btConvexShape*); - -public: - GL_ShapeDrawer(); - - virtual ~GL_ShapeDrawer(); - - ///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); - virtual void drawShadow(btScalar* m, const btVector3& extrusion,const btCollisionShape* shape,const btVector3& worldBoundsMin,const btVector3& worldBoundsMax); - - bool enableTexture(bool enable) { bool p=m_textureenabled;m_textureenabled=enable;return(p); } - bool hasTextureEnabled() const - { - return m_textureenabled; - } - - static void drawCylinder(float radius,float halfHeight, int upAxis); - void drawSphere(btScalar r, int lats, int longs); - static void drawCoordSystem(); - -}; - -void OGL_displaylist_register_shape(btCollisionShape * shape); -void OGL_displaylist_clean(); - -#endif //GL_SHAPE_DRAWER_H - diff --git a/Extras/RigidBodyGpuPipeline/dynamics/testbed/GL_Simplex1to4.cpp b/Extras/RigidBodyGpuPipeline/dynamics/testbed/GL_Simplex1to4.cpp deleted file mode 100644 index b364a1b98..000000000 --- a/Extras/RigidBodyGpuPipeline/dynamics/testbed/GL_Simplex1to4.cpp +++ /dev/null @@ -1,76 +0,0 @@ -/* -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 "GL_Simplex1to4.h" -#include "BulletCollision/NarrowPhaseCollision/btSimplexSolverInterface.h" -#include "GL_ShapeDrawer.h" -#ifdef _WIN32 -#include -#endif - -//think different -#if defined(__APPLE__) && !defined (VMDMESA) -#include -#include -#else -#include -#endif -#include "GlutStuff.h" -#include "LinearMath/btTransform.h" - -GL_Simplex1to4::GL_Simplex1to4() -:m_simplexSolver(0) -{ -} - -/// -/// Debugging method calcClosest calculates the closest point to the origin, using m_simplexSolver -/// -void GL_Simplex1to4::calcClosest(btScalar* m) -{ - btTransform tr; - tr.setFromOpenGLMatrix(m); - - - - GL_ShapeDrawer::drawCoordSystem(); - - if (m_simplexSolver) - { - m_simplexSolver->reset(); - bool res; - - btVector3 v; - - for (int i=0;iaddVertex(v,v,btVector3(0.f,0.f,0.f)); - res = m_simplexSolver->closest(v); - } - - //draw v? - glDisable(GL_LIGHTING); - glBegin(GL_LINES); - btglColor3(1.f, 0.f, 0.f); - btglVertex3(0.f, 0.f, 0.f); - btglVertex3(v.x(),v.y(),v.z()); - glEnd(); - - glEnable(GL_LIGHTING); - - - } - -} diff --git a/Extras/RigidBodyGpuPipeline/dynamics/testbed/GL_Simplex1to4.h b/Extras/RigidBodyGpuPipeline/dynamics/testbed/GL_Simplex1to4.h deleted file mode 100644 index c75e3573b..000000000 --- a/Extras/RigidBodyGpuPipeline/dynamics/testbed/GL_Simplex1to4.h +++ /dev/null @@ -1,40 +0,0 @@ -/* -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 GL_SIMPLEX_1TO4_H -#define GL_SIMPLEX_1TO4_H - -#include "BulletCollision/CollisionShapes/btTetrahedronShape.h" - -#include "BulletCollision/NarrowPhaseCollision/btSimplexSolverInterface.h" - -///GL_Simplex1to4 is a class to debug a Simplex Solver with 1 to 4 points. -///Can be used by GJK. -class GL_Simplex1to4 : public btBU_Simplex1to4 -{ - btSimplexSolverInterface* m_simplexSolver; - - public: - - GL_Simplex1to4(); - - void calcClosest(btScalar* m); - - void setSimplexSolver(btSimplexSolverInterface* simplexSolver) { - m_simplexSolver = simplexSolver; - } - -}; - -#endif //GL_SIMPLEX_1TO4_H diff --git a/Extras/RigidBodyGpuPipeline/dynamics/testbed/GlutDemoApplication.cpp b/Extras/RigidBodyGpuPipeline/dynamics/testbed/GlutDemoApplication.cpp deleted file mode 100644 index 0ceaede76..000000000 --- a/Extras/RigidBodyGpuPipeline/dynamics/testbed/GlutDemoApplication.cpp +++ /dev/null @@ -1,87 +0,0 @@ - -#ifndef _WINDOWS - -#include "GlutDemoApplication.h" - -#include "GlutStuff.h" - -#include "BulletDynamics/Dynamics/btDiscreteDynamicsWorld.h" -#include "BulletDynamics/Dynamics/btRigidBody.h" - -void GlutDemoApplication::updateModifierKeys() -{ - m_modifierKeys = 0; - if (glutGetModifiers() & GLUT_ACTIVE_ALT) - m_modifierKeys |= BT_ACTIVE_ALT; - - if (glutGetModifiers() & GLUT_ACTIVE_CTRL) - m_modifierKeys |= BT_ACTIVE_CTRL; - - if (glutGetModifiers() & GLUT_ACTIVE_SHIFT) - m_modifierKeys |= BT_ACTIVE_SHIFT; -} - -void GlutDemoApplication::specialKeyboard(int key, int x, int y) -{ - (void)x; - (void)y; - - switch (key) - { - case GLUT_KEY_F1: - { - - break; - } - - case GLUT_KEY_F2: - { - - break; - } - - - case GLUT_KEY_END: - { - int numObj = getDynamicsWorld()->getNumCollisionObjects(); - if (numObj) - { - btCollisionObject* obj = getDynamicsWorld()->getCollisionObjectArray()[numObj-1]; - - getDynamicsWorld()->removeCollisionObject(obj); - btRigidBody* body = btRigidBody::upcast(obj); - if (body && body->getMotionState()) - { - delete body->getMotionState(); - } - delete obj; - - - } - break; - } - case GLUT_KEY_LEFT : stepLeft(); break; - case GLUT_KEY_RIGHT : stepRight(); break; - case GLUT_KEY_UP : stepFront(); break; - case GLUT_KEY_DOWN : stepBack(); break; - case GLUT_KEY_PAGE_UP : zoomIn(); break; - case GLUT_KEY_PAGE_DOWN : zoomOut(); break; - case GLUT_KEY_HOME : toggleIdle(); break; - default: - // std::cout << "unused (special) key : " << key << std::endl; - break; - } - - glutPostRedisplay(); - -} - -void GlutDemoApplication::swapBuffers() -{ - glutSwapBuffers(); - -} - -#endif //_WINDOWS - - diff --git a/Extras/RigidBodyGpuPipeline/dynamics/testbed/GlutDemoApplication.h b/Extras/RigidBodyGpuPipeline/dynamics/testbed/GlutDemoApplication.h deleted file mode 100644 index e2727a777..000000000 --- a/Extras/RigidBodyGpuPipeline/dynamics/testbed/GlutDemoApplication.h +++ /dev/null @@ -1,34 +0,0 @@ -/* -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 GLUT_DEMO_APPLICATION_H -#define GLUT_DEMO_APPLICATION_H - -#include "DemoApplication.h" - -class GlutDemoApplication : public DemoApplication -{ -public: - - void specialKeyboard(int key, int x, int y); - - virtual void swapBuffers(); - - virtual void updateModifierKeys(); - -}; -#endif //GLUT_DEMO_APPLICATION_H - diff --git a/Extras/RigidBodyGpuPipeline/dynamics/testbed/GlutStuff.cpp b/Extras/RigidBodyGpuPipeline/dynamics/testbed/GlutStuff.cpp deleted file mode 100644 index 92872a130..000000000 --- a/Extras/RigidBodyGpuPipeline/dynamics/testbed/GlutStuff.cpp +++ /dev/null @@ -1,119 +0,0 @@ -/* -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 _WINDOWS - -#include "DemoApplication.h" - -//glut is C code, this global gDemoApplication links glut to the C++ demo -static DemoApplication* gDemoApplication = 0; - - -#include "GlutStuff.h" - -static void glutKeyboardCallback(unsigned char key, int x, int y) -{ - gDemoApplication->keyboardCallback(key,x,y); -} - -static void glutKeyboardUpCallback(unsigned char key, int x, int y) -{ - gDemoApplication->keyboardUpCallback(key,x,y); -} - -static void glutSpecialKeyboardCallback(int key, int x, int y) -{ - gDemoApplication->specialKeyboard(key,x,y); -} - -static void glutSpecialKeyboardUpCallback(int key, int x, int y) -{ - gDemoApplication->specialKeyboardUp(key,x,y); -} - - -static void glutReshapeCallback(int w, int h) -{ - gDemoApplication->reshape(w,h); -} - -static void glutMoveAndDisplayCallback() -{ - gDemoApplication->moveAndDisplay(); -} - -static void glutMouseFuncCallback(int button, int state, int x, int y) -{ - gDemoApplication->mouseFunc(button,state,x,y); -} - - -static void glutMotionFuncCallback(int x,int y) -{ - gDemoApplication->mouseMotionFunc(x,y); -} - - -static void glutDisplayCallback(void) -{ - gDemoApplication->displayCallback(); -} - - -int glutmain(int argc, char **argv,int width,int height,const char* title,DemoApplication* demoApp) { - - gDemoApplication = demoApp; - - glutInit(&argc, argv); - glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL); - glutInitWindowPosition(0, 0); - glutInitWindowSize(width, height); - glutCreateWindow(title); -#ifdef BT_USE_FREEGLUT - glutSetOption (GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_GLUTMAINLOOP_RETURNS); -#endif - - gDemoApplication->myinit(); - - glutKeyboardFunc(glutKeyboardCallback); - glutKeyboardUpFunc(glutKeyboardUpCallback); - glutSpecialFunc(glutSpecialKeyboardCallback); - glutSpecialUpFunc(glutSpecialKeyboardUpCallback); - - glutReshapeFunc(glutReshapeCallback); - //createMenu(); - glutIdleFunc(glutMoveAndDisplayCallback); - glutMouseFunc(glutMouseFuncCallback); - glutPassiveMotionFunc(glutMotionFuncCallback); - glutMotionFunc(glutMotionFuncCallback); - glutDisplayFunc( glutDisplayCallback ); - - glutMoveAndDisplayCallback(); - -//enable vsync to avoid tearing on Apple (todo: for Windows) - -#if defined(__APPLE__) && !defined (VMDMESA) -int swap_interval = 1; -CGLContextObj cgl_context = CGLGetCurrentContext(); -CGLSetParameter(cgl_context, kCGLCPSwapInterval, &swap_interval); -#endif - - - - return 0; -} - - -#endif //_WINDOWS diff --git a/Extras/RigidBodyGpuPipeline/dynamics/testbed/GlutStuff.h b/Extras/RigidBodyGpuPipeline/dynamics/testbed/GlutStuff.h deleted file mode 100644 index 5891e769d..000000000 --- a/Extras/RigidBodyGpuPipeline/dynamics/testbed/GlutStuff.h +++ /dev/null @@ -1,86 +0,0 @@ -/* -Bullet Continuous Collision Detection and Physics Library -Copyright (c) 2003-2012 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 GLUT_STUFF_H -#define GLUT_STUFF_H - -#ifdef _WIN32//for glut.h -#include -#endif - -//think different -#if defined(__APPLE__) && !defined (VMDMESA) -#include -#include -#include -#include -#else - - -#ifdef _WINDOWS -#include -#include -#include -#else -#include -#include -#endif //_WINDOWS -#endif //APPLE - -#ifdef _WINDOWS -#define BT_ACTIVE_ALT VK_LMENU - -#else -#define BT_KEY_K 'k' -#define BT_KEY_LEFT GLUT_KEY_LEFT -#define BT_KEY_RIGHT GLUT_KEY_RIGHT -#define BT_KEY_UP GLUT_KEY_UP -#define BT_KEY_DOWN GLUT_KEY_DOWN -#define BT_KEY_F1 GLUT_KEY_F1 -#define BT_KEY_F2 GLUT_KEY_F2 -#define BT_KEY_F3 GLUT_KEY_F3 -#define BT_KEY_F4 GLUT_KEY_F4 -#define BT_KEY_F5 GLUT_KEY_F5 -#define BT_KEY_PAGEUP GLUT_KEY_PAGE_UP -#define BT_KEY_PAGEDOWN GLUT_KEY_PAGE_DOWN -#define BT_KEY_END GLUT_KEY_END -#define BT_KEY_HOME GLUT_KEY_HOME -#define BT_ACTIVE_ALT GLUT_ACTIVE_ALT -#define BT_ACTIVE_CTRL GLUT_ACTIVE_ALT -#define BT_ACTIVE_SHIFT GLUT_ACTIVE_SHIFT -#endif - -#if BT_USE_FREEGLUT -#include "GL/freeglut_ext.h" //to be able to return from glutMainLoop() -#endif - - - -class DemoApplication; - -int glutmain(int argc, char **argv,int width,int height,const char* title,DemoApplication* demoApp); - -#if defined(BT_USE_DOUBLE_PRECISION) -#define btglLoadMatrix glLoadMatrixd -#define btglMultMatrix glMultMatrixd -#define btglColor3 glColor3d -#define btglVertex3 glVertex3d -#else -#define btglLoadMatrix glLoadMatrixf -#define btglMultMatrix glMultMatrixf -#define btglColor3 glColor3f -#define btglVertex3 glVertex3d -#endif - -#endif //GLUT_STUFF_H diff --git a/Extras/RigidBodyGpuPipeline/dynamics/testbed/RenderTexture.cpp b/Extras/RigidBodyGpuPipeline/dynamics/testbed/RenderTexture.cpp deleted file mode 100644 index 2c8b88b82..000000000 --- a/Extras/RigidBodyGpuPipeline/dynamics/testbed/RenderTexture.cpp +++ /dev/null @@ -1,86 +0,0 @@ -/* -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 "RenderTexture.h" -#include - - -renderTexture::renderTexture(int width,int height) -:m_height(height),m_width(width) -{ - m_buffer = new unsigned char[m_width*m_height*4]; - - //clear screen - memset(m_buffer,0,m_width*m_height*4); - - //clear screen version 2 - for (int x=0;x>=1; - y++; - } - x++; - } - //xx+=16; - xx+=10; - } -} - -renderTexture::~renderTexture() -{ - delete [] m_buffer; -} - - - diff --git a/Extras/RigidBodyGpuPipeline/dynamics/testbed/RenderTexture.h b/Extras/RigidBodyGpuPipeline/dynamics/testbed/RenderTexture.h deleted file mode 100644 index 1aee51d79..000000000 --- a/Extras/RigidBodyGpuPipeline/dynamics/testbed/RenderTexture.h +++ /dev/null @@ -1,73 +0,0 @@ -/* -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 RENDER_TEXTURE_H -#define RENDER_TEXTURE_H - -#include "LinearMath/btVector3.h" -#include "GLDebugFont.h" - -/// -///renderTexture provides a software-render context (setpixel/printf) -/// -class renderTexture -{ - int m_height; - int m_width; - unsigned char* m_buffer; - -public: - - renderTexture(int width,int height); - ~renderTexture(); - - ///rgba input is in range [0..1] for each component - inline void setPixel(int x,int y,const btVector4& rgba) - { - unsigned char* pixel = &m_buffer[ (x+y*m_width) * 4]; - - pixel[0] = (unsigned char)(255.*rgba.getX()); - pixel[1] = (unsigned char)(255.*rgba.getY()); - pixel[2] = (unsigned char)(255.*rgba.getZ()); - pixel[3] = (unsigned char)(255.*rgba.getW()); - } - - inline void addPixel(int x,int y,const btVector4& rgba) - { - unsigned char* pixel = &m_buffer[ (x+y*m_width) * 4]; - pixel[0] = (unsigned char)btMin(btScalar(255.f),((btScalar)pixel[0] + btScalar(255.f)*rgba.getX())); - pixel[1] = (unsigned char)btMin(btScalar(255.f),((btScalar)pixel[1] + btScalar(255.f)*rgba.getY())); - pixel[2] = (unsigned char)btMin(btScalar(255.f),((btScalar)pixel[2] + btScalar(255.f)*rgba.getZ())); -// pixel[3] = (unsigned char)btMin(btScalar(255.f),((btScalar)pixel[3] + btScalar(255.f)*rgba.getW())); - } - - inline btVector4 getPixel(int x,int y) - { - unsigned char* pixel = &m_buffer[ (x+y*m_width) * 4]; - return btVector4(pixel[0]*1.f/255.f, - pixel[1]*1.f/255.f, - pixel[2]*1.f/255.f, - pixel[3]*1.f/255.f); - } - - const unsigned char* getBuffer() const { return m_buffer;} - int getWidth() const { return m_width;} - int getHeight() const { return m_height;} - void grapicalPrintf(char* str, void* fontData, int startx = 0,int starty=0); - -}; - -#endif //RENDER_TEXTURE_H - diff --git a/Extras/RigidBodyGpuPipeline/dynamics/testbed/Win32AppMain.cpp b/Extras/RigidBodyGpuPipeline/dynamics/testbed/Win32AppMain.cpp deleted file mode 100644 index 84f48a316..000000000 --- a/Extras/RigidBodyGpuPipeline/dynamics/testbed/Win32AppMain.cpp +++ /dev/null @@ -1,405 +0,0 @@ -#ifdef _WINDOWS -/* -Bullet Continuous Collision Detection and Physics Library -Copyright (c) 2003-2010 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 -#include - - -#include "DemoApplication.h" - -#include "GLDebugDrawer.h" -#include "GLDebugFont.h" - -#include "BulletDynamics/Dynamics/btDynamicsWorld.h" - -/// This Win32AppMain is shared code between all demos. -/// The actual demo, derived from DemoApplication is created using 'createDemo', in a separate .cpp file -DemoApplication* gDemoApplication = 0; -DemoApplication* createDemo(); - - -// Function Declarations - -LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); -void EnableOpenGL(HWND hWnd, HDC * hDC, HGLRC * hRC); -void DisableOpenGL(HWND hWnd, HDC hDC, HGLRC hRC); -static bool sOpenGLInitialized = false; -static int sWidth = 0; -static int sHeight =0; -static int quitRequest = 0; - -// WinMain - -int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, - LPSTR lpCmdLine, int iCmdShow) -{ - WNDCLASS wc; - HWND hWnd; - HDC hDC; - HGLRC hRC; - MSG msg; - BOOL quit = FALSE; - float theta = 0.0f; - - gDemoApplication = createDemo(); - - - // register window class - wc.style = CS_OWNDC; - wc.lpfnWndProc = WndProc; - wc.cbClsExtra = 0; - wc.cbWndExtra = 0; - wc.hInstance = hInstance; - wc.hIcon = LoadIcon( NULL, IDI_APPLICATION ); - wc.hCursor = LoadCursor( NULL, IDC_ARROW ); - wc.hbrBackground = (HBRUSH)GetStockObject( BLACK_BRUSH ); - wc.lpszMenuName = NULL; - wc.lpszClassName = "BulletPhysics"; - RegisterClass( &wc ); - - // create main window - hWnd = CreateWindow( - "BulletPhysics", "Bullet Physics Sample. http://bulletphysics.org", - WS_CAPTION | WS_VISIBLE | WS_OVERLAPPEDWINDOW, -// 0, 0, 640, 480, - 0, 0, 1024, 768, - NULL, NULL, hInstance, NULL ); - - // enable OpenGL for the window - EnableOpenGL( hWnd, &hDC, &hRC ); - - - GLDebugDrawer debugDraw; - gDemoApplication->myinit(); - //gDemoApplication->reshape(1024, 768); - gDemoApplication->initPhysics(); - if (gDemoApplication->getDynamicsWorld()) - gDemoApplication->getDynamicsWorld()->setDebugDrawer(&debugDraw); - - gDemoApplication->reshape(sWidth,sHeight); - - // program main loop - while ( !quit ) - { - - // check for messages - if ( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) ) - { - - // handle or dispatch messages - if ( msg.message == WM_QUIT ) - { - quit = TRUE; - } - else - { - TranslateMessage( &msg ); - DispatchMessage( &msg ); - } - -// gDemoApplication->displayCallback(); - - - }; - - // OpenGL animation code goes here - - glClearColor( .7f, 0.7f, 0.7f, 1.f ); - - gDemoApplication->moveAndDisplay(); - - - SwapBuffers( hDC ); - - theta += 1.0f; - - - } - - - - // shutdown OpenGL - DisableOpenGL( hWnd, hDC, hRC ); - - // destroy the window explicitly - DestroyWindow( hWnd ); - - delete gDemoApplication; - - return msg.wParam; - -} - -// Window Procedure - -LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) -{ - - - - switch (message) - { - - case WM_SYSKEYDOWN: - { - if (lParam & 1<<29) - { - gDemoApplication->m_modifierKeys = VK_LMENU; - } - break; - } - case WM_SYSKEYUP: - { - if (lParam & 1<<29) - { - gDemoApplication->m_modifierKeys = VK_LMENU; - } else - { - gDemoApplication->m_modifierKeys = 0; - } - - break; - } - - - case WM_SIZE: // Size Action Has Taken Place - - switch (wParam) // Evaluate Size Action - { - case SIZE_MINIMIZED: // Was Window Minimized? - return 0; // Return - - case SIZE_MAXIMIZED: // Was Window Maximized? - sWidth = LOWORD (lParam); - sHeight = HIWORD (lParam); - if (sOpenGLInitialized) - { - gDemoApplication->reshape(sWidth,sHeight); - } - return 0; // Return - - case SIZE_RESTORED: // Was Window Restored? - sWidth = LOWORD (lParam); - sHeight = HIWORD (lParam); - if (sOpenGLInitialized) - { - gDemoApplication->reshape(sWidth,sHeight); - } - return 0; // Return - } - break; - - case WM_CREATE: - return 0; - - case WM_MBUTTONUP: - { - int xPos = LOWORD(lParam); - int yPos = HIWORD(lParam); - gDemoApplication->mouseFunc(1,1,xPos,yPos); - break; - } - case WM_MBUTTONDOWN: - { - int xPos = LOWORD(lParam); - int yPos = HIWORD(lParam); - gDemoApplication->mouseFunc(1,0,xPos,yPos); - break; - } - - case WM_LBUTTONUP: - { - int xPos = LOWORD(lParam); - int yPos = HIWORD(lParam); - gDemoApplication->mouseFunc(0,1,xPos,yPos); - break; - } - case 0x020A://WM_MOUSEWHEEL: - { - - int zDelta = (short)HIWORD(wParam); - int xPos = LOWORD(lParam); - int yPos = HIWORD(lParam); - if (zDelta>0) - gDemoApplication->zoomIn(); - else - gDemoApplication->zoomOut(); - break; - } - - case WM_MOUSEMOVE: - { - int xPos = LOWORD(lParam); - int yPos = HIWORD(lParam); - gDemoApplication->mouseMotionFunc(xPos,yPos); - break; - } - case WM_RBUTTONUP: - { - int xPos = LOWORD(lParam); - int yPos = HIWORD(lParam); - gDemoApplication->mouseFunc(2,1,xPos,yPos); - break; - } - case WM_RBUTTONDOWN: - { - int xPos = LOWORD(lParam); - int yPos = HIWORD(lParam); - gDemoApplication->mouseFunc(2,0,xPos,yPos); - break; - } - case WM_LBUTTONDOWN: - { - int xPos = LOWORD(lParam); - int yPos = HIWORD(lParam); - gDemoApplication->mouseFunc(0,0,xPos,yPos); - break; - } -/*#define WM_LBUTTONUP 0x0202 -#define WM_LBUTTONDBLCLK 0x0203 -#define WM_RBUTTONDOWN 0x0204 -#define WM_RBUTTONUP 0x0205 -#define WM_RBUTTONDBLCLK 0x0206 -#define WM_MBUTTONDOWN 0x0207 -#define WM_MBUTTONUP 0x0208 -#define WM_MBUTTONDBLCLK 0x0209 -*/ - - - - case WM_CLOSE: - PostQuitMessage( 0 ); - return 0; - - case WM_DESTROY: - return 0; - - case WM_KEYUP: - switch ( wParam ) - { - - case VK_PRIOR: - case VK_NEXT: - case VK_END: - case VK_HOME: - case VK_LEFT: - case VK_UP: - case VK_RIGHT: - case VK_DOWN: - { - if (gDemoApplication) - gDemoApplication->specialKeyboardUp(wParam,0,0); - return 0; - } - default: - { - gDemoApplication->keyboardUpCallback(tolower(wParam),0,0); - } - return DefWindowProc( hWnd, message, wParam, lParam ); - } - - case WM_KEYDOWN: - printf("bla\n"); - switch ( wParam ) - { - case VK_CONTROL: - case VK_PRIOR: - case VK_NEXT: - case VK_END: - case VK_HOME: - case VK_LEFT: - case VK_UP: - case VK_RIGHT: - case VK_DOWN: - { - if (gDemoApplication) - gDemoApplication->specialKeyboard(wParam,0,0); - break; - } - - case ' ': - { - if (gDemoApplication) - gDemoApplication->clientResetScene(); - break; - } - case 'Q': - case VK_ESCAPE: - { - quitRequest = 1; - PostQuitMessage(0); - } - return 0; - - } - return 0; - - case WM_CHAR: - if (!quitRequest) - gDemoApplication->keyboardCallback(wParam,0,0); - break; - - default: - return DefWindowProc( hWnd, message, wParam, lParam ); - - } - return 0; -} - -// Enable OpenGL - -void EnableOpenGL(HWND hWnd, HDC * hDC, HGLRC * hRC) -{ - PIXELFORMATDESCRIPTOR pfd; - int format; - - // get the device context (DC) - *hDC = GetDC( hWnd ); - - // set the pixel format for the DC - ZeroMemory( &pfd, sizeof( pfd ) ); - pfd.nSize = sizeof( pfd ); - pfd.nVersion = 1; - pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; - pfd.iPixelType = PFD_TYPE_RGBA; - pfd.cColorBits = 24; - pfd.cDepthBits = 16; - pfd.cStencilBits = 1; - pfd.iLayerType = PFD_MAIN_PLANE; - format = ChoosePixelFormat( *hDC, &pfd ); - SetPixelFormat( *hDC, format, &pfd ); - - // create and enable the render context (RC) - *hRC = wglCreateContext( *hDC ); - wglMakeCurrent( *hDC, *hRC ); - sOpenGLInitialized = true; - - -} - -// Disable OpenGL - -void DisableOpenGL(HWND hWnd, HDC hDC, HGLRC hRC) -{ - sOpenGLInitialized = false; - - wglMakeCurrent( NULL, NULL ); - wglDeleteContext( hRC ); - ReleaseDC( hWnd, hDC ); -} - -#endif //_WINDOWS diff --git a/Extras/RigidBodyGpuPipeline/dynamics/testbed/Win32DemoApplication.cpp b/Extras/RigidBodyGpuPipeline/dynamics/testbed/Win32DemoApplication.cpp deleted file mode 100644 index f959cbf4f..000000000 --- a/Extras/RigidBodyGpuPipeline/dynamics/testbed/Win32DemoApplication.cpp +++ /dev/null @@ -1,79 +0,0 @@ -/* -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. -*/ - -#ifdef _WINDOWS - -#include "Win32DemoApplication.h" - - - - -#if 0 -void Win32DemoApplication::renderme() -{ -} -void Win32DemoApplication::setTexturing(bool useTexture) -{ -} - -void Win32DemoApplication::setShadows(bool useShadows) -{ -} - -void Win32DemoApplication::setCameraDistance(float camDist) -{ -} -void Win32DemoApplication::clientResetScene() -{ - -} -#endif - -void Win32DemoApplication::updateModifierKeys() -{ - //not yet -} - - - -void Win32DemoApplication::specialKeyboard(int key, int x, int y) -{ - (void)x; - (void)y; - - switch (key) - { - case VK_LEFT : stepLeft(); break; - case VK_RIGHT : stepRight(); break; - case VK_UP : stepFront(); break; - case VK_DOWN : stepBack(); break; - -// case GLUT_KEY_PAGE_UP : zoomIn(); break; -// case GLUT_KEY_PAGE_DOWN : zoomOut(); break; -// case GLUT_KEY_HOME : toggleIdle(); break; - - default: - // std::cout << "unused (special) key : " << key << std::endl; - break; - } - -} - -void Win32DemoApplication::swapBuffers() -{ -} - -#endif - diff --git a/Extras/RigidBodyGpuPipeline/dynamics/testbed/Win32DemoApplication.h b/Extras/RigidBodyGpuPipeline/dynamics/testbed/Win32DemoApplication.h deleted file mode 100644 index 0c2a1ee49..000000000 --- a/Extras/RigidBodyGpuPipeline/dynamics/testbed/Win32DemoApplication.h +++ /dev/null @@ -1,40 +0,0 @@ -/* -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 WIN32_DEMO_APPLICATION_H -#define WIN32_DEMO_APPLICATION_H - - -#include "DemoApplication.h" - -class Win32DemoApplication : public DemoApplication -{ -protected: - - -public: - - - virtual void swapBuffers(); - - void specialKeyboard(int key, int x, int y); - - virtual void updateModifierKeys(); - - -}; - -#endif //WIN32_DEMO_APPLICATION_H \ No newline at end of file diff --git a/Extras/RigidBodyGpuPipeline/dynamics/testbed/premake4.lua b/Extras/RigidBodyGpuPipeline/dynamics/testbed/premake4.lua deleted file mode 100644 index 576aa0fb7..000000000 --- a/Extras/RigidBodyGpuPipeline/dynamics/testbed/premake4.lua +++ /dev/null @@ -1,18 +0,0 @@ - project "testbed" - - kind "StaticLib" - targetdir "../../build/lib" - includedirs { - ".", - "../../bullet2" - } - configuration {"Windows"} - includedirs { - "../../rendering/GlutGlewWindows" - } - configuration{} - - files { - "**.cpp", - "**.h" - } diff --git a/Extras/RigidBodyGpuPipeline/opencl/3dGridBroadphase/AMD/premake4.lua b/Extras/RigidBodyGpuPipeline/opencl/3dGridBroadphase/AMD/premake4.lua deleted file mode 100644 index 2ae27f6f4..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/3dGridBroadphase/AMD/premake4.lua +++ /dev/null @@ -1,29 +0,0 @@ - - hasCL = findOpenCL_AMD() - - if (hasCL) then - - project "OpenCL_bt3dGridBroadphase_AMD" - - initOpenCL_AMD() - - language "C++" - - kind "StaticLib" - targetdir "../../../bin" - - libdirs {"../../../rendering/GlutGlewWindows"} - - includedirs { --- "../../../rendering/GlutGlewWindows", - "../../../opencl/3dGridBroadphase/Shared", - "../../../../../src", - "../../primitives" - } - - files { - "../Shared/*.cpp", - "../Shared/*.h" - } - - end \ No newline at end of file diff --git a/Extras/RigidBodyGpuPipeline/opencl/3dGridBroadphase/MiniCL/MiniCLTaskWrap.cpp b/Extras/RigidBodyGpuPipeline/opencl/3dGridBroadphase/MiniCL/MiniCLTaskWrap.cpp deleted file mode 100644 index 1398190f2..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/3dGridBroadphase/MiniCL/MiniCLTaskWrap.cpp +++ /dev/null @@ -1,23 +0,0 @@ -/* -Bullet Continuous Collision Detection and Physics Library -Copyright (c) 2003-2007 Erwin Coumans http://bulletphysics.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 - -extern "C" -{ - #define MSTRINGIFY(A) A - #include "bt3dGridBroadphaseOCL.cl" - #undef MSTRINGIFY -} diff --git a/Extras/RigidBodyGpuPipeline/opencl/3dGridBroadphase/Shared/bt3dGridBroadphaseOCL.cl b/Extras/RigidBodyGpuPipeline/opencl/3dGridBroadphase/Shared/bt3dGridBroadphaseOCL.cl deleted file mode 100644 index f66b6e28b..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/3dGridBroadphase/Shared/bt3dGridBroadphaseOCL.cl +++ /dev/null @@ -1,349 +0,0 @@ - -MSTRINGIFY( - -int getPosHash(int4 gridPos, __global float4* pParams) -{ - int4 gridDim = *((__global int4*)(pParams + 1)); - gridPos.x &= gridDim.x - 1; - gridPos.y &= gridDim.y - 1; - gridPos.z &= gridDim.z - 1; - int hash = gridPos.z * gridDim.y * gridDim.x + gridPos.y * gridDim.x + gridPos.x; - return hash; -} - -int4 getGridPos(float4 worldPos, __global float4* pParams) -{ - int4 gridPos; - int4 gridDim = *((__global int4*)(pParams + 1)); - gridPos.x = (int)floor(worldPos.x * pParams[0].x) & (gridDim.x - 1); - gridPos.y = (int)floor(worldPos.y * pParams[0].y) & (gridDim.y - 1); - gridPos.z = (int)floor(worldPos.z * pParams[0].z) & (gridDim.z - 1); - return gridPos; -} - - -// calculate grid hash value for each body using its AABB -__kernel void kCalcHashAABB(int numObjects, __global float4* pAABB, __global int2* pHash, __global float4* pParams GUID_ARG) -{ - int index = get_global_id(0); - if(index >= numObjects) - { - return; - } - float4 bbMin = pAABB[index*2]; - float4 bbMax = pAABB[index*2 + 1]; - float4 pos; - pos.x = (bbMin.x + bbMax.x) * 0.5f; - pos.y = (bbMin.y + bbMax.y) * 0.5f; - pos.z = (bbMin.z + bbMax.z) * 0.5f; - pos.w = 0.f; - // get address in grid - int4 gridPos = getGridPos(pos, pParams); - int gridHash = getPosHash(gridPos, pParams); - // store grid hash and body index - int2 hashVal; - hashVal.x = gridHash; - hashVal.y = index; - pHash[index] = hashVal; -} - -__kernel void kClearCellStart( int numCells, - __global int* pCellStart GUID_ARG) -{ - int index = get_global_id(0); - if(index >= numCells) - { - return; - } - pCellStart[index] = -1; -} - -__kernel void kFindCellStart(int numObjects, __global int2* pHash, __global int* cellStart GUID_ARG) -{ - __local int sharedHash[513]; - int index = get_global_id(0); - int2 sortedData; - if(index < numObjects) - { - sortedData = pHash[index]; - // Load hash data into shared memory so that we can look - // at neighboring body's hash value without loading - // two hash values per thread - sharedHash[get_local_id(0) + 1] = sortedData.x; - if((index > 0) && (get_local_id(0) == 0)) - { - // first thread in block must load neighbor body hash - sharedHash[0] = pHash[index-1].x; - } - } - barrier(CLK_LOCAL_MEM_FENCE); - if(index < numObjects) - { - if((index == 0) || (sortedData.x != sharedHash[get_local_id(0)])) - { - cellStart[sortedData.x] = index; - } - } -} - -int testAABBOverlap(float4 min0, float4 max0, float4 min1, float4 max1) -{ - return (min0.x <= max1.x)&& (min1.x <= max0.x) && - (min0.y <= max1.y)&& (min1.y <= max0.y) && - (min0.z <= max1.z)&& (min1.z <= max0.z); -} - - - - - -void findPairsInCell( int numObjects, - int4 gridPos, - int index, - __global int2* pHash, - __global int* pCellStart, - __global float4* pAABB, - __global int* pPairBuff, - __global int2* pPairBuffStartCurr, - __global float4* pParams) -{ - int4 pGridDim = *((__global int4*)(pParams + 1)); - int maxBodiesPerCell = pGridDim.w; - int gridHash = getPosHash(gridPos, pParams); - // get start of bucket for this cell - int bucketStart = pCellStart[gridHash]; - if (bucketStart == -1) - { - return; // cell empty - } - // iterate over bodies in this cell - int2 sortedData = pHash[index]; - int unsorted_indx = sortedData.y; - float4 min0 = pAABB[unsorted_indx*2 + 0]; - float4 max0 = pAABB[unsorted_indx*2 + 1]; - int handleIndex = as_int(min0.w); - int2 start_curr = pPairBuffStartCurr[handleIndex]; - int start = start_curr.x; - int curr = start_curr.y; - int2 start_curr_next = pPairBuffStartCurr[handleIndex+1]; - int curr_max = start_curr_next.x - start - 1; - int bucketEnd = bucketStart + maxBodiesPerCell; - bucketEnd = (bucketEnd > numObjects) ? numObjects : bucketEnd; - for(int index2 = bucketStart; index2 < bucketEnd; index2++) - { - int2 cellData = pHash[index2]; - if (cellData.x != gridHash) - { - break; // no longer in same bucket - } - int unsorted_indx2 = cellData.y; - if (unsorted_indx2 < unsorted_indx) // check not colliding with self - { - float4 min1 = pAABB[unsorted_indx2*2 + 0]; - float4 max1 = pAABB[unsorted_indx2*2 + 1]; - if(testAABBOverlap(min0, max0, min1, max1)) - { - int handleIndex2 = as_int(min1.w); - int k; - for(k = 0; k < curr; k++) - { - int old_pair = pPairBuff[start+k] & (~0x60000000); - if(old_pair == handleIndex2) - { - pPairBuff[start+k] |= 0x40000000; - break; - } - } - if(k == curr) - { - if(curr >= curr_max) - { // not a good solution, but let's avoid crash - break; - } - pPairBuff[start+curr] = handleIndex2 | 0x20000000; - curr++; - } - } - } - } - int2 newStartCurr; - newStartCurr.x = start; - newStartCurr.y = curr; - pPairBuffStartCurr[handleIndex] = newStartCurr; - return; -} - -__kernel void kFindOverlappingPairs( int numObjects, - __global float4* pAABB, - __global int2* pHash, - __global int* pCellStart, - __global int* pPairBuff, - __global int2* pPairBuffStartCurr, - __global float4* pParams GUID_ARG) - -{ - int index = get_global_id(0); - if(index >= numObjects) - { - return; - } - int2 sortedData = pHash[index]; - int unsorted_indx = sortedData.y; - float4 bbMin = pAABB[unsorted_indx*2 + 0]; - float4 bbMax = pAABB[unsorted_indx*2 + 1]; - float4 pos; - pos.x = (bbMin.x + bbMax.x) * 0.5f; - pos.y = (bbMin.y + bbMax.y) * 0.5f; - pos.z = (bbMin.z + bbMax.z) * 0.5f; - // get address in grid - int4 gridPosA = getGridPos(pos, pParams); - int4 gridPosB; - // examine only neighbouring cells - for(int z=-1; z<=1; z++) - { - gridPosB.z = gridPosA.z + z; - for(int y=-1; y<=1; y++) - { - gridPosB.y = gridPosA.y + y; - for(int x=-1; x<=1; x++) - { - gridPosB.x = gridPosA.x + x; - findPairsInCell(numObjects, gridPosB, index, pHash, pCellStart, pAABB, pPairBuff, pPairBuffStartCurr, pParams); - } - } - } -} - - -__kernel void kFindPairsLarge( int numObjects, - __global float4* pAABB, - __global int2* pHash, - __global int* pCellStart, - __global int* pPairBuff, - __global int2* pPairBuffStartCurr, - uint numLarge GUID_ARG) -{ - int index = get_global_id(0); - if(index >= numObjects) - { - return; - } - int2 sortedData = pHash[index]; - int unsorted_indx = sortedData.y; - float4 min0 = pAABB[unsorted_indx*2 + 0]; - float4 max0 = pAABB[unsorted_indx*2 + 1]; - int handleIndex = as_int(min0.w); - int2 start_curr = pPairBuffStartCurr[handleIndex]; - int start = start_curr.x; - int curr = start_curr.y; - int2 start_curr_next = pPairBuffStartCurr[handleIndex+1]; - int curr_max = start_curr_next.x - start - 1; - for(uint i = 0; i < numLarge; i++) - { - int indx2 = numObjects + i; - float4 min1 = pAABB[indx2*2 + 0]; - float4 max1 = pAABB[indx2*2 + 1]; - if(testAABBOverlap(min0, max0, min1, max1)) - { - int k; - int handleIndex2 = as_int(min1.w); - for(k = 0; k < curr; k++) - { - int old_pair = pPairBuff[start+k] & (~0x60000000); - if(old_pair == handleIndex2) - { - pPairBuff[start+k] |= 0x40000000; - break; - } - } - if(k == curr) - { - pPairBuff[start+curr] = handleIndex2 | 0x20000000; - if(curr >= curr_max) - { // not a good solution, but let's avoid crash - break; - } - curr++; - } - } - } - int2 newStartCurr; - newStartCurr.x = start; - newStartCurr.y = curr; - pPairBuffStartCurr[handleIndex] = newStartCurr; - return; -} - -__kernel void kComputePairCacheChanges( int numObjects, - __global int* pPairBuff, - __global int2* pPairBuffStartCurr, - __global int* pPairScan, - __global float4* pAABB GUID_ARG) -{ - int index = get_global_id(0); - if(index >= numObjects) - { - return; - } - float4 bbMin = pAABB[index * 2]; - int handleIndex = as_int(bbMin.w); - int2 start_curr = pPairBuffStartCurr[handleIndex]; - int start = start_curr.x; - int curr = start_curr.y; - __global int *pInp = pPairBuff + start; - int num_changes = 0; - for(int k = 0; k < curr; k++, pInp++) - { - if(!((*pInp) & 0x40000000)) - { - num_changes++; - } - } - pPairScan[index+1] = num_changes; -} - -__kernel void kSqueezeOverlappingPairBuff( int numObjects, - __global int* pPairBuff, - __global int2* pPairBuffStartCurr, - __global int* pPairScan, - __global int* pPairOut, - __global float4* pAABB GUID_ARG) -{ - int index = get_global_id(0); - if(index >= numObjects) - { - return; - } - float4 bbMin = pAABB[index * 2]; - int handleIndex = as_int(bbMin.w); - int2 start_curr = pPairBuffStartCurr[handleIndex]; - int start = start_curr.x; - int curr = start_curr.y; - __global int* pInp = pPairBuff + start; - __global int* pOut = pPairOut + pPairScan[index+1]; - __global int* pOut2 = pInp; - int num = 0; - for(int k = 0; k < curr; k++, pInp++) - { - if(!((*pInp) & 0x40000000)) - { - *pOut = *pInp; - pOut++; - } - if((*pInp) & 0x60000000) - { - *pOut2 = (*pInp) & (~0x60000000); - pOut2++; - num++; - } - } - int2 newStartCurr; - newStartCurr.x = start; - newStartCurr.y = num; - pPairBuffStartCurr[handleIndex] = newStartCurr; -} - - - - -); \ No newline at end of file diff --git a/Extras/RigidBodyGpuPipeline/opencl/3dGridBroadphase/Shared/bt3dGridBroadphaseOCL.cpp b/Extras/RigidBodyGpuPipeline/opencl/3dGridBroadphase/Shared/bt3dGridBroadphaseOCL.cpp deleted file mode 100644 index ca08ef5a6..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/3dGridBroadphase/Shared/bt3dGridBroadphaseOCL.cpp +++ /dev/null @@ -1,695 +0,0 @@ -/* -Bullet Continuous Collision Detection and Physics Library, http://bulletphysics.org -Copyright (C) 2006 - 2009 Sony Computer Entertainment Inc. - -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/btAlignedAllocator.h" -#include "LinearMath/btQuickprof.h" -#include "BulletCollision/BroadphaseCollision/btOverlappingPairCache.h" -#include "../basic_initialize/btOpenCLUtils.h" - -#include "bt3dGridBroadphaseOCL.h" - -#include -#include -#include "Adl/Adl.h" -#include -#include -#include - -#define ADD_BLOCKING_CL_FINISH_FOR_BENCHMARK - -#define GRID_OCL_PATH "..\\..\\opencl\\3dGridBroadphase\\Shared\\bt3dGridBroadphaseOCL.cl" - - -#define MSTRINGIFY(A) #A - -static const char* spProgramSource = -#include "bt3dGridBroadphaseOCL.cl" - -adl::PrefixScan::Data* gData1=0; -adl::Buffer* m_srcClBuffer=0; - -struct MySortData -{ - int key; - int value; -}; - -adl::RadixSort32::Data* dataC = 0; -adl::RadixSort::Data* dataHost = 0; - - -static unsigned int infElem = 0x2fffffff; - -static unsigned int zeroEl = 0; -static unsigned int minusOne= -1; - - -bt3dGridBroadphaseOCL::bt3dGridBroadphaseOCL( btOverlappingPairCache* overlappingPairCache, - const btVector3& cellSize, - int gridSizeX, int gridSizeY, int gridSizeZ, - int maxSmallProxies, int maxLargeProxies, int maxPairsPerSmallProxy, - btScalar maxSmallProxySize, - int maxSmallProxiesPerCell, - cl_context context, cl_device_id device, cl_command_queue queue, - adl::DeviceCL* deviceCL - ) : - btGpu3DGridBroadphase(overlappingPairCache, cellSize, gridSizeX, gridSizeY, gridSizeZ, maxSmallProxies, maxLargeProxies, maxPairsPerSmallProxy, maxSmallProxySize, maxSmallProxiesPerCell) -{ - - - initCL(context, device, queue); - allocateBuffers(); - - prefillBuffers(); - - initKernels(); - - //create an Adl device host and OpenCL device - - adl::DeviceUtils::Config cfg; - m_deviceHost = adl::DeviceUtils::allocate( adl::TYPE_HOST, cfg ); - m_ownsDevice = false; - if (!deviceCL) - { - m_ownsDevice = true; - deviceCL = new adl::DeviceCL; - deviceCL->m_context = context; - deviceCL->m_deviceIdx = device; - deviceCL->m_commandQueue = queue; - deviceCL->m_kernelManager = new adl::KernelManager; - } - - m_deviceCL = deviceCL; - - int minSize = 256*1024; - int maxSortBuffer = maxSmallProxies < minSize ? minSize :maxSmallProxies; - - m_srcClBuffer = new adl::Buffer (m_deviceCL,maxSmallProxies+2); - m_srcClBuffer->write(&zeroEl,1,0); - - //m_srcClBuffer->write(&infElem,maxSmallProxies,0); - m_srcClBuffer->write(&infElem,1,maxSmallProxies); - m_srcClBuffer->write(&zeroEl,1,maxSmallProxies+1); - m_deviceCL->waitForCompletion(); - - gData1 = adl::PrefixScan::allocate( m_deviceCL, maxSortBuffer+2,adl::PrefixScanBase::EXCLUSIVE ); - dataHost = adl::RadixSort::allocate( m_deviceHost, maxSmallProxies+2 ); - dataC = adl::RadixSort32::allocate( m_deviceCL, maxSortBuffer+2 ); - -} - - - -bt3dGridBroadphaseOCL::~bt3dGridBroadphaseOCL() -{ - //btSimpleBroadphase will free memory of btSortedOverlappingPairCache, because m_ownsPairCache - assert(m_bInitialized); - adl::RadixSort::deallocate(dataHost); - adl::PrefixScan::deallocate(gData1); - adl::RadixSort32::deallocate(dataC); - adl::DeviceUtils::deallocate(m_deviceHost); - delete m_srcClBuffer; - if (m_ownsDevice) - { - delete m_deviceCL->m_kernelManager; - delete m_deviceCL; - } -} - -#ifdef CL_PLATFORM_MINI_CL -// there is a problem with MSVC9 : static constructors are not called if variables defined in library and are not used -// looks like it is because of optimization -// probably this will happen with other compilers as well -// so to make it robust, register kernels again (it is safe) -#define MINICL_DECLARE(a) extern "C" void a(); -MINICL_DECLARE(kCalcHashAABB) -MINICL_DECLARE(kClearCellStart) -MINICL_DECLARE(kFindCellStart) -MINICL_DECLARE(kFindOverlappingPairs) -MINICL_DECLARE(kFindPairsLarge) -MINICL_DECLARE(kComputePairCacheChanges) -MINICL_DECLARE(kSqueezeOverlappingPairBuff) -#undef MINICL_DECLARE -#endif - -void bt3dGridBroadphaseOCL::initCL(cl_context context, cl_device_id device, cl_command_queue queue) -{ - - #ifdef CL_PLATFORM_MINI_CL - // call constructors here - MINICL_REGISTER(kCalcHashAABB) - MINICL_REGISTER(kClearCellStart) - MINICL_REGISTER(kFindCellStart) - MINICL_REGISTER(kFindOverlappingPairs) - MINICL_REGISTER(kFindPairsLarge) - MINICL_REGISTER(kComputePairCacheChanges) - MINICL_REGISTER(kSqueezeOverlappingPairBuff) - #endif - - cl_int ciErrNum; - - btAssert(context); - m_cxMainContext = context; - btAssert(device); - m_cdDevice = device; - btAssert(queue); - m_cqCommandQue = queue; - - //adl::Kernel kern = m_deviceCL->getKernel(fileName,funcName,options,src); - - m_cpProgram = btOpenCLUtils::compileCLProgramFromString(m_cxMainContext,m_cdDevice,spProgramSource, &ciErrNum,"-DGUID_ARG=""""",GRID_OCL_PATH); - - printf("OK\n"); -} - - -void bt3dGridBroadphaseOCL::initKernels() -{ - initKernel(GRID3DOCL_KERNEL_CALC_HASH_AABB, "kCalcHashAABB"); - setKernelArg(GRID3DOCL_KERNEL_CALC_HASH_AABB, 1, sizeof(cl_mem),(void*)&m_dAABB); - setKernelArg(GRID3DOCL_KERNEL_CALC_HASH_AABB, 2, sizeof(cl_mem),(void*)&m_dBodiesHash); - setKernelArg(GRID3DOCL_KERNEL_CALC_HASH_AABB, 3, sizeof(cl_mem),(void*)&m_dBpParams); - - initKernel(GRID3DOCL_KERNEL_CLEAR_CELL_START, "kClearCellStart"); - setKernelArg(GRID3DOCL_KERNEL_CLEAR_CELL_START, 1, sizeof(cl_mem),(void*)&m_dCellStart); - - initKernel(GRID3DOCL_KERNEL_FIND_CELL_START, "kFindCellStart"); - setKernelArg(GRID3DOCL_KERNEL_FIND_CELL_START, 1, sizeof(cl_mem),(void*)&m_dBodiesHash); - setKernelArg(GRID3DOCL_KERNEL_FIND_CELL_START, 2, sizeof(cl_mem),(void*)&m_dCellStart); - - initKernel(GRID3DOCL_KERNEL_FIND_OVERLAPPING_PAIRS, "kFindOverlappingPairs"); - setKernelArg(GRID3DOCL_KERNEL_FIND_OVERLAPPING_PAIRS, 1, sizeof(cl_mem),(void*)&m_dAABB); - setKernelArg(GRID3DOCL_KERNEL_FIND_OVERLAPPING_PAIRS, 2, sizeof(cl_mem),(void*)&m_dBodiesHash); - setKernelArg(GRID3DOCL_KERNEL_FIND_OVERLAPPING_PAIRS, 3, sizeof(cl_mem),(void*)&m_dCellStart); - setKernelArg(GRID3DOCL_KERNEL_FIND_OVERLAPPING_PAIRS, 4, sizeof(cl_mem),(void*)&m_dPairBuff); - setKernelArg(GRID3DOCL_KERNEL_FIND_OVERLAPPING_PAIRS, 5, sizeof(cl_mem),(void*)&m_dPairBuffStartCurr); - setKernelArg(GRID3DOCL_KERNEL_FIND_OVERLAPPING_PAIRS, 6, sizeof(cl_mem),(void*)&m_dBpParams); - - initKernel(GRID3DOCL_KERNEL_FIND_PAIRS_LARGE, "kFindPairsLarge"); - setKernelArg(GRID3DOCL_KERNEL_FIND_PAIRS_LARGE, 1, sizeof(cl_mem),(void*)&m_dAABB); - setKernelArg(GRID3DOCL_KERNEL_FIND_PAIRS_LARGE, 2, sizeof(cl_mem),(void*)&m_dBodiesHash); - setKernelArg(GRID3DOCL_KERNEL_FIND_PAIRS_LARGE, 3, sizeof(cl_mem),(void*)&m_dCellStart); - setKernelArg(GRID3DOCL_KERNEL_FIND_PAIRS_LARGE, 4, sizeof(cl_mem),(void*)&m_dPairBuff); - setKernelArg(GRID3DOCL_KERNEL_FIND_PAIRS_LARGE, 5, sizeof(cl_mem),(void*)&m_dPairBuffStartCurr); - - initKernel(GRID3DOCL_KERNEL_COMPUTE_CACHE_CHANGES, "kComputePairCacheChanges"); - setKernelArg(GRID3DOCL_KERNEL_COMPUTE_CACHE_CHANGES, 1, sizeof(cl_mem),(void*)&m_dPairBuff); - setKernelArg(GRID3DOCL_KERNEL_COMPUTE_CACHE_CHANGES, 2, sizeof(cl_mem),(void*)&m_dPairBuffStartCurr); - setKernelArg(GRID3DOCL_KERNEL_COMPUTE_CACHE_CHANGES, 3, sizeof(cl_mem),(void*)&m_dPairScanChanged); - setKernelArg(GRID3DOCL_KERNEL_COMPUTE_CACHE_CHANGES, 4, sizeof(cl_mem),(void*)&m_dAABB); - - initKernel(GRID3DOCL_KERNEL_SQUEEZE_PAIR_BUFF, "kSqueezeOverlappingPairBuff"); - setKernelArg(GRID3DOCL_KERNEL_SQUEEZE_PAIR_BUFF, 1, sizeof(cl_mem),(void*)&m_dPairBuff); - setKernelArg(GRID3DOCL_KERNEL_SQUEEZE_PAIR_BUFF, 2, sizeof(cl_mem),(void*)&m_dPairBuffStartCurr); - setKernelArg(GRID3DOCL_KERNEL_SQUEEZE_PAIR_BUFF, 3, sizeof(cl_mem),(void*)&m_dPairScanChanged); - setKernelArg(GRID3DOCL_KERNEL_SQUEEZE_PAIR_BUFF, 4, sizeof(cl_mem),(void*)&m_dPairsChanged); - setKernelArg(GRID3DOCL_KERNEL_SQUEEZE_PAIR_BUFF, 5, sizeof(cl_mem),(void*)&m_dAABB); - -} - - -void bt3dGridBroadphaseOCL::allocateBuffers() -{ - cl_int ciErrNum; - unsigned int memSize; - // current version of bitonic sort works for power of 2 arrays only, so ... - m_hashSize = 1; - for(int bit = 1; bit < 32; bit++) - { - if(m_hashSize >= m_maxHandles) - { - break; - } - m_hashSize <<= 1; - } - memSize = m_hashSize * 2 * sizeof(unsigned int); - if (memSize < 1024*1024) - memSize = 1024*1024; - - m_dBodiesHash = clCreateBuffer(m_cxMainContext, CL_MEM_READ_WRITE, memSize, NULL, &ciErrNum); - GRID3DOCL_CHECKERROR(ciErrNum, CL_SUCCESS); - - memSize = m_numCells * sizeof(unsigned int); - m_dCellStart = clCreateBuffer(m_cxMainContext, CL_MEM_READ_WRITE, memSize, NULL, &ciErrNum); - GRID3DOCL_CHECKERROR(ciErrNum, CL_SUCCESS); - - memSize = m_maxHandles * m_maxPairsPerBody * sizeof(unsigned int); - m_dPairBuff = clCreateBuffer(m_cxMainContext, CL_MEM_READ_WRITE, memSize, NULL, &ciErrNum); - GRID3DOCL_CHECKERROR(ciErrNum, CL_SUCCESS); - - memSize = (m_maxHandles * 2 + 1) * sizeof(unsigned int); - m_dPairBuffStartCurr = clCreateBuffer(m_cxMainContext, CL_MEM_READ_WRITE, memSize, NULL, &ciErrNum); - GRID3DOCL_CHECKERROR(ciErrNum, CL_SUCCESS); - - unsigned int numAABB = m_maxHandles + m_maxLargeHandles; - memSize = numAABB * sizeof(float) * 4 * 2; - m_dAABB = clCreateBuffer(m_cxMainContext, CL_MEM_READ_WRITE, memSize, NULL, &ciErrNum); - GRID3DOCL_CHECKERROR(ciErrNum, CL_SUCCESS); - - memSize = (m_maxHandles + 2) * sizeof(unsigned int); - m_dPairScanChanged = clCreateBuffer(m_cxMainContext, CL_MEM_READ_WRITE, memSize, NULL, &ciErrNum); - GRID3DOCL_CHECKERROR(ciErrNum, CL_SUCCESS); - - memSize = m_maxHandles * m_maxPairsPerBody * sizeof(unsigned int); - m_dPairsChanged = clCreateBuffer(m_cxMainContext, CL_MEM_READ_WRITE, memSize, NULL, &ciErrNum); - GRID3DOCL_CHECKERROR(ciErrNum, CL_SUCCESS); - - - memSize = 3 * 4 * sizeof(float); - m_dBpParams = clCreateBuffer(m_cxMainContext, CL_MEM_READ_WRITE, memSize, NULL, &ciErrNum); - GRID3DOCL_CHECKERROR(ciErrNum, CL_SUCCESS); -} - -void bt3dGridBroadphaseOCL::prefillBuffers() -{ - memset(m_hBodiesHash, 0xFF, m_maxHandles*2*sizeof(unsigned int)); - copyArrayToDevice(m_dBodiesHash, m_hBodiesHash, m_maxHandles * 2 * sizeof(unsigned int)); - // now fill the rest (bitonic sorting works with size == pow of 2) - int remainder = m_hashSize - m_maxHandles; - if(remainder) - { - copyArrayToDevice(m_dBodiesHash, m_hBodiesHash, remainder * 2 * sizeof(unsigned int), m_maxHandles * 2 * sizeof(unsigned int), 0); - } - copyArrayToDevice(m_dPairBuffStartCurr, m_hPairBuffStartCurr, (m_maxHandles * 2 + 1) * sizeof(unsigned int)); - memset(m_hPairBuff, 0x00, m_maxHandles * m_maxPairsPerBody * sizeof(unsigned int)); - copyArrayToDevice(m_dPairBuff, m_hPairBuff, m_maxHandles * m_maxPairsPerBody * sizeof(unsigned int)); -} - - -void bt3dGridBroadphaseOCL::initKernel(int kernelId, char* pName) -{ - - cl_int ciErrNum; - cl_kernel kernel = clCreateKernel(m_cpProgram, pName, &ciErrNum); - GRID3DOCL_CHECKERROR(ciErrNum, CL_SUCCESS); - size_t wgSize; - ciErrNum = clGetKernelWorkGroupInfo(kernel, m_cdDevice, CL_KERNEL_WORK_GROUP_SIZE, sizeof(size_t), &wgSize, NULL); - GRID3DOCL_CHECKERROR(ciErrNum, CL_SUCCESS); - m_kernels[kernelId].m_Id = kernelId; - m_kernels[kernelId].m_kernel = kernel; - m_kernels[kernelId].m_name = pName; - m_kernels[kernelId].m_workgroupSize = (int)wgSize; - return; -} - -void bt3dGridBroadphaseOCL::runKernelWithWorkgroupSize(int kernelId, int globalSize) -{ - if(globalSize <= 0) - { - return; - } - cl_kernel kernelFunc = m_kernels[kernelId].m_kernel; - cl_int ciErrNum = clSetKernelArg(kernelFunc, 0, sizeof(int), (void*)&globalSize); - GRID3DOCL_CHECKERROR(ciErrNum, CL_SUCCESS); - int workgroupSize = btMin(64,m_kernels[kernelId].m_workgroupSize); - - if(workgroupSize <= 0) - { // let OpenCL library calculate workgroup size - size_t globalWorkSize[2]; - globalWorkSize[0] = globalSize; - globalWorkSize[1] = 1; - ciErrNum = clEnqueueNDRangeKernel(m_cqCommandQue, kernelFunc, 1, NULL, globalWorkSize, NULL, 0,0,0 ); - } - else - { - size_t localWorkSize[2], globalWorkSize[2]; - //workgroupSize = btMin(workgroupSize, globalSize); - int num_t = globalSize / workgroupSize; - int num_g = num_t * workgroupSize; - if(num_g < globalSize) - { - num_t++; - } - localWorkSize[0] = workgroupSize; - globalWorkSize[0] = num_t * workgroupSize; - localWorkSize[1] = 1; - globalWorkSize[1] = 1; - ciErrNum = clEnqueueNDRangeKernel(m_cqCommandQue, kernelFunc, 1, NULL, globalWorkSize, localWorkSize, 0,0,0 ); - } - GRID3DOCL_CHECKERROR(ciErrNum, CL_SUCCESS); - ciErrNum = clFlush(m_cqCommandQue); - GRID3DOCL_CHECKERROR(ciErrNum, CL_SUCCESS); -} - - -void bt3dGridBroadphaseOCL::setKernelArg(int kernelId, int argNum, int argSize, void* argPtr) -{ - cl_int ciErrNum; - ciErrNum = clSetKernelArg(m_kernels[kernelId].m_kernel, argNum, argSize, argPtr); - GRID3DOCL_CHECKERROR(ciErrNum, CL_SUCCESS); -} - - -void bt3dGridBroadphaseOCL::copyArrayToDevice(cl_mem device, const void* host, unsigned int size, int devOffs, int hostOffs) -{ - if (size) - { - cl_int ciErrNum; - char* pHost = (char*)host + hostOffs; - ciErrNum = clEnqueueWriteBuffer(m_cqCommandQue, device, CL_TRUE, devOffs, size, pHost, 0, NULL, NULL); - GRID3DOCL_CHECKERROR(ciErrNum, CL_SUCCESS); - } -} - -void bt3dGridBroadphaseOCL::copyArrayFromDevice(void* host, const cl_mem device, unsigned int size, int hostOffs, int devOffs) -{ - if (size) - { - cl_int ciErrNum; - char* pHost = (char*)host + hostOffs; - ciErrNum = clEnqueueReadBuffer(m_cqCommandQue, device, CL_TRUE, devOffs, size, pHost, 0, NULL, NULL); - GRID3DOCL_CHECKERROR(ciErrNum, CL_SUCCESS); - } -} - - - -// -// overrides -// - - -void bt3dGridBroadphaseOCL::prepareAABB() -{ - btGpu3DGridBroadphase::prepareAABB(); - copyArrayToDevice(m_dAABB, m_hAABB, sizeof(bt3DGrid3F1U) * 2 * (m_numHandles + m_numLargeHandles)); - return; -} - -void bt3dGridBroadphaseOCL::setParameters(bt3DGridBroadphaseParams* hostParams) -{ - btGpu3DGridBroadphase::setParameters(hostParams); - struct btParamsBpOCL - { - float m_invCellSize[4]; - int m_gridSize[4]; - }; - btParamsBpOCL hParams; - hParams.m_invCellSize[0] = m_params.m_invCellSizeX; - hParams.m_invCellSize[1] = m_params.m_invCellSizeY; - hParams.m_invCellSize[2] = m_params.m_invCellSizeZ; - hParams.m_invCellSize[3] = 0.f; - hParams.m_gridSize[0] = m_params.m_gridSizeX; - hParams.m_gridSize[1] = m_params.m_gridSizeY; - hParams.m_gridSize[2] = m_params.m_gridSizeZ; - hParams.m_gridSize[3] = m_params.m_maxBodiesPerCell; - copyArrayToDevice(m_dBpParams, &hParams, sizeof(btParamsBpOCL)); - return; -} - - -void bt3dGridBroadphaseOCL::calcHashAABB() -{ - BT_PROFILE("calcHashAABB"); -#if 1 - runKernelWithWorkgroupSize(GRID3DOCL_KERNEL_CALC_HASH_AABB, m_numHandles); -#ifdef ADD_BLOCKING_CL_FINISH_FOR_BENCHMARK - clFinish(m_cqCommandQue); -#endif //ADD_BLOCKING_CL_FINISH_FOR_BENCHMARK - -#else - btGpu3DGridBroadphase::calcHashAABB(); -#endif - - return; -} - - -void bt3dGridBroadphaseOCL::sortHash() -{ - BT_PROFILE("sortHash"); -#ifdef CL_PLATFORM_MINI_CL - //copyArrayFromDevice(m_hBodiesHash, m_dBodiesHash, m_numHandles * 2 * sizeof(unsigned int)); - btGpu3DGridBroadphase::sortHash(); - copyArrayToDevice(m_dBodiesHash, m_hBodiesHash, m_numHandles * 2 * sizeof(unsigned int)); -#else - -//#define USE_HOST -#ifdef USE_HOST - copyArrayFromDevice(m_hBodiesHash, m_dBodiesHash, m_numHandles * 2 * sizeof(unsigned int)); - //adl::Buffer keysIn,keysOut,valuesIn,valuesOut; - ///adl::RadixSort32::execute(dataC,keysIn,keysOut,valuesIn,valuesOut,m_numHandles); - adl::HostBuffer inoutHost; - inoutHost.m_device = m_deviceHost; - inoutHost.m_ptr = (adl::SortData*)m_hBodiesHash; - inoutHost.m_size = m_numHandles; - adl::RadixSort::execute(dataHost, inoutHost,m_numHandles); - copyArrayToDevice(m_dBodiesHash, m_hBodiesHash, m_numHandles * 2 * sizeof(unsigned int)); -#else - { - clFinish(m_cqCommandQue); - BT_PROFILE("RadixSort32::execute"); - adl::Buffer inout; - inout.m_device = this->m_deviceCL; - inout.m_size = m_numHandles; - inout.m_ptr = (adl::SortData*)m_dBodiesHash; - int actualHandles = m_numHandles; - int dataAlignment = adl::RadixSort32::DATA_ALIGNMENT; - - if (actualHandles%dataAlignment) - { - actualHandles += dataAlignment-(actualHandles%dataAlignment); - } - - adl::RadixSort32::execute(dataC,inout, actualHandles); -#ifdef ADD_BLOCKING_CL_FINISH_FOR_BENCHMARK - clFinish(m_cqCommandQue); -#endif //ADD_BLOCKING_CL_FINISH_FOR_BENCHMARK - } - { - //BT_PROFILE("copyArrayFromDevice"); - //copyArrayFromDevice(m_hBodiesHash, m_dBodiesHash, m_numHandles * 2 * sizeof(unsigned int)); -#ifdef ADD_BLOCKING_CL_FINISH_FOR_BENCHMARK - clFinish(m_cqCommandQue); -#endif //ADD_BLOCKING_CL_FINISH_FOR_BENCHMARK - } - - -#endif //USE_HOST -#endif - - return; -} - - - -void bt3dGridBroadphaseOCL::findCellStart() -{ -#if 1 - BT_PROFILE("findCellStart"); - - #if defined(CL_PLATFORM_MINI_CL) - btGpu3DGridBroadphase::findCellStart(); - copyArrayToDevice(m_dCellStart, m_hCellStart, m_numCells * sizeof(unsigned int)); - #else - runKernelWithWorkgroupSize(GRID3DOCL_KERNEL_CLEAR_CELL_START, m_numCells); - runKernelWithWorkgroupSize(GRID3DOCL_KERNEL_FIND_CELL_START, m_numHandles); - #endif -#ifdef ADD_BLOCKING_CL_FINISH_FOR_BENCHMARK - clFinish(m_cqCommandQue); -#endif - -#else - btGpu3DGridBroadphase::findCellStart(); -#endif - - return; -} - - - -void bt3dGridBroadphaseOCL::findOverlappingPairs() -{ -#if 1 - BT_PROFILE("findOverlappingPairs"); - runKernelWithWorkgroupSize(GRID3DOCL_KERNEL_FIND_OVERLAPPING_PAIRS, m_numHandles); -#ifdef ADD_BLOCKING_CL_FINISH_FOR_BENCHMARK - clFinish(m_cqCommandQue); -#endif - -#else - btGpu3DGridBroadphase::findOverlappingPairs(); - copyArrayToDevice(m_dPairBuffStartCurr, m_hPairBuffStartCurr, (m_maxHandles * 2 + 1) * sizeof(unsigned int)); - copyArrayToDevice(m_dPairBuff, m_hPairBuff, m_maxHandles * m_maxPairsPerBody * sizeof(unsigned int)); -#endif - return; -} - - -void bt3dGridBroadphaseOCL::findPairsLarge() -{ - BT_PROFILE("findPairsLarge"); -#if 1 - if(m_numLargeHandles) - { - setKernelArg(GRID3DOCL_KERNEL_FIND_PAIRS_LARGE, 6, sizeof(int),(void*)&m_numLargeHandles); - runKernelWithWorkgroupSize(GRID3DOCL_KERNEL_FIND_PAIRS_LARGE, m_numHandles); - } -#ifdef ADD_BLOCKING_CL_FINISH_FOR_BENCHMARK - clFinish(m_cqCommandQue); -#endif - -#else - btGpu3DGridBroadphase::findPairsLarge(); -#endif - return; -} - - - -void bt3dGridBroadphaseOCL::computePairCacheChanges() -{ - BT_PROFILE("computePairCacheChanges"); -#if 1 - runKernelWithWorkgroupSize(GRID3DOCL_KERNEL_COMPUTE_CACHE_CHANGES, m_numHandles); -#ifdef ADD_BLOCKING_CL_FINISH_FOR_BENCHMARK - clFinish(m_cqCommandQue); -#endif - copyArrayFromDevice( m_hPairScanChanged,m_dPairScanChanged, sizeof(unsigned int)*(m_numHandles + 2)); - -#else - btGpu3DGridBroadphase::computePairCacheChanges(); - copyArrayToDevice(m_dPairScanChanged, m_hPairScanChanged, sizeof(unsigned int)*(m_numHandles + 2)); - - -#endif - return; -} - - - - -extern cl_device_type deviceType; - -void bt3dGridBroadphaseOCL::scanOverlappingPairBuff(bool copyToCpu) -{ - - //Intel/CPU version doesn't handlel Adl scan well -#if 0 - { - copyArrayFromDevice(m_hPairScanChanged, m_dPairScanChanged, sizeof(unsigned int)*(m_numHandles + 2)); - btGpu3DGridBroadphase::scanOverlappingPairBuff(); - copyArrayToDevice(m_dPairScanChanged, m_hPairScanChanged, sizeof(unsigned int)*(m_numHandles + 2)); - m_numPrefixSum = m_hPairScanChanged[m_numHandles+1]; - clFinish(m_cqCommandQue); - //memset(m_hPairScanChanged,0,sizeof(int)*m_maxHandles + 2); - } -#else - { - - // copyArrayFromDevice(m_hPairScanChanged, m_dPairScanChanged, sizeof(unsigned int)*(m_numHandles + 2)); - // btGpu3DGridBroadphase::scanOverlappingPairBuff(); - - adl::Buffer destBuffer; - - { - BT_PROFILE("copy GPU->GPU"); - - destBuffer.m_ptr = (unsigned int*)m_dPairScanChanged; - destBuffer.m_device = m_deviceCL; - destBuffer.m_size = sizeof(unsigned int)*(m_numHandles+2); - m_deviceCL->copy(m_srcClBuffer, &destBuffer,m_numHandles,1,1); - -#ifdef ADD_BLOCKING_CL_FINISH_FOR_BENCHMARK - clFinish(m_cqCommandQue); -#endif - - } - - { - BT_PROFILE("PrefixScan"); - - adl::PrefixScan::execute(gData1,*m_srcClBuffer,destBuffer, m_numHandles+2,&m_numPrefixSum); - -#ifdef ADD_BLOCKING_CL_FINISH_FOR_BENCHMARK - clFinish(m_cqCommandQue); -#endif - //if (m_numPrefixSum>0x1000) - // { - // printf("error m_numPrefixSum==%d\n",m_numPrefixSum); - // } - - } - -#if 0 - unsigned int* verifyhPairScanChanged = new unsigned int[m_maxHandles + 2]; - memset(verifyhPairScanChanged,0,sizeof(int)*m_maxHandles + 2); - - copyArrayFromDevice(verifyhPairScanChanged, m_dPairScanChanged, sizeof(unsigned int)*(m_numHandles + 2)); - clFinish(m_cqCommandQue); - - /*for (int i=0;i CPU"); - copyArrayFromDevice(m_hPairScanChanged, m_dPairScanChanged, sizeof(unsigned int)*(m_numHandles + 2)); -#ifdef ADD_BLOCKING_CL_FINISH_FOR_BENCHMARK - clFinish(m_cqCommandQue); -#endif - } - - } - - } -#endif - - -} - - - -void bt3dGridBroadphaseOCL::squeezeOverlappingPairBuff() -{ - BT_PROFILE("btCuda_squeezeOverlappingPairBuff"); -#if 1 - runKernelWithWorkgroupSize(GRID3DOCL_KERNEL_SQUEEZE_PAIR_BUFF, m_numHandles); -// btCuda_squeezeOverlappingPairBuff(m_dPairBuff, m_dPairBuffStartCurr, m_dPairScanChanged, m_dPairsChanged, m_dAABB, m_numHandles); - - //copyArrayFromDevice(m_hPairsChanged, m_dPairsChanged, sizeof(unsigned int) * m_numPrefixSum);//m_hPairScanChanged[m_numHandles+1]); //gSum -#ifdef ADD_BLOCKING_CL_FINISH_FOR_BENCHMARK - clFinish(m_cqCommandQue); -#endif - -#else - btGpu3DGridBroadphase::squeezeOverlappingPairBuff(); -#endif - return; -} - - - -void bt3dGridBroadphaseOCL::resetPool(btDispatcher* dispatcher) -{ - btGpu3DGridBroadphase::resetPool(dispatcher); - prefillBuffers(); -} - - diff --git a/Extras/RigidBodyGpuPipeline/opencl/3dGridBroadphase/Shared/bt3dGridBroadphaseOCL.h b/Extras/RigidBodyGpuPipeline/opencl/3dGridBroadphase/Shared/bt3dGridBroadphaseOCL.h deleted file mode 100644 index c12efa37a..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/3dGridBroadphase/Shared/bt3dGridBroadphaseOCL.h +++ /dev/null @@ -1,145 +0,0 @@ -/* -Bullet Continuous Collision Detection and Physics Library, http://bulletphysics.org -Copyright (C) 2006 - 2009 Sony Computer Entertainment Inc. - -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 BT3DGRIDBROADPHASEOCL_H -#define BT3DGRIDBROADPHASEOCL_H - -#ifdef __APPLE__ -#ifdef USE_MINICL - #include -#else - #include -#endif -//CL_PLATFORM_MINI_CL could be defined in build system -#else -//#include -// standard utility and system includes -#ifdef USE_MINICL - #include -#else - #include -#endif -// Extra CL/GL include -//#include -#endif //__APPLE__ - -namespace adl -{ - struct Device; - struct DeviceCL; -}; - -#include "BulletCollision/BroadphaseCollision/btSimpleBroadphase.h" -#include "btGpu3DGridBroadphaseSharedTypes.h" -#include "btGpu3DGridBroadphase.h" - - -#define GRID3DOCL_CHECKERROR(a, b) if((a)!=(b)) { printf("3D GRID OCL Error : %d\n", (a)); btAssert((a) == (b)); } - -enum -{ - GRID3DOCL_KERNEL_CALC_HASH_AABB = 0, - GRID3DOCL_KERNEL_CLEAR_CELL_START, - GRID3DOCL_KERNEL_FIND_CELL_START, - GRID3DOCL_KERNEL_FIND_OVERLAPPING_PAIRS, - GRID3DOCL_KERNEL_FIND_PAIRS_LARGE, - GRID3DOCL_KERNEL_COMPUTE_CACHE_CHANGES, - GRID3DOCL_KERNEL_SQUEEZE_PAIR_BUFF, - GRID3DOCL_KERNEL_TOTAL -}; - -struct bt3dGridOCLKernelInfo -{ - int m_Id; - cl_kernel m_kernel; - char* m_name; - int m_workgroupSize; -}; - - -///The bt3dGridBroadphaseOCL uses OpenCL-capable GPU to compute overlapping pairs - -class bt3dGridBroadphaseOCL : public btGpu3DGridBroadphase -{ -protected: - int m_hashSize; - cl_context m_cxMainContext; - cl_device_id m_cdDevice; - cl_command_queue m_cqCommandQue; - cl_program m_cpProgram; - bt3dGridOCLKernelInfo m_kernels[GRID3DOCL_KERNEL_TOTAL]; - // data buffers - cl_mem m_dBodiesHash; - cl_mem m_dCellStart; - cl_mem m_dPairBuff; - cl_mem m_dPairBuffStartCurr; -public: - cl_mem m_dAABB; -protected: - cl_mem m_dPairScanChanged; - cl_mem m_dPairsChanged; - cl_mem m_dBpParams; - - adl::Device* m_deviceHost; - adl::DeviceCL* m_deviceCL; - bool m_ownsDevice; - - -public: - unsigned int m_numPrefixSum; - - bt3dGridBroadphaseOCL( btOverlappingPairCache* overlappingPairCache, - const btVector3& cellSize, - int gridSizeX, int gridSizeY, int gridSizeZ, - int maxSmallProxies, int maxLargeProxies, int maxPairsPerSmallProxy, - btScalar maxSmallProxySize, - int maxSmallProxiesPerCell = 8, - cl_context context = NULL, - cl_device_id device = NULL, - cl_command_queue queue = NULL, - adl::DeviceCL* deviceCL = 0 - ); - virtual ~bt3dGridBroadphaseOCL(); - -protected: - void initCL(cl_context context, cl_device_id device, cl_command_queue queue); - void initKernels(); - void allocateBuffers(); - void prefillBuffers(); - void initKernel(int kernelId, char* pName); - void allocateArray(void** devPtr, unsigned int size); - void freeArray(void* devPtr); - void runKernelWithWorkgroupSize(int kernelId, int globalSize); - void setKernelArg(int kernelId, int argNum, int argSize, void* argPtr); - void copyArrayToDevice(cl_mem device, const void* host, unsigned int size, int devOffs = 0, int hostOffs = 0); - void copyArrayFromDevice(void* host, const cl_mem device, unsigned int size, int hostOffs = 0, int devOffs = 0); - -// overrides - virtual void setParameters(bt3DGridBroadphaseParams* hostParams); - virtual void prepareAABB(); - virtual void calcHashAABB(); - virtual void sortHash(); - virtual void findCellStart(); - virtual void findOverlappingPairs(); - virtual void findPairsLarge(); - virtual void computePairCacheChanges(); - virtual void scanOverlappingPairBuff(bool copyToCpu=true); - virtual void squeezeOverlappingPairBuff(); - virtual void resetPool(btDispatcher* dispatcher); -}; - -#endif //BT3DGRIDBROADPHASEOCL_H \ No newline at end of file diff --git a/Extras/RigidBodyGpuPipeline/opencl/3dGridBroadphase/Shared/btGpu3DGridBroadphase.cpp b/Extras/RigidBodyGpuPipeline/opencl/3dGridBroadphase/Shared/btGpu3DGridBroadphase.cpp deleted file mode 100644 index 3ecb6a2fb..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/3dGridBroadphase/Shared/btGpu3DGridBroadphase.cpp +++ /dev/null @@ -1,626 +0,0 @@ -/* -Bullet Continuous Collision Detection and Physics Library, http://bulletphysics.org -Copyright (C) 2006, 2009 Sony Computer Entertainment Inc. - -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. -*/ - -///The 3 following lines include the CPU implementation of the kernels, keep them in this order. -#include "btGpuDefines.h" -#include "btGpuUtilsSharedDefs.h" -#include "btGpuUtilsSharedCode.h" - - - -#include "LinearMath/btAlignedAllocator.h" -#include "LinearMath/btQuickprof.h" -#include "BulletCollision/BroadphaseCollision/btOverlappingPairCache.h" - - - -#include "btGpuDefines.h" -#include "btGpuUtilsSharedDefs.h" - -#include "btGpu3DGridBroadphaseSharedDefs.h" - -#include "btGpu3DGridBroadphase.h" -#include //for memset - - -#include - - - -static bt3DGridBroadphaseParams s3DGridBroadphaseParams; - - - -btGpu3DGridBroadphase::btGpu3DGridBroadphase( const btVector3& cellSize, - int gridSizeX, int gridSizeY, int gridSizeZ, - int maxSmallProxies, int maxLargeProxies, int maxPairsPerBody, - btScalar maxSmallProxySize, - int maxBodiesPerCell) : - btSimpleBroadphase(maxSmallProxies, -// new (btAlignedAlloc(sizeof(btSortedOverlappingPairCache),16)) btSortedOverlappingPairCache), - new (btAlignedAlloc(sizeof(btHashedOverlappingPairCache),16)) btHashedOverlappingPairCache), - m_bInitialized(false), - m_numBodies(0) -{ - _initialize(cellSize, gridSizeX, gridSizeY, gridSizeZ, - maxSmallProxies, maxLargeProxies, maxPairsPerBody, - maxSmallProxySize, maxBodiesPerCell); -} - - - -btGpu3DGridBroadphase::btGpu3DGridBroadphase( btOverlappingPairCache* overlappingPairCache, - const btVector3& cellSize, - int gridSizeX, int gridSizeY, int gridSizeZ, - int maxSmallProxies, int maxLargeProxies, int maxPairsPerBody, - btScalar maxSmallProxySize, - int maxBodiesPerCell) : - btSimpleBroadphase(maxSmallProxies, overlappingPairCache), - m_bInitialized(false), - m_numBodies(0) -{ - _initialize(cellSize, gridSizeX, gridSizeY, gridSizeZ, - maxSmallProxies, maxLargeProxies, maxPairsPerBody, - maxSmallProxySize, maxBodiesPerCell); -} - - - -btGpu3DGridBroadphase::~btGpu3DGridBroadphase() -{ - //btSimpleBroadphase will free memory of btSortedOverlappingPairCache, because m_ownsPairCache - assert(m_bInitialized); - _finalize(); - - -} - -// returns 2^n : 2^(n+1) > val >= 2^n -int btGpu3DGridBroadphase::getFloorPowOfTwo(int val) -{ - int mask = 0x40000000; - for(int k = 0; k < 30; k++, mask >>= 1) - { - if(mask & val) - { - break; - } - } - return mask; -} - - - -void btGpu3DGridBroadphase::_initialize( const btVector3& cellSize, - int gridSizeX, int gridSizeY, int gridSizeZ, - int maxSmallProxies, int maxLargeProxies, int maxPairsPerBody, - btScalar maxSmallProxySize, - int maxBodiesPerCell) -{ - // set various paramerers - m_ownsPairCache = true; - m_params.m_gridSizeX = getFloorPowOfTwo(gridSizeX); - m_params.m_gridSizeY = getFloorPowOfTwo(gridSizeY); - m_params.m_gridSizeZ = getFloorPowOfTwo(gridSizeZ); - m_params.m_numCells = m_params.m_gridSizeX * m_params.m_gridSizeY * m_params.m_gridSizeZ; - m_numCells = m_params.m_numCells; - m_params.m_invCellSizeX = btScalar(1.f) / cellSize[0]; - m_params.m_invCellSizeY = btScalar(1.f) / cellSize[1]; - m_params.m_invCellSizeZ = btScalar(1.f) / cellSize[2]; - m_maxRadius = maxSmallProxySize * btScalar(0.5f); - m_params.m_numBodies = m_numBodies; - m_params.m_maxBodiesPerCell = maxBodiesPerCell; - - m_numLargeHandles = 0; - m_maxLargeHandles = maxLargeProxies; - - m_maxPairsPerBody = maxPairsPerBody; - - m_LastLargeHandleIndex = -1; - - assert(!m_bInitialized); - - // allocate host storage - m_hBodiesHash = new unsigned int[m_maxHandles * 2]; - memset(m_hBodiesHash, 0x00, m_maxHandles*2*sizeof(unsigned int)); - - m_hCellStart = new unsigned int[m_params.m_numCells]; - memset(m_hCellStart, 0x00, m_params.m_numCells * sizeof(unsigned int)); - - m_hPairBuffStartCurr = new unsigned int[m_maxHandles * 2 + 2]; - // --------------- for now, init with m_maxPairsPerBody for each body - m_hPairBuffStartCurr[0] = 0; - m_hPairBuffStartCurr[1] = 0; - for(int i = 1; i <= m_maxHandles; i++) - { - m_hPairBuffStartCurr[i * 2] = m_hPairBuffStartCurr[(i-1) * 2] + m_maxPairsPerBody; - m_hPairBuffStartCurr[i * 2 + 1] = 0; - } - //---------------- - unsigned int numAABB = m_maxHandles + m_maxLargeHandles; - m_hAABB = new bt3DGrid3F1U[numAABB * 2]; // AABB Min & Max - - m_hPairBuff = new unsigned int[m_maxHandles * m_maxPairsPerBody]; - memset(m_hPairBuff, 0x00, m_maxHandles * m_maxPairsPerBody * sizeof(unsigned int)); // needed? - - m_hPairScanChanged = new unsigned int[m_maxHandles + 2]; - memset(m_hPairScanChanged,0,sizeof(int)*m_maxHandles + 2); - - m_hPairsChanged = new unsigned int[m_maxHandles * m_maxPairsPerBody]; - memset(m_hPairsChanged,0,sizeof(int)*(m_maxHandles * m_maxPairsPerBody)); - - m_hAllOverlappingPairs= new MyUint2[m_maxHandles * m_maxPairsPerBody]; - memset(m_hAllOverlappingPairs,0,sizeof(MyUint2)*(m_maxHandles * m_maxPairsPerBody)); - - -// large proxies - - // allocate handles buffer and put all handles on free list - m_pLargeHandlesRawPtr = btAlignedAlloc(sizeof(btSimpleBroadphaseProxy) * m_maxLargeHandles, 16); - m_pLargeHandles = new(m_pLargeHandlesRawPtr) btSimpleBroadphaseProxy[m_maxLargeHandles]; - m_firstFreeLargeHandle = 0; - { - for (int i = m_firstFreeLargeHandle; i < m_maxLargeHandles; i++) - { - m_pLargeHandles[i].SetNextFree(i + 1); - m_pLargeHandles[i].m_uniqueId = m_maxHandles+2+i; - } - m_pLargeHandles[m_maxLargeHandles - 1].SetNextFree(0); - } - -// debug data - m_numPairsAdded = 0; - m_numOverflows = 0; - - - m_bInitialized = true; -} - - - -void btGpu3DGridBroadphase::_finalize() -{ - assert(m_bInitialized); - delete [] m_hBodiesHash; - delete [] m_hCellStart; - delete [] m_hPairBuffStartCurr; - delete [] m_hAABB; - delete [] m_hPairBuff; - delete [] m_hPairScanChanged; - delete [] m_hPairsChanged; - delete [] m_hAllOverlappingPairs; - btAlignedFree(m_pLargeHandlesRawPtr); - m_bInitialized = false; -} - - - -void btGpu3DGridBroadphase::calculateOverlappingPairs(btDispatcher* dispatcher) -{ - btSimpleBroadphase::calculateOverlappingPairs(dispatcher); - - if(m_numHandles <= 0) - { - BT_PROFILE("addLarge2LargePairsToCache"); - addLarge2LargePairsToCache(dispatcher); - return; - } - // update constants - { - BT_PROFILE("setParameters"); - setParameters(&m_params); - } - - // prepare AABB array - { - BT_PROFILE("prepareAABB"); - prepareAABB(); - } - // calculate hash - { - BT_PROFILE("calcHashAABB"); - calcHashAABB(); - } - { - BT_PROFILE("sortHash"); - // sort bodies based on hash - sortHash(); - } - // find start of each cell - { - BT_PROFILE("findCellStart"); - findCellStart(); - } - { - BT_PROFILE("findOverlappingPairs"); - // findOverlappingPairs (small/small) - findOverlappingPairs(); - } - // findOverlappingPairs (small/large) - { - BT_PROFILE("findPairsLarge"); - findPairsLarge(); - } - // add pairs to CPU cache - { - BT_PROFILE("computePairCacheChanges"); - computePairCacheChanges(); - } - { - BT_PROFILE("scanOverlappingPairBuff"); - scanOverlappingPairBuff(); - } - { - BT_PROFILE("squeezeOverlappingPairBuff"); - squeezeOverlappingPairBuff(); - } - { - BT_PROFILE("addPairsToCache"); - addPairsToCache(dispatcher); - } - // find and add large/large pairs to CPU cache - { - BT_PROFILE("addLarge2LargePairsToCache"); - addLarge2LargePairsToCache(dispatcher); - } - return; -} - - - -void btGpu3DGridBroadphase::addPairsToCache(btDispatcher* dispatcher) -{ - m_numPairsAdded = 0; - m_numPairsRemoved = 0; - for(int i = 0; i < m_numHandles; i++) - { - unsigned int num = m_hPairScanChanged[i+2] - m_hPairScanChanged[i+1]; - if(!num) - { - continue; - } - unsigned int* pInp = m_hPairsChanged + m_hPairScanChanged[i+1]; - unsigned int index0 = m_hAABB[i * 2].uw; - btSimpleBroadphaseProxy* proxy0 = &m_pHandles[index0]; - for(unsigned int j = 0; j < num; j++) - { - unsigned int indx1_s = pInp[j]; - unsigned int index1 = indx1_s & (~BT_3DGRID_PAIR_ANY_FLG); - btSimpleBroadphaseProxy* proxy1; - if(index1 < (unsigned int)m_maxHandles) - { - proxy1 = &m_pHandles[index1]; - } - else - { - index1 -= m_maxHandles; - btAssert((index1 >= 0) && (index1 < (unsigned int)m_maxLargeHandles)); - proxy1 = &m_pLargeHandles[index1]; - } - if(indx1_s & BT_3DGRID_PAIR_NEW_FLG) - { - m_pairCache->addOverlappingPair(proxy0,proxy1); - m_numPairsAdded++; - } - else - { - m_pairCache->removeOverlappingPair(proxy0,proxy1,dispatcher); - m_numPairsRemoved++; - } - } - } -} - - - -btBroadphaseProxy* btGpu3DGridBroadphase::createProxy( const btVector3& aabbMin, const btVector3& aabbMax,int shapeType,void* userPtr ,short int collisionFilterGroup,short int collisionFilterMask, btDispatcher* dispatcher,void* multiSapProxy) -{ - btBroadphaseProxy* proxy; - bool bIsLarge = isLargeProxy(aabbMin, aabbMax); - if(bIsLarge) - { - if (m_numLargeHandles >= m_maxLargeHandles) - { - ///you have to increase the cell size, so 'large' proxies become 'small' proxies (fitting a cell) - btAssert(0); - return 0; //should never happen, but don't let the game crash ;-) - } - btAssert((aabbMin[0]<= aabbMax[0]) && (aabbMin[1]<= aabbMax[1]) && (aabbMin[2]<= aabbMax[2])); - int newHandleIndex = allocLargeHandle(); - proxy = new (&m_pLargeHandles[newHandleIndex])btSimpleBroadphaseProxy(aabbMin,aabbMax,shapeType,userPtr,collisionFilterGroup,collisionFilterMask,multiSapProxy); - } - else - { - proxy = btSimpleBroadphase::createProxy(aabbMin, aabbMax, shapeType, userPtr, collisionFilterGroup, collisionFilterMask, dispatcher, multiSapProxy); - } - return proxy; -} - - - -void btGpu3DGridBroadphase::destroyProxy(btBroadphaseProxy* proxy, btDispatcher* dispatcher) -{ - bool bIsLarge = isLargeProxy(proxy); - if(bIsLarge) - { - - btSimpleBroadphaseProxy* proxy0 = static_cast(proxy); - freeLargeHandle(proxy0); - m_pairCache->removeOverlappingPairsContainingProxy(proxy,dispatcher); - } - else - { - btSimpleBroadphase::destroyProxy(proxy, dispatcher); - } - return; -} - - - -void btGpu3DGridBroadphase::resetPool(btDispatcher* dispatcher) -{ - m_hPairBuffStartCurr[0] = 0; - m_hPairBuffStartCurr[1] = 0; - for(int i = 1; i <= m_maxHandles; i++) - { - m_hPairBuffStartCurr[i * 2] = m_hPairBuffStartCurr[(i-1) * 2] + m_maxPairsPerBody; - m_hPairBuffStartCurr[i * 2 + 1] = 0; - } -} - - - -bool btGpu3DGridBroadphase::isLargeProxy(const btVector3& aabbMin, const btVector3& aabbMax) -{ - btVector3 diag = aabbMax - aabbMin; - ///use the bounding sphere radius of this bounding box, to include rotation - btScalar radius = diag.length() * btScalar(0.5f); - return (radius > m_maxRadius); -} - - - -bool btGpu3DGridBroadphase::isLargeProxy(btBroadphaseProxy* proxy) -{ - return (proxy->getUid() >= (m_maxHandles+2)); -} - - - -void btGpu3DGridBroadphase::addLarge2LargePairsToCache(btDispatcher* dispatcher) -{ - int i,j; - if (m_numLargeHandles <= 0) - { - return; - } - int new_largest_index = -1; - for(i = 0; i <= m_LastLargeHandleIndex; i++) - { - btSimpleBroadphaseProxy* proxy0 = &m_pLargeHandles[i]; - new_largest_index = i; - for(j = i + 1; j <= m_LastLargeHandleIndex; j++) - { - btSimpleBroadphaseProxy* proxy1 = &m_pLargeHandles[j]; - btAssert(proxy0 != proxy1); - btSimpleBroadphaseProxy* p0 = getSimpleProxyFromProxy(proxy0); - btSimpleBroadphaseProxy* p1 = getSimpleProxyFromProxy(proxy1); - if(aabbOverlap(p0,p1)) - { - if (!m_pairCache->findPair(proxy0,proxy1)) - { - m_pairCache->addOverlappingPair(proxy0,proxy1); - } - } - else - { - if(m_pairCache->findPair(proxy0,proxy1)) - { - m_pairCache->removeOverlappingPair(proxy0,proxy1,dispatcher); - } - } - } - } - m_LastLargeHandleIndex = new_largest_index; - return; -} - - - -void btGpu3DGridBroadphase::rayTest(const btVector3& rayFrom,const btVector3& rayTo, btBroadphaseRayCallback& rayCallback) -{ - btSimpleBroadphase::rayTest(rayFrom, rayTo, rayCallback); - for (int i=0; i <= m_LastLargeHandleIndex; i++) - { - btSimpleBroadphaseProxy* proxy = &m_pLargeHandles[i]; - rayCallback.process(proxy); - } -} - - - -// -// overrides for CPU version -// - - - -void btGpu3DGridBroadphase::prepareAABB() -{ - BT_PROFILE("prepareAABB"); - bt3DGrid3F1U* pBB = m_hAABB; - int i; - int new_largest_index = -1; - unsigned int num_small = 0; - for(i = 0; i <= m_LastHandleIndex; i++) - { - btSimpleBroadphaseProxy* proxy0 = &m_pHandles[i]; - new_largest_index = i; - pBB->fx = proxy0->m_aabbMin.getX(); - pBB->fy = proxy0->m_aabbMin.getY(); - pBB->fz = proxy0->m_aabbMin.getZ(); - pBB->uw = i; - pBB++; - pBB->fx = proxy0->m_aabbMax.getX(); - pBB->fy = proxy0->m_aabbMax.getY(); - pBB->fz = proxy0->m_aabbMax.getZ(); - pBB->uw = num_small; - pBB++; - num_small++; - } - m_LastHandleIndex = new_largest_index; - new_largest_index = -1; - unsigned int num_large = 0; - for(i = 0; i <= m_LastLargeHandleIndex; i++) - { - btSimpleBroadphaseProxy* proxy0 = &m_pLargeHandles[i]; - new_largest_index = i; - pBB->fx = proxy0->m_aabbMin.getX(); - pBB->fy = proxy0->m_aabbMin.getY(); - pBB->fz = proxy0->m_aabbMin.getZ(); - pBB->uw = i + m_maxHandles; - pBB++; - pBB->fx = proxy0->m_aabbMax.getX(); - pBB->fy = proxy0->m_aabbMax.getY(); - pBB->fz = proxy0->m_aabbMax.getZ(); - pBB->uw = num_large + m_maxHandles; - pBB++; - num_large++; - } - m_LastLargeHandleIndex = new_largest_index; - // paranoid checks - btAssert(num_small == m_numHandles); - btAssert(num_large == m_numLargeHandles); - return; -} - - - -void btGpu3DGridBroadphase::setParameters(bt3DGridBroadphaseParams* hostParams) -{ - s3DGridBroadphaseParams = *hostParams; - return; -} - - - -void btGpu3DGridBroadphase::calcHashAABB() -{ - BT_PROFILE("bt3DGrid_calcHashAABB"); - btGpu_calcHashAABB(m_hAABB, m_hBodiesHash, m_numHandles); - return; -} - - - -void btGpu3DGridBroadphase::sortHash() -{ - class bt3DGridHashKey - { - public: - unsigned int hash; - unsigned int index; - void quickSort(bt3DGridHashKey* pData, int lo, int hi) - { - int i=lo, j=hi; - bt3DGridHashKey x = pData[(lo+hi)/2]; - do - { - while(pData[i].hash > x.hash) i++; - while(x.hash > pData[j].hash) j--; - if(i <= j) - { - bt3DGridHashKey t = pData[i]; - pData[i] = pData[j]; - pData[j] = t; - i++; j--; - } - } while(i <= j); - if(lo < j) pData->quickSort(pData, lo, j); - if(i < hi) pData->quickSort(pData, i, hi); - } - }; - BT_PROFILE("bt3DGrid_sortHash"); - bt3DGridHashKey* pHash = (bt3DGridHashKey*)m_hBodiesHash; - pHash->quickSort(pHash, 0, m_numHandles - 1); - return; -} - - - -void btGpu3DGridBroadphase::findCellStart() -{ - BT_PROFILE("bt3DGrid_findCellStart"); - btGpu_findCellStart(m_hBodiesHash, m_hCellStart, m_numHandles, m_params.m_numCells); - return; -} - - - -void btGpu3DGridBroadphase::findOverlappingPairs() -{ - BT_PROFILE("bt3DGrid_findOverlappingPairs"); - btGpu_findOverlappingPairs(m_hAABB, m_hBodiesHash, m_hCellStart, m_hPairBuff, m_hPairBuffStartCurr, m_numHandles); - return; -} - - - -void btGpu3DGridBroadphase::findPairsLarge() -{ - BT_PROFILE("bt3DGrid_findPairsLarge"); - btGpu_findPairsLarge(m_hAABB, m_hBodiesHash, m_hCellStart, m_hPairBuff, m_hPairBuffStartCurr, m_numHandles, m_numLargeHandles); - return; -} - - - -void btGpu3DGridBroadphase::computePairCacheChanges() -{ - BT_PROFILE("bt3DGrid_computePairCacheChanges"); - btGpu_computePairCacheChanges(m_hPairBuff, m_hPairBuffStartCurr, m_hPairScanChanged, m_hAABB, m_numHandles); - return; -} - - -void btGpu3DGridBroadphase::scanOverlappingPairBuff(bool copyToCpu) -{ - BT_PROFILE("bt3DGrid_scanOverlappingPairBuff"); - unsigned int sum = 0; - m_hPairScanChanged[0]=0; - for(int i = 0; i <= m_numHandles+1; i++) - { - unsigned int delta = m_hPairScanChanged[i]; - m_hPairScanChanged[i] = sum; - sum += delta; - } - return; -} - - - -void btGpu3DGridBroadphase::squeezeOverlappingPairBuff() -{ - BT_PROFILE("bt3DGrid_squeezeOverlappingPairBuff"); - //btGpu_squeezeOverlappingPairBuff(m_hPairBuff, m_hPairBuffStartCurr, m_hPairScanChanged, m_hPairsChanged, m_hAABB, m_numHandles); - btGpu_squeezeOverlappingPairBuff(m_hPairBuff, m_hPairBuffStartCurr, m_hPairScanChanged, (unsigned int*)m_hAllOverlappingPairs, m_hAABB, m_numHandles); - - return; -} - - - -#include "btGpu3DGridBroadphaseSharedCode.h" - diff --git a/Extras/RigidBodyGpuPipeline/opencl/3dGridBroadphase/Shared/btGpu3DGridBroadphase.h b/Extras/RigidBodyGpuPipeline/opencl/3dGridBroadphase/Shared/btGpu3DGridBroadphase.h deleted file mode 100644 index 8441151f7..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/3dGridBroadphase/Shared/btGpu3DGridBroadphase.h +++ /dev/null @@ -1,154 +0,0 @@ -/* -Bullet Continuous Collision Detection and Physics Library, http://bulletphysics.org -Copyright (C) 2006, 2009 Sony Computer Entertainment Inc. - -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 BTGPU3DGRIDBROADPHASE_H -#define BTGPU3DGRIDBROADPHASE_H - -//---------------------------------------------------------------------------------------- - -#include "BulletCollision/BroadphaseCollision/btSimpleBroadphase.h" - -#include "btGpu3DGridBroadphaseSharedTypes.h" -struct MyUint2 -{ - int x; - int y; -}; - -//---------------------------------------------------------------------------------------- - -///The btGpu3DGridBroadphase uses GPU-style code compiled for CPU to compute overlapping pairs - -class btGpu3DGridBroadphase : public btSimpleBroadphase -{ -protected: - bool m_bInitialized; - unsigned int m_numBodies; - unsigned int m_numCells; - unsigned int m_maxPairsPerBody; - unsigned int m_maxBodiesPerCell; - bt3DGridBroadphaseParams m_params; - btScalar m_maxRadius; - // CPU data - unsigned int* m_hBodiesHash; - unsigned int* m_hCellStart; - unsigned int* m_hPairBuffStartCurr; - bt3DGrid3F1U* m_hAABB; - unsigned int* m_hPairBuff; - unsigned int* m_hPairScanChanged; - unsigned int* m_hPairsChanged; - MyUint2* m_hAllOverlappingPairs; -// large proxies - int m_numLargeHandles; - int m_maxLargeHandles; - int m_LastLargeHandleIndex; - btSimpleBroadphaseProxy* m_pLargeHandles; - void* m_pLargeHandlesRawPtr; - int m_firstFreeLargeHandle; - int allocLargeHandle() - { - btAssert(m_numLargeHandles < m_maxLargeHandles); - int freeLargeHandle = m_firstFreeLargeHandle; - m_firstFreeLargeHandle = m_pLargeHandles[freeLargeHandle].GetNextFree(); - m_numLargeHandles++; - if(freeLargeHandle > m_LastLargeHandleIndex) - { - m_LastLargeHandleIndex = freeLargeHandle; - } - return freeLargeHandle; - } - void freeLargeHandle(btSimpleBroadphaseProxy* proxy) - { - int handle = int(proxy - m_pLargeHandles); - btAssert((handle >= 0) && (handle < m_maxHandles)); - if(handle == m_LastLargeHandleIndex) - { - m_LastLargeHandleIndex--; - } - proxy->SetNextFree(m_firstFreeLargeHandle); - m_firstFreeLargeHandle = handle; - proxy->m_clientObject = 0; - m_numLargeHandles--; - } - bool isLargeProxy(const btVector3& aabbMin, const btVector3& aabbMax); - bool isLargeProxy(btBroadphaseProxy* proxy); -// debug - unsigned int m_numPairsAdded; - unsigned int m_numPairsRemoved; - unsigned int m_numOverflows; -// -public: - virtual int getNumOverlap() - { - return m_hPairScanChanged[m_numHandles+1]; - } - virtual MyUint2* getOverlap() - { - return m_hAllOverlappingPairs; - } - // NOTE : for better results gridSizeX, gridSizeY and gridSizeZ should be powers of 2 - btGpu3DGridBroadphase(const btVector3& cellSize, - int gridSizeX, int gridSizeY, int gridSizeZ, - int maxSmallProxies, int maxLargeProxies, int maxPairsPerBody, - btScalar maxSmallProxySize, - int maxBodiesPerCell = 8); - btGpu3DGridBroadphase( btOverlappingPairCache* overlappingPairCache, - const btVector3& cellSize, - int gridSizeX, int gridSizeY, int gridSizeZ, - int maxSmallProxies, int maxLargeProxies, int maxPairsPerBody, - btScalar maxSmallProxySize, - int maxBodiesPerCell = 8); - virtual ~btGpu3DGridBroadphase(); - virtual void calculateOverlappingPairs(btDispatcher* dispatcher); - - virtual btBroadphaseProxy* createProxy(const btVector3& aabbMin, const btVector3& aabbMax,int shapeType,void* userPtr ,short int collisionFilterGroup,short int collisionFilterMask, btDispatcher* dispatcher,void* multiSapProxy); - virtual void destroyProxy(btBroadphaseProxy* proxy,btDispatcher* dispatcher); - virtual void rayTest(const btVector3& rayFrom,const btVector3& rayTo, btBroadphaseRayCallback& rayCallback); - virtual void resetPool(btDispatcher* dispatcher); - - static int getFloorPowOfTwo(int val); // returns 2^n : 2^(n+1) > val >= 2^n - -protected: - void _initialize( const btVector3& cellSize, - int gridSizeX, int gridSizeY, int gridSizeZ, - int maxSmallProxies, int maxLargeProxies, int maxPairsPerBody, - btScalar maxSmallProxySize, - int maxBodiesPerCell); - void _finalize(); - void addPairsToCache(btDispatcher* dispatcher); - void addLarge2LargePairsToCache(btDispatcher* dispatcher); - -// overrides for CPU version - virtual void setParameters(bt3DGridBroadphaseParams* hostParams); - virtual void prepareAABB(); - virtual void calcHashAABB(); - virtual void sortHash(); - virtual void findCellStart(); - virtual void findOverlappingPairs(); - virtual void findPairsLarge(); - virtual void computePairCacheChanges(); - virtual void scanOverlappingPairBuff(bool copyToCpu=true); - virtual void squeezeOverlappingPairBuff(); -}; - -//---------------------------------------------------------------------------------------- - -#endif //BTGPU3DGRIDBROADPHASE_H - -//---------------------------------------------------------------------------------------- -//---------------------------------------------------------------------------------------- -//---------------------------------------------------------------------------------------- diff --git a/Extras/RigidBodyGpuPipeline/opencl/3dGridBroadphase/Shared/btGpu3DGridBroadphaseSharedCode.h b/Extras/RigidBodyGpuPipeline/opencl/3dGridBroadphase/Shared/btGpu3DGridBroadphaseSharedCode.h deleted file mode 100644 index 08df68a65..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/3dGridBroadphase/Shared/btGpu3DGridBroadphaseSharedCode.h +++ /dev/null @@ -1,428 +0,0 @@ -/* -Bullet Continuous Collision Detection and Physics Library, http://bulletphysics.org -Copyright (C) 2006, 2009 Sony Computer Entertainment Inc. - -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. -*/ - -//---------------------------------------------------------------------------------------- - -//---------------------------------------------------------------------------------------- -//---------------------------------------------------------------------------------------- -//---------------------------------------------------------------------------------------- -//---------------------------------------------------------------------------------------- -// K E R N E L F U N C T I O N S -//---------------------------------------------------------------------------------------- -//---------------------------------------------------------------------------------------- -//---------------------------------------------------------------------------------------- -//---------------------------------------------------------------------------------------- -//---------------------------------------------------------------------------------------- -//---------------------------------------------------------------------------------------- - -// calculate position in uniform grid -BT_GPU___device__ int3 bt3DGrid_calcGridPos(float4 p) -{ - int3 gridPos; - gridPos.x = (int)floor(p.x * BT_GPU_params.m_invCellSizeX) & (BT_GPU_params.m_gridSizeX - 1); - gridPos.y = (int)floor(p.y * BT_GPU_params.m_invCellSizeY) & (BT_GPU_params.m_gridSizeY - 1); - gridPos.z = (int)floor(p.z * BT_GPU_params.m_invCellSizeZ) & (BT_GPU_params.m_gridSizeZ - 1); - return gridPos; -} // bt3DGrid_calcGridPos() - -//---------------------------------------------------------------------------------------- - -// calculate address in grid from position (clamping to edges) -BT_GPU___device__ uint bt3DGrid_calcGridHash(int3 gridPos) -{ - gridPos.x &= (BT_GPU_params.m_gridSizeX - 1); - gridPos.y &= (BT_GPU_params.m_gridSizeY - 1); - gridPos.z &= (BT_GPU_params.m_gridSizeZ - 1); - return BT_GPU___mul24(BT_GPU___mul24(gridPos.z, BT_GPU_params.m_gridSizeY), BT_GPU_params.m_gridSizeX) + BT_GPU___mul24(gridPos.y, BT_GPU_params.m_gridSizeX) + gridPos.x; -} // bt3DGrid_calcGridHash() - -//---------------------------------------------------------------------------------------- - -// calculate grid hash value for each body using its AABB -BT_GPU___global__ void calcHashAABBD(bt3DGrid3F1U* pAABB, uint2* pHash, uint numBodies) -{ - int index = BT_GPU___mul24(BT_GPU_blockIdx.x, BT_GPU_blockDim.x) + BT_GPU_threadIdx.x; - if(index >= (int)numBodies) - { - return; - } - bt3DGrid3F1U bbMin = pAABB[index*2]; - bt3DGrid3F1U bbMax = pAABB[index*2 + 1]; - float4 pos; - pos.x = (bbMin.fx + bbMax.fx) * 0.5f; - pos.y = (bbMin.fy + bbMax.fy) * 0.5f; - pos.z = (bbMin.fz + bbMax.fz) * 0.5f; - // get address in grid - int3 gridPos = bt3DGrid_calcGridPos(pos); - uint gridHash = bt3DGrid_calcGridHash(gridPos); - // store grid hash and body index - pHash[index] = BT_GPU_make_uint2(gridHash, index); -} // calcHashAABBD() - -//---------------------------------------------------------------------------------------- - -BT_GPU___global__ void findCellStartD(uint2* pHash, uint* cellStart, uint numBodies) -{ - int index = BT_GPU___mul24(BT_GPU_blockIdx.x, BT_GPU_blockDim.x) + BT_GPU_threadIdx.x; - if(index >= (int)numBodies) - { - return; - } - uint2 sortedData = pHash[index]; - // Load hash data into shared memory so that we can look - // at neighboring body's hash value without loading - // two hash values per thread - BT_GPU___shared__ uint sharedHash[257]; - sharedHash[BT_GPU_threadIdx.x+1] = sortedData.x; - if((index > 0) && (BT_GPU_threadIdx.x == 0)) - { - // first thread in block must load neighbor body hash - volatile uint2 prevData = pHash[index-1]; - sharedHash[0] = prevData.x; - } - BT_GPU___syncthreads(); - if((index == 0) || (sortedData.x != sharedHash[BT_GPU_threadIdx.x])) - { - cellStart[sortedData.x] = index; - } -} // findCellStartD() - -//---------------------------------------------------------------------------------------- - -BT_GPU___device__ uint cudaTestAABBOverlap(bt3DGrid3F1U min0, bt3DGrid3F1U max0, bt3DGrid3F1U min1, bt3DGrid3F1U max1) -{ - return (min0.fx <= max1.fx)&& (min1.fx <= max0.fx) && - (min0.fy <= max1.fy)&& (min1.fy <= max0.fy) && - (min0.fz <= max1.fz)&& (min1.fz <= max0.fz); -} // cudaTestAABBOverlap() - -//---------------------------------------------------------------------------------------- - -BT_GPU___device__ void findPairsInCell( int3 gridPos, - uint index, - uint2* pHash, - uint* pCellStart, - bt3DGrid3F1U* pAABB, - uint* pPairBuff, - uint2* pPairBuffStartCurr, - uint numBodies) -{ - uint gridHash = bt3DGrid_calcGridHash(gridPos); - // get start of bucket for this cell - uint bucketStart = pCellStart[gridHash]; - if (bucketStart == 0xffffffff) - { - return; // cell empty - } - // iterate over bodies in this cell - uint2 sortedData = pHash[index]; - uint unsorted_indx = sortedData.y; - bt3DGrid3F1U min0 = BT_GPU_FETCH(pAABB, unsorted_indx*2); - bt3DGrid3F1U max0 = BT_GPU_FETCH(pAABB, unsorted_indx*2 + 1); - uint handleIndex = min0.uw; - uint2 start_curr = pPairBuffStartCurr[handleIndex]; - uint start = start_curr.x; - uint curr = start_curr.y; - uint2 start_curr_next = pPairBuffStartCurr[handleIndex+1]; - uint curr_max = start_curr_next.x - start - 1; - uint bucketEnd = bucketStart + BT_GPU_params.m_maxBodiesPerCell; - bucketEnd = (bucketEnd > numBodies) ? numBodies : bucketEnd; - for(uint index2 = bucketStart; index2 < bucketEnd; index2++) - { - uint2 cellData = pHash[index2]; - if (cellData.x != gridHash) - { - break; // no longer in same bucket - } - uint unsorted_indx2 = cellData.y; - if (unsorted_indx2 < unsorted_indx) // check not colliding with self - { - bt3DGrid3F1U min1 = BT_GPU_FETCH(pAABB, unsorted_indx2*2); - bt3DGrid3F1U max1 = BT_GPU_FETCH(pAABB, unsorted_indx2*2 + 1); - if(cudaTestAABBOverlap(min0, max0, min1, max1)) - { - uint handleIndex2 = min1.uw; - uint k; - for(k = 0; k < curr; k++) - { - uint old_pair = pPairBuff[start+k] & (~BT_3DGRID_PAIR_ANY_FLG); - if(old_pair == handleIndex2) - { - pPairBuff[start+k] |= BT_3DGRID_PAIR_FOUND_FLG; - break; - } - } - if(k == curr) - { - if(curr >= curr_max) - { // not a good solution, but let's avoid crash - break; - } - pPairBuff[start+curr] = handleIndex2 | BT_3DGRID_PAIR_NEW_FLG; - curr++; - } - } - } - } - pPairBuffStartCurr[handleIndex] = BT_GPU_make_uint2(start, curr); - return; -} // findPairsInCell() - -//---------------------------------------------------------------------------------------- - -BT_GPU___global__ void findOverlappingPairsD( bt3DGrid3F1U* pAABB, uint2* pHash, uint* pCellStart, - uint* pPairBuff, uint2* pPairBuffStartCurr, uint numBodies) -{ - int index = BT_GPU___mul24(BT_GPU_blockIdx.x, BT_GPU_blockDim.x) + BT_GPU_threadIdx.x; - if(index >= (int)numBodies) - { - return; - } - uint2 sortedData = pHash[index]; - uint unsorted_indx = sortedData.y; - bt3DGrid3F1U bbMin = BT_GPU_FETCH(pAABB, unsorted_indx*2); - bt3DGrid3F1U bbMax = BT_GPU_FETCH(pAABB, unsorted_indx*2 + 1); - float4 pos; - pos.x = (bbMin.fx + bbMax.fx) * 0.5f; - pos.y = (bbMin.fy + bbMax.fy) * 0.5f; - pos.z = (bbMin.fz + bbMax.fz) * 0.5f; - // get address in grid - int3 gridPos = bt3DGrid_calcGridPos(pos); - // examine only neighbouring cells - for(int z=-1; z<=1; z++) { - for(int y=-1; y<=1; y++) { - for(int x=-1; x<=1; x++) { - findPairsInCell(gridPos + BT_GPU_make_int3(x, y, z), index, pHash, pCellStart, pAABB, pPairBuff, pPairBuffStartCurr, numBodies); - } - } - } -} // findOverlappingPairsD() - -//---------------------------------------------------------------------------------------- - -BT_GPU___global__ void findPairsLargeD( bt3DGrid3F1U* pAABB, uint2* pHash, uint* pCellStart, uint* pPairBuff, - uint2* pPairBuffStartCurr, uint numBodies, uint numLarge) -{ - int index = BT_GPU___mul24(BT_GPU_blockIdx.x, BT_GPU_blockDim.x) + BT_GPU_threadIdx.x; - if(index >= (int)numBodies) - { - return; - } - uint2 sortedData = pHash[index]; - uint unsorted_indx = sortedData.y; - bt3DGrid3F1U min0 = BT_GPU_FETCH(pAABB, unsorted_indx*2); - bt3DGrid3F1U max0 = BT_GPU_FETCH(pAABB, unsorted_indx*2 + 1); - uint handleIndex = min0.uw; - uint2 start_curr = pPairBuffStartCurr[handleIndex]; - uint start = start_curr.x; - uint curr = start_curr.y; - uint2 start_curr_next = pPairBuffStartCurr[handleIndex+1]; - uint curr_max = start_curr_next.x - start - 1; - for(uint i = 0; i < numLarge; i++) - { - uint indx2 = numBodies + i; - bt3DGrid3F1U min1 = BT_GPU_FETCH(pAABB, indx2*2); - bt3DGrid3F1U max1 = BT_GPU_FETCH(pAABB, indx2*2 + 1); - if(cudaTestAABBOverlap(min0, max0, min1, max1)) - { - uint k; - uint handleIndex2 = min1.uw; - for(k = 0; k < curr; k++) - { - uint old_pair = pPairBuff[start+k] & (~BT_3DGRID_PAIR_ANY_FLG); - if(old_pair == handleIndex2) - { - pPairBuff[start+k] |= BT_3DGRID_PAIR_FOUND_FLG; - break; - } - } - if(k == curr) - { - pPairBuff[start+curr] = handleIndex2 | BT_3DGRID_PAIR_NEW_FLG; - if(curr >= curr_max) - { // not a good solution, but let's avoid crash - break; - } - curr++; - } - } - } - pPairBuffStartCurr[handleIndex] = BT_GPU_make_uint2(start, curr); - return; -} // findPairsLargeD() - -//---------------------------------------------------------------------------------------- - -BT_GPU___global__ void computePairCacheChangesD(uint* pPairBuff, uint2* pPairBuffStartCurr, - uint* pPairScan, bt3DGrid3F1U* pAABB, uint numBodies) -{ - int index = BT_GPU___mul24(BT_GPU_blockIdx.x, BT_GPU_blockDim.x) + BT_GPU_threadIdx.x; - if(index >= (int)numBodies) - { - return; - } - bt3DGrid3F1U bbMin = pAABB[index * 2]; - uint handleIndex = bbMin.uw; - uint2 start_curr = pPairBuffStartCurr[handleIndex]; - uint start = start_curr.x; - uint curr = start_curr.y; - uint *pInp = pPairBuff + start; - uint num_changes = 0; - for(uint k = 0; k < curr; k++, pInp++) - { - //if(!((*pInp) & BT_3DGRID_PAIR_FOUND_FLG)) - if(((*pInp) & BT_3DGRID_PAIR_ANY_FLG)) - { - num_changes++; - } - } - pPairScan[index+1] = num_changes; -} // computePairCacheChangesD() - -//---------------------------------------------------------------------------------------- - -BT_GPU___global__ void squeezeOverlappingPairBuffD(uint* pPairBuff, uint2* pPairBuffStartCurr, uint* pPairScan, - uint2* pPairOut, bt3DGrid3F1U* pAABB, uint numBodies) -{ - int index = BT_GPU___mul24(BT_GPU_blockIdx.x, BT_GPU_blockDim.x) + BT_GPU_threadIdx.x; - if(index >= (int)numBodies) - { - return; - } - bt3DGrid3F1U bbMin = pAABB[index * 2]; - uint handleIndex = bbMin.uw; - uint2 start_curr = pPairBuffStartCurr[handleIndex]; - uint start = start_curr.x; - uint curr = start_curr.y; - uint* pInp = pPairBuff + start; - uint2* pOut = pPairOut + pPairScan[index+1]; - uint* pOut2 = pInp; - uint num = 0; - for(uint k = 0; k < curr; k++, pInp++) - { - if((*pInp) & BT_3DGRID_PAIR_ANY_FLG) - //if(!((*pInp) & BT_3DGRID_PAIR_FOUND_FLG)) - { - pOut->x = handleIndex; - pOut->y = (*pInp) & (~BT_3DGRID_PAIR_ANY_FLG); - - pOut++; - } - if((*pInp) & BT_3DGRID_PAIR_ANY_FLG) - { - *pOut2 = (*pInp) & (~BT_3DGRID_PAIR_ANY_FLG); - pOut2++; - num++; - } - } - pPairBuffStartCurr[handleIndex] = BT_GPU_make_uint2(start, num); -} // squeezeOverlappingPairBuffD() - - -//---------------------------------------------------------------------------------------- -//---------------------------------------------------------------------------------------- -//---------------------------------------------------------------------------------------- -//---------------------------------------------------------------------------------------- -// E N D O F K E R N E L F U N C T I O N S -//---------------------------------------------------------------------------------------- -//---------------------------------------------------------------------------------------- -//---------------------------------------------------------------------------------------- -//---------------------------------------------------------------------------------------- - -extern "C" -{ - -//---------------------------------------------------------------------------------------- - -void BT_GPU_PREF(calcHashAABB)(bt3DGrid3F1U* pAABB, unsigned int* hash, unsigned int numBodies) -{ - int numThreads, numBlocks; - BT_GPU_PREF(computeGridSize)(numBodies, 256, numBlocks, numThreads); - // execute the kernel - BT_GPU_EXECKERNEL(numBlocks, numThreads, calcHashAABBD, (pAABB, (uint2*)hash, numBodies)); - // check if kernel invocation generated an error - BT_GPU_CHECK_ERROR("calcHashAABBD kernel execution failed"); -} // calcHashAABB() - -//---------------------------------------------------------------------------------------- - -void BT_GPU_PREF(findCellStart(unsigned int* hash, unsigned int* cellStart, unsigned int numBodies, unsigned int numCells)) -{ - int numThreads, numBlocks; - BT_GPU_PREF(computeGridSize)(numBodies, 256, numBlocks, numThreads); - BT_GPU_SAFE_CALL(BT_GPU_Memset(cellStart, 0xffffffff, numCells*sizeof(uint))); - BT_GPU_EXECKERNEL(numBlocks, numThreads, findCellStartD, ((uint2*)hash, (uint*)cellStart, numBodies)); - BT_GPU_CHECK_ERROR("Kernel execution failed: findCellStartD"); -} // findCellStart() - -//---------------------------------------------------------------------------------------- - -void BT_GPU_PREF(findOverlappingPairs(bt3DGrid3F1U* pAABB, unsigned int* pHash, unsigned int* pCellStart, unsigned int* pPairBuff, unsigned int* pPairBuffStartCurr, unsigned int numBodies)) -{ -#if B_CUDA_USE_TEX - BT_GPU_SAFE_CALL(cudaBindTexture(0, pAABBTex, pAABB, numBodies * 2 * sizeof(bt3DGrid3F1U))); -#endif - int numThreads, numBlocks; - BT_GPU_PREF(computeGridSize)(numBodies, 64, numBlocks, numThreads); - BT_GPU_EXECKERNEL(numBlocks, numThreads, findOverlappingPairsD, (pAABB,(uint2*)pHash,(uint*)pCellStart,(uint*)pPairBuff,(uint2*)pPairBuffStartCurr,numBodies)); - BT_GPU_CHECK_ERROR("Kernel execution failed: bt_CudaFindOverlappingPairsD"); -#if B_CUDA_USE_TEX - BT_GPU_SAFE_CALL(cudaUnbindTexture(pAABBTex)); -#endif -} // findOverlappingPairs() - -//---------------------------------------------------------------------------------------- - -void BT_GPU_PREF(findPairsLarge(bt3DGrid3F1U* pAABB, unsigned int* pHash, unsigned int* pCellStart, unsigned int* pPairBuff, unsigned int* pPairBuffStartCurr, unsigned int numBodies, unsigned int numLarge)) -{ -#if B_CUDA_USE_TEX - BT_GPU_SAFE_CALL(cudaBindTexture(0, pAABBTex, pAABB, (numBodies+numLarge) * 2 * sizeof(bt3DGrid3F1U))); -#endif - int numThreads, numBlocks; - BT_GPU_PREF(computeGridSize)(numBodies, 64, numBlocks, numThreads); - BT_GPU_EXECKERNEL(numBlocks, numThreads, findPairsLargeD, (pAABB,(uint2*)pHash,(uint*)pCellStart,(uint*)pPairBuff,(uint2*)pPairBuffStartCurr,numBodies,numLarge)); - BT_GPU_CHECK_ERROR("Kernel execution failed: btCuda_findPairsLargeD"); -#if B_CUDA_USE_TEX - BT_GPU_SAFE_CALL(cudaUnbindTexture(pAABBTex)); -#endif -} // findPairsLarge() - -//---------------------------------------------------------------------------------------- - -void BT_GPU_PREF(computePairCacheChanges(unsigned int* pPairBuff, unsigned int* pPairBuffStartCurr, unsigned int* pPairScan, bt3DGrid3F1U* pAABB, unsigned int numBodies)) -{ - int numThreads, numBlocks; - BT_GPU_PREF(computeGridSize)(numBodies, 256, numBlocks, numThreads); - BT_GPU_EXECKERNEL(numBlocks, numThreads, computePairCacheChangesD, ((uint*)pPairBuff,(uint2*)pPairBuffStartCurr,(uint*)pPairScan,pAABB,numBodies)); - BT_GPU_CHECK_ERROR("Kernel execution failed: btCudaComputePairCacheChangesD"); -} // computePairCacheChanges() - -//---------------------------------------------------------------------------------------- - -void BT_GPU_PREF(squeezeOverlappingPairBuff(unsigned int* pPairBuff, unsigned int* pPairBuffStartCurr, unsigned int* pPairScan, unsigned int* pPairOut, bt3DGrid3F1U* pAABB, unsigned int numBodies)) -{ - int numThreads, numBlocks; - BT_GPU_PREF(computeGridSize)(numBodies, 256, numBlocks, numThreads); - BT_GPU_EXECKERNEL(numBlocks, numThreads, squeezeOverlappingPairBuffD, ((uint*)pPairBuff,(uint2*)pPairBuffStartCurr,(uint*)pPairScan,(uint2*)pPairOut,pAABB,numBodies)); - BT_GPU_CHECK_ERROR("Kernel execution failed: btCudaSqueezeOverlappingPairBuffD"); -} // btCuda_squeezeOverlappingPairBuff() - -//------------------------------------------------------------------------------------------------ - -} // extern "C" - -//------------------------------------------------------------------------------------------------ -//------------------------------------------------------------------------------------------------ -//------------------------------------------------------------------------------------------------ diff --git a/Extras/RigidBodyGpuPipeline/opencl/3dGridBroadphase/Shared/btGpu3DGridBroadphaseSharedDefs.h b/Extras/RigidBodyGpuPipeline/opencl/3dGridBroadphase/Shared/btGpu3DGridBroadphaseSharedDefs.h deleted file mode 100644 index 607bda7ed..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/3dGridBroadphase/Shared/btGpu3DGridBroadphaseSharedDefs.h +++ /dev/null @@ -1,61 +0,0 @@ -/* -Bullet Continuous Collision Detection and Physics Library, http://bulletphysics.org -Copyright (C) 2006, 2009 Sony Computer Entertainment Inc. - -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. -*/ - -//---------------------------------------------------------------------------------------- - -// Shared definitions for GPU-based 3D Grid collision detection broadphase - -//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -// Keep this file free from Bullet headers -// it is included into both CUDA and CPU code -//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - -//---------------------------------------------------------------------------------------- - -#ifndef BTGPU3DGRIDBROADPHASESHAREDDEFS_H -#define BTGPU3DGRIDBROADPHASESHAREDDEFS_H - -//---------------------------------------------------------------------------------------- - -#include "btGpu3DGridBroadphaseSharedTypes.h" - -//---------------------------------------------------------------------------------------- - -extern "C" -{ - -//---------------------------------------------------------------------------------------- - -void BT_GPU_PREF(calcHashAABB)(bt3DGrid3F1U* pAABB, unsigned int* hash, unsigned int numBodies); - -void BT_GPU_PREF(findCellStart)(unsigned int* hash, unsigned int* cellStart, unsigned int numBodies, unsigned int numCells); - -void BT_GPU_PREF(findOverlappingPairs)(bt3DGrid3F1U* pAABB, unsigned int* pHash, unsigned int* pCellStart, unsigned int* pPairBuff, unsigned int* pPairBuffStartCurr, unsigned int numBodies); - -void BT_GPU_PREF(findPairsLarge)(bt3DGrid3F1U* pAABB, unsigned int* pHash, unsigned int* pCellStart, unsigned int* pPairBuff, unsigned int* pPairBuffStartCurr, unsigned int numBodies, unsigned int numLarge); - -void BT_GPU_PREF(computePairCacheChanges)(unsigned int* pPairBuff, unsigned int* pPairBuffStartCurr, unsigned int* pPairScan, bt3DGrid3F1U* pAABB, unsigned int numBodies); - -void BT_GPU_PREF(squeezeOverlappingPairBuff)(unsigned int* pPairBuff, unsigned int* pPairBuffStartCurr, unsigned int* pPairScan, unsigned int* pPairOut, bt3DGrid3F1U* pAABB, unsigned int numBodies); - - -//---------------------------------------------------------------------------------------- - -} // extern "C" - -//---------------------------------------------------------------------------------------- - -#endif // BTGPU3DGRIDBROADPHASESHAREDDEFS_H - diff --git a/Extras/RigidBodyGpuPipeline/opencl/3dGridBroadphase/Shared/btGpu3DGridBroadphaseSharedTypes.h b/Extras/RigidBodyGpuPipeline/opencl/3dGridBroadphase/Shared/btGpu3DGridBroadphaseSharedTypes.h deleted file mode 100644 index 5b2e65ec0..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/3dGridBroadphase/Shared/btGpu3DGridBroadphaseSharedTypes.h +++ /dev/null @@ -1,64 +0,0 @@ -/* -Bullet Continuous Collision Detection and Physics Library, http://bulletphysics.org -Copyright (C) 2006, 2009 Sony Computer Entertainment Inc. - -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. -*/ - -//---------------------------------------------------------------------------------------- - -// Shared definitions for GPU-based 3D Grid collision detection broadphase - -//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -// Keep this file free from Bullet headers -// it is included into both CUDA and CPU code -//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - -//---------------------------------------------------------------------------------------- - -#ifndef BTGPU3DGRIDBROADPHASESHAREDTYPES_H -#define BTGPU3DGRIDBROADPHASESHAREDTYPES_H - -//---------------------------------------------------------------------------------------- - -#define BT_3DGRID_PAIR_FOUND_FLG (0x40000000) -#define BT_3DGRID_PAIR_NEW_FLG (0x20000000) -#define BT_3DGRID_PAIR_ANY_FLG (BT_3DGRID_PAIR_FOUND_FLG | BT_3DGRID_PAIR_NEW_FLG) - -//---------------------------------------------------------------------------------------- - -struct bt3DGridBroadphaseParams -{ - unsigned int m_gridSizeX; - unsigned int m_gridSizeY; - unsigned int m_gridSizeZ; - unsigned int m_numCells; - float m_invCellSizeX; - float m_invCellSizeY; - float m_invCellSizeZ; - unsigned int m_numBodies; - unsigned int m_maxBodiesPerCell; -}; - -//---------------------------------------------------------------------------------------- - -struct bt3DGrid3F1U -{ - float fx; - float fy; - float fz; - unsigned int uw; -}; - -//---------------------------------------------------------------------------------------- - -#endif // BTGPU3DGRIDBROADPHASESHAREDTYPES_H - diff --git a/Extras/RigidBodyGpuPipeline/opencl/3dGridBroadphase/Shared/btGpuDefines.h b/Extras/RigidBodyGpuPipeline/opencl/3dGridBroadphase/Shared/btGpuDefines.h deleted file mode 100644 index f9315ab64..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/3dGridBroadphase/Shared/btGpuDefines.h +++ /dev/null @@ -1,211 +0,0 @@ -/* -Bullet Continuous Collision Detection and Physics Library, http://bulletphysics.org -Copyright (C) 2006, 2009 Sony Computer Entertainment Inc. - -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. -*/ - - - -// definitions for "GPU on CPU" code - - -#ifndef BT_GPU_DEFINES_H -#define BT_GPU_DEFINES_H - -typedef unsigned int uint; - -struct int2 -{ - int x, y; -}; - -struct uint2 -{ - unsigned int x, y; -}; - -struct int3 -{ - int x, y, z; -}; - -struct uint3 -{ - unsigned int x, y, z; -}; - -struct float4 -{ - float x, y, z, w; -}; - -struct float3 -{ - float x, y, z; -}; - - -#define BT_GPU___device__ inline -#define BT_GPU___devdata__ -#define BT_GPU___constant__ -#define BT_GPU_max(a, b) ((a) > (b) ? (a) : (b)) -#define BT_GPU_min(a, b) ((a) < (b) ? (a) : (b)) -#define BT_GPU_params s3DGridBroadphaseParams -#define BT_GPU___mul24(a, b) ((a)*(b)) -#define BT_GPU___global__ inline -#define BT_GPU___shared__ static -#define BT_GPU___syncthreads() -#define CUDART_PI_F SIMD_PI - -static inline uint2 bt3dGrid_make_uint2(unsigned int x, unsigned int y) -{ - uint2 t; t.x = x; t.y = y; return t; -} -#define BT_GPU_make_uint2(x, y) bt3dGrid_make_uint2(x, y) - -static inline int3 bt3dGrid_make_int3(int x, int y, int z) -{ - int3 t; t.x = x; t.y = y; t.z = z; return t; -} -#define BT_GPU_make_int3(x, y, z) bt3dGrid_make_int3(x, y, z) - -static inline float3 bt3dGrid_make_float3(float x, float y, float z) -{ - float3 t; t.x = x; t.y = y; t.z = z; return t; -} -#define BT_GPU_make_float3(x, y, z) bt3dGrid_make_float3(x, y, z) - -static inline float3 bt3dGrid_make_float34(float4 f) -{ - float3 t; t.x = f.x; t.y = f.y; t.z = f.z; return t; -} -#define BT_GPU_make_float34(f) bt3dGrid_make_float34(f) - -static inline float3 bt3dGrid_make_float31(float f) -{ - float3 t; t.x = t.y = t.z = f; return t; -} -#define BT_GPU_make_float31(x) bt3dGrid_make_float31(x) - -static inline float4 bt3dGrid_make_float42(float3 v, float f) -{ - float4 t; t.x = v.x; t.y = v.y; t.z = v.z; t.w = f; return t; -} -#define BT_GPU_make_float42(a, b) bt3dGrid_make_float42(a, b) - -static inline float4 bt3dGrid_make_float44(float a, float b, float c, float d) -{ - float4 t; t.x = a; t.y = b; t.z = c; t.w = d; return t; -} -#define BT_GPU_make_float44(a, b, c, d) bt3dGrid_make_float44(a, b, c, d) - -inline int3 operator+(int3 a, int3 b) -{ - return bt3dGrid_make_int3(a.x + b.x, a.y + b.y, a.z + b.z); -} - -inline float4 operator+(const float4& a, const float4& b) -{ - float4 r; r.x = a.x+b.x; r.y = a.y+b.y; r.z = a.z+b.z; r.w = a.w+b.w; return r; -} -inline float4 operator*(const float4& a, float fact) -{ - float4 r; r.x = a.x*fact; r.y = a.y*fact; r.z = a.z*fact; r.w = a.w*fact; return r; -} -inline float4 operator*(float fact, float4& a) -{ - return (a * fact); -} -inline float4& operator*=(float4& a, float fact) -{ - a = fact * a; - return a; -} -inline float4& operator+=(float4& a, const float4& b) -{ - a = a + b; - return a; -} - -inline float3 operator+(const float3& a, const float3& b) -{ - float3 r; r.x = a.x+b.x; r.y = a.y+b.y; r.z = a.z+b.z; return r; -} -inline float3 operator-(const float3& a, const float3& b) -{ - float3 r; r.x = a.x-b.x; r.y = a.y-b.y; r.z = a.z-b.z; return r; -} -static inline float bt3dGrid_dot(float3& a, float3& b) -{ - return a.x*b.x+a.y*b.y+a.z*b.z; -} -#define BT_GPU_dot(a,b) bt3dGrid_dot(a,b) - -static inline float bt3dGrid_dot4(float4& a, float4& b) -{ - return a.x*b.x+a.y*b.y+a.z*b.z+a.w*b.w; -} -#define BT_GPU_dot4(a,b) bt3dGrid_dot4(a,b) - -static inline float3 bt3dGrid_cross(const float3& a, const float3& b) -{ - float3 r; r.x = a.y*b.z-a.z*b.y; r.y = -a.x*b.z+a.z*b.x; r.z = a.x*b.y-a.y*b.x; return r; -} -#define BT_GPU_cross(a,b) bt3dGrid_cross(a,b) - - -inline float3 operator*(const float3& a, float fact) -{ - float3 r; r.x = a.x*fact; r.y = a.y*fact; r.z = a.z*fact; return r; -} - - -inline float3& operator+=(float3& a, const float3& b) -{ - a = a + b; - return a; -} -inline float3& operator-=(float3& a, const float3& b) -{ - a = a - b; - return a; -} -inline float3& operator*=(float3& a, float fact) -{ - a = a * fact; - return a; -} -inline float3 operator-(const float3& v) -{ - float3 r; r.x = -v.x; r.y = -v.y; r.z = -v.z; return r; -} - - -#define BT_GPU_FETCH(a, b) a[b] -#define BT_GPU_FETCH4(a, b) a[b] -#define BT_GPU_PREF(func) btGpu_##func -#define BT_GPU_SAFE_CALL(func) func -#define BT_GPU_Memset memset -#define BT_GPU_MemcpyToSymbol(a, b, c) memcpy(&a, b, c) -#define BT_GPU_BindTexture(a, b, c, d) -#define BT_GPU_UnbindTexture(a) - -static uint2 s_blockIdx, s_blockDim, s_threadIdx; -#define BT_GPU_blockIdx s_blockIdx -#define BT_GPU_blockDim s_blockDim -#define BT_GPU_threadIdx s_threadIdx -#define BT_GPU_EXECKERNEL(numb, numt, kfunc, args) {s_blockDim.x=numt;for(int nb=0;nb -#else -#include -#endif -#else -#ifdef USE_MINICL -#include -#else -#include -#ifdef _WIN32 -#include "CL/cl_gl.h" -#endif //_WIN32 -#endif -#endif //__APPLE__ - -#include -#include -#define oclCHECKERROR(a, b) if((a)!=(b)) { printf("OCL Error : %d\n", (a)); assert((a) == (b)); } - - -#endif //BT_OPENCL_INCLUDE_H - diff --git a/Extras/RigidBodyGpuPipeline/opencl/basic_initialize/btOpenCLUtils.cpp b/Extras/RigidBodyGpuPipeline/opencl/basic_initialize/btOpenCLUtils.cpp deleted file mode 100644 index e278401e9..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/basic_initialize/btOpenCLUtils.cpp +++ /dev/null @@ -1,731 +0,0 @@ -/* -Bullet Continuous Collision Detection and Physics Library, http://bulletphysics.org -Copyright (C) 2006 - 2011 Sony Computer Entertainment Inc. - -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. -*/ - -//original author: Roman Ponomarev -//cleanup by Erwin Coumans - -#include - -#include "btOpenCLUtils.h" -#include -#include - -#define BT_MAX_CL_DEVICES 16 //who needs 16 devices? - -#ifdef _WIN32 -#include -#include - -#define btAssert assert -#endif - -//Set the preferred platform vendor using the OpenCL SDK -static char* spPlatformVendor = -#if defined(CL_PLATFORM_MINI_CL) -"MiniCL, SCEA"; -#elif defined(CL_PLATFORM_AMD) -"Advanced Micro Devices, Inc."; -#elif defined(CL_PLATFORM_NVIDIA) -"NVIDIA Corporation"; -#elif defined(CL_PLATFORM_INTEL) -"Intel(R) Corporation"; -#else -"Unknown Vendor"; -#endif - -#ifndef CL_PLATFORM_MINI_CL -#ifdef _WIN32 -#include "CL/cl_gl.h" -#endif //_WIN32 -#endif - -int btOpenCLUtils::getNumPlatforms(cl_int* pErrNum) -{ - cl_uint numPlatforms=0; - cl_int ciErrNum = clGetPlatformIDs(0, NULL, &numPlatforms); - - if(ciErrNum != CL_SUCCESS) - { - if(pErrNum != NULL) - *pErrNum = ciErrNum; - } - return numPlatforms; -} - -const char* btOpenCLUtils::getSdkVendorName() -{ - return spPlatformVendor; -} - -cl_platform_id btOpenCLUtils::getPlatform(int platformIndex, cl_int* pErrNum) -{ - cl_platform_id platform = 0; - - cl_uint numPlatforms; - cl_int ciErrNum = clGetPlatformIDs(0, NULL, &numPlatforms); - - if (platformIndex>=0 && platformIndex=0 && preferredDeviceIndex 0) - { - cl_platform_id* platforms = new cl_platform_id[numPlatforms]; - ciErrNum = clGetPlatformIDs(numPlatforms, platforms, NULL); - if(ciErrNum != CL_SUCCESS) - { - if(pErrNum != NULL) *pErrNum = ciErrNum; - return NULL; - } - int i; - - - for ( i = 0; i < numPlatforms; ++i) - { - char pbuf[128]; - ciErrNum = clGetPlatformInfo( platforms[i], - CL_PLATFORM_VENDOR, - sizeof(pbuf), - pbuf, - NULL); - if(ciErrNum != CL_SUCCESS) - { - if(pErrNum != NULL) *pErrNum = ciErrNum; - return NULL; - } - - if (preferredPlatformIndex>=0 && i==preferredPlatformIndex) - { - cl_platform_id tmpPlatform = platforms[0]; - platforms[0] = platforms[i]; - platforms[i] = tmpPlatform; - break; - } else - { - if(!strcmp(pbuf, spPlatformVendor)) - { - cl_platform_id tmpPlatform = platforms[0]; - platforms[0] = platforms[i]; - platforms[i] = tmpPlatform; - break; - } - } - } - - for (i = 0; i < numPlatforms; ++i) - { - cl_platform_id platform = platforms[i]; - assert(platform); - - retContext = btOpenCLUtils::createContextFromPlatform(platform,deviceType,pErrNum,pGLContext,pGLDC,preferredDeviceIndex); - - if (retContext) - { -// printf("OpenCL platform details:\n"); - btOpenCLPlatformInfo platformInfo; - - btOpenCLUtils::getPlatformInfo(platform, platformInfo); - - printf(" CL_PLATFORM_VENDOR: \t\t\t%s\n",platformInfo.m_platformVendor); - printf(" CL_PLATFORM_NAME: \t\t\t%s\n",platformInfo.m_platformName); - printf(" CL_PLATFORM_VERSION: \t\t\t%s\n",platformInfo.m_platformVersion); - - break; - } - } - - delete[] platforms; - } - return retContext; -} - - -////////////////////////////////////////////////////////////////////////////// -//! Gets the id of the nth device from the context -//! -//! @return the id or -1 when out of range -//! @param cxMainContext OpenCL context -//! @param device_idx index of the device of interest -////////////////////////////////////////////////////////////////////////////// -cl_device_id btOpenCLUtils::getDevice(cl_context cxMainContext, int deviceIndex) -{ - size_t szParmDataBytes; - cl_device_id* cdDevices; - - // get the list of devices associated with context - clGetContextInfo(cxMainContext, CL_CONTEXT_DEVICES, 0, NULL, &szParmDataBytes); - - if( szParmDataBytes / sizeof(cl_device_id) < deviceIndex ) { - return (cl_device_id)-1; - } - - cdDevices = (cl_device_id*) malloc(szParmDataBytes); - - clGetContextInfo(cxMainContext, CL_CONTEXT_DEVICES, szParmDataBytes, cdDevices, NULL); - - cl_device_id device = cdDevices[deviceIndex]; - free(cdDevices); - - return device; -} - -int btOpenCLUtils::getNumDevices(cl_context cxMainContext) -{ - size_t szParamDataBytes; - clGetContextInfo(cxMainContext, CL_CONTEXT_DEVICES, 0, NULL, &szParamDataBytes); - int device_count = (int) szParamDataBytes/ sizeof(cl_device_id); - return device_count; -} - -void btOpenCLUtils::printDeviceInfo(cl_device_id device) -{ - btOpenCLDeviceInfo info; - getDeviceInfo(device,info); - - printf(" CL_DEVICE_NAME: \t\t\t%s\n", info.m_deviceName); - printf(" CL_DEVICE_VENDOR: \t\t\t%s\n", info.m_deviceVendor); - printf(" CL_DRIVER_VERSION: \t\t\t%s\n", info.m_driverVersion); - - if( info.m_deviceType & CL_DEVICE_TYPE_CPU ) - printf(" CL_DEVICE_TYPE:\t\t\t%s\n", "CL_DEVICE_TYPE_CPU"); - if( info.m_deviceType & CL_DEVICE_TYPE_GPU ) - printf(" CL_DEVICE_TYPE:\t\t\t%s\n", "CL_DEVICE_TYPE_GPU"); - if( info.m_deviceType & CL_DEVICE_TYPE_ACCELERATOR ) - printf(" CL_DEVICE_TYPE:\t\t\t%s\n", "CL_DEVICE_TYPE_ACCELERATOR"); - if( info.m_deviceType & CL_DEVICE_TYPE_DEFAULT ) - printf(" CL_DEVICE_TYPE:\t\t\t%s\n", "CL_DEVICE_TYPE_DEFAULT"); - - printf(" CL_DEVICE_MAX_COMPUTE_UNITS:\t\t%u\n", info.m_computeUnits); - printf(" CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS:\t%u\n", info.m_workitemDims); - printf(" CL_DEVICE_MAX_WORK_ITEM_SIZES:\t%u / %u / %u \n", info.m_workItemSize[0], info.m_workItemSize[1], info.m_workItemSize[2]); - printf(" CL_DEVICE_MAX_WORK_GROUP_SIZE:\t%u\n", info.m_workgroupSize); - printf(" CL_DEVICE_MAX_CLOCK_FREQUENCY:\t%u MHz\n", info.m_clockFrequency); - printf(" CL_DEVICE_ADDRESS_BITS:\t\t%u\n", info.m_addressBits); - printf(" CL_DEVICE_MAX_MEM_ALLOC_SIZE:\t\t%u MByte\n", (unsigned int)(info.m_maxMemAllocSize/ (1024 * 1024))); - printf(" CL_DEVICE_GLOBAL_MEM_SIZE:\t\t%u MByte\n", (unsigned int)(info.m_globalMemSize/ (1024 * 1024))); - printf(" CL_DEVICE_ERROR_CORRECTION_SUPPORT:\t%s\n", info.m_errorCorrectionSupport== CL_TRUE ? "yes" : "no"); - printf(" CL_DEVICE_LOCAL_MEM_TYPE:\t\t%s\n", info.m_localMemType == 1 ? "local" : "global"); - printf(" CL_DEVICE_LOCAL_MEM_SIZE:\t\t%u KByte\n", (unsigned int)(info.m_localMemSize / 1024)); - printf(" CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE:\t%u KByte\n", (unsigned int)(info.m_constantBufferSize / 1024)); - if( info.m_queueProperties & CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE ) - printf(" CL_DEVICE_QUEUE_PROPERTIES:\t\t%s\n", "CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE"); - if( info.m_queueProperties & CL_QUEUE_PROFILING_ENABLE ) - printf(" CL_DEVICE_QUEUE_PROPERTIES:\t\t%s\n", "CL_QUEUE_PROFILING_ENABLE"); - - printf(" CL_DEVICE_IMAGE_SUPPORT:\t\t%u\n", info.m_imageSupport); - - printf(" CL_DEVICE_MAX_READ_IMAGE_ARGS:\t%u\n", info.m_maxReadImageArgs); - printf(" CL_DEVICE_MAX_WRITE_IMAGE_ARGS:\t%u\n", info.m_maxWriteImageArgs); - printf("\n CL_DEVICE_IMAGE "); - printf("\t\t\t2D_MAX_WIDTH\t %u\n", info.m_image2dMaxWidth); - printf("\t\t\t\t\t2D_MAX_HEIGHT\t %u\n", info.m_image2dMaxHeight); - printf("\t\t\t\t\t3D_MAX_WIDTH\t %u\n", info.m_image3dMaxWidth); - printf("\t\t\t\t\t3D_MAX_HEIGHT\t %u\n", info.m_image3dMaxHeight); - printf("\t\t\t\t\t3D_MAX_DEPTH\t %u\n", info.m_image3dMaxDepth); - if (info.m_deviceExtensions != 0) - printf("\n CL_DEVICE_EXTENSIONS:%s\n",info.m_deviceExtensions); - else - printf(" CL_DEVICE_EXTENSIONS: None\n"); - printf(" CL_DEVICE_PREFERRED_VECTOR_WIDTH_\t"); - printf("CHAR %u, SHORT %u, INT %u,LONG %u, FLOAT %u, DOUBLE %u\n\n\n", - info.m_vecWidthChar, info.m_vecWidthShort, info.m_vecWidthInt, info.m_vecWidthLong,info.m_vecWidthFloat, info.m_vecWidthDouble); - - -} - -void btOpenCLUtils::getDeviceInfo(cl_device_id device, btOpenCLDeviceInfo& info) -{ - - // CL_DEVICE_NAME - clGetDeviceInfo(device, CL_DEVICE_NAME, BT_MAX_STRING_LENGTH, &info.m_deviceName, NULL); - - // CL_DEVICE_VENDOR - clGetDeviceInfo(device, CL_DEVICE_VENDOR, BT_MAX_STRING_LENGTH, &info.m_deviceVendor, NULL); - - // CL_DRIVER_VERSION - clGetDeviceInfo(device, CL_DRIVER_VERSION, BT_MAX_STRING_LENGTH, &info.m_driverVersion, NULL); - - // CL_DEVICE_INFO - clGetDeviceInfo(device, CL_DEVICE_TYPE, sizeof(cl_device_type), &info.m_deviceType, NULL); - - // CL_DEVICE_MAX_COMPUTE_UNITS - clGetDeviceInfo(device, CL_DEVICE_MAX_COMPUTE_UNITS, sizeof(info.m_computeUnits), &info.m_computeUnits, NULL); - - // CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS - clGetDeviceInfo(device, CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS, sizeof(info.m_workitemDims), &info.m_workitemDims, NULL); - - // CL_DEVICE_MAX_WORK_ITEM_SIZES - clGetDeviceInfo(device, CL_DEVICE_MAX_WORK_ITEM_SIZES, sizeof(info.m_workItemSize), &info.m_workItemSize, NULL); - - // CL_DEVICE_MAX_WORK_GROUP_SIZE - clGetDeviceInfo(device, CL_DEVICE_MAX_WORK_GROUP_SIZE, sizeof(info.m_workgroupSize), &info.m_workgroupSize, NULL); - - // CL_DEVICE_MAX_CLOCK_FREQUENCY - clGetDeviceInfo(device, CL_DEVICE_MAX_CLOCK_FREQUENCY, sizeof(info.m_clockFrequency), &info.m_clockFrequency, NULL); - - // CL_DEVICE_ADDRESS_BITS - clGetDeviceInfo(device, CL_DEVICE_ADDRESS_BITS, sizeof(info.m_addressBits), &info.m_addressBits, NULL); - - // CL_DEVICE_MAX_MEM_ALLOC_SIZE - clGetDeviceInfo(device, CL_DEVICE_MAX_MEM_ALLOC_SIZE, sizeof(info.m_maxMemAllocSize), &info.m_maxMemAllocSize, NULL); - - // CL_DEVICE_GLOBAL_MEM_SIZE - clGetDeviceInfo(device, CL_DEVICE_GLOBAL_MEM_SIZE, sizeof(info.m_globalMemSize), &info.m_globalMemSize, NULL); - - // CL_DEVICE_ERROR_CORRECTION_SUPPORT - clGetDeviceInfo(device, CL_DEVICE_ERROR_CORRECTION_SUPPORT, sizeof(info.m_errorCorrectionSupport), &info.m_errorCorrectionSupport, NULL); - - // CL_DEVICE_LOCAL_MEM_TYPE - clGetDeviceInfo(device, CL_DEVICE_LOCAL_MEM_TYPE, sizeof(info.m_localMemType), &info.m_localMemType, NULL); - - // CL_DEVICE_LOCAL_MEM_SIZE - clGetDeviceInfo(device, CL_DEVICE_LOCAL_MEM_SIZE, sizeof(info.m_localMemSize), &info.m_localMemSize, NULL); - - // CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE - clGetDeviceInfo(device, CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE, sizeof(info.m_constantBufferSize), &info.m_constantBufferSize, NULL); - - // CL_DEVICE_QUEUE_PROPERTIES - clGetDeviceInfo(device, CL_DEVICE_QUEUE_PROPERTIES, sizeof(info.m_queueProperties), &info.m_queueProperties, NULL); - - // CL_DEVICE_IMAGE_SUPPORT - clGetDeviceInfo(device, CL_DEVICE_IMAGE_SUPPORT, sizeof(info.m_imageSupport), &info.m_imageSupport, NULL); - - // CL_DEVICE_MAX_READ_IMAGE_ARGS - clGetDeviceInfo(device, CL_DEVICE_MAX_READ_IMAGE_ARGS, sizeof(info.m_maxReadImageArgs), &info.m_maxReadImageArgs, NULL); - - // CL_DEVICE_MAX_WRITE_IMAGE_ARGS - clGetDeviceInfo(device, CL_DEVICE_MAX_WRITE_IMAGE_ARGS, sizeof(info.m_maxWriteImageArgs), &info.m_maxWriteImageArgs, NULL); - - // CL_DEVICE_IMAGE2D_MAX_WIDTH, CL_DEVICE_IMAGE2D_MAX_HEIGHT, CL_DEVICE_IMAGE3D_MAX_WIDTH, CL_DEVICE_IMAGE3D_MAX_HEIGHT, CL_DEVICE_IMAGE3D_MAX_DEPTH - clGetDeviceInfo(device, CL_DEVICE_IMAGE2D_MAX_WIDTH, sizeof(size_t), &info.m_image2dMaxWidth, NULL); - clGetDeviceInfo(device, CL_DEVICE_IMAGE2D_MAX_HEIGHT, sizeof(size_t), &info.m_image2dMaxHeight, NULL); - clGetDeviceInfo(device, CL_DEVICE_IMAGE3D_MAX_WIDTH, sizeof(size_t), &info.m_image3dMaxWidth, NULL); - clGetDeviceInfo(device, CL_DEVICE_IMAGE3D_MAX_HEIGHT, sizeof(size_t), &info.m_image3dMaxHeight, NULL); - clGetDeviceInfo(device, CL_DEVICE_IMAGE3D_MAX_DEPTH, sizeof(size_t), &info.m_image3dMaxDepth, NULL); - - // CL_DEVICE_EXTENSIONS: get device extensions, and if any then parse & log the string onto separate lines - clGetDeviceInfo(device, CL_DEVICE_EXTENSIONS, BT_MAX_STRING_LENGTH, &info.m_deviceExtensions, NULL); - - // CL_DEVICE_PREFERRED_VECTOR_WIDTH_ - clGetDeviceInfo(device, CL_DEVICE_PREFERRED_VECTOR_WIDTH_CHAR, sizeof(cl_uint), &info.m_vecWidthChar, NULL); - clGetDeviceInfo(device, CL_DEVICE_PREFERRED_VECTOR_WIDTH_SHORT, sizeof(cl_uint), &info.m_vecWidthShort, NULL); - clGetDeviceInfo(device, CL_DEVICE_PREFERRED_VECTOR_WIDTH_INT, sizeof(cl_uint), &info.m_vecWidthInt, NULL); - clGetDeviceInfo(device, CL_DEVICE_PREFERRED_VECTOR_WIDTH_LONG, sizeof(cl_uint), &info.m_vecWidthLong, NULL); - clGetDeviceInfo(device, CL_DEVICE_PREFERRED_VECTOR_WIDTH_FLOAT, sizeof(cl_uint), &info.m_vecWidthFloat, NULL); - clGetDeviceInfo(device, CL_DEVICE_PREFERRED_VECTOR_WIDTH_DOUBLE, sizeof(cl_uint), &info.m_vecWidthDouble, NULL); -} - -static const char* strip2(const char* name, const char* pattern) -{ - size_t const patlen = strlen(pattern); - size_t patcnt = 0; - const char * oriptr; - const char * patloc; - // find how many times the pattern occurs in the original string - for (oriptr = name; patloc = strstr(oriptr, pattern); oriptr = patloc + patlen) - { - patcnt++; - } - return oriptr; -} - -cl_program btOpenCLUtils::compileCLProgramFromString(cl_context clContext, cl_device_id device, const char* kernelSource, cl_int* pErrNum, const char* additionalMacros , const char* clFileNameForCaching) -{ - - cl_program m_cpProgram=0; - cl_int status; - - char binaryFileName[522]; - - if (clFileNameForCaching) - { - - char deviceName[256]; - char driverVersion[256]; - clGetDeviceInfo(device, CL_DEVICE_NAME, 256, &deviceName, NULL); - clGetDeviceInfo(device, CL_DRIVER_VERSION, 256, &driverVersion, NULL); - - - const char* strippedName = strip2(clFileNameForCaching,"\\"); - strippedName = strip2(strippedName,"/"); - - sprintf_s(binaryFileName,"cache/%s.%s.%s.bin",strippedName, deviceName,driverVersion ); - //printf("searching for %s\n", binaryFileName); - - bool fileUpToDate = false; - bool binaryFileValid=false; - - FILETIME modtimeBinary; - -#ifdef _WIN32 - CreateDirectory("cache",0); - { - - HANDLE binaryFileHandle = CreateFile(binaryFileName,GENERIC_READ,0,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0); - if (binaryFileHandle ==INVALID_HANDLE_VALUE) - { - DWORD errorCode; - errorCode = GetLastError(); - switch (errorCode) - { - case ERROR_FILE_NOT_FOUND: - { - printf("\nCached file not found %s\n", binaryFileName); - break; - } - case ERROR_PATH_NOT_FOUND: - { - printf("\nCached file path not found %s\n", binaryFileName); - break; - } - default: - { - printf("\nFailed reading cached file with errorCode = %d\n", errorCode); - } - } - } else - { - if (GetFileTime(binaryFileHandle, NULL, NULL, &modtimeBinary)==0) - { - DWORD errorCode; - errorCode = GetLastError(); - printf("\nGetFileTime errorCode = %d\n", errorCode); - } else - { - binaryFileValid = true; - } - CloseHandle(binaryFileHandle); - } - - if (binaryFileValid) - { - HANDLE srcFileHandle = CreateFile(clFileNameForCaching,GENERIC_READ,0,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0); - if (srcFileHandle!=INVALID_HANDLE_VALUE) - { - FILETIME modtimeSrc; - if (GetFileTime(srcFileHandle, NULL, NULL, &modtimeSrc)==0) - { - DWORD errorCode; - errorCode = GetLastError(); - printf("\nGetFileTime errorCode = %d\n", errorCode); - } - if ( ( modtimeSrc.dwHighDateTime < modtimeBinary.dwHighDateTime) - ||(( modtimeSrc.dwHighDateTime == modtimeBinary.dwHighDateTime)&&(modtimeSrc.dwLowDateTime <= modtimeBinary.dwLowDateTime))) - { - fileUpToDate=true; - } else - { - printf("\nCached binary file out-of-date (%s)\n",binaryFileName); - } - CloseHandle(srcFileHandle); - } - else - { -#ifdef _DEBUG - DWORD errorCode; - errorCode = GetLastError(); - switch (errorCode) - { - case ERROR_FILE_NOT_FOUND: - { - printf("\nSrc file not found %s\n", clFileNameForCaching); - break; - } - case ERROR_PATH_NOT_FOUND: - { - printf("\nSrc path not found %s\n", clFileNameForCaching); - break; - } - default: - { - printf("\nnSrc file reading errorCode = %d\n", errorCode); - } - } - - //we should make sure the src file exists so we can verify the timestamp with binary - assert(0); -#else - //if we cannot find the source, assume it is OK in release builds - fileUpToDate = true; -#endif - } - } - - - } - - if( fileUpToDate) - { - FILE* file = fopen(binaryFileName, "rb"); - if (file) - { - fseek( file, 0L, SEEK_END ); - size_t binarySize = ftell( file ); - rewind( file ); - char* binary = new char[binarySize]; - fread( binary, sizeof(char), binarySize, file ); - fclose( file ); - - m_cpProgram = clCreateProgramWithBinary( clContext, 1,&device, &binarySize, (const unsigned char**)&binary, 0, &status ); - btAssert( status == CL_SUCCESS ); - status = clBuildProgram( m_cpProgram, 1, &device, additionalMacros, 0, 0 ); - btAssert( status == CL_SUCCESS ); - - if( status != CL_SUCCESS ) - { - char *build_log; - size_t ret_val_size; - clGetProgramBuildInfo(m_cpProgram, device, CL_PROGRAM_BUILD_LOG, 0, NULL, &ret_val_size); - build_log = new char[ret_val_size+1]; - clGetProgramBuildInfo(m_cpProgram, device, CL_PROGRAM_BUILD_LOG, ret_val_size, build_log, NULL); - build_log[ret_val_size] = '\0'; - printf("%s\n", build_log); - delete build_log; - btAssert(0); - m_cpProgram = 0; - } - delete[] binary; - } - } -#endif //_WIN32 - - } - - if (!m_cpProgram) - { - cl_kernel kernel; - cl_int localErrNum; - size_t program_length = strlen(kernelSource); - - m_cpProgram = clCreateProgramWithSource(clContext, 1, (const char**)&kernelSource, &program_length, &localErrNum); - if (localErrNum!= CL_SUCCESS) - { - if (pErrNum) - *pErrNum = localErrNum; - return 0; - } - - // Build the program with 'mad' Optimization option - - - #ifdef MAC - char* flags = "-cl-mad-enable -DMAC -DGUID_ARG"; - #else - //const char* flags = "-DGUID_ARG= -fno-alias"; - const char* flags = "-DGUID_ARG= "; - #endif - - char* compileFlags = new char[strlen(additionalMacros) + strlen(flags) + 5]; - sprintf(compileFlags, "%s %s", flags, additionalMacros); - localErrNum = clBuildProgram(m_cpProgram, 1, &device, compileFlags, NULL, NULL); - if (localErrNum!= CL_SUCCESS) - { - char *build_log; - size_t ret_val_size; - clGetProgramBuildInfo(m_cpProgram, device, CL_PROGRAM_BUILD_LOG, 0, NULL, &ret_val_size); - build_log = new char[ret_val_size+1]; - clGetProgramBuildInfo(m_cpProgram, device, CL_PROGRAM_BUILD_LOG, ret_val_size, build_log, NULL); - - // to be carefully, terminate with \0 - // there's no information in the reference whether the string is 0 terminated or not - build_log[ret_val_size] = '\0'; - - - printf("Error in clBuildProgram, Line %u in file %s, Log: \n%s\n !!!\n\n", __LINE__, __FILE__, build_log); - delete[] build_log; - if (pErrNum) - *pErrNum = localErrNum; - return 0; - } - - if( clFileNameForCaching ) - { // write to binary - - cl_uint numAssociatedDevices; - status = clGetProgramInfo( m_cpProgram, CL_PROGRAM_NUM_DEVICES, sizeof(cl_uint), &numAssociatedDevices, 0 ); - btAssert( status == CL_SUCCESS ); - if (numAssociatedDevices==1) - { - - size_t binarySize; - status = clGetProgramInfo( m_cpProgram, CL_PROGRAM_BINARY_SIZES, sizeof(size_t), &binarySize, 0 ); - btAssert( status == CL_SUCCESS ); - - char* binary = new char[binarySize]; - - status = clGetProgramInfo( m_cpProgram, CL_PROGRAM_BINARIES, sizeof(char*), &binary, 0 ); - btAssert( status == CL_SUCCESS ); - - { - FILE* file = fopen(binaryFileName, "wb"); - if (file) - { - fwrite( binary, sizeof(char), binarySize, file ); - fclose( file ); - } else - { - printf("cannot write file %s\n", binaryFileName); - } - } - - delete [] binary; - } - } - delete [] compileFlags; - } - - return m_cpProgram; -} - - -cl_kernel btOpenCLUtils::compileCLKernelFromString(cl_context clContext, cl_device_id device, const char* kernelSource, const char* kernelName, cl_int* pErrNum, cl_program prog, const char* additionalMacros ) -{ - printf("compiling kernel %s ",kernelName); - cl_kernel kernel; - cl_int localErrNum; - size_t program_length = strlen(kernelSource); - - - cl_program m_cpProgram = prog; - if (!m_cpProgram) - { - m_cpProgram = compileCLProgramFromString(clContext,device,kernelSource,pErrNum, additionalMacros); - } - - - // Create the kernel - kernel = clCreateKernel(m_cpProgram, kernelName, &localErrNum); - if (localErrNum != CL_SUCCESS) - { - printf("Error in clCreateKernel, Line %u in file %s, cannot find kernel function %s !!!\n\n", __LINE__, __FILE__, kernelName); - if (pErrNum) - *pErrNum = localErrNum; - return 0; - } - - if (!prog && m_cpProgram) - { - clReleaseProgram(m_cpProgram); - } - printf("ready. \n"); - - - if (pErrNum) - *pErrNum = CL_SUCCESS; - return kernel; - -} diff --git a/Extras/RigidBodyGpuPipeline/opencl/basic_initialize/btOpenCLUtils.h b/Extras/RigidBodyGpuPipeline/opencl/basic_initialize/btOpenCLUtils.h deleted file mode 100644 index 4e41b415b..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/basic_initialize/btOpenCLUtils.h +++ /dev/null @@ -1,104 +0,0 @@ -/* -Bullet Continuous Collision Detection and Physics Library, http://bulletphysics.org -Copyright (C) 2006 - 2011 Sony Computer Entertainment Inc. - -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. -*/ - -//original author: Roman Ponomarev -//cleanup by Erwin Coumans - -#ifndef BT_OPENCL_UTILS_H -#define BT_OPENCL_UTILS_H - -#include "btOpenCLInclude.h" - - -#define BT_MAX_STRING_LENGTH 1024 - -struct btOpenCLDeviceInfo -{ - char m_deviceName[BT_MAX_STRING_LENGTH]; - char m_deviceVendor[BT_MAX_STRING_LENGTH]; - char m_driverVersion[BT_MAX_STRING_LENGTH]; - char m_deviceExtensions[BT_MAX_STRING_LENGTH]; - - cl_device_type m_deviceType; - cl_uint m_computeUnits; - size_t m_workitemDims; - size_t m_workItemSize[3]; - size_t m_image2dMaxWidth; - size_t m_image2dMaxHeight; - size_t m_image3dMaxWidth; - size_t m_image3dMaxHeight; - size_t m_image3dMaxDepth; - size_t m_workgroupSize; - cl_uint m_clockFrequency; - cl_ulong m_constantBufferSize; - cl_ulong m_localMemSize; - cl_ulong m_globalMemSize; - cl_bool m_errorCorrectionSupport; - cl_device_local_mem_type m_localMemType; - cl_uint m_maxReadImageArgs; - cl_uint m_maxWriteImageArgs; - - - - cl_uint m_addressBits; - cl_ulong m_maxMemAllocSize; - cl_command_queue_properties m_queueProperties; - cl_bool m_imageSupport; - cl_uint m_vecWidthChar; - cl_uint m_vecWidthShort; - cl_uint m_vecWidthInt; - cl_uint m_vecWidthLong; - cl_uint m_vecWidthFloat; - cl_uint m_vecWidthDouble; - -}; - -struct btOpenCLPlatformInfo -{ - char m_platformVendor[BT_MAX_STRING_LENGTH]; - char m_platformName[BT_MAX_STRING_LENGTH]; - char m_platformVersion[BT_MAX_STRING_LENGTH]; -}; - -class btOpenCLUtils -{ -public: - - /// CL Context optionally takes a GL context. This is a generic type because we don't really want this code - /// to have to understand GL types. It is a HGLRC in _WIN32 or a GLXContext otherwise. - static cl_context createContextFromType(cl_device_type deviceType, cl_int* pErrNum, void* pGLCtx = 0, void* pGLDC = 0, int preferredDeviceIndex = -1, int preferredPlatformIndex= - 1); - - static int getNumDevices(cl_context cxMainContext); - static cl_device_id getDevice(cl_context cxMainContext, int nr); - static void getDeviceInfo(cl_device_id device, btOpenCLDeviceInfo& info); - static void printDeviceInfo(cl_device_id device); - - static cl_kernel compileCLKernelFromString( cl_context clContext,cl_device_id device, const char* kernelSource, const char* kernelName, cl_int* pErrNum=0, cl_program prog=0,const char* additionalMacros = "" ); - - //optional - static cl_program compileCLProgramFromString( cl_context clContext,cl_device_id device, const char* kernelSource, cl_int* pErrNum=0,const char* additionalMacros = "" , const char* srcFileNameForCaching=0); - - //the following optional APIs provide access using specific platform information - static int getNumPlatforms(cl_int* pErrNum=0); - ///get the nr'th platform, where nr is in the range [0..getNumPlatforms) - static cl_platform_id getPlatform(int nr, cl_int* pErrNum=0); - static void getPlatformInfo(cl_platform_id platform, btOpenCLPlatformInfo& platformInfo); - static const char* getSdkVendorName(); - static cl_context createContextFromPlatform(cl_platform_id platform, cl_device_type deviceType, cl_int* pErrNum, void* pGLCtx = 0, void* pGLDC = 0,int preferredDeviceIndex = -1, int preferredPlatformIndex= -1); -}; - - - -#endif // BT_OPENCL_UTILS_H diff --git a/Extras/RigidBodyGpuPipeline/opencl/basic_initialize/main.cpp b/Extras/RigidBodyGpuPipeline/opencl/basic_initialize/main.cpp deleted file mode 100644 index 2890d7d19..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/basic_initialize/main.cpp +++ /dev/null @@ -1,92 +0,0 @@ -/* -Bullet Continuous Collision Detection and Physics Library -Copyright (c) 2011 Advanced Micro Devices, Inc. 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. -*/ - -///original author: Erwin Coumans - -#include "btOpenCLUtils.h" -#include - -cl_context g_cxMainContext; -cl_command_queue g_cqCommandQue; - - - -int main(int argc, char* argv[]) -{ - int ciErrNum = 0; - - cl_device_type deviceType = CL_DEVICE_TYPE_ALL; - const char* vendorSDK = btOpenCLUtils::getSdkVendorName(); - - printf("This program was compiled using the %s OpenCL SDK\n",vendorSDK); - int numPlatforms = btOpenCLUtils::getNumPlatforms(); - printf("Num Platforms = %d\n", numPlatforms); - - for (int i=0;i=0) - { - btAABBCL minAabb = plocalShapeAABB[shapeIndex*2]; - btAABBCL maxAabb = plocalShapeAABB[shapeIndex*2+1]; - - float4 halfExtents = ((float4)(maxAabb.fx - minAabb.fx,maxAabb.fy - minAabb.fy,maxAabb.fz - minAabb.fz,0.f))*0.5f; - - Matrix3x3 abs_b = qtGetRotationMatrix(orientation); - float4 extent = (float4) ( dot(abs_b.m_row[0],halfExtents),dot(abs_b.m_row[1],halfExtents),dot(abs_b.m_row[2],halfExtents),0.f); - - - pAABB[nodeID*2].fx = position.x-extent.x; - pAABB[nodeID*2].fy = position.y-extent.y; - pAABB[nodeID*2].fz = position.z-extent.z; - pAABB[nodeID*2].uw = nodeID; - - pAABB[nodeID*2+1].fx = position.x+extent.x; - pAABB[nodeID*2+1].fy = position.y+extent.y; - pAABB[nodeID*2+1].fz = position.z+extent.z; - pAABB[nodeID*2+1].uw = nodeID; - } - } -} - - -__kernel void - broadphaseColorKernel( const int startOffset, const int numNodes, __global float4 *g_vertexBuffer, __global int2* pOverlappingPairs, const int numOverlap) -{ - int nodeID = get_global_id(0); - if( nodeID < numOverlap ) - { - int2 pair = pOverlappingPairs[nodeID]; - float4 red = (float4)(1.f,0.4f,0.4f,1.f); - - g_vertexBuffer[pair.x + startOffset/4+numNodes+numNodes] = red; - g_vertexBuffer[pair.y + startOffset/4+numNodes+numNodes] = red; - } -} - - - -__kernel void - broadphaseKernel( const int startOffset, const int numNodes, __global float4 *g_vertexBuffer) -{ - int nodeID = get_global_id(0); - -// float BT_GPU_ANGULAR_MOTION_THRESHOLD = (0.25f * 3.14159254); - - if( nodeID < numNodes ) - { - float4 position = g_vertexBuffer[nodeID + startOffset/4]; - //float4 orientation = g_vertexBuffer[nodeID + startOffset/4+numNodes]; - float4 color = g_vertexBuffer[nodeID + startOffset/4+numNodes+numNodes]; - - float4 red = (float4)(1.f,0.f,0.f,0.f); - float4 green = (float4)(0.f,1.f,0.f,0.f); - float4 blue = (float4)(0.f,0.f,1.f,0.f); - float overlap=0; - int equal = 0; - - g_vertexBuffer[nodeID + startOffset/4+numNodes+numNodes] = green; - - for (int i=0;i0.f) - g_vertexBuffer[nodeID + startOffset/4+numNodes+numNodes]=red*overlap; - else - g_vertexBuffer[nodeID + startOffset/4+numNodes+numNodes]=green; - } - } -} - -); \ No newline at end of file diff --git a/Extras/RigidBodyGpuPipeline/opencl/broadphase_benchmark/btGridBroadphaseCL.cpp b/Extras/RigidBodyGpuPipeline/opencl/broadphase_benchmark/btGridBroadphaseCL.cpp deleted file mode 100644 index 4cd9264a7..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/broadphase_benchmark/btGridBroadphaseCL.cpp +++ /dev/null @@ -1,230 +0,0 @@ - -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Roman Ponomarev, Erwin Coumans - -#ifdef RELEASE_ME -#define COMPUTE_AABB_KERNEL_PATH "computeAabbKernelOCL.cl" -#else -#define COMPUTE_AABB_KERNEL_PATH "..\\..\\opencl\\broadphase_benchmark\\computeAabbKernelOCL" -#endif - - -#include "btGridBroadphaseCl.h" -#include "LinearMath/btQuickprof.h" -#include "Adl/Adl.h" -#include "AdlPrimitives/Math/Math.h" - -#include "Adl/AdlKernel.h" -#include "../basic_initialize/btOpenCLUtils.h" -#define MSTRINGIFY(A) #A -static const char* spComputeAabbSource= -#include "computeAabbKernelOCL.cl" - -struct btTmpAabb -{ - float minfx; - float minfy; - float minfz; - unsigned int index0; - float maxfx; - float maxfy; - float maxfz; - unsigned int index1; -} ; - - - - -btGridBroadphaseCl::btGridBroadphaseCl( btOverlappingPairCache* overlappingPairCache, - const btVector3& cellSize, - int gridSizeX, int gridSizeY, int gridSizeZ, - int maxSmallProxies, int maxLargeProxies, int maxPairsPerSmallProxy, - btScalar maxSmallProxySize, - int maxSmallProxiesPerCell, - cl_context context, - cl_device_id device, - cl_command_queue queue, - adl::DeviceCL* deviceCL) -:bt3dGridBroadphaseOCL(overlappingPairCache,cellSize, - gridSizeX, gridSizeY, gridSizeZ, - maxSmallProxies, maxLargeProxies, maxPairsPerSmallProxy, - maxSmallProxySize,maxSmallProxiesPerCell, - context,device,queue,deviceCL) -{ - - m_countOverlappingPairs = m_deviceCL->getKernel(COMPUTE_AABB_KERNEL_PATH,"countOverlappingpairs","",spComputeAabbSource); - - m_squeezePairCaches = m_deviceCL->getKernel(COMPUTE_AABB_KERNEL_PATH,"squeezePairCaches","",spComputeAabbSource); - - m_aabbConstBuffer = new adl::Buffer(m_deviceCL,1,adl::BufferBase::BUFFER_CONST); - - size_t memSize = m_maxHandles * m_maxPairsPerBody * sizeof(unsigned int)*2; - cl_int ciErrNum=0; - m_dAllOverlappingPairs = clCreateBuffer(m_cxMainContext, CL_MEM_READ_WRITE, memSize, NULL, &ciErrNum); - - memset(m_hAllOverlappingPairs, 0x00, sizeof(MyUint2)*m_maxHandles * m_maxPairsPerBody); - copyArrayToDevice(m_dAllOverlappingPairs, m_hAllOverlappingPairs, m_maxHandles * m_maxPairsPerBody * sizeof(MyUint2)); - - - - oclCHECKERROR(ciErrNum, CL_SUCCESS); - - - -} - -btGridBroadphaseCl::~btGridBroadphaseCl() -{ - clReleaseMemObject(m_dAllOverlappingPairs); - - delete m_aabbConstBuffer; - -} - - - -void btGridBroadphaseCl::prepareAABB(float* positions, int numObjects) -{ - return; -#if 0 -bt3dGridBroadphaseOCL::prepareAABB(); -#else - BT_PROFILE("prepareAABB"); - bt3DGrid3F1U* pBB = m_hAABB; - - int new_largest_index = numObjects; - unsigned int num_small = numObjects; - m_LastHandleIndex = new_largest_index; - new_largest_index = -1; - unsigned int num_large = 0; - m_LastLargeHandleIndex = new_largest_index; - // paranoid checks - //btAssert(num_small == m_numHandles); - //btAssert(num_large == m_numLargeHandles); - - //copyArrayFromDevice( m_hAABB, m_dAABB, sizeof(bt3DGrid3F1U) * 2 * (m_numHandles + m_numLargeHandles)); - //clFinish(m_cqCommandQue); -#endif - -} -void btGridBroadphaseCl::calcHashAABB() -{ - bt3dGridBroadphaseOCL::calcHashAABB(); -} - - -void btGridBroadphaseCl::calculateOverlappingPairs(float* positions, int numObjects) -{ - btDispatcher* dispatcher=0; - - // update constants - { - BT_PROFILE("setParameters"); - setParameters(&m_params); - } - - // prepare AABB array - { - BT_PROFILE("prepareAABB"); - prepareAABB(positions, numObjects); - } - // calculate hash - { - BT_PROFILE("calcHashAABB"); - calcHashAABB(); - } - - { - BT_PROFILE("sortHash"); - // sort bodies based on hash - sortHash(); - } - - // find start of each cell - { - BT_PROFILE("findCellStart"); - findCellStart(); - } - - { - BT_PROFILE("findOverlappingPairs"); - // findOverlappingPairs (small/small) - findOverlappingPairs(); - } - - // add pairs to CPU cache - { - BT_PROFILE("computePairCacheChanges"); -#if 0 - computePairCacheChanges(); -#else - int ciErrNum=0; - - ciErrNum=clSetKernelArg((cl_kernel)m_countOverlappingPairs->m_kernel, 0, sizeof(int), (void*)&numObjects); - ciErrNum=clSetKernelArg((cl_kernel)m_countOverlappingPairs->m_kernel, 1, sizeof(cl_mem),(void*)&m_dPairBuff); - ciErrNum=clSetKernelArg((cl_kernel)m_countOverlappingPairs->m_kernel, 2, sizeof(cl_mem),(void*)&m_dPairBuffStartCurr); - ciErrNum=clSetKernelArg((cl_kernel)m_countOverlappingPairs->m_kernel, 3, sizeof(cl_mem),(void*)&m_dPairScanChanged); - ciErrNum=clSetKernelArg((cl_kernel)m_countOverlappingPairs->m_kernel, 4, sizeof(cl_mem),(void*)&m_dAABB); - - - size_t localWorkSize=64; - size_t numWorkItems = localWorkSize*((numObjects+ (localWorkSize)) / localWorkSize); - - - ciErrNum = clEnqueueNDRangeKernel(m_cqCommandQue, (cl_kernel)m_countOverlappingPairs->m_kernel, 1, NULL, &numWorkItems, &localWorkSize, 0,0,0 ); -oclCHECKERROR(ciErrNum, CL_SUCCESS); - ciErrNum = clFlush(m_cqCommandQue); -#endif - - - } - { - BT_PROFILE("scanOverlappingPairBuff"); - scanOverlappingPairBuff(false); - } - { - BT_PROFILE("squeezeOverlappingPairBuff"); -//#define FORCE_CPU -#ifdef FORCE_CPU - bt3dGridBroadphaseOCL::squeezeOverlappingPairBuff(); - copyArrayToDevice(m_dPairsChangedXY, m_hPairsChangedXY, sizeof( MyUint2) * m_numPrefixSum); //gSum -#else - //squeezeOverlappingPairBuff(); - int ciErrNum = 0; - ciErrNum=clSetKernelArg((cl_kernel)m_squeezePairCaches->m_kernel, 0, sizeof(int), (void*)&numObjects); - ciErrNum=clSetKernelArg((cl_kernel)m_squeezePairCaches->m_kernel, 1, sizeof(cl_mem),(void*)&m_dPairBuff); - ciErrNum=clSetKernelArg((cl_kernel)m_squeezePairCaches->m_kernel, 2, sizeof(cl_mem),(void*)&m_dPairBuffStartCurr); - ciErrNum=clSetKernelArg((cl_kernel)m_squeezePairCaches->m_kernel, 3, sizeof(cl_mem),(void*)&m_dPairScanChanged); - ciErrNum=clSetKernelArg((cl_kernel)m_squeezePairCaches->m_kernel, 4, sizeof(cl_mem),(void*)&m_dAllOverlappingPairs); - ciErrNum=clSetKernelArg((cl_kernel)m_squeezePairCaches->m_kernel, 5, sizeof(cl_mem),(void*)&m_dAABB); - - size_t workGroupSize = 64; - size_t numWorkItems = workGroupSize*((numObjects+ (workGroupSize)) / workGroupSize); - - - ciErrNum = clEnqueueNDRangeKernel(m_cqCommandQue, (cl_kernel)m_squeezePairCaches->m_kernel, 1, NULL, &numWorkItems, &workGroupSize, 0,0,0 ); - oclCHECKERROR(ciErrNum, CL_SUCCESS); - - -// copyArrayFromDevice(m_hAllOverlappingPairs, m_dAllOverlappingPairs, sizeof(unsigned int) * m_numPrefixSum*2); //gSum -// clFinish(m_cqCommandQue); -#endif - - } - - - return; -} - diff --git a/Extras/RigidBodyGpuPipeline/opencl/broadphase_benchmark/btGridBroadphaseCL.h b/Extras/RigidBodyGpuPipeline/opencl/broadphase_benchmark/btGridBroadphaseCL.h deleted file mode 100644 index 51a7d9f76..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/broadphase_benchmark/btGridBroadphaseCL.h +++ /dev/null @@ -1,72 +0,0 @@ - -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Roman Ponomarev, Erwin Coumans - -#ifndef GRID_BROADPHASE_CL_H -#define GRID_BROADPHASE_CL_H - -#include "../3dGridBroadphase/Shared/bt3dGridBroadphaseOCL.h" - -#include "Adl/Adl.h" -#include "Adl/AdlKernel.h" - - -struct MyAabbConstData -{ - int bla; - int numElem; -}; - - - -class btGridBroadphaseCl : public bt3dGridBroadphaseOCL -{ -protected: - - adl::Kernel* m_countOverlappingPairs; - adl::Kernel* m_squeezePairCaches; - - - adl::Buffer* m_aabbConstBuffer; - - - public: - - cl_mem m_dAllOverlappingPairs; - - - btGridBroadphaseCl( btOverlappingPairCache* overlappingPairCache, - const btVector3& cellSize, - int gridSizeX, int gridSizeY, int gridSizeZ, - int maxSmallProxies, int maxLargeProxies, int maxPairsPerSmallProxy, - btScalar maxSmallProxySize, - int maxSmallProxiesPerCell = 4, - cl_context context = NULL, - cl_device_id device = NULL, - cl_command_queue queue = NULL, - adl::DeviceCL* deviceCL=0 - ); - - virtual void prepareAABB(float* positions, int numObjects); - virtual void calcHashAABB(); - - void calculateOverlappingPairs(float* positions, int numObjects); - - virtual ~btGridBroadphaseCl(); - -}; - -#endif //GRID_BROADPHASE_CL_H - diff --git a/Extras/RigidBodyGpuPipeline/opencl/broadphase_benchmark/computeAabbKernelOCL.cl b/Extras/RigidBodyGpuPipeline/opencl/broadphase_benchmark/computeAabbKernelOCL.cl deleted file mode 100644 index 3cf7550c0..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/broadphase_benchmark/computeAabbKernelOCL.cl +++ /dev/null @@ -1,112 +0,0 @@ -MSTRINGIFY( - -typedef struct -{ - int bla; - int numElem; -} MyAabbConstDataCL ; - -typedef struct -{ - float minfx; - float minfy; - float minfz; - unsigned int index0; - float maxfx; - float maxfy; - float maxfz; - unsigned int index1; -} btAabbCL; - - -__kernel void computeAabb( __global btAabbCL* aabbs,__global float4* positions, MyAabbConstDataCL cb) -{ - int nodeID = get_global_id(0); - - if( nodeID < cb.numElem ) - { - aabbs[nodeID].minfx = positions[nodeID].x -1.f; - aabbs[nodeID].minfy = positions[nodeID].y -1.f; - aabbs[nodeID].minfz = positions[nodeID].z -1.f; - aabbs[nodeID].index0 = nodeID; - aabbs[nodeID].maxfx = positions[nodeID].x +1.f; - aabbs[nodeID].maxfy = positions[nodeID].y +1.f; - aabbs[nodeID].maxfz = positions[nodeID].z +1.f; - aabbs[nodeID].index1 = nodeID; - } -} - - -__kernel void countOverlappingpairs( int numObjects, - __global int* pPairBuff, - __global int2* pPairBuffStartCurr, - __global int* pPairScan, - __global float4* pAABB ) -{ - int index = get_global_id(0); - if(index >= numObjects) - { - return; - } - float4 bbMin = pAABB[index * 2]; - int handleIndex = as_int(bbMin.w); - int2 start_curr = pPairBuffStartCurr[handleIndex]; - int start = start_curr.x; - int curr = start_curr.y; - __global int *pInp = pPairBuff + start; - int num_changes = 0; - for(int k = 0; k < curr; k++, pInp++) - { - if(((*pInp) & 0x60000000))//either new or existing pairs (ignore old non-overlapping pairs) - { - num_changes++; - } - } - pPairScan[index+1] = num_changes; -} - - -__kernel void squeezePairCaches( int numObjects, - __global int* pPairBuff, - __global int2* pPairBuffStartCurr, - __global int* pPairScan, - __global int2* pPairOut, - __global float4* pAABB ) -{ - int index = get_global_id(0); - if(index >= numObjects) - { - return; - } - float4 bbMin = pAABB[index * 2]; - int handleIndex = as_int(bbMin.w); - int2 start_curr = pPairBuffStartCurr[handleIndex]; - int start = start_curr.x; - int curr = start_curr.y; - __global int* pInp = pPairBuff + start; - __global int2* pOut = pPairOut + pPairScan[index+1]; - __global int* pOut2 = pInp; - int num = 0; - for(int k = 0; k < curr; k++, pInp++) - { - if(((*pInp) & 0x60000000)) - { - int2 newpair; - newpair.x = handleIndex; - newpair.y = (*pInp) & (~0x60000000); - *pOut = newpair; - pOut++; - } - if((*pInp) & 0x60000000) - { - *pOut2 = (*pInp) & (~0x60000000); - pOut2++; - num++; - } - } - int2 newStartCurr; - newStartCurr.x = start; - newStartCurr.y = num; - pPairBuffStartCurr[handleIndex] = newStartCurr; -} -); \ No newline at end of file diff --git a/Extras/RigidBodyGpuPipeline/opencl/broadphase_benchmark/findPairsOpenCL.cpp b/Extras/RigidBodyGpuPipeline/opencl/broadphase_benchmark/findPairsOpenCL.cpp deleted file mode 100644 index d90e37054..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/broadphase_benchmark/findPairsOpenCL.cpp +++ /dev/null @@ -1,204 +0,0 @@ - -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Roman Ponomarev, Erwin Coumans - -#include "findPairsOpenCL.h" -#include "../basic_initialize/btOpenCLUtils.h" - -#define MSTRINGIFY(A) #A -static char* broadphaseKernelString = -#include "broadphaseKernel.cl" - -#define GRID_BROADPHASE_PATH "..\\..\\opencl\\broadphase_benchmark\\broadphaseKernel.cl" - - - - -void initFindPairs(btFindPairsIO& fpio,cl_context cxMainContext, cl_device_id device, cl_command_queue commandQueue, int maxHandles, int maxPairsPerBody) -{ - - //m_proxies.push_back( proxy ); - - fpio.m_mainContext = cxMainContext; - fpio.m_cqCommandQue = commandQueue; - fpio.m_device = device; - cl_int pErrNum; - cl_program prog = btOpenCLUtils::compileCLProgramFromString(cxMainContext, device, broadphaseKernelString, &pErrNum ,"",GRID_BROADPHASE_PATH); - - fpio.m_broadphaseBruteForceKernel = btOpenCLUtils::compileCLKernelFromString(cxMainContext,device, broadphaseKernelString, "broadphaseKernel" ,&pErrNum,prog); - fpio.m_initializeGpuAabbsKernelSimple = btOpenCLUtils::compileCLKernelFromString(cxMainContext,device, broadphaseKernelString, "initializeGpuAabbsSimple" ,&pErrNum,prog); - fpio.m_initializeGpuAabbsKernelFull = btOpenCLUtils::compileCLKernelFromString(cxMainContext,device, broadphaseKernelString, "initializeGpuAabbsFull" ,&pErrNum,prog); - - fpio.m_broadphaseColorKernel = btOpenCLUtils::compileCLKernelFromString(cxMainContext,device, broadphaseKernelString, "broadphaseColorKernel" ,&pErrNum,prog); - - fpio.m_setupBodiesKernel = btOpenCLUtils::compileCLKernelFromString(cxMainContext,device, broadphaseKernelString, "setupBodiesKernel" ,&pErrNum,prog); - fpio.m_copyVelocitiesKernel = btOpenCLUtils::compileCLKernelFromString(cxMainContext,device, broadphaseKernelString, "copyVelocitiesKernel" ,&pErrNum,prog); - - - -} - -void findPairsOpenCLBruteForce(btFindPairsIO& fpio) -{ - - int ciErrNum = 0; - - int numObjects = fpio.m_numObjects; - int offset = fpio.m_positionOffset; - - ciErrNum = clSetKernelArg(fpio.m_broadphaseBruteForceKernel, 0, sizeof(int), &offset); - ciErrNum = clSetKernelArg(fpio.m_broadphaseBruteForceKernel, 1, sizeof(int), &numObjects); - ciErrNum = clSetKernelArg(fpio.m_broadphaseBruteForceKernel, 2, sizeof(cl_mem), (void*)&fpio.m_clObjectsBuffer); - - size_t numWorkItems = numObjects;///workGroupSize*((NUM_OBJECTS + (workGroupSize)) / workGroupSize); - size_t workGroupSize = 64; - ciErrNum = clEnqueueNDRangeKernel(fpio.m_cqCommandQue, fpio.m_broadphaseBruteForceKernel, 1, NULL, &numWorkItems, &workGroupSize,0 ,0 ,0); - oclCHECKERROR(ciErrNum, CL_SUCCESS); -} - -void setupGpuAabbsFull(btFindPairsIO& fpio, cl_mem bodies) -{ - - int ciErrNum = 0; - - int numObjects = fpio.m_numObjects; - int offset = fpio.m_positionOffset; - - ciErrNum = clSetKernelArg(fpio.m_initializeGpuAabbsKernelFull, 0, sizeof(int), &offset); - ciErrNum = clSetKernelArg(fpio.m_initializeGpuAabbsKernelFull, 1, sizeof(int), &numObjects); - ciErrNum = clSetKernelArg(fpio.m_initializeGpuAabbsKernelFull, 2, sizeof(cl_mem), (void*)&fpio.m_clObjectsBuffer); - ciErrNum = clSetKernelArg(fpio.m_initializeGpuAabbsKernelFull, 3, sizeof(cl_mem), (void*)&bodies); - ciErrNum = clSetKernelArg(fpio.m_initializeGpuAabbsKernelFull, 4, sizeof(cl_mem), (void*)&fpio.m_dlocalShapeAABB); - ciErrNum = clSetKernelArg(fpio.m_initializeGpuAabbsKernelFull, 5, sizeof(cl_mem), (void*)&fpio.m_dAABB); - size_t workGroupSize = 64; - size_t numWorkItems = workGroupSize*((numObjects+ (workGroupSize)) / workGroupSize); - - ciErrNum = clEnqueueNDRangeKernel(fpio.m_cqCommandQue, fpio.m_initializeGpuAabbsKernelFull, 1, NULL, &numWorkItems, &workGroupSize,0 ,0 ,0); - oclCHECKERROR(ciErrNum, CL_SUCCESS); -} - -void setupGpuAabbsSimple(btFindPairsIO& fpio) -{ - - int ciErrNum = 0; - - int numObjects = fpio.m_numObjects; - int offset = fpio.m_positionOffset; - - ciErrNum = clSetKernelArg(fpio.m_initializeGpuAabbsKernelSimple, 0, sizeof(int), &offset); - ciErrNum = clSetKernelArg(fpio.m_initializeGpuAabbsKernelSimple, 1, sizeof(int), &numObjects); - ciErrNum = clSetKernelArg(fpio.m_initializeGpuAabbsKernelSimple, 2, sizeof(cl_mem), (void*)&fpio.m_clObjectsBuffer); - ciErrNum = clSetKernelArg(fpio.m_initializeGpuAabbsKernelSimple, 3, sizeof(cl_mem), (void*)&fpio.m_dAABB); - size_t workGroupSize = 64; - size_t numWorkItems = workGroupSize*((numObjects+ (workGroupSize)) / workGroupSize); - - ciErrNum = clEnqueueNDRangeKernel(fpio.m_cqCommandQue, fpio.m_initializeGpuAabbsKernelSimple, 1, NULL, &numWorkItems, &workGroupSize,0 ,0 ,0); - oclCHECKERROR(ciErrNum, CL_SUCCESS); -} - - -void setupBodies(btFindPairsIO& fpio, cl_mem linVelMem, cl_mem angVelMem, cl_mem bodies, cl_mem bodyInertias) -{ - int ciErrNum = 0; - - int numObjects = fpio.m_numObjects; - int offset = fpio.m_positionOffset; - - ciErrNum = clSetKernelArg(fpio.m_setupBodiesKernel, 0, sizeof(int), &offset); - ciErrNum = clSetKernelArg(fpio.m_setupBodiesKernel, 1, sizeof(int), &fpio.m_numObjects); - ciErrNum = clSetKernelArg(fpio.m_setupBodiesKernel, 2, sizeof(cl_mem), (void*)&fpio.m_clObjectsBuffer); - - ciErrNum = clSetKernelArg(fpio.m_setupBodiesKernel, 3, sizeof(cl_mem), (void*)&linVelMem); - ciErrNum = clSetKernelArg(fpio.m_setupBodiesKernel, 4, sizeof(cl_mem), (void*)&angVelMem); - ciErrNum = clSetKernelArg(fpio.m_setupBodiesKernel, 5, sizeof(cl_mem), (void*)&bodies); - ciErrNum = clSetKernelArg(fpio.m_setupBodiesKernel, 6, sizeof(cl_mem), (void*)&bodyInertias); - - if (numObjects) - { - size_t workGroupSize = 64; - size_t numWorkItems = workGroupSize*((numObjects+ (workGroupSize)) / workGroupSize); - - ciErrNum = clEnqueueNDRangeKernel(fpio.m_cqCommandQue, fpio.m_setupBodiesKernel, 1, NULL, &numWorkItems, &workGroupSize,0 ,0 ,0); - oclCHECKERROR(ciErrNum, CL_SUCCESS); - } - -} - - -void copyBodyVelocities(btFindPairsIO& fpio, cl_mem linVelMem, cl_mem angVelMem, cl_mem bodies, cl_mem bodyInertias) -{ - int ciErrNum = 0; - - int numObjects = fpio.m_numObjects; - int offset = fpio.m_positionOffset; - - ciErrNum = clSetKernelArg(fpio.m_copyVelocitiesKernel, 0, sizeof(int), &offset); - ciErrNum = clSetKernelArg(fpio.m_copyVelocitiesKernel, 1, sizeof(int), &fpio.m_numObjects); - ciErrNum = clSetKernelArg(fpio.m_copyVelocitiesKernel, 2, sizeof(cl_mem), (void*)&fpio.m_clObjectsBuffer); - - ciErrNum = clSetKernelArg(fpio.m_copyVelocitiesKernel, 3, sizeof(cl_mem), (void*)&linVelMem); - ciErrNum = clSetKernelArg(fpio.m_copyVelocitiesKernel, 4, sizeof(cl_mem), (void*)&angVelMem); - ciErrNum = clSetKernelArg(fpio.m_copyVelocitiesKernel, 5, sizeof(cl_mem), (void*)&bodies); - ciErrNum = clSetKernelArg(fpio.m_copyVelocitiesKernel, 6, sizeof(cl_mem), (void*)&bodyInertias); - - if (numObjects) - { - size_t workGroupSize = 64; - size_t numWorkItems = workGroupSize*((numObjects+ (workGroupSize)) / workGroupSize); - - ciErrNum = clEnqueueNDRangeKernel(fpio.m_cqCommandQue, fpio.m_copyVelocitiesKernel, 1, NULL, &numWorkItems, &workGroupSize,0 ,0 ,0); - oclCHECKERROR(ciErrNum, CL_SUCCESS); - } - -} - -void colorPairsOpenCL(btFindPairsIO& fpio) -{ - int ciErrNum = 0; - - int numObjects = fpio.m_numObjects; - int offset = fpio.m_positionOffset; - - ciErrNum = clSetKernelArg(fpio.m_broadphaseColorKernel, 0, sizeof(int), &offset); - ciErrNum = clSetKernelArg(fpio.m_broadphaseColorKernel, 1, sizeof(int), &fpio.m_numObjects); - ciErrNum = clSetKernelArg(fpio.m_broadphaseColorKernel, 2, sizeof(cl_mem), (void*)&fpio.m_clObjectsBuffer); - ciErrNum = clSetKernelArg(fpio.m_broadphaseColorKernel, 3, sizeof(cl_mem), (void*)&fpio.m_dAllOverlappingPairs); - ciErrNum = clSetKernelArg(fpio.m_broadphaseColorKernel, 4, sizeof(int), &fpio.m_numOverlap); - - - if (fpio.m_numOverlap) - { - size_t workGroupSize = 64; - size_t numWorkItems = workGroupSize*((fpio.m_numOverlap+ (workGroupSize)) / workGroupSize); - - ciErrNum = clEnqueueNDRangeKernel(fpio.m_cqCommandQue, fpio.m_broadphaseColorKernel, 1, NULL, &numWorkItems, &workGroupSize,0 ,0 ,0); - oclCHECKERROR(ciErrNum, CL_SUCCESS); - } -} - - - -void releaseFindPairs(btFindPairsIO& fpio) -{ - clReleaseKernel(fpio.m_initializeGpuAabbsKernelSimple); - clReleaseKernel(fpio.m_initializeGpuAabbsKernelFull); - clReleaseKernel(fpio.m_broadphaseColorKernel); - clReleaseKernel(fpio.m_broadphaseBruteForceKernel); - clReleaseKernel(fpio.m_setupBodiesKernel); - clReleaseKernel(fpio.m_copyVelocitiesKernel); - - -} - diff --git a/Extras/RigidBodyGpuPipeline/opencl/broadphase_benchmark/findPairsOpenCL.h b/Extras/RigidBodyGpuPipeline/opencl/broadphase_benchmark/findPairsOpenCL.h deleted file mode 100644 index 771543685..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/broadphase_benchmark/findPairsOpenCL.h +++ /dev/null @@ -1,90 +0,0 @@ - -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Roman Ponomarev, Erwin Coumans - -#ifndef FIND_PAIRS_H -#define FIND_PAIRS_H - -#include "../basic_initialize/btOpenCLInclude.h" - -struct btKernelInfo -{ - int m_Id; - cl_kernel m_kernel; - char* m_name; - int m_workgroupSize; -}; - - - -struct btFindPairsIO -{ - int m_numObjects; - - cl_mem m_clObjectsBuffer; //for memory layout details see main.cpp (todo, make it flexible) - int m_positionOffset;//offset in m_clObjectsBuffer where position array starts - - cl_command_queue m_cqCommandQue; - cl_kernel m_initializeGpuAabbsKernelSimple; - cl_kernel m_initializeGpuAabbsKernelFull; - cl_kernel m_broadphaseColorKernel; - cl_kernel m_broadphaseBruteForceKernel; - - cl_kernel m_setupBodiesKernel; - cl_kernel m_copyVelocitiesKernel; - - cl_context m_mainContext; - cl_device_id m_device; - - cl_kernel m_calcHashAabbKernel; - cl_kernel m_clearCellStartKernel; - cl_kernel m_findCellStartKernel; - cl_kernel m_findOverlappingPairsKernel; - cl_kernel m_computePairChangeKernel; - cl_kernel m_squeezePairBuffKernel; - - - cl_mem m_dAllOverlappingPairs; - int m_numOverlap; - - cl_mem m_dBpParams; - cl_mem m_dBodiesHash; - cl_mem m_dCellStart; - cl_mem m_dPairBuff; - cl_mem m_dPairBuffStartCurr; - cl_mem m_dlocalShapeAABB; - cl_mem m_dAABB; - cl_mem m_dPairScan; - cl_mem m_dPairOut; -}; - - -void initFindPairs(btFindPairsIO& fpio,cl_context cxMainContext, cl_device_id device, cl_command_queue commandQueue, int maxHandles,int maxPairsPerBody = 16); - -void findPairsOpenCLBruteForce(btFindPairsIO& fpio); - -void setupGpuAabbsSimple(btFindPairsIO& fpio); - -void setupGpuAabbsFull(btFindPairsIO& fpio, cl_mem bodies); - - -void colorPairsOpenCL(btFindPairsIO& fpio); - -void setupBodies(btFindPairsIO& fpio, cl_mem linVelMem, cl_mem angVelMem, cl_mem bodies, cl_mem bodyInertias); -void copyBodyVelocities(btFindPairsIO& fpio, cl_mem linVelMem, cl_mem angVelMem, cl_mem bodies, cl_mem bodyInertias); - -void releaseFindPairs(btFindPairsIO& fpio); - -#endif //FIND_PAIRS_H diff --git a/Extras/RigidBodyGpuPipeline/opencl/broadphase_benchmark/integrateKernel.cl b/Extras/RigidBodyGpuPipeline/opencl/broadphase_benchmark/integrateKernel.cl deleted file mode 100644 index 87d2b2569..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/broadphase_benchmark/integrateKernel.cl +++ /dev/null @@ -1,116 +0,0 @@ -MSTRINGIFY( - -float4 quatMult(float4 q1, float4 q2) -{ - float4 q; - q.x = q1.w * q2.x + q1.x * q2.w + q1.y * q2.z - q1.z * q2.y; - q.y = q1.w * q2.y + q1.y * q2.w + q1.z * q2.x - q1.x * q2.z; - q.z = q1.w * q2.z + q1.z * q2.w + q1.x * q2.y - q1.y * q2.x; - q.w = q1.w * q2.w - q1.x * q2.x - q1.y * q2.y - q1.z * q2.z; - return q; -} - -float4 quatNorm(float4 q) -{ - float len = native_sqrt(dot(q, q)); - if(len > 0.f) - { - q *= 1.f / len; - } - else - { - q.x = q.y = q.z = 0.f; - q.w = 1.f; - } - return q; -} - - - - - -__kernel void - integrateTransformsKernel( const int startOffset, const int numNodes, __global float4 *g_vertexBuffer, - __global float4 *linVel, - __global float4 *pAngVel, - __global float* pBodyTimes) -{ - int nodeID = get_global_id(0); - - - - float BT_GPU_ANGULAR_MOTION_THRESHOLD = (0.25f * 3.14159254f); - float mAmplitude = 66.f; - float timeStep = 0.0166666f; - - if( nodeID < numNodes ) - { - - //g_vertexBuffer[nodeID + startOffset/4+numNodes] += pAngVel[nodeID]; - if (1) - { - float4 axis; - //add some hardcoded angular damping - pAngVel[nodeID].x *= 0.99f; - pAngVel[nodeID].y *= 0.99f; - pAngVel[nodeID].z *= 0.99f; - - float4 angvel = pAngVel[nodeID]; - float fAngle = native_sqrt(dot(angvel, angvel)); - //limit the angular motion - if(fAngle*timeStep > BT_GPU_ANGULAR_MOTION_THRESHOLD) - { - fAngle = BT_GPU_ANGULAR_MOTION_THRESHOLD / timeStep; - } - if(fAngle < 0.001f) - { - // use Taylor's expansions of sync function - axis = angvel * (0.5f*timeStep-(timeStep*timeStep*timeStep)*0.020833333333f * fAngle * fAngle); - } - else - { - // sync(fAngle) = sin(c*fAngle)/t - axis = angvel * ( native_sin(0.5f * fAngle * timeStep) / fAngle); - } - float4 dorn = axis; - dorn.w = native_cos(fAngle * timeStep * 0.5f); - float4 orn0 = g_vertexBuffer[nodeID + startOffset/4+numNodes]; - float4 predictedOrn = quatMult(dorn, orn0); - predictedOrn = quatNorm(predictedOrn); - g_vertexBuffer[nodeID + startOffset/4+numNodes]=predictedOrn; - } - - //linear velocity - g_vertexBuffer[nodeID + startOffset/4] += linVel[nodeID] * timeStep; - - } -} - - -__kernel void - sineWaveKernel( const int startOffset, const int numNodes, __global float4 *g_vertexBuffer, - __global float4 *linVel, - __global float4 *pAngVel, - __global float* pBodyTimes) -{ - int nodeID = get_global_id(0); - float timeStepPos = 0.000166666; - - float BT_GPU_ANGULAR_MOTION_THRESHOLD = (0.25f * 3.14159254f); - float mAmplitude = 166.f; - - - if( nodeID < numNodes ) - { - pBodyTimes[nodeID] += timeStepPos; - float4 position = g_vertexBuffer[nodeID + startOffset/4]; - position.x = native_cos(pBodyTimes[nodeID]*2.17f)*mAmplitude + native_sin(pBodyTimes[nodeID])*mAmplitude*0.5f; - position.y = native_cos(pBodyTimes[nodeID]*1.38f)*mAmplitude + native_sin(pBodyTimes[nodeID]*mAmplitude); - position.z = native_cos(pBodyTimes[nodeID]*2.17f)*mAmplitude + native_sin(pBodyTimes[nodeID]*0.777f)*mAmplitude; - g_vertexBuffer[nodeID + startOffset/4] = position; - } -} - - - -); \ No newline at end of file diff --git a/Extras/RigidBodyGpuPipeline/opencl/broadphase_benchmark/main.cpp b/Extras/RigidBodyGpuPipeline/opencl/broadphase_benchmark/main.cpp deleted file mode 100644 index 3e52c1976..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/broadphase_benchmark/main.cpp +++ /dev/null @@ -1,1565 +0,0 @@ - -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Erwin Coumans - -//starts crashing when more than 32700 objects on my Geforce 260, unless _USE_SUB_DATA is defined (still unstable though) -//runs fine with fewer objects - -#define NUM_OBJECTS_X 42 -//327 -#define NUM_OBJECTS_Y 42 -#define NUM_OBJECTS_Z 42 -//#define NUM_OBJECTS_Z 20 - -//#define _USE_SUB_DATA - -//#define NUM_OBJECTS_X 100 -//#define NUM_OBJECTS_Y 100 -//#define NUM_OBJECTS_Z 100 - -///RECREATE_CL_AND_SHADERS_ON_RESIZE will delete and re-create OpenCL and GLSL shaders/buffers at each resize -//#define RECREATE_CL_AND_SHADERS_ON_RESIZE - -/// -/// OpenCL - OpenGL interop example. Updating transforms of many cubes on GPU, without going through main memory/using the PCIe bus -/// Create all OpenGL resources AFTER create OpenCL context! -/// - - -#include -#include - -#include "btGlutInclude.h" -#include "../opengl_interop/btStopwatch.h" - - -#include "LinearMath/btVector3.h" -#include "LinearMath/btQuaternion.h" -#include "LinearMath/btMatrix3x3.h" -static float sAngle(0); - -#include - -#ifdef _WIN32 -#include -#endif - -#include -#include -#include "../3dGridBroadphase/Shared/btGpu3DGridBroadphase.h" -#include "../3dGridBroadphase/Shared/bt3dGridBroadphaseOCL.h" -#include "btGridBroadphaseCl.h" - -#define USE_NEW -#ifdef USE_NEW -btGridBroadphaseCl* sBroadphase=0; -#else -btGpu3DGridBroadphase* sBroadphase=0; -#endif - -btAlignedObjectArray proxyArray; - - -#define RS_SCALE (1.0 / (1.0 + RAND_MAX)) - - -int randbiased (double x) { - for (;;) { - double p = rand () * RS_SCALE; - if (p >= x) return 0; - if (p+RS_SCALE <= x) return 1; - /* p < x < p+RS_SCALE */ - x = (x - p) * (1.0 + RAND_MAX); - } -} - -size_t randrange (size_t n) -{ - double xhi; - double resolution = n * RS_SCALE; - double x = resolution * rand (); /* x in [0,n) */ - size_t lo = (size_t) floor (x); - - xhi = x + resolution; - - for (;;) { - lo++; - if (lo >= xhi || randbiased ((lo - x) / (xhi - x))) return lo-1; - x = lo; - } -} - -//OpenCL stuff -#include "../basic_initialize/btOpenCLUtils.h" -#include "../opengl_interop/btOpenCLGLInteropBuffer.h" -#include "findPairsOpenCL.h" - -btFindPairsIO gFpIO; - -cl_context g_cxMainContext; -cl_command_queue g_cqCommandQue; -cl_device_id g_device; -static const size_t workGroupSize = 64; -cl_mem gLinVelMem; -cl_mem gAngVelMem; -cl_mem gBodyTimes; - -btVector3 m_cameraPosition(142,220,142); -btVector3 m_cameraTargetPosition(0,-30,0); -btScalar m_cameraDistance = 200; -btVector3 m_cameraUp(0,1,0); -float m_azi=-50.f; -float m_ele=0.f; - - - - -btOpenCLGLInteropBuffer* g_interopBuffer = 0; -cl_kernel g_sineWaveKernel; - - - -////for Adl -#include - -adl::DeviceCL* g_deviceCL=0; - - - -bool useCPU = false; -bool printStats = false; -bool runOpenCLKernels = true; - -#define MSTRINGIFY(A) #A -static char* interopKernelString = -#include "integrateKernel.cl" - - -btStopwatch gStopwatch; -int m_glutScreenWidth = 640; -int m_glutScreenHeight= 480; - -bool m_ortho = false; - -static GLuint instancingShader; // The instancing renderer -static GLuint cube_vao; -static GLuint cube_vbo; -static GLuint index_vbo; -static GLuint m_texturehandle; - -static bool done = false; -static GLint angle_loc = 0; -static GLint ModelViewMatrix; -static GLint ProjectionMatrix; - -void writeTransforms(); - -static GLint uniform_texture_diffuse = 0; - -//used for dynamic loading from disk (default switched off) -#define MAX_SHADER_LENGTH 8192 -static GLubyte shaderText[MAX_SHADER_LENGTH]; - -static const char* vertexShader= \ -"#version 330\n" -"precision highp float;\n" -"\n" -"\n" -"\n" -"layout (location = 0) in vec4 position;\n" -"layout (location = 1) in vec4 instance_position;\n" -"layout (location = 2) in vec4 instance_quaternion;\n" -"layout (location = 3) in vec2 uvcoords;\n" -"layout (location = 4) in vec3 vertexnormal;\n" -"layout (location = 5) in vec4 instance_color;\n" -"layout (location = 6) in vec3 instance_scale;\n" -"\n" -"\n" -"uniform float angle = 0.0;\n" -"uniform mat4 ModelViewMatrix;\n" -"uniform mat4 ProjectionMatrix;\n" -"\n" -"out Fragment\n" -"{\n" -" vec4 color;\n" -"} fragment;\n" -"\n" -"out Vert\n" -"{\n" -" vec2 texcoord;\n" -"} vert;\n" -"\n" -"\n" -"vec4 quatMul ( in vec4 q1, in vec4 q2 )\n" -"{\n" -" vec3 im = q1.w * q2.xyz + q1.xyz * q2.w + cross ( q1.xyz, q2.xyz );\n" -" vec4 dt = q1 * q2;\n" -" float re = dot ( dt, vec4 ( -1.0, -1.0, -1.0, 1.0 ) );\n" -" return vec4 ( im, re );\n" -"}\n" -"\n" -"vec4 quatFromAxisAngle(vec4 axis, in float angle)\n" -"{\n" -" float cah = cos(angle*0.5);\n" -" float sah = sin(angle*0.5);\n" -" float d = inversesqrt(dot(axis,axis));\n" -" vec4 q = vec4(axis.x*sah*d,axis.y*sah*d,axis.z*sah*d,cah);\n" -" return q;\n" -"}\n" -"//\n" -"// vector rotation via quaternion\n" -"//\n" -"vec4 quatRotate3 ( in vec3 p, in vec4 q )\n" -"{\n" -" vec4 temp = quatMul ( q, vec4 ( p, 0.0 ) );\n" -" return quatMul ( temp, vec4 ( -q.x, -q.y, -q.z, q.w ) );\n" -"}\n" -"vec4 quatRotate ( in vec4 p, in vec4 q )\n" -"{\n" -" vec4 temp = quatMul ( q, p );\n" -" return quatMul ( temp, vec4 ( -q.x, -q.y, -q.z, q.w ) );\n" -"}\n" -"\n" -"out vec3 lightDir,normal,ambient;\n" -"\n" -"void main(void)\n" -"{\n" -" vec4 q = instance_quaternion;\n" -" ambient = vec3(0.2,0.2,0.2);\n" -" \n" -" \n" -" vec4 local_normal = (quatRotate3( vertexnormal,q));\n" -" vec3 light_pos = vec3(10000,10000,10000);\n" -" normal = normalize(ModelViewMatrix * local_normal).xyz;\n" -"\n" -" lightDir = normalize(light_pos);//gl_LightSource[0].position.xyz));\n" -"// lightDir = normalize(vec3(gl_LightSource[0].position));\n" -" \n" -" vec4 axis = vec4(1,1,1,0);\n" -" vec4 localcoord = quatRotate3( position.xyz*instance_scale,q);\n" -" vec4 vertexPos = ProjectionMatrix * ModelViewMatrix *(instance_position+localcoord);\n" -"\n" -" gl_Position = vertexPos;\n" -" \n" -" fragment.color = instance_color;\n" -" vert.texcoord = uvcoords;\n" -"}\n" -; - - -static const char* fragmentShader= \ -"#version 330\n" -"precision highp float;\n" -"\n" -"in Fragment\n" -"{\n" -" vec4 color;\n" -"} fragment;\n" -"\n" -"in Vert\n" -"{\n" -" vec2 texcoord;\n" -"} vert;\n" -"\n" -"uniform sampler2D Diffuse;\n" -"\n" -"in vec3 lightDir,normal,ambient;\n" -"\n" -"out vec4 color;\n" -"\n" -"void main_textured(void)\n" -"{\n" -" color = texture2D(Diffuse,vert.texcoord);//fragment.color;\n" -"}\n" -"\n" -"void main(void)\n" -"{\n" -" vec4 texel = fragment.color*texture2D(Diffuse,vert.texcoord);//fragment.color;\n" -" vec3 ct,cf;\n" -" float intensity,at,af;\n" -" intensity = max(dot(lightDir,normalize(normal)),0.5);\n" -" cf = intensity*vec3(1.0,1.0,1.0);//intensity * (gl_FrontMaterial.diffuse).rgb+ambient;//gl_FrontMaterial.ambient.rgb;\n" -" af = 1.0;\n" -" \n" -" ct = texel.rgb;\n" -" at = texel.a;\n" -" \n" -" color = vec4(ct * cf, at * af); \n" -"}\n" -; - - -// Load the shader from the source text -void gltLoadShaderSrc(const char *szShaderSrc, GLuint shader) -{ - GLchar *fsStringPtr[1]; - - fsStringPtr[0] = (GLchar *)szShaderSrc; - glShaderSource(shader, 1, (const GLchar **)fsStringPtr, NULL); -} - - -//////////////////////////////////////////////////////////////// -// Load the shader from the specified file. Returns false if the -// shader could not be loaded -bool gltLoadShaderFile(const char *szFile, GLuint shader) -{ - GLint shaderLength = 0; - FILE *fp; - - // Open the shader file - fp = fopen(szFile, "r"); - if(fp != NULL) - { - // See how long the file is - while (fgetc(fp) != EOF) - shaderLength++; - - // Allocate a block of memory to send in the shader - assert(shaderLength < MAX_SHADER_LENGTH); // make me bigger! - if(shaderLength > MAX_SHADER_LENGTH) - { - fclose(fp); - return false; - } - - // Go back to beginning of file - rewind(fp); - - // Read the whole file in - if (shaderText != NULL) - fread(shaderText, 1, shaderLength, fp); - - // Make sure it is null terminated and close the file - shaderText[shaderLength] = '\0'; - fclose(fp); - } - else - return false; - - // printf(shaderText); - // Load the string - gltLoadShaderSrc((const char *)shaderText, shader); - - return true; -} - - -///////////////////////////////////////////////////////////////// -// Load a pair of shaders, compile, and link together. Specify the complete -// file path for each shader. Note, there is no support for -// just loading say a vertex program... you have to do both. -GLuint gltLoadShaderPair(const char *szVertexProg, const char *szFragmentProg, bool loadFromFile) -{ - // Temporary Shader objects - GLuint hVertexShader; - GLuint hFragmentShader; - GLuint hReturn = 0; - GLint testVal; - - // Create shader objects - hVertexShader = glCreateShader(GL_VERTEX_SHADER); - hFragmentShader = glCreateShader(GL_FRAGMENT_SHADER); - - if (loadFromFile) - { - - if(gltLoadShaderFile(szVertexProg, hVertexShader) == false) - { - glDeleteShader(hVertexShader); - glDeleteShader(hFragmentShader); - return (GLuint)NULL; - } - - if(gltLoadShaderFile(szFragmentProg, hFragmentShader) == false) - { - glDeleteShader(hVertexShader); - glDeleteShader(hFragmentShader); - return (GLuint)NULL; - } - } else - { - gltLoadShaderSrc(vertexShader, hVertexShader); - gltLoadShaderSrc(fragmentShader, hFragmentShader); - } - // Compile them - glCompileShader(hVertexShader); - glCompileShader(hFragmentShader); - - // Check for errors - glGetShaderiv(hVertexShader, GL_COMPILE_STATUS, &testVal); - if(testVal == GL_FALSE) - { - char temp[256] = ""; - glGetShaderInfoLog( hVertexShader, 256, NULL, temp); - fprintf( stderr, "Compile failed:\n%s\n", temp); - assert(0); - exit(0); - glDeleteShader(hVertexShader); - glDeleteShader(hFragmentShader); - return (GLuint)NULL; - } - - glGetShaderiv(hFragmentShader, GL_COMPILE_STATUS, &testVal); - if(testVal == GL_FALSE) - { - char temp[256] = ""; - glGetShaderInfoLog( hFragmentShader, 256, NULL, temp); - fprintf( stderr, "Compile failed:\n%s\n", temp); - assert(0); - exit(0); - glDeleteShader(hVertexShader); - glDeleteShader(hFragmentShader); - return (GLuint)NULL; - } - - // Link them - assuming it works... - hReturn = glCreateProgram(); - glAttachShader(hReturn, hVertexShader); - glAttachShader(hReturn, hFragmentShader); - - glLinkProgram(hReturn); - - // These are no longer needed - glDeleteShader(hVertexShader); - glDeleteShader(hFragmentShader); - - // Make sure link worked too - glGetProgramiv(hReturn, GL_LINK_STATUS, &testVal); - if(testVal == GL_FALSE) - { - glDeleteProgram(hReturn); - return (GLuint)NULL; - } - - return hReturn; -} - -///position xyz, unused w, normal, uv -static const GLfloat cube_vertices[] = -{ - -1.0f, -1.0f, 1.0f, 0.0f, 0,0,1, 0,0,//0 - 1.0f, -1.0f, 1.0f, 0.0f, 0,0,1, 1,0,//1 - 1.0f, 1.0f, 1.0f, 0.0f, 0,0,1, 1,1,//2 - -1.0f, 1.0f, 1.0f, 0.0f, 0,0,1, 0,1 ,//3 - - -1.0f, -1.0f, -1.0f, 1.0f, 0,0,-1, 0,0,//4 - 1.0f, -1.0f, -1.0f, 1.0f, 0,0,-1, 1,0,//5 - 1.0f, 1.0f, -1.0f, 1.0f, 0,0,-1, 1,1,//6 - -1.0f, 1.0f, -1.0f, 1.0f, 0,0,-1, 0,1,//7 - - -1.0f, -1.0f, -1.0f, 1.0f, -1,0,0, 0,0, - -1.0f, 1.0f, -1.0f, 1.0f, -1,0,0, 1,0, - -1.0f, 1.0f, 1.0f, 1.0f, -1,0,0, 1,1, - -1.0f, -1.0f, 1.0f, 1.0f, -1,0,0, 0,1, - - 1.0f, -1.0f, -1.0f, 1.0f, 1,0,0, 0,0, - 1.0f, 1.0f, -1.0f, 1.0f, 1,0,0, 1,0, - 1.0f, 1.0f, 1.0f, 1.0f, 1,0,0, 1,1, - 1.0f, -1.0f, 1.0f, 1.0f, 1,0,0, 0,1, - - -1.0f, -1.0f, -1.0f, 1.0f, 0,-1,0, 0,0, - -1.0f, -1.0f, 1.0f, 1.0f, 0,-1,0, 1,0, - 1.0f, -1.0f, 1.0f, 1.0f, 0,-1,0, 1,1, - 1.0f,-1.0f, -1.0f, 1.0f, 0,-1,0, 0,1, - - -1.0f, 1.0f, -1.0f, 1.0f, 0,1,0, 0,0, - -1.0f, 1.0f, 1.0f, 1.0f, 0,1,0, 1,0, - 1.0f, 1.0f, 1.0f, 1.0f, 0,1,0, 1,1, - 1.0f,1.0f, -1.0f, 1.0f, 0,1,0, 0,1, -}; - -static const int cube_indices[]= -{ - 0,1,2,0,2,3,//ground face - 4,5,6,4,6,7,//top face - 8,9,10,8,10,11, - 12,13,14,12,14,15, - 16,17,18,16,18,19, - 20,21,22,20,22,23 -}; - -int m_mouseOldX = -1; -int m_mouseOldY = -1; -int m_mouseButtons = 0; - - -void mouseFunc(int button, int state, int x, int y) -{ - if (state == 0) - { - m_mouseButtons |= 1<0) - { - g_device= btOpenCLUtils::getDevice(g_cxMainContext,0); - btOpenCLDeviceInfo clInfo; - btOpenCLUtils::getDeviceInfo(g_device,clInfo); - btOpenCLUtils::printDeviceInfo(g_device); - // create a command-queue - g_cqCommandQue = clCreateCommandQueue(g_cxMainContext, g_device, 0, &ciErrNum); - oclCHECKERROR(ciErrNum, CL_SUCCESS); - //normally you would create and execute kernels using this command queue - - } - - -} - -#define NUM_OBJECTS (NUM_OBJECTS_X*NUM_OBJECTS_Y*NUM_OBJECTS_Z) -#define POSITION_BUFFER_SIZE (NUM_OBJECTS*sizeof(float)*4) -#define ORIENTATION_BUFFER_SIZE (NUM_OBJECTS*sizeof(float)*4) -#define COLOR_BUFFER_SIZE (NUM_OBJECTS*sizeof(float)*4) -#define SCALE_BUFFER_SIZE (NUM_OBJECTS*sizeof(float)*3) - - -GLfloat* instance_positions_ptr = 0; -GLfloat* instance_quaternion_ptr = 0; -GLfloat* instance_colors_ptr = 0; -GLfloat* instance_scale_ptr= 0; - - -void DeleteShaders() -{ - glDeleteVertexArrays(1, &cube_vao); - glDeleteBuffers(1,&index_vbo); - glDeleteBuffers(1,&cube_vbo); - glDeleteProgram(instancingShader); -} - - -void InitShaders() -{ - - btOverlappingPairCache* overlappingPairCache=0; -#ifdef USE_NEW - sBroadphase = new btGridBroadphaseCl(overlappingPairCache,btVector3(3.f, 3.f, 3.f), 32, 32, 32,NUM_OBJECTS, NUM_OBJECTS, 64, 100.f, 16, - g_cxMainContext ,g_device,g_cqCommandQue); -#else - sBroadphase = new btGpu3DGridBroadphase(btVector3(10.f, 10.f, 10.f), 32, 32, 32,NUM_OBJECTS, NUM_OBJECTS, 64, 100.f, 16); -#endif - - - -// sBroadphase = new bt3dGridBroadphaseOCL(overlappingPairCache,btVector3(10.f, 10.f, 10.f), 32, 32, 32,NUM_OBJECTS, NUM_OBJECTS, 64, 100.f, 16, -// g_cxMainContext ,g_device,g_cqCommandQue); - - - - bool loadFromFile = false; - instancingShader = gltLoadShaderPair("instancing.vs","instancing.fs", loadFromFile); - - glLinkProgram(instancingShader); - glUseProgram(instancingShader); - angle_loc = glGetUniformLocation(instancingShader, "angle"); - ModelViewMatrix = glGetUniformLocation(instancingShader, "ModelViewMatrix"); - ProjectionMatrix = glGetUniformLocation(instancingShader, "ProjectionMatrix"); - uniform_texture_diffuse = glGetUniformLocation(instancingShader, "Diffuse"); - - GLuint offset = 0; - - - glGenBuffers(1, &cube_vbo); - glBindBuffer(GL_ARRAY_BUFFER, cube_vbo); - - instance_positions_ptr = (GLfloat*)new float[NUM_OBJECTS*4]; - instance_quaternion_ptr = (GLfloat*)new float[NUM_OBJECTS*4]; - instance_colors_ptr = (GLfloat*)new float[NUM_OBJECTS*4]; - instance_scale_ptr = (GLfloat*)new float[NUM_OBJECTS*3]; - - int index=0; - for (int i=0;icreateProxy(aabbMin,aabbMax,shapeType,myptr,1,1,0,0);//m_dispatcher); - proxyArray.push_back(proxy); - - instance_quaternion_ptr[index*4]=0; - instance_quaternion_ptr[index*4+1]=0; - instance_quaternion_ptr[index*4+2]=0; - instance_quaternion_ptr[index*4+3]=1; - - instance_colors_ptr[index*4]=j m_glutScreenHeight) - { - aspect = m_glutScreenWidth / (float)m_glutScreenHeight; - extents.setValue(aspect * 1.0f, 1.0f,0); - } else - { - aspect = m_glutScreenHeight / (float)m_glutScreenWidth; - extents.setValue(1.0f, aspect*1.f,0); - } - - - if (m_ortho) - { - // reset matrix - glLoadIdentity(); - extents *= m_cameraDistance; - btVector3 lower = m_cameraTargetPosition - extents; - btVector3 upper = m_cameraTargetPosition + extents; - glOrtho(lower.getX(), upper.getX(), lower.getY(), upper.getY(),-1000,1000); - - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - } else - { - if (m_glutScreenWidth > m_glutScreenHeight) - { - glFrustum (-aspect * m_frustumZNear, aspect * m_frustumZNear, -m_frustumZNear, m_frustumZNear, m_frustumZNear, m_frustumZFar); - } else - { - glFrustum (-aspect * m_frustumZNear, aspect * m_frustumZNear, -m_frustumZNear, m_frustumZNear, m_frustumZNear, m_frustumZFar); - } - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - gluLookAt(m_cameraPosition[0], m_cameraPosition[1], m_cameraPosition[2], - m_cameraTargetPosition[0], m_cameraTargetPosition[1], m_cameraTargetPosition[2], - m_cameraUp.getX(),m_cameraUp.getY(),m_cameraUp.getZ()); - } - -} - - - -void myinit() -{ - - - - // GLfloat light_ambient[] = { btScalar(0.2), btScalar(0.2), btScalar(0.2), btScalar(1.0) }; - GLfloat light_ambient[] = { btScalar(1.0), btScalar(1.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 )}; - /* light_position is NOT default value */ - GLfloat light_position0[] = { btScalar(10000.0), btScalar(10000.0), btScalar(10000.0), btScalar(0.0 )}; - GLfloat light_position1[] = { btScalar(-1.0), btScalar(-10.0), btScalar(-1.0), btScalar(0.0) }; - - glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient); - glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse); - glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular); - glLightfv(GL_LIGHT0, GL_POSITION, light_position0); - - glLightfv(GL_LIGHT1, GL_AMBIENT, light_ambient); - glLightfv(GL_LIGHT1, GL_DIFFUSE, light_diffuse); - glLightfv(GL_LIGHT1, GL_SPECULAR, light_specular); - glLightfv(GL_LIGHT1, GL_POSITION, light_position1); - - glEnable(GL_LIGHTING); - glEnable(GL_LIGHT0); - glEnable(GL_LIGHT1); - - - // glShadeModel(GL_FLAT);//GL_SMOOTH); - glShadeModel(GL_SMOOTH); - - glEnable(GL_DEPTH_TEST); - glDepthFunc(GL_LESS); - - glClearColor(float(0.7),float(0.7),float(0.7),float(0)); - glEnable(GL_LIGHTING); - glEnable(GL_LIGHT0); - - - static bool m_textureenabled = true; - static bool m_textureinitialized = false; - - - if(m_textureenabled) - { - if(!m_textureinitialized) - { - glActiveTexture(GL_TEXTURE0); - - GLubyte* image=new GLubyte[256*256*3]; - for(int y=0;y<256;++y) - { - const int t=y>>5; - GLubyte* pi=image+y*256*3; - for(int x=0;x<256;++x) - { - const int s=x>>5; - const GLubyte b=180; - GLubyte c=b+((s+t&1)&1)*(255-b); - pi[0]=c; - pi[1]=c; - pi[2]=c; - pi+=3; - } - } - - glGenTextures(1,(GLuint*)&m_texturehandle); - glBindTexture(GL_TEXTURE_2D,m_texturehandle); - glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE); - glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR); - glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR_MIPMAP_LINEAR); - glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT); - glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT); - gluBuild2DMipmaps(GL_TEXTURE_2D,3,256,256,GL_RGB,GL_UNSIGNED_BYTE,image); - delete[] image; - m_textureinitialized=true; - } - // glMatrixMode(GL_TEXTURE); - // glLoadIdentity(); - // glMatrixMode(GL_MODELVIEW); - - glEnable(GL_TEXTURE_2D); - glBindTexture(GL_TEXTURE_2D,m_texturehandle); - - } else - { - glDisable(GL_TEXTURE_2D); - } - - glEnable(GL_COLOR_MATERIAL); - - - // glEnable(GL_CULL_FACE); - // glCullFace(GL_BACK); -} - -//#pragma optimize( "g", off ) - - - -void writeTransforms() -{ - - - glFlush(); - char* bla = (char*)glMapBuffer( GL_ARRAY_BUFFER,GL_READ_WRITE);//GL_WRITE_ONLY - - float* positions = (float*)(bla+sizeof(cube_vertices)); - float* orientations = (float*)(bla+sizeof(cube_vertices) + POSITION_BUFFER_SIZE); - float* colors= (float*)(bla+sizeof(cube_vertices) + POSITION_BUFFER_SIZE+ORIENTATION_BUFFER_SIZE); - float* scaling= (float*)(bla+sizeof(cube_vertices) + POSITION_BUFFER_SIZE+ORIENTATION_BUFFER_SIZE+COLOR_BUFFER_SIZE); - - // positions[0]+=0.001f; - - static int offset=0; - //offset++; - - static btVector3 axis(1,0,0); - sAngle += 0.01f; - int index=0; - btQuaternion orn(axis,sAngle); - for (int i=0;igetCLBUffer(); - cl_int ciErrNum = CL_SUCCESS; - ciErrNum = clEnqueueAcquireGLObjects(g_cqCommandQue, 1, &clBuffer, 0, 0, NULL); - oclCHECKERROR(ciErrNum, CL_SUCCESS); - if (runOpenCLKernels) - { - int numObjects = NUM_OBJECTS; - int offset = (sizeof(cube_vertices) )/4; - - ciErrNum = clSetKernelArg(g_sineWaveKernel, 0, sizeof(int), &offset); - ciErrNum = clSetKernelArg(g_sineWaveKernel, 1, sizeof(int), &numObjects); - ciErrNum = clSetKernelArg(g_sineWaveKernel, 2, sizeof(cl_mem), (void*)&clBuffer ); - - ciErrNum = clSetKernelArg(g_sineWaveKernel, 3, sizeof(cl_mem), (void*)&gLinVelMem); - ciErrNum = clSetKernelArg(g_sineWaveKernel, 4, sizeof(cl_mem), (void*)&gAngVelMem); - ciErrNum = clSetKernelArg(g_sineWaveKernel, 5, sizeof(cl_mem), (void*)&gBodyTimes); - - - - - - size_t numWorkItems = workGroupSize*((NUM_OBJECTS + (workGroupSize)) / workGroupSize); - ciErrNum = clEnqueueNDRangeKernel(g_cqCommandQue, g_sineWaveKernel, 1, NULL, &numWorkItems, &workGroupSize,0 ,0 ,0); - oclCHECKERROR(ciErrNum, CL_SUCCESS); - } - - ciErrNum = clEnqueueReleaseGLObjects(g_cqCommandQue, 1, &clBuffer, 0, 0, 0); - oclCHECKERROR(ciErrNum, CL_SUCCESS); - clFinish(g_cqCommandQue); - - } - -} - - -void cpuBroadphase() -{ - glFlush(); - char* bla = (char*)glMapBuffer( GL_ARRAY_BUFFER,GL_READ_WRITE);//GL_WRITE_ONLY - - float* positions = (float*)(bla+sizeof(cube_vertices)); - float* orientations = (float*)(bla+sizeof(cube_vertices) + POSITION_BUFFER_SIZE); - float* colors= (float*)(bla+sizeof(cube_vertices) + POSITION_BUFFER_SIZE+ORIENTATION_BUFFER_SIZE); - float* scaling= (float*)(bla+sizeof(cube_vertices) + POSITION_BUFFER_SIZE+ORIENTATION_BUFFER_SIZE+COLOR_BUFFER_SIZE); - - int index=0; - - for (int i=0;isetAabb(proxyArray[index],aabbMin,aabbMax,0); - - index++; - } - } - } - -#ifdef USE_NEW - - -#else - sBroadphase->calculateOverlappingPairs(0); - int overlap = sBroadphase->getOverlappingPairCache()->getNumOverlappingPairs(); - for (int i=0;igetOverlappingPairCache()->getOverlappingPairArray()[i]; - int indexA = (int)pair.m_pProxy0->m_clientObject; - int indexB = (int)pair.m_pProxy1->m_clientObject; - colors[indexA*4] = 1.f; - colors[indexA*4+1] = 0.f; - colors[indexA*4+2] = 0.f; - colors[indexA*4+3] = 1.f; - - colors[indexB*4] = 1.f; - colors[indexB*4+1] = 0.f; - colors[indexB*4+2] = 0.f; - colors[indexB*4+3] = 1.f; - } -#endif - - //now color the overlap - - - - glUnmapBuffer( GL_ARRAY_BUFFER); - //if this glFinish is removed, the animation is not always working/blocks - //@todo: figure out why - glFlush(); -} - -void broadphase() -{ - if (useCPU) - { - cpuBroadphase(); - - } - else - { - - glFinish(); - - cl_mem clBuffer = g_interopBuffer->getCLBUffer(); - cl_int ciErrNum = CL_SUCCESS; - ciErrNum = clEnqueueAcquireGLObjects(g_cqCommandQue, 1, &clBuffer, 0, 0, NULL); - oclCHECKERROR(ciErrNum, CL_SUCCESS); - if (runOpenCLKernels) - { - - gFpIO.m_numObjects = NUM_OBJECTS; - gFpIO.m_positionOffset = (sizeof(cube_vertices) )/4; - gFpIO.m_clObjectsBuffer = clBuffer; - gFpIO.m_dAABB = sBroadphase->m_dAABB; - setupGpuAabbsSimple(gFpIO); - - sBroadphase->calculateOverlappingPairs(0, NUM_OBJECTS); - - - gFpIO.m_dAllOverlappingPairs = sBroadphase->m_dAllOverlappingPairs; - gFpIO.m_numOverlap = sBroadphase->m_numPrefixSum; - - colorPairsOpenCL(gFpIO); - - } - - ciErrNum = clEnqueueReleaseGLObjects(g_cqCommandQue, 1, &clBuffer, 0, 0, 0); - oclCHECKERROR(ciErrNum, CL_SUCCESS); - clFinish(g_cqCommandQue); - - - - } -} - - -//#pragma optimize( "g", on ) - -void RenderScene(void) -{ - -#if 0 - float modelview[20]={0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9}; - // get the current modelview matrix - glGetFloatv(GL_MODELVIEW_MATRIX , modelview); - float projection[20]={0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9}; - glGetFloatv(GL_PROJECTION_MATRIX, projection); -#endif - - myinit(); - - updateCamera(); - - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - //render coordinate system - glBegin(GL_LINES); - glColor3f(1,0,0); - glVertex3f(0,0,0); - glVertex3f(1,0,0); - glColor3f(0,1,0); - glVertex3f(0,0,0); - glVertex3f(0,1,0); - glColor3f(0,0,1); - glVertex3f(0,0,0); - glVertex3f(0,0,1); - glEnd(); - - //do a finish, to make sure timings are clean - // glFinish(); - - float start = gStopwatch.getTimeMilliseconds(); - - // glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ARRAY_BUFFER, cube_vbo); - glFlush(); - - updatePos(); - - broadphase(); - - //useCPU = true; - - float stop = gStopwatch.getTimeMilliseconds(); - gStopwatch.reset(); - - if (printStats) - { - printf("updatePos=%f ms on ",stop-start); - - if (useCPU) - { - printf("CPU \n"); - } else - { - printf("OpenCL "); - if (runOpenCLKernels) - printf("running the kernels"); - else - printf("without running the kernels"); - printf("\n"); - } - } - - glBindVertexArray(cube_vao); - - glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 9*sizeof(float), 0); - glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, (GLvoid *)(sizeof(cube_vertices))); - glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, 0, (GLvoid *)(sizeof(cube_vertices)+POSITION_BUFFER_SIZE)); - int uvoffset = 7*sizeof(float); - int normaloffset = 4*sizeof(float); - - glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, 9*sizeof(float), (GLvoid *)uvoffset); - glVertexAttribPointer(4, 3, GL_FLOAT, GL_FALSE, 9*sizeof(float), (GLvoid *)normaloffset); - glVertexAttribPointer(5, 4, GL_FLOAT, GL_FALSE, 0, (GLvoid *)(sizeof(cube_vertices)+POSITION_BUFFER_SIZE+ORIENTATION_BUFFER_SIZE)); - glVertexAttribPointer(6, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid *)(sizeof(cube_vertices)+POSITION_BUFFER_SIZE+ORIENTATION_BUFFER_SIZE+COLOR_BUFFER_SIZE)); - - glEnableVertexAttribArray(0); - glEnableVertexAttribArray(1); - glEnableVertexAttribArray(2); - glEnableVertexAttribArray(3); - glEnableVertexAttribArray(4); - glEnableVertexAttribArray(5); - glEnableVertexAttribArray(6); - - glVertexAttribDivisor(0, 0); - glVertexAttribDivisor(1, 1); - glVertexAttribDivisor(2, 1); - glVertexAttribDivisor(3, 0); - glVertexAttribDivisor(4, 0); - glVertexAttribDivisor(5, 1); - glVertexAttribDivisor(6, 1); - - glUseProgram(instancingShader); - glUniform1f(angle_loc, 0); - GLfloat pm[16]; - glGetFloatv(GL_PROJECTION_MATRIX, pm); - glUniformMatrix4fv(ProjectionMatrix, 1, false, &pm[0]); - - GLfloat mvm[16]; - glGetFloatv(GL_MODELVIEW_MATRIX, mvm); - glUniformMatrix4fv(ModelViewMatrix, 1, false, &mvm[0]); - - glUniform1i(uniform_texture_diffuse, 0); - - glFlush(); - int numInstances = NUM_OBJECTS; - int indexCount = sizeof(cube_indices)/sizeof(int); - int indexOffset = 0; - - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_vbo); - glDrawElementsInstanced(GL_TRIANGLES, indexCount, GL_UNSIGNED_INT, (void*)indexOffset, numInstances); - - glUseProgram(0); - glBindBuffer(GL_ARRAY_BUFFER,0); - glBindVertexArray(0); - - glutSwapBuffers(); - glutPostRedisplay(); - - GLint err = glGetError(); - assert(err==GL_NO_ERROR); -} - - -void ChangeSize(int w, int h) -{ - m_glutScreenWidth = w; - m_glutScreenHeight = h; - -#ifdef RECREATE_CL_AND_SHADERS_ON_RESIZE - delete g_interopBuffer; - clReleaseKernel(g_sineWaveKernel); - releaseFindPairs(fpio); - DeleteCL(); - DeleteShaders(); -#endif //RECREATE_CL_AND_SHADERS_ON_RESIZE - - // Set Viewport to window dimensions - glViewport(0, 0, w, h); - -#ifdef RECREATE_CL_AND_SHADERS_ON_RESIZE - InitCL(); - InitShaders(); - - g_interopBuffer = new btOpenCLGLInteropBuffer(g_cxMainContext,g_cqCommandQue,cube_vbo); - clFinish(g_cqCommandQue); - g_sineWaveKernel = btOpenCLUtils::compileCLKernelFromString(g_cxMainContext, interopKernelString, "interopKernel" ); - initFindPairs(...); -#endif //RECREATE_CL_AND_SHADERS_ON_RESIZE - -} - -void Keyboard(unsigned char key, int x, int y) -{ - switch (key) - { - case 27: - done = true; - break; - case 'O': - case 'o': - { - m_ortho = !m_ortho; - break; - } - case 'c': - case 'C': - { - useCPU = !useCPU; - if (useCPU) - printf("using CPU\n"); - else - printf("using OpenCL\n"); - break; - } - case 's': - case 'S': - { - printStats = !printStats; - break; - } - case 'k': - case 'K': - { - runOpenCLKernels=!runOpenCLKernels; - break; - } - case 'q': - case 'Q': - exit(0); - default: - break; - } -} - -// Cleanup -void ShutdownRC(void) -{ - glDeleteBuffers(1, &cube_vbo); - glDeleteVertexArrays(1, &cube_vao); -} - -int main(int argc, char* argv[]) -{ - srand(0); - // printf("vertexShader = \n%s\n",vertexShader); - // printf("fragmentShader = \n%s\n",fragmentShader); - - glutInit(&argc, argv); - - glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA); - - - glutInitWindowSize(m_glutScreenWidth, m_glutScreenHeight); - char buf[1024]; - sprintf(buf,"OpenCL broadphase benchmark, %d cubes on the GPU", NUM_OBJECTS); - glutCreateWindow(buf); - - glutReshapeFunc(ChangeSize); - - glutMouseFunc(mouseFunc); - glutMotionFunc(mouseMotionFunc); - - glutKeyboardFunc(Keyboard); - glutDisplayFunc(RenderScene); - - GLenum err = glewInit(); - if (GLEW_OK != err) - { - /* Problem: glewInit failed, something is seriously wrong. */ - fprintf(stderr, "Error: %s\n", glewGetErrorString(err)); - } - - //ChangeSize(m_glutScreenWidth,m_glutScreenHeight); - - InitCL(); - - -#define CUSTOM_CL_INITIALIZATION -#ifdef CUSTOM_CL_INITIALIZATION - g_deviceCL = new adl::DeviceCL(); - g_deviceCL->m_deviceIdx = g_device; - g_deviceCL->m_context = g_cxMainContext; - g_deviceCL->m_commandQueue = g_cqCommandQue; - -#else - DeviceUtils::Config cfg; - cfg.m_type = DeviceUtils::Config::DEVICE_CPU; - g_deviceCL = DeviceUtils::allocate( TYPE_CL, cfg ); -#endif - - int size = NUM_OBJECTS; - adl::Buffer linvelBuf( g_deviceCL, size ); - adl::Buffer angvelBuf( g_deviceCL, size ); - adl::Buffer bodyTimes(g_deviceCL,size); - - gLinVelMem = (cl_mem)linvelBuf.m_ptr; - gAngVelMem = (cl_mem)angvelBuf.m_ptr; - gBodyTimes = (cl_mem)bodyTimes.m_ptr; - - btVector3* linVelHost= new btVector3[size]; - btVector3* angVelHost = new btVector3[size]; - float* bodyTimesHost = new float[size]; - - for (int i=0;i - -cl_context g_cxMainContext; -cl_command_queue g_cqCommandQue; -cl_kernel g_atomicsKernel; -static const size_t workGroupSize = 128;//todo figure out an appropriate workgroup size suitable for the OpenCL platform/context/device/kernel -#define NUM_OBJECTS 1024 - -#include "globalAtomicsKernel.h" - - -char * findAndReplace( char const * const original, char const * const pattern, char const * const replacement); - - -#include -#include - - -int main(int argc, char* argv[]) -{ - int ciErrNum = 0; - - printf("press a key to start\n"); - getchar(); - - const char* vendorSDK = btOpenCLUtils::getSdkVendorName(); - printf("This program was compiled using the %s OpenCL SDK\n",vendorSDK); - - cl_device_type deviceType = CL_DEVICE_TYPE_GPU;//CL_DEVICE_TYPE_ALL - - void* glCtx=0; - void* glDC = 0; - printf("Initialize OpenCL using btOpenCLUtils::createContextFromType for CL_DEVICE_TYPE_GPU\n"); - g_cxMainContext = btOpenCLUtils::createContextFromType(deviceType, &ciErrNum, glCtx, glDC); - oclCHECKERROR(ciErrNum, CL_SUCCESS); - - int numDev = btOpenCLUtils::getNumDevices(g_cxMainContext); - - if (numDev>0) - { - int deviceIndex=0; - - cl_device_id device; - device = btOpenCLUtils::getDevice(g_cxMainContext,deviceIndex); - btOpenCLDeviceInfo clInfo; - btOpenCLUtils::getDeviceInfo(device,clInfo); - btOpenCLUtils::printDeviceInfo(device); - - - const char* globalAtomicsKernelStringPatched = globalAtomicsKernelString; - if (!strstr(clInfo.m_deviceExtensions,"cl_ext_atomic_counters_32")) - { - globalAtomicsKernelStringPatched = findAndReplace(globalAtomicsKernelString,"counter32_t", "volatile __global int*"); - } - - - - // create a command-queue - g_cqCommandQue = clCreateCommandQueue(g_cxMainContext, device, 0, &ciErrNum); - oclCHECKERROR(ciErrNum, CL_SUCCESS); - - cl_mem counterBuffer = clCreateBuffer(g_cxMainContext, CL_MEM_READ_WRITE, sizeof(int), NULL, &ciErrNum); - oclCHECKERROR(ciErrNum, CL_SUCCESS); - - char* kernelMethods[] = - { - "globalAtomicKernelOpenCL1_1", - "counterAtomicKernelExt", - "globalAtomicKernelExt", - "globalAtomicKernelCounters32Broken" - }; - int numKernelMethods = sizeof(kernelMethods)/sizeof(char*); - - for (int i=0;i -#include - -char * findAndReplace( - char const * const original, - char const * const pattern, - char const * const replacement -) { - size_t const replen = strlen(replacement); - size_t const patlen = strlen(pattern); - size_t const orilen = strlen(original); - - size_t patcnt = 0; - const char * oriptr; - const char * patloc; - - // find how many times the pattern occurs in the original string - for (oriptr = original; patloc = strstr(oriptr, pattern); oriptr = patloc + patlen) - { - patcnt++; - } - - { - // allocate memory for the new string - size_t const retlen = orilen + patcnt * (replen - patlen); - char * const returned = (char *) malloc( sizeof(char) * (retlen + 1) ); - - if (returned != NULL) - { - // copy the original string, - // replacing all the instances of the pattern - char * retptr = returned; - for (oriptr = original; patloc = strstr(oriptr, pattern); oriptr = patloc + patlen) - { - size_t const skplen = patloc - oriptr; - // copy the section until the occurence of the pattern - strncpy(retptr, oriptr, skplen); - retptr += skplen; - // copy the replacement - strncpy(retptr, replacement, replen); - retptr += replen; - } - // copy the rest of the string. - strcpy(retptr, oriptr); - } - return returned; - } -} - -#ifdef _WIN32 -#pragma warning( pop ) -#endif //_WIN32 diff --git a/Extras/RigidBodyGpuPipeline/opencl/global_atomics/premake4.lua b/Extras/RigidBodyGpuPipeline/opencl/global_atomics/premake4.lua deleted file mode 100644 index 3a926c990..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/global_atomics/premake4.lua +++ /dev/null @@ -1,4 +0,0 @@ - - include "AMD" - --include "Intel" - --include "NVIDIA" diff --git a/Extras/RigidBodyGpuPipeline/opencl/global_atomics/stringify.py b/Extras/RigidBodyGpuPipeline/opencl/global_atomics/stringify.py deleted file mode 100644 index e79e281e4..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/global_atomics/stringify.py +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/env python -import sys -import os -import shutil - -arg = sys.argv[1] -fh = open(arg) - -print 'static const char* '+sys.argv[2]+'= \\' -for line in fh.readlines(): - a = line.strip('\n') - print '"'+a+'\\n"' -print ';' diff --git a/Extras/RigidBodyGpuPipeline/opencl/global_atomics/stringifykernels.bat b/Extras/RigidBodyGpuPipeline/opencl/global_atomics/stringifykernels.bat deleted file mode 100644 index 1415f8e5b..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/global_atomics/stringifykernels.bat +++ /dev/null @@ -1,5 +0,0 @@ -stringify.py global_atomics.cl globalAtomicsKernelString >globalAtomicsKernel.h - - - - diff --git a/Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline/AMD/premake4.lua b/Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline/AMD/premake4.lua deleted file mode 100644 index 2000f3ea2..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline/AMD/premake4.lua +++ /dev/null @@ -1,58 +0,0 @@ - - hasCL = findOpenCL_AMD() - - if (hasCL) then - - project "OpenCL_gpu_rigidbody_pipeline_AMD" - - initOpenCL_AMD() - - language "C++" - - kind "ConsoleApp" - targetdir "../../../bin" - - initOpenGL() - initGlut() - initGlew() - - - includedirs { - "../../../rendering/BulletMath", - "../../primitives", - "../../../../../src" - } - - files { - "../main.cpp", - "../btConvexUtility.cpp", - "../btConvexUtility.h", - "../btGpuNarrowPhaseAndSolver.cpp", - "../btGpuNarrowPhaseAndSolver.h", - "../../../dynamics/basic_demo/ConvexHeightFieldShape.cpp", - "../../../dynamics/basic_demo/ConvexHeightFieldShape.h", - "../../../../../src/LinearMath/btConvexHullComputer.cpp", - "../../../../../src/LinearMath/btConvexHullComputer.h", - "../../broadphase_benchmark/findPairsOpenCL.cpp", - "../../broadphase_benchmark/findPairsOpenCL.h", - "../../broadphase_benchmark/btGridBroadphaseCL.cpp", - "../../broadphase_benchmark/btGridBroadphaseCL.h", - "../../3dGridBroadphase/Shared/bt3dGridBroadphaseOCL.cpp", - "../../3dGridBroadphase/Shared/bt3dGridBroadphaseOCL.h", - "../../3dGridBroadphase/Shared/btGpu3DGridBroadphase.cpp", - "../../3dGridBroadphase/Shared/btGpu3DGridBroadphase.h", - "../../../../../src/LinearMath/btAlignedAllocator.cpp", - "../../../../../src/LinearMath/btQuickprof.cpp", - "../../../../../src/LinearMath/btQuickprof.h", - "../../../../../src/BulletCollision/BroadphaseCollision/btBroadphaseProxy.cpp", - "../../../../../src/BulletCollision/BroadphaseCollision/btOverlappingPairCache.cpp", - "../../../../../src/BulletCollision/BroadphaseCollision/btSimpleBroadphase.cpp", - "../../basic_initialize/btOpenCLUtils.cpp", - "../../basic_initialize/btOpenCLUtils.h", - "../../opengl_interop/btOpenCLGLInteropBuffer.cpp", - "../../opengl_interop/btOpenCLGLInteropBuffer.h", - "../../opengl_interop/btStopwatch.cpp", - "../../opengl_interop/btStopwatch.h" - } - - end \ No newline at end of file diff --git a/Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline/CommandLineArgs.h b/Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline/CommandLineArgs.h deleted file mode 100644 index b64610303..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline/CommandLineArgs.h +++ /dev/null @@ -1,91 +0,0 @@ -#ifndef COMMAND_LINE_ARGS_H -#define COMMAND_LINE_ARGS_H - -/****************************************************************************** - * Command-line parsing - ******************************************************************************/ -#include -#include -#include -#include -class CommandLineArgs -{ -protected: - - std::map pairs; - -public: - - // Constructor - CommandLineArgs(int argc, char **argv) - { - using namespace std; - - for (int i = 1; i < argc; i++) - { - string arg = argv[i]; - - if ((arg[0] != '-') || (arg[1] != '-')) { - continue; - } - - string::size_type pos; - string key, val; - if ((pos = arg.find( '=')) == string::npos) { - key = string(arg, 2, arg.length() - 2); - val = ""; - } else { - key = string(arg, 2, pos - 2); - val = string(arg, pos + 1, arg.length() - 1); - } - pairs[key] = val; - } - } - - bool CheckCmdLineFlag(const char* arg_name) - { - using namespace std; - map::iterator itr; - if ((itr = pairs.find(arg_name)) != pairs.end()) { - return true; - } - return false; - } - - template - void GetCmdLineArgument(const char *arg_name, T &val); - - int ParsedArgc() - { - return pairs.size(); - } -}; - -template -void CommandLineArgs::GetCmdLineArgument(const char *arg_name, T &val) -{ - using namespace std; - map::iterator itr; - if ((itr = pairs.find(arg_name)) != pairs.end()) { - istringstream strstream(itr->second); - strstream >> val; - } -} - -template <> -void CommandLineArgs::GetCmdLineArgument(const char* arg_name, char* &val) -{ - using namespace std; - map::iterator itr; - if ((itr = pairs.find(arg_name)) != pairs.end()) { - - string s = itr->second; - val = (char*) malloc(sizeof(char) * (s.length() + 1)); - strcpy(val, s.c_str()); - - } else { - val = NULL; - } -} - -#endif //COMMAND_LINE_ARGS_H diff --git a/Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline/Intel/premake4.lua b/Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline/Intel/premake4.lua deleted file mode 100644 index 541dc7941..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline/Intel/premake4.lua +++ /dev/null @@ -1,58 +0,0 @@ - - hasCL = findOpenCL_Intel() - - if (hasCL) then - - project "OpenCL_gpu_rigidbody_pipeline_Intel" - - initOpenCL_Intel() - - language "C++" - - kind "ConsoleApp" - targetdir "../../../bin" - - initOpenGL() - initGlut() - initGlew() - - - includedirs { - "../../../rendering/BulletMath", - "../../primitives", - "../../../../../src" - } - - files { - "../main.cpp", - "../btConvexUtility.cpp", - "../btConvexUtility.h", - "../btGpuNarrowPhaseAndSolver.cpp", - "../btGpuNarrowPhaseAndSolver.h", - "../../../dynamics/basic_demo/ConvexHeightFieldShape.cpp", - "../../../dynamics/basic_demo/ConvexHeightFieldShape.h", - "../../../../../src/LinearMath/btConvexHullComputer.cpp", - "../../../../../src/LinearMath/btConvexHullComputer.h", - "../../broadphase_benchmark/findPairsOpenCL.cpp", - "../../broadphase_benchmark/findPairsOpenCL.h", - "../../broadphase_benchmark/btGridBroadphaseCL.cpp", - "../../broadphase_benchmark/btGridBroadphaseCL.h", - "../../3dGridBroadphase/Shared/bt3dGridBroadphaseOCL.cpp", - "../../3dGridBroadphase/Shared/bt3dGridBroadphaseOCL.h", - "../../3dGridBroadphase/Shared/btGpu3DGridBroadphase.cpp", - "../../3dGridBroadphase/Shared/btGpu3DGridBroadphase.h", - "../../../../../src/LinearMath/btAlignedAllocator.cpp", - "../../../../../src/LinearMath/btQuickprof.cpp", - "../../../../../src/LinearMath/btQuickprof.h", - "../../../../../src/BulletCollision/BroadphaseCollision/btBroadphaseProxy.cpp", - "../../../../../src/BulletCollision/BroadphaseCollision/btOverlappingPairCache.cpp", - "../../../../../src/BulletCollision/BroadphaseCollision/btSimpleBroadphase.cpp", - "../../basic_initialize/btOpenCLUtils.cpp", - "../../basic_initialize/btOpenCLUtils.h", - "../../opengl_interop/btOpenCLGLInteropBuffer.cpp", - "../../opengl_interop/btOpenCLGLInteropBuffer.h", - "../../opengl_interop/btStopwatch.cpp", - "../../opengl_interop/btStopwatch.h" - } - - end \ No newline at end of file diff --git a/Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline/NVIDIA/premake4.lua b/Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline/NVIDIA/premake4.lua deleted file mode 100644 index 095e08f39..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline/NVIDIA/premake4.lua +++ /dev/null @@ -1,57 +0,0 @@ - - hasCL = findOpenCL_NVIDIA() - - if (hasCL) then - - project "OpenCL_gpu_rigidbody_pipeline_NVIDIA" - - initOpenCL_NVIDIA() - - language "C++" - - kind "ConsoleApp" - targetdir "../../../bin" - - initOpenGL() - initGlut() - initGlew() - - includedirs { - "../../../rendering/BulletMath", - "../../primitives", - "../../../../../src" - } - - files { - "../main.cpp", - "../btConvexUtility.cpp", - "../btConvexUtility.h", - "../btGpuNarrowPhaseAndSolver.cpp", - "../btGpuNarrowPhaseAndSolver.h", - "../../../dynamics/basic_demo/ConvexHeightFieldShape.cpp", - "../../../dynamics/basic_demo/ConvexHeightFieldShape.h", - "../../../../../src/LinearMath/btConvexHullComputer.cpp", - "../../../../../src/LinearMath/btConvexHullComputer.h", - "../../broadphase_benchmark/findPairsOpenCL.cpp", - "../../broadphase_benchmark/findPairsOpenCL.h", - "../../broadphase_benchmark/btGridBroadphaseCL.cpp", - "../../broadphase_benchmark/btGridBroadphaseCL.h", - "../../3dGridBroadphase/Shared/bt3dGridBroadphaseOCL.cpp", - "../../3dGridBroadphase/Shared/bt3dGridBroadphaseOCL.h", - "../../3dGridBroadphase/Shared/btGpu3DGridBroadphase.cpp", - "../../3dGridBroadphase/Shared/btGpu3DGridBroadphase.h", - "../../../../../src/LinearMath/btAlignedAllocator.cpp", - "../../../../../src/LinearMath/btQuickprof.cpp", - "../../../../../src/LinearMath/btQuickprof.h", - "../../../../../src/BulletCollision/BroadphaseCollision/btBroadphaseProxy.cpp", - "../../../../../src/BulletCollision/BroadphaseCollision/btOverlappingPairCache.cpp", - "../../../../../src/BulletCollision/BroadphaseCollision/btSimpleBroadphase.cpp", - "../../basic_initialize/btOpenCLUtils.cpp", - "../../basic_initialize/btOpenCLUtils.h", - "../../opengl_interop/btOpenCLGLInteropBuffer.cpp", - "../../opengl_interop/btOpenCLGLInteropBuffer.h", - "../../opengl_interop/btStopwatch.cpp", - "../../opengl_interop/btStopwatch.h" - } - - end \ No newline at end of file diff --git a/Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline/btConvexUtility.cpp b/Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline/btConvexUtility.cpp deleted file mode 100644 index 7f24449f7..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline/btConvexUtility.cpp +++ /dev/null @@ -1,240 +0,0 @@ -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Erwin Coumans - - -#include "btConvexUtility.h" -#include "LinearMath/btConvexHullComputer.h" -#include "LinearMath/btGrahamScan2dConvexHull.h" -#include "LinearMath/btQuaternion.h" - -bool btConvexUtility::initializePolyhedralFeatures(const btAlignedObjectArray& orgVertices, bool mergeCoplanarTriangles) -{ - - - btConvexHullComputer conv; - conv.compute(&orgVertices[0].getX(), sizeof(btVector3),orgVertices.size(),0.f,0.f); - - btAlignedObjectArray faceNormals; - int numFaces = conv.faces.size(); - faceNormals.resize(numFaces); - btConvexHullComputer* convexUtil = &conv; - - - btAlignedObjectArray tmpFaces; - tmpFaces.resize(numFaces); - - int numVertices = convexUtil->vertices.size(); - m_vertices.resize(numVertices); - for (int p=0;pvertices[p]; - } - - - for (int i=0;ifaces[i]; - //printf("face=%d\n",face); - const btConvexHullComputer::Edge* firstEdge = &convexUtil->edges[face]; - const btConvexHullComputer::Edge* edge = firstEdge; - - btVector3 edges[3]; - int numEdges = 0; - //compute face normals - - btScalar maxCross2 = 0.f; - int chosenEdge = -1; - - do - { - - int src = edge->getSourceVertex(); - tmpFaces[i].m_indices.push_back(src); - int targ = edge->getTargetVertex(); - btVector3 wa = convexUtil->vertices[src]; - - btVector3 wb = convexUtil->vertices[targ]; - btVector3 newEdge = wb-wa; - newEdge.normalize(); - if (numEdges<2) - edges[numEdges++] = newEdge; - - edge = edge->getNextEdgeOfFace(); - } while (edge!=firstEdge); - - btScalar planeEq = 1e30f; - - - if (numEdges==2) - { - faceNormals[i] = edges[0].cross(edges[1]); - faceNormals[i].normalize(); - tmpFaces[i].m_plane[0] = faceNormals[i].getX(); - tmpFaces[i].m_plane[1] = faceNormals[i].getY(); - tmpFaces[i].m_plane[2] = faceNormals[i].getZ(); - tmpFaces[i].m_plane[3] = planeEq; - - } - else - { - btAssert(0);//degenerate? - faceNormals[i].setZero(); - } - - for (int v=0;veq) - { - planeEq=eq; - } - } - tmpFaces[i].m_plane[3] = -planeEq; - } - - //merge coplanar faces - - btScalar faceWeldThreshold= 0.999f; - btAlignedObjectArray todoFaces; - for (int i=0;i coplanarFaceGroup; - int refFace = todoFaces[todoFaces.size()-1]; - - coplanarFaceGroup.push_back(refFace); - btFace& faceA = tmpFaces[refFace]; - todoFaces.pop_back(); - - btVector3 faceNormalA(faceA.m_plane[0],faceA.m_plane[1],faceA.m_plane[2]); - for (int j=todoFaces.size()-1;j>=0;j--) - { - int i = todoFaces[j]; - btFace& faceB = tmpFaces[i]; - btVector3 faceNormalB(faceB.m_plane[0],faceB.m_plane[1],faceB.m_plane[2]); - if (faceNormalA.dot(faceNormalB)>faceWeldThreshold) - { - coplanarFaceGroup.push_back(i); - todoFaces.remove(i); - } - } - - - bool did_merge = false; - if (mergeCoplanarTriangles && coplanarFaceGroup.size()>1) - { - //do the merge: use Graham Scan 2d convex hull - - btAlignedObjectArray orgpoints; - - for (int i=0;i hull; - GrahamScanConvexHull2D(orgpoints,hull); - - for (int i=0;i m_indices; -// btAlignedObjectArray m_connectedFaces; - btScalar m_plane[4]; -}; - -class btConvexUtility -{ - public: - - btAlignedObjectArray m_vertices; - btAlignedObjectArray m_faces; - - bool initializePolyhedralFeatures(const btAlignedObjectArray& orgVertices, bool mergeCoplanarTriangles); - -}; -#endif - \ No newline at end of file diff --git a/Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline/btGpuNarrowPhaseAndSolver.cpp b/Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline/btGpuNarrowPhaseAndSolver.cpp deleted file mode 100644 index 6f377afd5..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline/btGpuNarrowPhaseAndSolver.cpp +++ /dev/null @@ -1,730 +0,0 @@ -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Erwin Coumans - -#include "btGpuNarrowphaseAndSolver.h" - -//#include "CustomConvexShape.h" -//#include "CustomConvexPairCollision.h" -#include "LinearMath/btQuickprof.h" - - -//#include "BulletDynamics/Dynamics/btRigidBody.h" - -#include "Adl/Adl.h" -#include "../../dynamics/basic_demo/Stubs/AdlMath.h" -#include "../../dynamics/basic_demo/Stubs/AdlContact4.h" -#include "../../dynamics/basic_demo/Stubs/AdlQuaternion.h" -#include "../../dynamics/basic_demo/Stubs/ChNarrowPhase.h" -#include "../../dynamics/basic_demo/Stubs/Solver.h" -#include - -int gpuBatchContacts = 1; - -int numPairsOut =0; -struct CPUSolveData -{ - u32 m_n[adl::SolverBase::N_SPLIT*adl::SolverBase::N_SPLIT]; - u32 m_offset[adl::SolverBase::N_SPLIT*adl::SolverBase::N_SPLIT]; -}; - - -struct ParallelSolveData -{ - adl::Buffer* m_numConstraints; - adl::Buffer* m_offsets; -}; - -struct CustomDispatchData -{ - adl::DeviceCL* m_deviceCL; - adl::Device* m_deviceHost; - ShapeDataType m_ShapeBuffer; - adl::HostBuffer* m_shapePointers; - - adl::HostBuffer* m_pBufPairsCPU; - - adl::Buffer* m_convexPairsOutGPU; - adl::Buffer* m_planePairs; - - adl::Buffer* m_pBufContactOutGPU; - adl::HostBuffer* m_pBufContactOutCPU; - adl::ChNarrowphase::Data* m_Data; - - - - adl::HostBuffer* m_bodyBufferCPU; - adl::Buffer* m_bodyBufferGPU; - - adl::Buffer* m_inertiaBufferCPU; - adl::Buffer* m_inertiaBufferGPU; - - adl::Solver::Data* m_solverDataGPU; - SolverData m_contactCGPU; - void* m_frictionCGPU; - - int m_numAcceleratedShapes; - int m_numAcceleratedRigidBodies; -}; - - -btGpuNarrowphaseAndSolver::btGpuNarrowphaseAndSolver(adl::DeviceCL* deviceCL) - :m_internalData(0) ,m_planeBodyIndex(-1) -{ - - if (deviceCL) - { - m_internalData = new CustomDispatchData(); - memset(m_internalData,0,sizeof(CustomDispatchData)); - - adl::DeviceUtils::Config cfg; - m_internalData->m_deviceCL = deviceCL; - - - m_internalData->m_deviceHost = adl::DeviceUtils::allocate( adl::TYPE_HOST, cfg ); - m_internalData->m_pBufPairsCPU = new adl::HostBuffer(m_internalData->m_deviceHost, MAX_BROADPHASE_COLLISION_CL); - - m_internalData->m_convexPairsOutGPU = new adl::Buffer(m_internalData->m_deviceCL,MAX_BROADPHASE_COLLISION_CL); - m_internalData->m_planePairs = new adl::Buffer(m_internalData->m_deviceCL,MAX_BROADPHASE_COLLISION_CL); - - m_internalData->m_pBufContactOutCPU = new adl::HostBuffer(m_internalData->m_deviceHost, MAX_BROADPHASE_COLLISION_CL); - m_internalData->m_bodyBufferCPU = new adl::HostBuffer(m_internalData->m_deviceHost, MAX_CONVEX_BODIES_CL); - - m_internalData->m_inertiaBufferCPU = new adl::Buffer(m_internalData->m_deviceHost,MAX_CONVEX_BODIES_CL); - m_internalData->m_pBufContactOutGPU = new adl::Buffer(m_internalData->m_deviceCL, MAX_BROADPHASE_COLLISION_CL); - m_internalData->m_inertiaBufferGPU = new adl::Buffer(m_internalData->m_deviceCL,MAX_CONVEX_BODIES_CL); - - m_internalData->m_solverDataGPU = adl::Solver::allocate( m_internalData->m_deviceCL, MAX_BROADPHASE_COLLISION_CL); - m_internalData->m_bodyBufferGPU = new adl::Buffer(m_internalData->m_deviceCL, MAX_CONVEX_BODIES_CL); - m_internalData->m_Data = adl::ChNarrowphase::allocate(m_internalData->m_deviceCL); -// m_internalData->m_DataCPU = adl::ChNarrowphase::allocate(m_internalData->m_deviceHost); - - - m_internalData->m_ShapeBuffer = adl::ChNarrowphase::allocateShapeBuffer(m_internalData->m_deviceCL, MAX_CONVEX_SHAPES_CL); - - m_internalData->m_shapePointers = new adl::HostBuffer(m_internalData->m_deviceHost,MAX_CONVEX_SHAPES_CL); - - m_internalData->m_numAcceleratedShapes = 0; - m_internalData->m_numAcceleratedRigidBodies = 0; - - m_internalData->m_contactCGPU = adl::Solver::allocateConstraint4( m_internalData->m_deviceCL, MAX_BROADPHASE_COLLISION_CL); - m_internalData->m_frictionCGPU = adl::Solver::allocateFrictionConstraint( m_internalData->m_deviceCL, MAX_BROADPHASE_COLLISION_CL); - - } -} - -int btGpuNarrowphaseAndSolver::registerShape(ConvexHeightField* convexShape) -{ - (*m_internalData->m_shapePointers)[m_internalData->m_numAcceleratedShapes] = convexShape; - adl::ChNarrowphase::setShape(m_internalData->m_ShapeBuffer, convexShape, m_internalData->m_numAcceleratedShapes, 0.01f); - return m_internalData->m_numAcceleratedShapes++; -} - -cl_mem btGpuNarrowphaseAndSolver::getBodiesGpu() -{ - return (cl_mem)m_internalData->m_bodyBufferGPU->m_ptr; -} - -cl_mem btGpuNarrowphaseAndSolver::getBodyInertiasGpu() -{ - return (cl_mem)m_internalData->m_inertiaBufferGPU->m_ptr; -} - - -int btGpuNarrowphaseAndSolver::registerRigidBody(int shapeIndex, float mass, const float* position, const float* orientation , bool writeToGpu) -{ - assert(m_internalData->m_numAcceleratedRigidBodies< (MAX_CONVEX_BODIES_CL-1)); - - RigidBodyBase::Body& body = m_internalData->m_bodyBufferCPU->m_ptr[m_internalData->m_numAcceleratedRigidBodies]; - - float friction = 1.f; - float restitution = 0.f; - - body.m_frictionCoeff = friction; - body.m_restituitionCoeff = restitution; - body.m_angVel = make_float4(0.f); - body.m_linVel = make_float4(0.f); - body.m_pos = make_float4(position[0],position[1],position[2],0.f); - body.m_quat = make_float4(orientation[0],orientation[1],orientation[2],orientation[3]); - body.m_shapeIdx = shapeIndex; - if (shapeIndex<0) - { - body.m_shapeType = CollisionShape::SHAPE_PLANE; - m_planeBodyIndex = m_internalData->m_numAcceleratedRigidBodies; - } else - { - body.m_shapeType = CollisionShape::SHAPE_CONVEX_HEIGHT_FIELD; - } - - body.m_invMass = mass? 1.f/mass : 0.f; - - if (writeToGpu) - m_internalData->m_bodyBufferGPU->write(&body,1,m_internalData->m_numAcceleratedRigidBodies); - - RigidBodyBase::Inertia& shapeInfo = m_internalData->m_inertiaBufferCPU->m_ptr[m_internalData->m_numAcceleratedRigidBodies]; - - if (mass==0.f) - { - shapeInfo.m_initInvInertia = mtZero(); - shapeInfo.m_invInertia = mtZero(); - } else - { - - assert(body.m_shapeIdx>=0); - - //approximate using the aabb of the shape - - Aabb aabb = (*m_internalData->m_shapePointers)[shapeIndex]->m_aabb; - float4 halfExtents = (aabb.m_max - aabb.m_min); - - float4 localInertia; - - float lx=2.f*halfExtents.x; - float ly=2.f*halfExtents.y; - float lz=2.f*halfExtents.z; - - localInertia = make_float4( (mass/12.0f) * (ly*ly + lz*lz), - (mass/12.0f) * (lx*lx + lz*lz), - (mass/12.0f) * (lx*lx + ly*ly)); - - float4 invLocalInertia; - invLocalInertia.x = 1.f/localInertia.x; - invLocalInertia.y = 1.f/localInertia.y; - invLocalInertia.z = 1.f/localInertia.z; - invLocalInertia.w = 0.f; - - shapeInfo.m_initInvInertia = mtZero(); - shapeInfo.m_initInvInertia.m_row[0].x = invLocalInertia.x; - shapeInfo.m_initInvInertia.m_row[1].y = invLocalInertia.y; - shapeInfo.m_initInvInertia.m_row[2].z = invLocalInertia.z; - - Matrix3x3 m = qtGetRotationMatrix( body.m_quat); - Matrix3x3 mT = mtTranspose( m ); - shapeInfo.m_invInertia = mtMul( mtMul( m, shapeInfo.m_initInvInertia ), mT ); - - } - - if (writeToGpu) - m_internalData->m_inertiaBufferGPU->write(&shapeInfo,1,m_internalData->m_numAcceleratedRigidBodies); - return m_internalData->m_numAcceleratedRigidBodies++; -} - -void btGpuNarrowphaseAndSolver::writeAllBodiesToGpu() -{ - m_internalData->m_bodyBufferGPU->write(m_internalData->m_bodyBufferCPU->m_ptr,m_internalData->m_numAcceleratedRigidBodies); - m_internalData->m_inertiaBufferGPU->write( m_internalData->m_inertiaBufferCPU->m_ptr,m_internalData->m_numAcceleratedRigidBodies); -} - - - -btGpuNarrowphaseAndSolver::~btGpuNarrowphaseAndSolver(void) -{ - if (m_internalData) - { - delete m_internalData->m_pBufPairsCPU; - delete m_internalData->m_convexPairsOutGPU; - delete m_internalData->m_planePairs; - delete m_internalData->m_pBufContactOutGPU; - delete m_internalData->m_inertiaBufferGPU; - delete m_internalData->m_pBufContactOutCPU; - delete m_internalData->m_shapePointers; - adl::ChNarrowphase::deallocateShapeBuffer(m_internalData->m_ShapeBuffer); - delete m_internalData->m_inertiaBufferCPU; - adl::Solver::deallocateConstraint4( m_internalData->m_contactCGPU ); - adl::Solver::deallocateFrictionConstraint( m_internalData->m_frictionCGPU ); - - delete m_internalData->m_bodyBufferGPU; - adl::Solver::deallocate( m_internalData->m_solverDataGPU); - delete m_internalData->m_bodyBufferCPU; - adl::ChNarrowphase::deallocate(m_internalData->m_Data); - - - - adl::DeviceUtils::deallocate(m_internalData->m_deviceHost); - - delete m_internalData; - } - -} - - - - - -void btGpuNarrowphaseAndSolver::computeContactsAndSolver(cl_mem broadphasePairs, int numBroadphasePairs) -{ - - BT_PROFILE("computeContactsAndSolver"); - bool bGPU = (m_internalData != 0); - int maxBodyIndex = m_internalData->m_numAcceleratedRigidBodies; - - if (!maxBodyIndex) - return; - int numOfConvexRBodies = maxBodyIndex; - - adl::ChNarrowphaseBase::Config cfgNP; - cfgNP.m_collisionMargin = 0.01f; - int nContactOut = 0; - //printf("convexPairsOut.m_size = %d\n",m_internalData->m_convexPairsOutGPU->m_size); - - - adl::Buffer broadphasePairsGPU; - broadphasePairsGPU.m_ptr = (int2*)broadphasePairs; - broadphasePairsGPU.m_size = numBroadphasePairs; - broadphasePairsGPU.m_device = m_internalData->m_deviceCL; - - - bool useCulling = true; - if (useCulling) - { - BT_PROFILE("ChNarrowphase::culling"); - adl::DeviceUtils::waitForCompletion(m_internalData->m_deviceCL); - - numPairsOut = adl::ChNarrowphase::culling( - m_internalData->m_Data, - &broadphasePairsGPU, - numBroadphasePairs, - m_internalData->m_bodyBufferGPU, m_internalData->m_ShapeBuffer, - m_internalData->m_convexPairsOutGPU, - cfgNP); - } - - { - BT_PROFILE("ChNarrowphase::execute"); - if (useCulling) - { - - if (m_planeBodyIndex>=0) - { - BT_PROFILE("ChNarrowphase:: plane versus convex"); - //todo: get rid of this dynamic allocation - int2* hostPairs = new int2[m_internalData->m_numAcceleratedRigidBodies-1]; - int index=0; - for (int i=0;im_numAcceleratedRigidBodies;i++) - { - if (i!=m_planeBodyIndex) - { - hostPairs[index].x = m_planeBodyIndex; - hostPairs[index].y = i; - index++; - } - } - assert(m_internalData->m_numAcceleratedRigidBodies-1 == index); - m_internalData->m_planePairs->write(hostPairs,index); - adl::DeviceUtils::waitForCompletion(m_internalData->m_deviceCL); - delete[]hostPairs; - //convex versus plane - adl::ChNarrowphase::execute(m_internalData->m_Data, m_internalData->m_planePairs, index, m_internalData->m_bodyBufferGPU, m_internalData->m_ShapeBuffer, - 0,0,m_internalData->m_pBufContactOutGPU, nContactOut, cfgNP); - } - - //convex versus convex - adl::ChNarrowphase::execute(m_internalData->m_Data, m_internalData->m_convexPairsOutGPU,numPairsOut, m_internalData->m_bodyBufferGPU, m_internalData->m_ShapeBuffer, m_internalData->m_pBufContactOutGPU, nContactOut, cfgNP); - } else - { - adl::ChNarrowphase::execute(m_internalData->m_Data, &broadphasePairsGPU, numBroadphasePairs, m_internalData->m_bodyBufferGPU, m_internalData->m_ShapeBuffer, m_internalData->m_pBufContactOutGPU, nContactOut, cfgNP); - } - - adl::DeviceUtils::waitForCompletion(m_internalData->m_deviceCL); - } - - if (!nContactOut) - return; - - - bool useSolver = true;//true;//false; - - if (useSolver) - { - float dt=1./60.; - adl::SolverBase::ConstraintCfg csCfg( dt ); - csCfg.m_enableParallelSolve = true; - csCfg.m_averageExtent = 0.2f;//@TODO m_averageObjExtent; - csCfg.m_staticIdx = m_planeBodyIndex; - - - bool exposeInternalBatchImplementation=true; - - adl::Solver::Data* cpuSolverData = 0; - if (exposeInternalBatchImplementation) - { - BT_PROFILE("Batching"); - - cpuSolverData = adl::Solver::allocate( m_internalData->m_deviceHost, nContactOut); - - adl::Buffer* contactsIn = m_internalData->m_pBufContactOutGPU; - const adl::Buffer* bodyBuf = m_internalData->m_bodyBufferGPU; - void* additionalData = m_internalData->m_frictionCGPU; - const adl::Buffer* shapeBuf = m_internalData->m_inertiaBufferGPU; - SolverData contactCOut = m_internalData->m_contactCGPU; - int nContacts = nContactOut; - - bool useCPU=false; - - if (useCPU) - { - BT_PROFILE("CPU batch"); - { - BT_PROFILE("CPU sortContacts2"); - sortContacts2( cpuSolverData, bodyBuf, contactsIn, additionalData, nContacts, csCfg ); - } - - CPUSolveData* dataCPU = (CPUSolveData*)cpuSolverData->m_parallelSolveData; - { - BT_PROFILE("CPU batchContacts2"); - - adl::Buffer n; n.setRawPtr( cpuSolverData->m_device, dataCPU->m_n, adl::SolverBase::N_SPLIT*adl::SolverBase::N_SPLIT ); - adl::Buffer offsets; offsets.setRawPtr( cpuSolverData->m_device, dataCPU->m_offset, adl::SolverBase::N_SPLIT*adl::SolverBase::N_SPLIT ); - batchContacts2( cpuSolverData, contactsIn, nContacts, &n, &offsets, csCfg.m_staticIdx ); - } - - { - BT_PROFILE("CPU convertToConstraints2"); - convertToConstraints2( cpuSolverData, bodyBuf, shapeBuf, contactsIn, contactCOut, additionalData, nContacts, csCfg ); - } - - { - BT_PROFILE("CPU -> GPU copy"); - ParallelSolveData* dataGPU = (ParallelSolveData*)m_internalData->m_solverDataGPU->m_parallelSolveData; - dataGPU->m_numConstraints->write(dataCPU->m_n,adl::SolverBase::N_SPLIT*adl::SolverBase::N_SPLIT); - dataGPU->m_offsets->write(dataCPU->m_offset,adl::SolverBase::N_SPLIT*adl::SolverBase::N_SPLIT); - adl::DeviceUtils::waitForCompletion( m_internalData->m_deviceCL); - } - - } - else - { - BT_PROFILE("GPU batch"); - - adl::Solver::Data* data = m_internalData->m_solverDataGPU; - - { - if( data->m_contactBuffer ) - { - if( data->m_contactBuffer->getSize() < nContacts ) - { - BT_PROFILE("delete data->m_contactBuffer;"); - delete data->m_contactBuffer; - data->m_contactBuffer = 0; - } - } - if( data->m_contactBuffer == 0 ) - { - data->m_contactBuffer = new adl::Buffer( data->m_device, nContacts ); - } - - adl::Buffer* contactNative = contactsIn; - - ParallelSolveData* nativeSolveData = (ParallelSolveData*)data->m_parallelSolveData; - - { - - ADLASSERT( data->m_device->m_type == adl::TYPE_CL ); - adl::Buffer* bodyNative = adl::BufferUtils::map( data->m_device, bodyBuf ); - adl::Buffer* contactNative = adl::BufferUtils::map( data->m_device, contactsIn ); - - const int sortAlignment = 512; // todo. get this out of sort - if( csCfg.m_enableParallelSolve ) - { - ParallelSolveData* nativeSolveData = (ParallelSolveData*)data->m_parallelSolveData; - - int sortSize = NEXTMULTIPLEOF( nContacts, sortAlignment ); - - adl::Buffer* countsNative = nativeSolveData->m_numConstraints;//BufferUtils::map( data->m_device, &countsHost ); - adl::Buffer* offsetsNative = nativeSolveData->m_offsets;//BufferUtils::map( data->m_device, &offsetsHost ); - - { // 2. set cell idx - BT_PROFILE("GPU set cell idx"); - struct CB - { - int m_nContacts; - int m_staticIdx; - float m_scale; - int m_nSplit; - }; - - ADLASSERT( sortSize%64 == 0 ); - CB cdata; - cdata.m_nContacts = nContacts; - cdata.m_staticIdx = csCfg.m_staticIdx; - cdata.m_scale = 1.f/(adl::SolverBase::N_OBJ_PER_SPLIT*csCfg.m_averageExtent); - cdata.m_nSplit = adl::SolverBase::N_SPLIT; - - adl::Buffer constBuffer( data->m_device, 1, adl::BufferBase::BUFFER_CONST ); - adl::Launcher::BufferInfo bInfo[] = { adl::Launcher::BufferInfo( contactNative ), adl::Launcher::BufferInfo( bodyNative ), adl::Launcher::BufferInfo( data->m_sortDataBuffer ) }; - adl::Launcher launcher( data->m_device, data->m_setSortDataKernel ); - launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(adl::Launcher::BufferInfo) ); - launcher.setConst( constBuffer, cdata ); - launcher.launch1D( sortSize, 64 ); - } - bool gpuRadixSort=true; - if (gpuRadixSort) - { // 3. sort by cell idx - BT_PROFILE("gpuRadixSort"); - int n = adl::SolverBase::N_SPLIT*adl::SolverBase::N_SPLIT; - int sortBit = 32; - //if( n <= 0xffff ) sortBit = 16; - //if( n <= 0xff ) sortBit = 8; - //adl::RadixSort::execute( data->m_sort, *data->m_sortDataBuffer, sortSize ); - adl::RadixSort32::execute( data->m_sort32, *data->m_sortDataBuffer, sortSize ); - - } else - { - BT_PROFILE("cpu RadixSort"); - adl::HostBuffer sortData(m_internalData->m_deviceHost,nContacts); - data->m_sortDataBuffer->read(sortData.m_ptr,nContacts); - adl::DeviceUtils::waitForCompletion( m_internalData->m_deviceCL); - - adl::RadixSort::Data* sData = adl::RadixSort::allocate( m_internalData->m_deviceHost, nContacts ); - adl::RadixSort::execute( sData, sortData, nContacts ); - adl::RadixSort::deallocate( sData ); - - data->m_sortDataBuffer->write(sortData.m_ptr,nContacts); - adl::DeviceUtils::waitForCompletion( m_internalData->m_deviceCL); - } - - - - bool gpuBoundSearch=true; - if (gpuBoundSearch) - { // 4. find entries - BT_PROFILE("gpuBoundSearch"); - adl::BoundSearch::execute( data->m_search, *data->m_sortDataBuffer, nContacts, *countsNative, - adl::SolverBase::N_SPLIT*adl::SolverBase::N_SPLIT, adl::BoundSearchBase::COUNT ); - - adl::PrefixScan::execute( data->m_scan, *countsNative, *offsetsNative, - adl::SolverBase::N_SPLIT*adl::SolverBase::N_SPLIT ); - } else - { - BT_PROFILE("cpuBoundSearch"); - adl::HostBuffer sortData(m_internalData->m_deviceHost,nContacts); - data->m_sortDataBuffer->read(sortData.m_ptr,nContacts); - adl::DeviceUtils::waitForCompletion( m_internalData->m_deviceCL); - - adl::HostBuffer n0( m_internalData->m_deviceHost, adl::SolverBase::N_SPLIT*adl::SolverBase::N_SPLIT ); - adl::HostBuffer offset0( m_internalData->m_deviceHost, adl::SolverBase::N_SPLIT*adl::SolverBase::N_SPLIT ); - for(int i=0; i=0); - assert(idxwrite(n0.m_ptr,adl::SolverBase::N_SPLIT*adl::SolverBase::N_SPLIT); - offsetsNative->write(offset0.m_ptr,adl::SolverBase::N_SPLIT*adl::SolverBase::N_SPLIT); - adl::DeviceUtils::waitForCompletion( data->m_device ); - - } - { // 5. sort constraints by cellIdx - { - BT_PROFILE("gpu m_reorderContactKernel"); - adl::Buffer constBuffer( data->m_device, 1, adl::BufferBase::BUFFER_CONST ); - - int4 cdata; cdata.x = nContacts; - adl::Launcher::BufferInfo bInfo[] = { adl::Launcher::BufferInfo( contactNative ), adl::Launcher::BufferInfo( data->m_contactBuffer ), adl::Launcher::BufferInfo( data->m_sortDataBuffer ) }; - adl::Launcher launcher( data->m_device, data->m_reorderContactKernel ); - launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(adl::Launcher::BufferInfo) ); - launcher.setConst( constBuffer, cdata ); - launcher.launch1D( nContacts, 64 ); - } - } - - } - - adl::BufferUtils::unmap( bodyNative, bodyBuf ); - adl::BufferUtils::unmap( contactNative, contactsIn ); - - } - - adl::DeviceUtils::waitForCompletion( m_internalData->m_deviceCL); - - { - BT_PROFILE("gpu m_copyConstraintKernel"); - adl::Buffer constBuffer( data->m_device, 1, adl::BufferBase::BUFFER_CONST ); - int4 cdata; cdata.x = nContacts; - adl::Launcher::BufferInfo bInfo[] = { adl::Launcher::BufferInfo( data->m_contactBuffer ), adl::Launcher::BufferInfo( contactNative ) }; - adl::Launcher launcher( data->m_device, data->m_copyConstraintKernel ); - launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(adl::Launcher::BufferInfo) ); - launcher.setConst( constBuffer, cdata ); - launcher.launch1D( nContacts, 64 ); - adl::DeviceUtils::waitForCompletion( data->m_device ); - } - - bool compareGPU = false; - if (gpuBatchContacts) - { - BT_PROFILE("gpu batchContacts"); - adl::Solver::batchContacts( data, contactNative, nContacts, nativeSolveData->m_numConstraints, nativeSolveData->m_offsets, csCfg.m_staticIdx ); - } - else - { - BT_PROFILE("cpu batchContacts2"); - cpuSolverData->m_parallelSolveData = 0;// - ParallelSolveData* dataGPU = (ParallelSolveData*)m_internalData->m_solverDataGPU->m_parallelSolveData; - adl::Buffer numConstraints(cpuSolverData->m_device,adl::SolverBase::N_SPLIT*adl::SolverBase::N_SPLIT); - adl::Buffer offsets(cpuSolverData->m_device,adl::SolverBase::N_SPLIT*adl::SolverBase::N_SPLIT); - - { - BT_PROFILE("gpu->cpu read m_numConstraints"); - dataGPU->m_numConstraints->read(numConstraints.m_ptr,adl::SolverBase::N_SPLIT*adl::SolverBase::N_SPLIT); - dataGPU->m_offsets->read(offsets.m_ptr,adl::SolverBase::N_SPLIT*adl::SolverBase::N_SPLIT); - adl::DeviceUtils::waitForCompletion( data->m_device ); - } - - adl::Buffer gpunumConstraints(cpuSolverData->m_device,adl::SolverBase::N_SPLIT*adl::SolverBase::N_SPLIT); - adl::Buffer gpuoffsets(cpuSolverData->m_device,adl::SolverBase::N_SPLIT*adl::SolverBase::N_SPLIT); - - if (compareGPU) - { - adl::Buffer contactNativeCopy (data->m_device,contactNative->getSize()); - contactNativeCopy.write(*contactNative,contactNative->getSize()); - adl::DeviceUtils::waitForCompletion( data->m_device ); - - adl::Buffer tmpNumGPU(data->m_device,adl::SolverBase::N_SPLIT*adl::SolverBase::N_SPLIT); - adl::Buffer tmpOffsetGPU(data->m_device,adl::SolverBase::N_SPLIT*adl::SolverBase::N_SPLIT); - tmpNumGPU.write(numConstraints.m_ptr,adl::SolverBase::N_SPLIT*adl::SolverBase::N_SPLIT); - tmpOffsetGPU.write(offsets.m_ptr,adl::SolverBase::N_SPLIT*adl::SolverBase::N_SPLIT); - adl::DeviceUtils::waitForCompletion( data->m_device ); - - BT_PROFILE("gpu batchContacts"); - //adl::Solver::batchContacts( data, contactNative, nContacts, nativeSolveData->m_numConstraints, nativeSolveData->m_offsets, csCfg.m_staticIdx ); - adl::Solver::batchContacts( data, &contactNativeCopy, nContacts, &tmpNumGPU, &tmpOffsetGPU, csCfg.m_staticIdx ); - - - adl::DeviceUtils::waitForCompletion( data->m_device ); - - //compare now - tmpNumGPU.read(gpunumConstraints,adl::SolverBase::N_SPLIT*adl::SolverBase::N_SPLIT); - tmpOffsetGPU.read(gpuoffsets,adl::SolverBase::N_SPLIT*adl::SolverBase::N_SPLIT); - adl::DeviceUtils::waitForCompletion( data->m_device ); - - } - - CPUSolveData* dataCPU = (CPUSolveData*)cpuSolverData->m_parallelSolveData; - - { - BT_PROFILE("cpu batchContacts2"); - batchContacts2( cpuSolverData, contactNative, nContacts, &numConstraints, &offsets, csCfg.m_staticIdx ); - } - - - if (compareGPU) - { - adl::DeviceUtils::waitForCompletion( data->m_device ); - dataGPU->m_numConstraints->write(numConstraints.m_ptr,adl::SolverBase::N_SPLIT*adl::SolverBase::N_SPLIT); - dataGPU->m_offsets->write(offsets.m_ptr,adl::SolverBase::N_SPLIT*adl::SolverBase::N_SPLIT); - adl::DeviceUtils::waitForCompletion( data->m_device ); - - - for (int i=0;i::convertToConstraints( data, bodyBuf, shapeBuf, contactNative, contactCOut, additionalData, nContacts, csCfg ); - adl::DeviceUtils::waitForCompletion( data->m_device ); - } - if (compareGPU) - { - adl::Buffer contactNativeCPU(cpuSolverData->m_device,contactNative->getSize()); - contactNative->read(contactNativeCPU,nContacts); - adl::DeviceUtils::waitForCompletion( data->m_device ); - for (int i=0;i::reorderConvertToConstraints( - m_internalData->m_solverDataGPU, - m_internalData->m_bodyBufferGPU, - m_internalData->m_inertiaBufferGPU, - m_internalData->m_pBufContactOutGPU, - m_internalData->m_contactCGPU, - m_internalData->m_frictionCGPU, - nContactOut, - csCfg ); - adl::DeviceUtils::waitForCompletion( m_internalData->m_deviceCL ); - } - - - if (1) - { - BT_PROFILE("GPU solveContactConstraint"); - m_internalData->m_solverDataGPU->m_nIterations = 5; - - adl::Solver::solveContactConstraint( m_internalData->m_solverDataGPU, - m_internalData->m_bodyBufferGPU, - m_internalData->m_inertiaBufferGPU, - m_internalData->m_contactCGPU, - 0, - nContactOut ); - - adl::DeviceUtils::waitForCompletion( m_internalData->m_deviceCL ); - } - - if (cpuSolverData) - adl::Solver::deallocate( cpuSolverData ); - - if (0) - { - BT_PROFILE("read body velocities back to CPU"); - //read body updated linear/angular velocities back to CPU - m_internalData->m_bodyBufferGPU->read( - m_internalData->m_bodyBufferCPU->m_ptr,numOfConvexRBodies); - adl::DeviceUtils::waitForCompletion( m_internalData->m_deviceCL ); - } - } - -} diff --git a/Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline/btGpuNarrowPhaseAndSolver.h b/Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline/btGpuNarrowPhaseAndSolver.h deleted file mode 100644 index 9d5941334..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline/btGpuNarrowPhaseAndSolver.h +++ /dev/null @@ -1,72 +0,0 @@ -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Erwin Coumans - -#ifndef GPU_NARROWPHASE_SOLVER_H -#define GPU_NARROWPHASE_SOLVER_H - - - -//#define MAX_CONVEX_BODIES_CL 8*1024 -#define MAX_CONVEX_BODIES_CL 128*1024 -#define MAX_PAIRS_PER_BODY_CL 16 -#define MAX_CONVEX_SHAPES_CL 8192 -#define MAX_BROADPHASE_COLLISION_CL (MAX_CONVEX_BODIES_CL*MAX_PAIRS_PER_BODY_CL) - -/* -#define MAX_CONVEX_BODIES_CL 1024 -#define MAX_PAIRS_PER_BODY_CL 32 -#define MAX_CONVEX_SHAPES_CL 8192 -#define MAX_BROADPHASE_COLLISION_CL (MAX_CONVEX_BODIES_CL*MAX_PAIRS_PER_BODY_CL) -*/ - -namespace adl -{ - struct DeviceCL; -}; - - -struct CustomDispatchData; - -#include "../basic_initialize/btOpenCLInclude.h" - - -class btGpuNarrowphaseAndSolver -{ -protected: - - CustomDispatchData* m_internalData; - int m_acceleratedCompanionShapeIndex; - int m_planeBodyIndex; - -public: - btGpuNarrowphaseAndSolver(adl::DeviceCL* deviceCL); - - virtual ~btGpuNarrowphaseAndSolver(void); - - int registerShape(class ConvexHeightField* convexShape); - int registerRigidBody(int shapeIndex, float mass, const float* position, const float* orientation, bool writeToGpu = true); - void writeAllBodiesToGpu(); - - //btBroadphasePair* GetPair(btBroadphasePairArray& pairArray, int idxBodyA, int idxBodyB); - - virtual void computeContactsAndSolver(cl_mem broadphasePairs, int numBroadphasePairs); - - cl_mem getBodiesGpu(); - - cl_mem getBodyInertiasGpu(); - -}; - -#endif //GPU_NARROWPHASE_SOLVER_H diff --git a/Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline/main.cpp b/Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline/main.cpp deleted file mode 100644 index 07dfc82b2..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline/main.cpp +++ /dev/null @@ -1,1775 +0,0 @@ -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Erwin Coumans - - -int NUM_OBJECTS_X = 54; -int NUM_OBJECTS_Y = 35; -int NUM_OBJECTS_Z = 54; - -float X_GAP = 12.f; -float Y_GAP = 2.f; -float Z_GAP = 2.f; - -int preferredGPU = -1; -int preferredPlatform=-1; -int USE_GL_CL_INTEROP=1; -extern int gpuBatchContacts; - - -#include -#include - -#include "btGlutInclude.h" -#include "../opengl_interop/btStopwatch.h" -#include "../../dynamics/basic_demo/ConvexHeightFieldShape.h" -#include "../../dynamics/basic_demo/Stubs/AdlRigidBody.h" - -#include "btGpuNarrowphaseAndSolver.h" - -#include "LinearMath/btQuickprof.h" - -#include "LinearMath/btVector3.h" -#include "LinearMath/btQuaternion.h" -#include "LinearMath/btMatrix3x3.h" -static float sAngle(0); - -#include - -#ifdef _WIN32 -#include -#endif - -#include -#include -#include "../3dGridBroadphase/Shared/btGpu3DGridBroadphase.h" -#include "../3dGridBroadphase/Shared/bt3dGridBroadphaseOCL.h" -#include "../broadphase_benchmark/btGridBroadphaseCl.h" -#include "btConvexUtility.h" - -#define USE_NEW -#ifdef USE_NEW -btGridBroadphaseCl* sBroadphase=0; -#else -btGpu3DGridBroadphase* sBroadphase=0; -#endif - -btAlignedObjectArray proxyArray; - -int gShapeIndex=0; - - -#define RS_SCALE (1.0 / (1.0 + RAND_MAX)) - - -int randbiased (double x) { - for (;;) { - double p = rand () * RS_SCALE; - if (p >= x) return 0; - if (p+RS_SCALE <= x) return 1; - /* p < x < p+RS_SCALE */ - x = (x - p) * (1.0 + RAND_MAX); - } -} - -size_t randrange (size_t n) -{ - double xhi; - double resolution = n * RS_SCALE; - double x = resolution * rand (); /* x in [0,n) */ - size_t lo = (size_t) floor (x); - - xhi = x + resolution; - - for (;;) { - lo++; - if (lo >= xhi || randbiased ((lo - x) / (xhi - x))) return lo-1; - x = lo; - } -} - -//OpenCL stuff -#include "../basic_initialize/btOpenCLUtils.h" -#include "../opengl_interop/btOpenCLGLInteropBuffer.h" - -#include "../broadphase_benchmark/findPairsOpenCL.h" - -btFindPairsIO gFpIO; - -cl_context g_cxMainContext; -cl_command_queue g_cqCommandQue; -cl_device_id g_device; - -cl_mem gLinVelMem; -cl_mem gAngVelMem; -cl_mem gBodyTimes; - -btVector3 m_cameraPosition(142,20,142); -btVector3 m_cameraTargetPosition(0,10,0); -btScalar m_cameraDistance = 55; -btVector3 m_cameraUp(0,1,0); -float m_azi=30.f; -float m_ele=5.f; - - - - -btOpenCLGLInteropBuffer* g_interopBuffer = 0; -cl_mem clBuffer=0; -char* hostPtr=0; -cl_bool blocking= CL_TRUE; - - -cl_kernel g_integrateTransformsKernel; - - - -////for Adl -#include - -adl::DeviceCL* g_deviceCL=0; - - - -bool useCPU = false; -bool printStats = true; -bool runOpenCLKernels = true; - -#define MSTRINGIFY(A) #A -static char* interopKernelString = -#include "../broadphase_benchmark/integrateKernel.cl" - -#define INTEROPKERNEL_SRC_PATH "../../opencl/broadphase_benchmark/integrateKernel.cl" - - -ConvexHeightField* s_convexHeightField = 0 ; -btGpuNarrowphaseAndSolver* narrowphaseAndSolver =0; - - -btStopwatch gStopwatch; -int m_glutScreenWidth = 640; -int m_glutScreenHeight= 480; - -bool m_ortho = false; - -static GLuint instancingShader; // The instancing renderer -static GLuint cube_vao; -static GLuint cube_vbo; -static GLuint index_vbo; -static GLuint m_texturehandle; - -static bool done = false; -static GLint angle_loc = 0; -static GLint ModelViewMatrix; -static GLint ProjectionMatrix; - -void writeTransforms(); - -static GLint uniform_texture_diffuse = 0; - -//used for dynamic loading from disk (default switched off) -#define MAX_SHADER_LENGTH 8192 -static GLubyte shaderText[MAX_SHADER_LENGTH]; - -static const char* vertexShader= \ -"#version 330\n" -"precision highp float;\n" -"\n" -"\n" -"\n" -"layout (location = 0) in vec4 position;\n" -"layout (location = 1) in vec4 instance_position;\n" -"layout (location = 2) in vec4 instance_quaternion;\n" -"layout (location = 3) in vec2 uvcoords;\n" -"layout (location = 4) in vec3 vertexnormal;\n" -"layout (location = 5) in vec4 instance_color;\n" -"layout (location = 6) in vec3 instance_scale;\n" -"\n" -"\n" -"uniform float angle = 0.0;\n" -"uniform mat4 ModelViewMatrix;\n" -"uniform mat4 ProjectionMatrix;\n" -"\n" -"out Fragment\n" -"{\n" -" vec4 color;\n" -"} fragment;\n" -"\n" -"out Vert\n" -"{\n" -" vec2 texcoord;\n" -"} vert;\n" -"\n" -"\n" -"vec4 quatMul ( in vec4 q1, in vec4 q2 )\n" -"{\n" -" vec3 im = q1.w * q2.xyz + q1.xyz * q2.w + cross ( q1.xyz, q2.xyz );\n" -" vec4 dt = q1 * q2;\n" -" float re = dot ( dt, vec4 ( -1.0, -1.0, -1.0, 1.0 ) );\n" -" return vec4 ( im, re );\n" -"}\n" -"\n" -"vec4 quatFromAxisAngle(vec4 axis, in float angle)\n" -"{\n" -" float cah = cos(angle*0.5);\n" -" float sah = sin(angle*0.5);\n" -" float d = inversesqrt(dot(axis,axis));\n" -" vec4 q = vec4(axis.x*sah*d,axis.y*sah*d,axis.z*sah*d,cah);\n" -" return q;\n" -"}\n" -"//\n" -"// vector rotation via quaternion\n" -"//\n" -"vec4 quatRotate3 ( in vec3 p, in vec4 q )\n" -"{\n" -" vec4 temp = quatMul ( q, vec4 ( p, 0.0 ) );\n" -" return quatMul ( temp, vec4 ( -q.x, -q.y, -q.z, q.w ) );\n" -"}\n" -"vec4 quatRotate ( in vec4 p, in vec4 q )\n" -"{\n" -" vec4 temp = quatMul ( q, p );\n" -" return quatMul ( temp, vec4 ( -q.x, -q.y, -q.z, q.w ) );\n" -"}\n" -"\n" -"out vec3 lightDir,normal,ambient;\n" -"\n" -"void main(void)\n" -"{\n" -" vec4 q = instance_quaternion;\n" -" ambient = vec3(0.3,.3,0.3);\n" -" \n" -" \n" -" vec4 local_normal = (quatRotate3( vertexnormal,q));\n" -" vec3 light_pos = vec3(-0.8,1,-0.6);\n" -" normal = local_normal.xyz;\n"//normalize(ModelViewMatrix * local_normal).xyz;\n" -"\n" -" lightDir = normalize(light_pos);//gl_LightSource[0].position.xyz));\n" -"// lightDir = normalize(vec3(gl_LightSource[0].position));\n" -" \n" -" vec4 axis = vec4(1,1,1,0);\n" -" vec4 localcoord = quatRotate3( position.xyz*instance_scale,q);\n" -" vec4 vertexPos = ProjectionMatrix * ModelViewMatrix *(instance_position+localcoord);\n" -"\n" -" gl_Position = vertexPos;\n" -" \n" -" fragment.color = instance_color;\n" -" vert.texcoord = uvcoords;\n" -"}\n" -; - - -static const char* fragmentShader= \ -"#version 330\n" -"precision highp float;\n" -"\n" -"in Fragment\n" -"{\n" -" vec4 color;\n" -"} fragment;\n" -"\n" -"in Vert\n" -"{\n" -" vec2 texcoord;\n" -"} vert;\n" -"\n" -"uniform sampler2D Diffuse;\n" -"\n" -"in vec3 lightDir,normal,ambient;\n" -"\n" -"out vec4 color;\n" -"\n" -"void main_textured(void)\n" -"{\n" -" color = texture2D(Diffuse,vert.texcoord);//fragment.color;\n" -"}\n" -"\n" -"void main(void)\n" -"{\n" -" vec4 texel = fragment.color*texture2D(Diffuse,vert.texcoord);//fragment.color;\n" -" vec3 ct,cf;\n" -" float intensity,at,af;\n" -" intensity = max(dot(lightDir,normalize(normal)),.2);\n" -" cf = intensity*vec3(1.0,1.0,1.0)+ambient;" -" af = 1.0;\n" -" \n" -" ct = texel.rgb;\n" -" at = texel.a;\n" -" \n" -" color = vec4(ct * cf, at * af); \n" -"}\n" -; - - -// Load the shader from the source text -void gltLoadShaderSrc(const char *szShaderSrc, GLuint shader) -{ - GLchar *fsStringPtr[1]; - - fsStringPtr[0] = (GLchar *)szShaderSrc; - glShaderSource(shader, 1, (const GLchar **)fsStringPtr, NULL); -} - - -//////////////////////////////////////////////////////////////// -// Load the shader from the specified file. Returns false if the -// shader could not be loaded -bool gltLoadShaderFile(const char *szFile, GLuint shader) -{ - GLint shaderLength = 0; - FILE *fp; - - // Open the shader file - fp = fopen(szFile, "r"); - if(fp != NULL) - { - // See how long the file is - while (fgetc(fp) != EOF) - shaderLength++; - - // Allocate a block of memory to send in the shader - assert(shaderLength < MAX_SHADER_LENGTH); // make me bigger! - if(shaderLength > MAX_SHADER_LENGTH) - { - fclose(fp); - return false; - } - - // Go back to beginning of file - rewind(fp); - - // Read the whole file in - if (shaderText != NULL) - fread(shaderText, 1, shaderLength, fp); - - // Make sure it is null terminated and close the file - shaderText[shaderLength] = '\0'; - fclose(fp); - } - else - return false; - - // printf(shaderText); - // Load the string - gltLoadShaderSrc((const char *)shaderText, shader); - - return true; -} - - -///////////////////////////////////////////////////////////////// -// Load a pair of shaders, compile, and link together. Specify the complete -// file path for each shader. Note, there is no support for -// just loading say a vertex program... you have to do both. -GLuint gltLoadShaderPair(const char *szVertexProg, const char *szFragmentProg, bool loadFromFile) -{ - // Temporary Shader objects - GLuint hVertexShader; - GLuint hFragmentShader; - GLuint hReturn = 0; - GLint testVal; - - // Create shader objects - hVertexShader = glCreateShader(GL_VERTEX_SHADER); - hFragmentShader = glCreateShader(GL_FRAGMENT_SHADER); - - if (loadFromFile) - { - - if(gltLoadShaderFile(szVertexProg, hVertexShader) == false) - { - glDeleteShader(hVertexShader); - glDeleteShader(hFragmentShader); - return (GLuint)NULL; - } - - if(gltLoadShaderFile(szFragmentProg, hFragmentShader) == false) - { - glDeleteShader(hVertexShader); - glDeleteShader(hFragmentShader); - return (GLuint)NULL; - } - } else - { - gltLoadShaderSrc(vertexShader, hVertexShader); - gltLoadShaderSrc(fragmentShader, hFragmentShader); - } - // Compile them - glCompileShader(hVertexShader); - glCompileShader(hFragmentShader); - - // Check for errors - glGetShaderiv(hVertexShader, GL_COMPILE_STATUS, &testVal); - if(testVal == GL_FALSE) - { - char temp[256] = ""; - glGetShaderInfoLog( hVertexShader, 256, NULL, temp); - fprintf( stderr, "Compile failed:\n%s\n", temp); - assert(0); - exit(0); - glDeleteShader(hVertexShader); - glDeleteShader(hFragmentShader); - return (GLuint)NULL; - } - - glGetShaderiv(hFragmentShader, GL_COMPILE_STATUS, &testVal); - if(testVal == GL_FALSE) - { - char temp[256] = ""; - glGetShaderInfoLog( hFragmentShader, 256, NULL, temp); - fprintf( stderr, "Compile failed:\n%s\n", temp); - assert(0); - exit(0); - glDeleteShader(hVertexShader); - glDeleteShader(hFragmentShader); - return (GLuint)NULL; - } - - // Link them - assuming it works... - hReturn = glCreateProgram(); - glAttachShader(hReturn, hVertexShader); - glAttachShader(hReturn, hFragmentShader); - - glLinkProgram(hReturn); - - // These are no longer needed - glDeleteShader(hVertexShader); - glDeleteShader(hFragmentShader); - - // Make sure link worked too - glGetProgramiv(hReturn, GL_LINK_STATUS, &testVal); - if(testVal == GL_FALSE) - { - glDeleteProgram(hReturn); - return (GLuint)NULL; - } - - return hReturn; -} - -///position xyz, unused w, normal, uv -static const GLfloat cube_vertices[] = -{ - -1.0f, -1.0f, 1.0f, 0.0f, 0,0,1, 0,0,//0 - 1.0f, -1.0f, 1.0f, 0.0f, 0,0,1, 1,0,//1 - 1.0f, 1.0f, 1.0f, 0.0f, 0,0,1, 1,1,//2 - -1.0f, 1.0f, 1.0f, 0.0f, 0,0,1, 0,1 ,//3 - - -1.0f, -1.0f, -1.0f, 1.0f, 0,0,-1, 0,0,//4 - 1.0f, -1.0f, -1.0f, 1.0f, 0,0,-1, 1,0,//5 - 1.0f, 1.0f, -1.0f, 1.0f, 0,0,-1, 1,1,//6 - -1.0f, 1.0f, -1.0f, 1.0f, 0,0,-1, 0,1,//7 - - -1.0f, -1.0f, -1.0f, 1.0f, -1,0,0, 0,0, - -1.0f, 1.0f, -1.0f, 1.0f, -1,0,0, 1,0, - -1.0f, 1.0f, 1.0f, 1.0f, -1,0,0, 1,1, - -1.0f, -1.0f, 1.0f, 1.0f, -1,0,0, 0,1, - - 1.0f, -1.0f, -1.0f, 1.0f, 1,0,0, 0,0, - 1.0f, 1.0f, -1.0f, 1.0f, 1,0,0, 1,0, - 1.0f, 1.0f, 1.0f, 1.0f, 1,0,0, 1,1, - 1.0f, -1.0f, 1.0f, 1.0f, 1,0,0, 0,1, - - -1.0f, -1.0f, -1.0f, 1.0f, 0,-1,0, 0,0, - -1.0f, -1.0f, 1.0f, 1.0f, 0,-1,0, 1,0, - 1.0f, -1.0f, 1.0f, 1.0f, 0,-1,0, 1,1, - 1.0f,-1.0f, -1.0f, 1.0f, 0,-1,0, 0,1, - - -1.0f, 1.0f, -1.0f, 1.0f, 0,1,0, 0,0, - -1.0f, 1.0f, 1.0f, 1.0f, 0,1,0, 1,0, - 1.0f, 1.0f, 1.0f, 1.0f, 0,1,0, 1,1, - 1.0f,1.0f, -1.0f, 1.0f, 0,1,0, 0,1, -}; - -static const int cube_indices[]= -{ - 0,1,2,0,2,3,//ground face - 4,5,6,4,6,7,//top face - 8,9,10,8,10,11, - 12,13,14,12,14,15, - 16,17,18,16,18,19, - 20,21,22,20,22,23 -}; - -int m_mouseOldX = -1; -int m_mouseOldY = -1; -int m_mouseButtons = 0; - - -void mouseFunc(int button, int state, int x, int y) -{ - if (state == 0) - { - m_mouseButtons |= 1<0) - { - g_device= btOpenCLUtils::getDevice(g_cxMainContext,0); - btOpenCLDeviceInfo clInfo; - btOpenCLUtils::getDeviceInfo(g_device,clInfo); - btOpenCLUtils::printDeviceInfo(g_device); - // create a command-queue - g_cqCommandQue = clCreateCommandQueue(g_cxMainContext, g_device, 0, &ciErrNum); - oclCHECKERROR(ciErrNum, CL_SUCCESS); - //normally you would create and execute kernels using this command queue - - } - - -} - -int NUM_OBJECTS = NUM_OBJECTS_X*NUM_OBJECTS_Y*NUM_OBJECTS_Z; -int POSITION_BUFFER_SIZE = (NUM_OBJECTS*sizeof(float)*4); -int ORIENTATION_BUFFER_SIZE = (NUM_OBJECTS*sizeof(float)*4); -int COLOR_BUFFER_SIZE = (NUM_OBJECTS*sizeof(float)*4); -int SCALE_BUFFER_SIZE = (NUM_OBJECTS*sizeof(float)*3); - -int VBOsize =0; - - -GLfloat* instance_positions_ptr = 0; -GLfloat* instance_quaternion_ptr = 0; -GLfloat* instance_colors_ptr = 0; -GLfloat* instance_scale_ptr= 0; - - -void DeleteShaders() -{ - glDeleteVertexArrays(1, &cube_vao); - glDeleteBuffers(1,&index_vbo); - glDeleteBuffers(1,&cube_vbo); - glDeleteProgram(instancingShader); -} - - -void InitShaders() -{ - - btOverlappingPairCache* overlappingPairCache=0; - int maxObjects = btMax(256,NUM_OBJECTS); -#ifdef USE_NEW - int maxPairsSmallProxy = 32; - - sBroadphase = new btGridBroadphaseCl(overlappingPairCache,btVector3(4.f, 4.f, 4.f), 128, 128, 128,maxObjects, maxObjects, maxPairsSmallProxy, 100.f, 128, - g_cxMainContext ,g_device,g_cqCommandQue, g_deviceCL); -#else - sBroadphase = new btGpu3DGridBroadphase(btVector3(2.f, 2.f, 2.f), 32, 32, 32,maxObjects, maxObjects, 64, 100.f, 64); -#endif - - - -// sBroadphase = new bt3dGridBroadphaseOCL(overlappingPairCache,btVector3(10.f, 10.f, 10.f), 32, 32, 32,NUM_OBJECTS, NUM_OBJECTS, 64, 100.f, 16, -// g_cxMainContext ,g_device,g_cqCommandQue); - - - - bool loadFromFile = false; - instancingShader = gltLoadShaderPair("instancing.vs","instancing.fs", loadFromFile); - - glLinkProgram(instancingShader); - glUseProgram(instancingShader); - angle_loc = glGetUniformLocation(instancingShader, "angle"); - ModelViewMatrix = glGetUniformLocation(instancingShader, "ModelViewMatrix"); - ProjectionMatrix = glGetUniformLocation(instancingShader, "ProjectionMatrix"); - uniform_texture_diffuse = glGetUniformLocation(instancingShader, "Diffuse"); - - GLuint offset = 0; - - - glGenBuffers(1, &cube_vbo); - glBindBuffer(GL_ARRAY_BUFFER, cube_vbo); - - instance_positions_ptr = (GLfloat*)new float[NUM_OBJECTS*4]; - instance_quaternion_ptr = (GLfloat*)new float[NUM_OBJECTS*4]; - instance_colors_ptr = (GLfloat*)new float[NUM_OBJECTS*4]; - instance_scale_ptr = (GLfloat*)new float[NUM_OBJECTS*3]; - - - - int index=0; - for (int i=0;icreateProxy(aabbMin,aabbMax,shapeType,myptr,1,1,0,0);//m_dispatcher); - proxyArray.push_back(proxy); - - instance_quaternion_ptr[index*4]=0; - instance_quaternion_ptr[index*4+1]=0; - instance_quaternion_ptr[index*4+2]=0; - instance_quaternion_ptr[index*4+3]=1; - - instance_colors_ptr[index*4]=jregisterRigidBody(gShapeIndex,mass,&instance_positions_ptr[index*4],&instance_quaternion_ptr[index*4],writeToGpu); - - index++; - } - } - } - - float posZero[4] = {0,-NUM_OBJECTS_Y/2-1,0,0}; - float ornZero[4] = {0,0,0,1}; - - //register a 'plane' - if (narrowphaseAndSolver) - narrowphaseAndSolver->registerRigidBody(-1, 0.f, posZero,ornZero,false); - - - - if (narrowphaseAndSolver) - narrowphaseAndSolver->writeAllBodiesToGpu(); - - - int size = sizeof(cube_vertices) + POSITION_BUFFER_SIZE+ORIENTATION_BUFFER_SIZE+COLOR_BUFFER_SIZE+SCALE_BUFFER_SIZE; - VBOsize = size; - - char* bla = (char*)malloc(size); - int szc = sizeof(cube_vertices); - memcpy(bla,&cube_vertices[0],szc); - memcpy(bla+sizeof(cube_vertices),instance_positions_ptr,POSITION_BUFFER_SIZE); - memcpy(bla+sizeof(cube_vertices)+POSITION_BUFFER_SIZE,instance_quaternion_ptr,ORIENTATION_BUFFER_SIZE); - memcpy(bla+sizeof(cube_vertices)+POSITION_BUFFER_SIZE+ORIENTATION_BUFFER_SIZE,instance_colors_ptr, COLOR_BUFFER_SIZE); - memcpy(bla+sizeof(cube_vertices)+POSITION_BUFFER_SIZE+ORIENTATION_BUFFER_SIZE+COLOR_BUFFER_SIZE,instance_scale_ptr, SCALE_BUFFER_SIZE); - - glBufferData(GL_ARRAY_BUFFER, size, bla, GL_DYNAMIC_DRAW);//GL_STATIC_DRAW); - - ///initialize parts of the buffer -#ifdef _USE_SUB_DATA - glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(cube_vertices)+ 16384, bla);//cube_vertices); -#endif - - char* dest= (char*)glMapBuffer( GL_ARRAY_BUFFER,GL_WRITE_ONLY);//GL_WRITE_ONLY - memcpy(dest,cube_vertices,sizeof(cube_vertices)); - //memcpy(dest+sizeof(cube_vertices),instance_colors,sizeof(instance_colors)); - glUnmapBuffer( GL_ARRAY_BUFFER); - - - - writeTransforms(); - - /* - glBufferSubData(GL_ARRAY_BUFFER, sizeof(cube_vertices) + sizeof(instance_colors), POSITION_BUFFER_SIZE, instance_positions_ptr); - glBufferSubData(GL_ARRAY_BUFFER, sizeof(cube_vertices) + sizeof(instance_colors)+POSITION_BUFFER_SIZE,ORIENTATION_BUFFER_SIZE , instance_quaternion_ptr); - */ - - glGenVertexArrays(1, &cube_vao); - glBindVertexArray(cube_vao); - glBindBuffer(GL_ARRAY_BUFFER, cube_vbo); - glBindVertexArray(0); - - glGenBuffers(1, &index_vbo); - int indexBufferSize = sizeof(cube_indices); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_vbo); - - glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexBufferSize, NULL, GL_STATIC_DRAW); - glBufferSubData(GL_ELEMENT_ARRAY_BUFFER,0,indexBufferSize,cube_indices); - - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - glBindBuffer(GL_ARRAY_BUFFER,0); - glBindVertexArray(0); - -} - - - -void updateCamera() -{ - - - - btVector3 m_cameraUp(0,1,0); - int m_forwardAxis=2; - - - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - - btScalar rele = m_ele * btScalar(0.01745329251994329547);// rads per deg - btScalar razi = m_azi * btScalar(0.01745329251994329547);// rads per deg - - - btQuaternion rot(m_cameraUp,razi); - - - btVector3 eyePos(0,0,0); - eyePos[m_forwardAxis] = -m_cameraDistance; - - btVector3 forward(eyePos[0],eyePos[1],eyePos[2]); - if (forward.length2() < SIMD_EPSILON) - { - forward.setValue(1.f,0.f,0.f); - } - btVector3 right = m_cameraUp.cross(forward); - btQuaternion roll(right,-rele); - - eyePos = btMatrix3x3(rot) * btMatrix3x3(roll) * eyePos; - - m_cameraPosition[0] = eyePos.getX(); - m_cameraPosition[1] = eyePos.getY(); - m_cameraPosition[2] = eyePos.getZ(); - m_cameraPosition += m_cameraTargetPosition; - - - float m_frustumZNear=1; - float m_frustumZFar=1000; - - if (m_glutScreenWidth == 0 && m_glutScreenHeight == 0) - return; - - float aspect; - btVector3 extents; - - if (m_glutScreenWidth > m_glutScreenHeight) - { - aspect = m_glutScreenWidth / (float)m_glutScreenHeight; - extents.setValue(aspect * 1.0f, 1.0f,0); - } else - { - aspect = m_glutScreenHeight / (float)m_glutScreenWidth; - extents.setValue(1.0f, aspect*1.f,0); - } - - - if (m_ortho) - { - // reset matrix - glLoadIdentity(); - extents *= m_cameraDistance; - btVector3 lower = m_cameraTargetPosition - extents; - btVector3 upper = m_cameraTargetPosition + extents; - glOrtho(lower.getX(), upper.getX(), lower.getY(), upper.getY(),-1000,1000); - - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - } else - { - if (m_glutScreenWidth > m_glutScreenHeight) - { - glFrustum (-aspect * m_frustumZNear, aspect * m_frustumZNear, -m_frustumZNear, m_frustumZNear, m_frustumZNear, m_frustumZFar); - } else - { - glFrustum (-aspect * m_frustumZNear, aspect * m_frustumZNear, -m_frustumZNear, m_frustumZNear, m_frustumZNear, m_frustumZFar); - } - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - gluLookAt(m_cameraPosition[0], m_cameraPosition[1], m_cameraPosition[2], - m_cameraTargetPosition[0], m_cameraTargetPosition[1], m_cameraTargetPosition[2], - m_cameraUp.getX(),m_cameraUp.getY(),m_cameraUp.getZ()); - } - -} - - - -void myinit() -{ - GLint err = glGetError(); - - // GLfloat light_ambient[] = { btScalar(0.2), btScalar(0.2), btScalar(0.2), btScalar(1.0) }; - GLfloat light_ambient[] = { btScalar(1.0), btScalar(1.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 )}; - /* light_position is NOT default value */ - GLfloat light_position0[] = { btScalar(10000.0), btScalar(10000.0), btScalar(10000.0), btScalar(0.0 )}; - GLfloat light_position1[] = { btScalar(-1.0), btScalar(-10.0), btScalar(-1.0), btScalar(0.0) }; - - glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient); - glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse); - glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular); - glLightfv(GL_LIGHT0, GL_POSITION, light_position0); - - glLightfv(GL_LIGHT1, GL_AMBIENT, light_ambient); - glLightfv(GL_LIGHT1, GL_DIFFUSE, light_diffuse); - glLightfv(GL_LIGHT1, GL_SPECULAR, light_specular); - glLightfv(GL_LIGHT1, GL_POSITION, light_position1); - - glEnable(GL_LIGHTING); - glEnable(GL_LIGHT0); - glEnable(GL_LIGHT1); - - - // glShadeModel(GL_FLAT);//GL_SMOOTH); - glShadeModel(GL_SMOOTH); - - glEnable(GL_DEPTH_TEST); - glDepthFunc(GL_LESS); - - glClearColor(float(0.7),float(0.7),float(0.7),float(0)); - glEnable(GL_LIGHTING); - glEnable(GL_LIGHT0); - - - static bool m_textureenabled = true; - static bool m_textureinitialized = false; - - - if(m_textureenabled) - { - if(!m_textureinitialized) - { - glActiveTexture(GL_TEXTURE0); - - GLubyte* image=new GLubyte[256*256*3]; - for(int y=0;y<256;++y) - { - const int t=y>>5; - GLubyte* pi=image+y*256*3; - for(int x=0;x<256;++x) - { - if (x<2||y<2||x>253||y>253) - { - pi[0]=0; - pi[1]=0; - pi[2]=0; - } else - { - pi[0]=255; - pi[1]=255; - pi[2]=255; - } - - /* - const int s=x>>5; - const GLubyte b=180; - GLubyte c=b+((s+t&1)&1)*(255-b); - pi[0]=c; - pi[1]=c; - pi[2]=c; - */ - - pi+=3; - } - } - - glGenTextures(1,(GLuint*)&m_texturehandle); - glBindTexture(GL_TEXTURE_2D,m_texturehandle); - glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE); - glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR); - glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); - glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT); - glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT); - gluBuild2DMipmaps(GL_TEXTURE_2D,3,256,256,GL_RGB,GL_UNSIGNED_BYTE,image); - delete[] image; - m_textureinitialized=true; - } - // glMatrixMode(GL_TEXTURE); - // glLoadIdentity(); - // glMatrixMode(GL_MODELVIEW); - - glEnable(GL_TEXTURE_2D); - glBindTexture(GL_TEXTURE_2D,m_texturehandle); - - } else - { - glDisable(GL_TEXTURE_2D); - } - - glEnable(GL_COLOR_MATERIAL); - - err = glGetError(); - assert(err==GL_NO_ERROR); - - // glEnable(GL_CULL_FACE); - // glCullFace(GL_BACK); -} - -//#pragma optimize( "g", off ) - - - -void writeTransforms() -{ - - - glFlush(); - char* bla = (char*)glMapBuffer( GL_ARRAY_BUFFER,GL_READ_WRITE);//GL_WRITE_ONLY - - float* positions = (float*)(bla+sizeof(cube_vertices)); - float* orientations = (float*)(bla+sizeof(cube_vertices) + POSITION_BUFFER_SIZE); - float* colors= (float*)(bla+sizeof(cube_vertices) + POSITION_BUFFER_SIZE+ORIENTATION_BUFFER_SIZE); - float* scaling= (float*)(bla+sizeof(cube_vertices) + POSITION_BUFFER_SIZE+ORIENTATION_BUFFER_SIZE+COLOR_BUFFER_SIZE); - - // positions[0]+=0.001f; - - static int offset=0; - //offset++; - - static btVector3 axis(1,0,0); - sAngle += 0.01f; - int index=0; - btQuaternion orn(axis,sAngle); - for (int i=0;igetCLBUffer(); - BT_PROFILE("clEnqueueAcquireGLObjects"); - ciErrNum = clEnqueueAcquireGLObjects(g_cqCommandQue, 1, &clBuffer, 0, 0, NULL); - adl::DeviceUtils::waitForCompletion( g_deviceCL ); - } else - { - - BT_PROFILE("glMapBuffer and clEnqueueWriteBuffer"); - - blocking= CL_TRUE; - hostPtr= (char*)glMapBuffer( GL_ARRAY_BUFFER,GL_READ_WRITE);//GL_WRITE_ONLY - if (!clBuffer) - { - clBuffer = clCreateBuffer(g_cxMainContext, CL_MEM_READ_WRITE, VBOsize, 0, &ciErrNum); - } - adl::DeviceUtils::waitForCompletion( g_deviceCL ); - ciErrNum = clEnqueueWriteBuffer ( g_cqCommandQue, - clBuffer, - blocking, - 0, - VBOsize, - hostPtr,0,0,0 - ); - adl::DeviceUtils::waitForCompletion( g_deviceCL ); - } - - - - oclCHECKERROR(ciErrNum, CL_SUCCESS); - if (runOpenCLKernels) - { - -#ifdef USE_NEW - gFpIO.m_numObjects = NUM_OBJECTS; - gFpIO.m_positionOffset = (sizeof(cube_vertices) )/4; - gFpIO.m_clObjectsBuffer = clBuffer; - gFpIO.m_dAABB = sBroadphase->m_dAABB; - - - { - BT_PROFILE("setupGpuAabbs"); - setupGpuAabbsSimple(gFpIO); - } - { - BT_PROFILE("calculateOverlappingPairs"); - sBroadphase->calculateOverlappingPairs(0, NUM_OBJECTS); - } - gFpIO.m_dAllOverlappingPairs = sBroadphase->m_dAllOverlappingPairs; - gFpIO.m_numOverlap = sBroadphase->m_numPrefixSum; - //printf("gFpIO.m_numOverlap = %d\n",gFpIO.m_numOverlap ); - if (gFpIO.m_numOverlap>=0 && gFpIO.m_numOverlapgetBodiesGpu(), narrowphaseAndSolver->getBodyInertiasGpu()); - } - if (gFpIO.m_numOverlap) - { - BT_PROFILE("computeContactsAndSolver"); - if (narrowphaseAndSolver) - narrowphaseAndSolver->computeContactsAndSolver(gFpIO.m_dAllOverlappingPairs,gFpIO.m_numOverlap); - } - - { - BT_PROFILE("copyBodyVelocities"); - if (narrowphaseAndSolver) - copyBodyVelocities(gFpIO, gLinVelMem, gAngVelMem, narrowphaseAndSolver->getBodiesGpu(), narrowphaseAndSolver->getBodyInertiasGpu()); - } - } else - { - printf("error, gFpIO.m_numOverlap = %d\n",gFpIO.m_numOverlap); - btAssert(0); - } - -#else - -#endif - { - BT_PROFILE("integrateTransforms"); - - if (runOpenCLKernels) - { - int numObjects = NUM_OBJECTS; - int offset = (sizeof(cube_vertices) )/4; - - ciErrNum = clSetKernelArg(g_integrateTransformsKernel, 0, sizeof(int), &offset); - ciErrNum = clSetKernelArg(g_integrateTransformsKernel, 1, sizeof(int), &numObjects); - ciErrNum = clSetKernelArg(g_integrateTransformsKernel, 2, sizeof(cl_mem), (void*)&clBuffer ); - - ciErrNum = clSetKernelArg(g_integrateTransformsKernel, 3, sizeof(cl_mem), (void*)&gLinVelMem); - ciErrNum = clSetKernelArg(g_integrateTransformsKernel, 4, sizeof(cl_mem), (void*)&gAngVelMem); - ciErrNum = clSetKernelArg(g_integrateTransformsKernel, 5, sizeof(cl_mem), (void*)&gBodyTimes); - - - - - size_t workGroupSize = 64; - size_t numWorkItems = workGroupSize*((NUM_OBJECTS + (workGroupSize)) / workGroupSize); - - if (workGroupSize>numWorkItems) - workGroupSize=numWorkItems; - - ciErrNum = clEnqueueNDRangeKernel(g_cqCommandQue, g_integrateTransformsKernel, 1, NULL, &numWorkItems, &workGroupSize,0 ,0 ,0); - oclCHECKERROR(ciErrNum, CL_SUCCESS); - } - } - - - } - - if (USE_GL_CL_INTEROP) - { - BT_PROFILE("clEnqueueReleaseGLObjects"); - ciErrNum = clEnqueueReleaseGLObjects(g_cqCommandQue, 1, &clBuffer, 0, 0, 0); - adl::DeviceUtils::waitForCompletion( g_deviceCL ); - } - else - { - BT_PROFILE("clEnqueueReadBuffer clReleaseMemObject and glUnmapBuffer"); - ciErrNum = clEnqueueReadBuffer ( g_cqCommandQue, - clBuffer, - blocking, - 0, - VBOsize, - hostPtr,0,0,0); - - //clReleaseMemObject(clBuffer); - adl::DeviceUtils::waitForCompletion( g_deviceCL ); - glUnmapBuffer( GL_ARRAY_BUFFER); - glFlush(); - } - - oclCHECKERROR(ciErrNum, CL_SUCCESS); - - - if (runOpenCLKernels) - { - BT_PROFILE("clFinish"); - clFinish(g_cqCommandQue); - } - - - - - } -} - - -//#pragma optimize( "g", on ) - - -void RenderScene(void) -{ - BT_PROFILE("GlutDisplayFunc"); - - -#if 0 - float modelview[20]={0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9}; - // get the current modelview matrix - glGetFloatv(GL_MODELVIEW_MATRIX , modelview); - float projection[20]={0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9}; - glGetFloatv(GL_PROJECTION_MATRIX, projection); -#endif - - myinit(); - - updateCamera(); - - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - //render coordinate system - glBegin(GL_LINES); - glColor3f(1,0,0); - glVertex3f(0,0,0); - glVertex3f(1,0,0); - glColor3f(0,1,0); - glVertex3f(0,0,0); - glVertex3f(0,1,0); - glColor3f(0,0,1); - glVertex3f(0,0,0); - glVertex3f(0,0,1); - glEnd(); - - //do a finish, to make sure timings are clean - // glFinish(); - - float start = gStopwatch.getTimeMilliseconds(); - - // glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ARRAY_BUFFER, cube_vbo); - glFlush(); - - //updatePos(); - - simulationLoop(); - - //useCPU = true; - - float stop = gStopwatch.getTimeMilliseconds(); - gStopwatch.reset(); - - if (0)//printStats) - { - printf("updatePos=%f ms on ",stop-start); - - if (useCPU) - { - printf("CPU \n"); - } else - { - printf("OpenCL "); - if (runOpenCLKernels) - printf("running the kernels"); - else - printf("without running the kernels"); - printf("\n"); - } - } - - glBindVertexArray(cube_vao); - - glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 9*sizeof(float), 0); - glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, (GLvoid *)(sizeof(cube_vertices))); - glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, 0, (GLvoid *)(sizeof(cube_vertices)+POSITION_BUFFER_SIZE)); - int uvoffset = 7*sizeof(float); - int normaloffset = 4*sizeof(float); - - glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, 9*sizeof(float), (GLvoid *)uvoffset); - glVertexAttribPointer(4, 3, GL_FLOAT, GL_FALSE, 9*sizeof(float), (GLvoid *)normaloffset); - glVertexAttribPointer(5, 4, GL_FLOAT, GL_FALSE, 0, (GLvoid *)(sizeof(cube_vertices)+POSITION_BUFFER_SIZE+ORIENTATION_BUFFER_SIZE)); - glVertexAttribPointer(6, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid *)(sizeof(cube_vertices)+POSITION_BUFFER_SIZE+ORIENTATION_BUFFER_SIZE+COLOR_BUFFER_SIZE)); - - glEnableVertexAttribArray(0); - glEnableVertexAttribArray(1); - glEnableVertexAttribArray(2); - glEnableVertexAttribArray(3); - glEnableVertexAttribArray(4); - glEnableVertexAttribArray(5); - glEnableVertexAttribArray(6); - - glVertexAttribDivisor(0, 0); - glVertexAttribDivisor(1, 1); - glVertexAttribDivisor(2, 1); - glVertexAttribDivisor(3, 0); - glVertexAttribDivisor(4, 0); - glVertexAttribDivisor(5, 1); - glVertexAttribDivisor(6, 1); - - glUseProgram(instancingShader); - glUniform1f(angle_loc, 0); - GLfloat pm[16]; - glGetFloatv(GL_PROJECTION_MATRIX, pm); - glUniformMatrix4fv(ProjectionMatrix, 1, false, &pm[0]); - - GLfloat mvm[16]; - glGetFloatv(GL_MODELVIEW_MATRIX, mvm); - glUniformMatrix4fv(ModelViewMatrix, 1, false, &mvm[0]); - - glUniform1i(uniform_texture_diffuse, 0); - - glFlush(); - int numInstances = NUM_OBJECTS; - int indexCount = sizeof(cube_indices)/sizeof(int); - int indexOffset = 0; - - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_vbo); - { - BT_PROFILE("glDrawElementsInstanced"); - glDrawElementsInstanced(GL_TRIANGLES, indexCount, GL_UNSIGNED_INT, (void*)indexOffset, numInstances); - } - glUseProgram(0); - glBindBuffer(GL_ARRAY_BUFFER,0); - glBindVertexArray(0); - - glutSwapBuffers(); - glutPostRedisplay(); - - GLint err = glGetError(); - assert(err==GL_NO_ERROR); -} - -extern int numPairsOut; -void mainloop(void) -{ - CProfileManager::Reset(); - RenderScene(); - CProfileManager::Increment_Frame_Counter(); - - if (printStats && runOpenCLKernels) - { - static int count = 10; - count--; - if (count<0) - { - CProfileManager::dumpAll(); - printf("total broadphase pairs= %d\n", gFpIO.m_numOverlap); - printf("numPairsOut (culled) = %d\n", numPairsOut); - - printStats = false; - } - } -} - - -void ChangeSize(int w, int h) -{ - m_glutScreenWidth = w; - m_glutScreenHeight = h; - -#ifdef RECREATE_CL_AND_SHADERS_ON_RESIZE - delete g_interopBuffer; - clReleaseKernel(g_integrateTransformsKernel); - releaseFindPairs(fpio); - DeleteCL(); - DeleteShaders(); -#endif //RECREATE_CL_AND_SHADERS_ON_RESIZE - - // Set Viewport to window dimensions - glViewport(0, 0, w, h); - -#ifdef RECREATE_CL_AND_SHADERS_ON_RESIZE - InitCL(); - InitShaders(); - - g_interopBuffer = new btOpenCLGLInteropBuffer(g_cxMainContext,g_cqCommandQue,cube_vbo); - clFinish(g_cqCommandQue); - g_integrateTransformsKernel = btOpenCLUtils::compileCLKernelFromString(g_cxMainContext, interopKernelString, "interopKernel" ); - initFindPairs(...); -#endif //RECREATE_CL_AND_SHADERS_ON_RESIZE - -} - -void Keyboard(unsigned char key, int x, int y) -{ - switch (key) - { - case 27: - done = true; - break; - case 'O': - case 'o': - { - m_ortho = !m_ortho; - break; - } - case 'c': - case 'C': - { - useCPU = !useCPU; - if (useCPU) - printf("using CPU\n"); - else - printf("using OpenCL\n"); - break; - } - case 's': - case 'S': - { - printStats = !printStats; - break; - } - case 'k': - case 'K': - { - runOpenCLKernels=!runOpenCLKernels; - break; - } - case 'q': - case 'Q': - exit(0); - default: - break; - } -} - -// Cleanup -void ShutdownRC(void) -{ - glDeleteBuffers(1, &cube_vbo); - glDeleteVertexArrays(1, &cube_vao); -} - -#include "CommandlineArgs.h" - -void Usage() -{ - printf("\nprogram.exe [--preferred_gpu=] [--batch_gpu=<0,1>] [--preferred_platform=] [--enable_interop=<0 or 1>] [--x_dim=] [--y_dim=] [--z_dim=] [--x_gap=] [--y_gap=] [--z_gap=]\n"); - printf("\n"); - printf("preferred_gpu : the index used for OpenCL, in case multiple OpenCL-capable GPU are available. This is ignored if interop is enabled"); - printf("preferred_platform : the platform index used for OpenCL, in case multiple OpenCL-capable platforms are available. This is ignored if interop is enabled"); - printf("enable_interop : Use OpenGL/OpenCL interoperability, avoiding memory copy between GPU and main memory"); - printf("batch_gpu : Use GPU to created solver batches. Set to zero to disable to improve compatibility with many GPUs"); - - -} - -int main(int argc, char* argv[]) -{ - - CommandLineArgs args(argc,argv); - - if (args.CheckCmdLineFlag("help")) - { - Usage(); - return 0; - } - - args.GetCmdLineArgument("x_dim", NUM_OBJECTS_X); - args.GetCmdLineArgument("y_dim", NUM_OBJECTS_Y); - args.GetCmdLineArgument("z_dim", NUM_OBJECTS_Z); - - args.GetCmdLineArgument("x_gap", X_GAP); - args.GetCmdLineArgument("y_gap", Y_GAP); - args.GetCmdLineArgument("z_gap", Z_GAP); - - args.GetCmdLineArgument("enable_interop", USE_GL_CL_INTEROP); - args.GetCmdLineArgument("preferred_gpu", preferredGPU); - args.GetCmdLineArgument("preferred_platform", preferredPlatform); - args.GetCmdLineArgument("batch_gpu", gpuBatchContacts); - - - - - printf("Dimensions (%d,%d,%d) with gap (%f,%f,%f), using interop=%d, gpu %d, cl platform %d, gpuBatchContacts %d \n",NUM_OBJECTS_X,NUM_OBJECTS_Y,NUM_OBJECTS_Z,X_GAP,Y_GAP,Z_GAP,USE_GL_CL_INTEROP,preferredGPU, preferredPlatform,gpuBatchContacts); - - - - - { - NUM_OBJECTS = NUM_OBJECTS_X*NUM_OBJECTS_Y*NUM_OBJECTS_Z; - POSITION_BUFFER_SIZE = (NUM_OBJECTS*sizeof(float)*4); - ORIENTATION_BUFFER_SIZE = (NUM_OBJECTS*sizeof(float)*4); - COLOR_BUFFER_SIZE = (NUM_OBJECTS*sizeof(float)*4); - SCALE_BUFFER_SIZE = (NUM_OBJECTS*sizeof(float)*3); - } - - srand(0); - // printf("vertexShader = \n%s\n",vertexShader); - // printf("fragmentShader = \n%s\n",fragmentShader); - - glutInit(&argc, argv); - - glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA); - - - glutInitWindowSize(m_glutScreenWidth, m_glutScreenHeight); - char buf[1024]; - if (USE_GL_CL_INTEROP) - { - sprintf(buf,"GPU rigid body pipeline using OpenCL - OpenGL interop, simulates %d cubes on the GPU (use c to toggle CPU/CL)", NUM_OBJECTS); - } else - { - sprintf(buf,"GPU rigid body pipeline, simulates %d cubes on the GPU (use c to toggle CPU/CL)", NUM_OBJECTS); - } - - glutCreateWindow(buf); - - glutReshapeFunc(ChangeSize); - - glutMouseFunc(mouseFunc); - glutMotionFunc(mouseMotionFunc); - - glutKeyboardFunc(Keyboard); - glutDisplayFunc(mainloop); - - GLenum err = glewInit(); - if (GLEW_OK != err) - { - /* Problem: glewInit failed, something is seriously wrong. */ - fprintf(stderr, "Error: %s\n", glewGetErrorString(err)); - } - - //ChangeSize(m_glutScreenWidth,m_glutScreenHeight); - - - InitCL(preferredGPU, preferredPlatform); - - -#define CUSTOM_CL_INITIALIZATION -#ifdef CUSTOM_CL_INITIALIZATION - g_deviceCL = new adl::DeviceCL(); - g_deviceCL->m_deviceIdx = g_device; - g_deviceCL->m_context = g_cxMainContext; - g_deviceCL->m_commandQueue = g_cqCommandQue; - g_deviceCL->m_kernelManager = new adl::KernelManager; - -#else - DeviceUtils::Config cfg; - cfg.m_type = DeviceUtils::Config::DEVICE_CPU; - g_deviceCL = DeviceUtils::allocate( TYPE_CL, cfg ); -#endif - - int size = NUM_OBJECTS; - adl::Buffer linvelBuf( g_deviceCL, size ); - adl::Buffer angvelBuf( g_deviceCL, size ); - adl::Buffer bodyTimes(g_deviceCL,size); - - gLinVelMem = (cl_mem)linvelBuf.m_ptr; - gAngVelMem = (cl_mem)angvelBuf.m_ptr; - gBodyTimes = (cl_mem)bodyTimes.m_ptr; - - btVector3* linVelHost= new btVector3[size]; - btVector3* angVelHost = new btVector3[size]; - float* bodyTimesHost = new float[size]; - - { - int index=0; - for (int i=0;i verts; - int numVertices = (sizeof(cube_vertices) )/(9*sizeof(GLfloat)); - - for (int i=0;iregisterShape(s_convexHeightField); - - InitShaders(); - - if (USE_GL_CL_INTEROP) - { - g_interopBuffer = new btOpenCLGLInteropBuffer(g_cxMainContext,g_cqCommandQue,cube_vbo); - clFinish(g_cqCommandQue); - } - - - cl_program prog = btOpenCLUtils::compileCLProgramFromString(g_cxMainContext,g_device,interopKernelString,0,"",INTEROPKERNEL_SRC_PATH); - g_integrateTransformsKernel = btOpenCLUtils::compileCLKernelFromString(g_cxMainContext, g_device,interopKernelString, "integrateTransformsKernel" ,0,prog); - - - initFindPairs(gFpIO, g_cxMainContext, g_device, g_cqCommandQue, NUM_OBJECTS); - - - - - - glutMainLoop(); - ShutdownRC(); - - return 0; -} diff --git a/Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline/premake4.lua b/Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline/premake4.lua deleted file mode 100644 index d2fbbc877..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline/premake4.lua +++ /dev/null @@ -1,5 +0,0 @@ - - include "AMD" --- include "Intel" - include "NVIDIA" - \ No newline at end of file diff --git a/Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline2/AMD/premake4.lua b/Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline2/AMD/premake4.lua deleted file mode 100644 index 8abbebb18..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline2/AMD/premake4.lua +++ /dev/null @@ -1,64 +0,0 @@ - - hasCL = findOpenCL_AMD() - - if (hasCL) then - - project "OpenCL_gpu_rigidbody_pipeline2_AMD" - - initOpenCL_AMD() - - language "C++" - - kind "ConsoleApp" - targetdir "../../../bin" - - - initOpenGL() - initGlew() - - includedirs { - "../../primitives", - "../../../../../src" - } - - files { - "../main.cpp", - "../CLPhysicsDemo.cpp", - "../CLPhysicsDemo.h", - "../GLInstancingRenderer.cpp", - "../GLInstancingRenderer.h", - "../GlutRenderer.cpp", - "../GlutRenderer.h", - "../Win32OpenGLRenderManager.cpp", - "../Win32OpenGLRenderManager.h", - "../../gpu_rigidbody_pipeline/btConvexUtility.cpp", - "../../gpu_rigidbody_pipeline/btConvexUtility.h", - "../../gpu_rigidbody_pipeline/btGpuNarrowPhaseAndSolver.cpp", - "../../gpu_rigidbody_pipeline/btGpuNarrowPhaseAndSolver.h", - "../../../dynamics/basic_demo/ConvexHeightFieldShape.cpp", - "../../../dynamics/basic_demo/ConvexHeightFieldShape.h", - "../../../../../src/LinearMath/btConvexHullComputer.cpp", - "../../../../../src/LinearMath/btConvexHullComputer.h", - "../../broadphase_benchmark/findPairsOpenCL.cpp", - "../../broadphase_benchmark/findPairsOpenCL.h", - "../../broadphase_benchmark/btGridBroadphaseCL.cpp", - "../../broadphase_benchmark/btGridBroadphaseCL.h", - "../../3dGridBroadphase/Shared/bt3dGridBroadphaseOCL.cpp", - "../../3dGridBroadphase/Shared/bt3dGridBroadphaseOCL.h", - "../../3dGridBroadphase/Shared/btGpu3DGridBroadphase.cpp", - "../../3dGridBroadphase/Shared/btGpu3DGridBroadphase.h", - "../../../../../src/LinearMath/btAlignedAllocator.cpp", - "../../../../../src/LinearMath/btQuickprof.cpp", - "../../../../../src/LinearMath/btQuickprof.h", - "../../../../../src/BulletCollision/BroadphaseCollision/btBroadphaseProxy.cpp", - "../../../../../src/BulletCollision/BroadphaseCollision/btOverlappingPairCache.cpp", - "../../../../../src/BulletCollision/BroadphaseCollision/btSimpleBroadphase.cpp", - "../../basic_initialize/btOpenCLUtils.cpp", - "../../basic_initialize/btOpenCLUtils.h", - "../../opengl_interop/btOpenCLGLInteropBuffer.cpp", - "../../opengl_interop/btOpenCLGLInteropBuffer.h", - "../../opengl_interop/btStopwatch.cpp", - "../../opengl_interop/btStopwatch.h" - } - - end diff --git a/Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline2/CLPhysicsDemo.cpp b/Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline2/CLPhysicsDemo.cpp deleted file mode 100644 index 8347423a8..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline2/CLPhysicsDemo.cpp +++ /dev/null @@ -1,533 +0,0 @@ -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Erwin Coumans - -#include "OpenGLInclude.h" - -#include "CLPhysicsDemo.h" -#include "LinearMath/btAlignedObjectArray.h" -#include "DemoSettings.h" -#include "../basic_initialize/btOpenCLUtils.h" -#include "../opengl_interop/btOpenCLGLInteropBuffer.h" -#include "../broadphase_benchmark/findPairsOpenCL.h" -#include "LinearMath/btVector3.h" -#include "LinearMath/btQuaternion.h" -#include "LinearMath/btMatrix3x3.h" -#include "../../opencl/gpu_rigidbody_pipeline/btGpuNarrowPhaseAndSolver.h" -#include "../../opencl/gpu_rigidbody_pipeline/btConvexUtility.h" -#include "../../dynamics/basic_demo/ConvexHeightFieldShape.h" -#include "../broadphase_benchmark/btGridBroadphaseCl.h" -#include "LinearMath/btQuickprof.h" - - -#define MSTRINGIFY(A) #A -static char* interopKernelString = -#include "../broadphase_benchmark/integrateKernel.cl" - -#define INTEROPKERNEL_SRC_PATH "../../opencl/broadphase_benchmark/integrateKernel.cl" - -cl_kernel g_integrateTransformsKernel; - - - -bool runOpenCLKernels = true; - - -btGpuNarrowphaseAndSolver* narrowphaseAndSolver = 0; -ConvexHeightField* s_convexHeightField = 0 ; -btOpenCLGLInteropBuffer* g_interopBuffer = 0; - -extern GLuint cube_vbo; -extern int VBOsize; - -cl_mem clBuffer=0; -char* hostPtr=0; -cl_bool blocking= CL_TRUE; - - - -btFindPairsIO gFpIO; - -cl_context g_cxMainContext; -cl_command_queue g_cqCommandQue; -cl_device_id g_device; - -cl_mem gLinVelMem=0; -cl_mem gAngVelMem=0; -cl_mem gBodyTimes=0; - -#include - -adl::DeviceCL* g_deviceCL=0; - -struct btAABBHost //keep this in sync with btAABBCL! -{ - float fx; - float fy; - float fz; - unsigned int uw; -}; - -struct InternalData -{ - adl::Buffer* m_linVelBuf; - adl::Buffer* m_angVelBuf; - adl::Buffer* m_bodyTimes; - bool m_useInterop; - btGridBroadphaseCl* m_Broadphase; - - adl::Buffer* m_localShapeAABB; - - btVector3* m_linVelHost; - btVector3* m_angVelHost; - float* m_bodyTimesHost; - - InternalData():m_linVelBuf(0),m_angVelBuf(0),m_bodyTimes(0),m_useInterop(0),m_Broadphase(0) - { - m_linVelHost= new btVector3[MAX_CONVEX_BODIES_CL]; - m_angVelHost = new btVector3[MAX_CONVEX_BODIES_CL]; - m_bodyTimesHost = new float[MAX_CONVEX_BODIES_CL]; - for (int i=0;i0) - { - g_device= btOpenCLUtils::getDevice(g_cxMainContext,0); - btOpenCLUtils::printDeviceInfo(g_device); - g_cqCommandQue = clCreateCommandQueue(g_cxMainContext, g_device, 0, &ciErrNum); - oclCHECKERROR(ciErrNum, CL_SUCCESS); - } - -} - - - - -CLPhysicsDemo::CLPhysicsDemo(Win32OpenGLWindow* renderer) -{ - m_numCollisionShapes=0; - m_numPhysicsInstances=0; - - m_data = new InternalData; -} - -CLPhysicsDemo::~CLPhysicsDemo() -{ - -} - - -void CLPhysicsDemo::writeBodiesToGpu() -{ - if (narrowphaseAndSolver) - narrowphaseAndSolver->writeAllBodiesToGpu(); -} - -int CLPhysicsDemo::registerCollisionShape(const float* vertices, int strideInBytes, int numVertices, const float* scaling) -{ - btAlignedObjectArray verts; - - unsigned char* vts = (unsigned char*) vertices; - for (int i=0;iregisterShape(s_convexHeightField); - - if (shapeIndex>=0) - { - btAABBHost aabbMin, aabbMax; - aabbMin.fx = s_convexHeightField->m_aabb.m_min.x; - aabbMin.fy = s_convexHeightField->m_aabb.m_min.y; - aabbMin.fz= s_convexHeightField->m_aabb.m_min.z; - aabbMin.uw = shapeIndex; - - aabbMax.fx = s_convexHeightField->m_aabb.m_max.x; - aabbMax.fy = s_convexHeightField->m_aabb.m_max.y; - aabbMax.fz= s_convexHeightField->m_aabb.m_max.z; - aabbMax.uw = shapeIndex; - - m_data->m_localShapeAABB->write(&aabbMin,1,shapeIndex*2); - m_data->m_localShapeAABB->write(&aabbMax,1,shapeIndex*2+1); - adl::DeviceUtils::waitForCompletion( g_deviceCL ); - } - - m_numCollisionShapes++; - delete[] eqn; - return shapeIndex; -} - -int CLPhysicsDemo::registerPhysicsInstance(float mass, const float* position, const float* orientation, int collisionShapeIndex, void* userPointer) -{ - btVector3 aabbMin(position[0],position[0],position[0]); - btVector3 aabbMax = aabbMin; - aabbMin -= btVector3(1.f,1.f,1.f); - aabbMax += btVector3(1.f,1.f,1.f); - - if (collisionShapeIndex>=0) - { - btBroadphaseProxy* proxy = m_data->m_Broadphase->createProxy(aabbMin,aabbMax,collisionShapeIndex,userPointer,1,1,0,0);//m_dispatcher); - } - - bool writeToGpu = false; - int bodyIndex = -1; - - if (narrowphaseAndSolver) - bodyIndex = narrowphaseAndSolver->registerRigidBody(collisionShapeIndex,mass,position,orientation,writeToGpu); - - m_numPhysicsInstances++; - return bodyIndex; -} - - - -void CLPhysicsDemo::init(int preferredDevice, int preferredPlatform, bool useInterop) -{ - - InitCL(-1,-1,useInterop); - -#define CUSTOM_CL_INITIALIZATION -#ifdef CUSTOM_CL_INITIALIZATION - g_deviceCL = new adl::DeviceCL(); - g_deviceCL->m_deviceIdx = g_device; - g_deviceCL->m_context = g_cxMainContext; - g_deviceCL->m_commandQueue = g_cqCommandQue; - g_deviceCL->m_kernelManager = new adl::KernelManager; - -#else - DeviceUtils::Config cfg; - cfg.m_type = DeviceUtils::Config::DEVICE_CPU; - g_deviceCL = DeviceUtils::allocate( TYPE_CL, cfg ); -#endif - - //adl::Solver::allocate(g_deviceCL->allocate( - m_data->m_linVelBuf = new adl::Buffer(g_deviceCL,MAX_CONVEX_BODIES_CL); - m_data->m_angVelBuf = new adl::Buffer(g_deviceCL,MAX_CONVEX_BODIES_CL); - m_data->m_bodyTimes = new adl::Buffer(g_deviceCL,MAX_CONVEX_BODIES_CL); - - m_data->m_localShapeAABB = new adl::Buffer(g_deviceCL,MAX_CONVEX_SHAPES_CL); - - gLinVelMem = (cl_mem)m_data->m_linVelBuf->m_ptr; - gAngVelMem = (cl_mem)m_data->m_angVelBuf->m_ptr; - gBodyTimes = (cl_mem)m_data->m_bodyTimes->m_ptr; - - writeVelocitiesToGpu(); - - - narrowphaseAndSolver = new btGpuNarrowphaseAndSolver(g_deviceCL); - - - - int maxObjects = btMax(256,MAX_CONVEX_BODIES_CL); - int maxPairsSmallProxy = 32; - btOverlappingPairCache* overlappingPairCache=0; - - m_data->m_Broadphase = new btGridBroadphaseCl(overlappingPairCache,btVector3(4.f, 4.f, 4.f), 128, 128, 128,maxObjects, maxObjects, maxPairsSmallProxy, 100.f, 128, - g_cxMainContext ,g_device,g_cqCommandQue, g_deviceCL); - - - - cl_program prog = btOpenCLUtils::compileCLProgramFromString(g_cxMainContext,g_device,interopKernelString,0,"",INTEROPKERNEL_SRC_PATH); - g_integrateTransformsKernel = btOpenCLUtils::compileCLKernelFromString(g_cxMainContext, g_device,interopKernelString, "integrateTransformsKernel" ,0,prog); - - - initFindPairs(gFpIO, g_cxMainContext, g_device, g_cqCommandQue, MAX_CONVEX_BODIES_CL); - - - - -} - - - -void CLPhysicsDemo::writeVelocitiesToGpu() -{ - m_data->m_linVelBuf->write(m_data->m_linVelHost,MAX_CONVEX_BODIES_CL); - m_data->m_angVelBuf->write(m_data->m_angVelHost,MAX_CONVEX_BODIES_CL); - m_data->m_bodyTimes->write(m_data->m_bodyTimesHost,MAX_CONVEX_BODIES_CL); - adl::DeviceUtils::waitForCompletion( g_deviceCL ); -} - - -void CLPhysicsDemo::setupInterop() -{ - m_data->m_useInterop = true; - - g_interopBuffer = new btOpenCLGLInteropBuffer(g_cxMainContext,g_cqCommandQue,cube_vbo); - clFinish(g_cqCommandQue); -} - -void CLPhysicsDemo::cleanup() -{ - delete narrowphaseAndSolver; - - delete m_data->m_linVelBuf; - delete m_data->m_angVelBuf; - delete m_data->m_bodyTimes; - delete m_data->m_localShapeAABB; - - delete m_data->m_Broadphase; - delete m_data; - - delete g_deviceCL->m_kernelManager; - delete g_deviceCL; - - m_data=0; - g_deviceCL=0; - delete g_interopBuffer; - delete s_convexHeightField; -} - - - - - -void CLPhysicsDemo::stepSimulation() -{ - BT_PROFILE("simulationLoop"); - - { - BT_PROFILE("glFinish"); - glFinish(); - } - cl_int ciErrNum = CL_SUCCESS; - - - if(m_data->m_useInterop) - { - clBuffer = g_interopBuffer->getCLBUffer(); - BT_PROFILE("clEnqueueAcquireGLObjects"); - ciErrNum = clEnqueueAcquireGLObjects(g_cqCommandQue, 1, &clBuffer, 0, 0, NULL); - adl::DeviceUtils::waitForCompletion( g_deviceCL ); - } else - { - - glBindBuffer(GL_ARRAY_BUFFER, cube_vbo); - glFlush(); - - BT_PROFILE("glMapBuffer and clEnqueueWriteBuffer"); - - blocking= CL_TRUE; - hostPtr= (char*)glMapBuffer( GL_ARRAY_BUFFER,GL_READ_WRITE);//GL_WRITE_ONLY - if (!clBuffer) - { - clBuffer = clCreateBuffer(g_cxMainContext, CL_MEM_READ_WRITE, VBOsize, 0, &ciErrNum); - } - adl::DeviceUtils::waitForCompletion( g_deviceCL ); - oclCHECKERROR(ciErrNum, CL_SUCCESS); - - ciErrNum = clEnqueueWriteBuffer ( g_cqCommandQue, - clBuffer, - blocking, - 0, - VBOsize, - hostPtr,0,0,0 - ); - adl::DeviceUtils::waitForCompletion( g_deviceCL ); - } - - - - oclCHECKERROR(ciErrNum, CL_SUCCESS); - if (runOpenCLKernels && m_numPhysicsInstances) - { - - gFpIO.m_numObjects = m_numPhysicsInstances; - gFpIO.m_positionOffset = SHAPE_VERTEX_BUFFER_SIZE/4; - gFpIO.m_clObjectsBuffer = clBuffer; - gFpIO.m_dAABB = m_data->m_Broadphase->m_dAABB; - gFpIO.m_dlocalShapeAABB = (cl_mem)m_data->m_localShapeAABB->m_ptr; - gFpIO.m_numOverlap = 0; - { - BT_PROFILE("setupGpuAabbs"); - setupGpuAabbsFull(gFpIO,narrowphaseAndSolver->getBodiesGpu() ); - } - if (1) - { - BT_PROFILE("calculateOverlappingPairs"); - m_data->m_Broadphase->calculateOverlappingPairs(0, m_numPhysicsInstances); - gFpIO.m_dAllOverlappingPairs = m_data->m_Broadphase->m_dAllOverlappingPairs; - gFpIO.m_numOverlap = m_data->m_Broadphase->m_numPrefixSum; - } - - //printf("gFpIO.m_numOverlap = %d\n",gFpIO.m_numOverlap ); - if (gFpIO.m_numOverlap>=0 && gFpIO.m_numOverlapgetBodiesGpu(), narrowphaseAndSolver->getBodyInertiasGpu()); - } - if (gFpIO.m_numOverlap) - { - BT_PROFILE("computeContactsAndSolver"); - if (narrowphaseAndSolver) - narrowphaseAndSolver->computeContactsAndSolver(gFpIO.m_dAllOverlappingPairs,gFpIO.m_numOverlap); - } - - { - BT_PROFILE("copyBodyVelocities"); - if (narrowphaseAndSolver) - copyBodyVelocities(gFpIO, gLinVelMem, gAngVelMem, narrowphaseAndSolver->getBodiesGpu(), narrowphaseAndSolver->getBodyInertiasGpu()); - } - } - - } else - { - printf("error, gFpIO.m_numOverlap = %d\n",gFpIO.m_numOverlap); - btAssert(0); - } - - - { - BT_PROFILE("integrateTransforms"); - - if (runOpenCLKernels) - { - int numObjects = m_numPhysicsInstances; - int offset = SHAPE_VERTEX_BUFFER_SIZE/4; - - ciErrNum = clSetKernelArg(g_integrateTransformsKernel, 0, sizeof(int), &offset); - ciErrNum = clSetKernelArg(g_integrateTransformsKernel, 1, sizeof(int), &numObjects); - ciErrNum = clSetKernelArg(g_integrateTransformsKernel, 2, sizeof(cl_mem), (void*)&clBuffer ); - - ciErrNum = clSetKernelArg(g_integrateTransformsKernel, 3, sizeof(cl_mem), (void*)&gLinVelMem); - ciErrNum = clSetKernelArg(g_integrateTransformsKernel, 4, sizeof(cl_mem), (void*)&gAngVelMem); - ciErrNum = clSetKernelArg(g_integrateTransformsKernel, 5, sizeof(cl_mem), (void*)&gBodyTimes); - - - - - size_t workGroupSize = 64; - size_t numWorkItems = workGroupSize*((m_numPhysicsInstances + (workGroupSize)) / workGroupSize); - - if (workGroupSize>numWorkItems) - workGroupSize=numWorkItems; - - ciErrNum = clEnqueueNDRangeKernel(g_cqCommandQue, g_integrateTransformsKernel, 1, NULL, &numWorkItems, &workGroupSize,0 ,0 ,0); - oclCHECKERROR(ciErrNum, CL_SUCCESS); - } - } - - - } - - if(m_data->m_useInterop) - { - BT_PROFILE("clEnqueueReleaseGLObjects"); - ciErrNum = clEnqueueReleaseGLObjects(g_cqCommandQue, 1, &clBuffer, 0, 0, 0); - adl::DeviceUtils::waitForCompletion( g_deviceCL ); - } - else - { - BT_PROFILE("clEnqueueReadBuffer clReleaseMemObject and glUnmapBuffer"); - ciErrNum = clEnqueueReadBuffer ( g_cqCommandQue, - clBuffer, - blocking, - 0, - VBOsize, - hostPtr,0,0,0); - - //clReleaseMemObject(clBuffer); - adl::DeviceUtils::waitForCompletion( g_deviceCL ); - glUnmapBuffer( GL_ARRAY_BUFFER); - glFlush(); - } - - oclCHECKERROR(ciErrNum, CL_SUCCESS); - - - if (runOpenCLKernels) - { - BT_PROFILE("clFinish"); - clFinish(g_cqCommandQue); - } - - -} \ No newline at end of file diff --git a/Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline2/CLPhysicsDemo.h b/Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline2/CLPhysicsDemo.h deleted file mode 100644 index 0ed2e7392..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline2/CLPhysicsDemo.h +++ /dev/null @@ -1,53 +0,0 @@ -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Erwin Coumans - -#ifndef CL_PHYSICS_DEMO_H -#define CL_PHYSICS_DEMO_H - -class Win32OpenGLWindow; - -struct CLPhysicsDemo -{ - Win32OpenGLWindow* m_renderer; - - int m_numCollisionShapes; - - int m_numPhysicsInstances; - - struct InternalData* m_data; - - CLPhysicsDemo(Win32OpenGLWindow* renderer); - - virtual ~CLPhysicsDemo(); - - //btOpenCLGLInteropBuffer* m_interopBuffer; - - void init(int preferredDevice, int preferredPlatform, bool useInterop); - - void setupInterop(); - - int registerCollisionShape(const float* vertices, int strideInBytes, int numVertices, const float* scaling); - - int registerPhysicsInstance(float mass, const float* position, const float* orientation, int collisionShapeIndex, void* userPointer); - - void writeVelocitiesToGpu(); - void writeBodiesToGpu(); - - void cleanup(); - - void stepSimulation(); -}; - -#endif//CL_PHYSICS_DEMO_H \ No newline at end of file diff --git a/Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline2/DemoSettings.h b/Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline2/DemoSettings.h deleted file mode 100644 index 5b55e001d..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline2/DemoSettings.h +++ /dev/null @@ -1,24 +0,0 @@ -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Erwin Coumans - -#ifndef DEMO_SETTINGS_H -#define DEMO_SETTINGS_H - -#define SHAPE_VERTEX_BUFFER_SIZE 1024*1024 - -#define SHAPE_BUFFER_SIZE (SHAPE_VERTEX_BUFFER_SIZE) - - -#endif //DEMO_SETTINGS_H \ No newline at end of file diff --git a/Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline2/GLInstancingRenderer.cpp b/Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline2/GLInstancingRenderer.cpp deleted file mode 100644 index 9e7525362..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline2/GLInstancingRenderer.cpp +++ /dev/null @@ -1,861 +0,0 @@ -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Erwin Coumans - -#include "OpenGLInclude.h" -#include "GLInstancingRenderer.h" - -#include -#include "DemoSettings.h" -#include -#include -#include "LinearMath/btVector3.h" -#include "LinearMath/btQuaternion.h" -#include "LinearMath/btQuickprof.h" -#include "LinearMath/btMatrix3x3.h" - -#include "../../opencl/gpu_rigidbody_pipeline/btGpuNarrowphaseAndSolver.h"//for MAX_CONVEX_BODIES_CL - -struct btGraphicsInstance -{ - GLuint m_cube_vao; - GLuint m_index_vbo; - int m_numIndices; - int m_numVertices; - - int m_numGraphicsInstances; - - int m_instanceOffset; - int m_vertexArrayOffset; - - btGraphicsInstance() :m_cube_vao(-1),m_index_vbo(-1),m_numIndices(-1),m_numVertices(-1),m_numGraphicsInstances(0),m_instanceOffset(0),m_vertexArrayOffset(0) - { - } - -}; - - - -bool m_ortho = false; -int m_glutScreenWidth = 1024; -int m_glutScreenHeight = 768; - - - -extern int gShapeIndex; - - -btVector3 m_cameraPosition(0,0,0);//will be overridden by a position computed from azi/ele -btVector3 m_cameraTargetPosition(30,-5,-20); -btScalar m_cameraDistance = 95; -btVector3 m_cameraUp(0,1,0); -float m_azi=95.f; -float m_ele=15.f; - - - - -int VBOsize =0; - - - -struct InternalDataRenderer -{ - GLfloat* m_instance_positions_ptr; - GLfloat* m_instance_quaternion_ptr; - GLfloat* m_instance_colors_ptr; - GLfloat* m_instance_scale_ptr; - - InternalDataRenderer() :m_instance_positions_ptr (0),m_instance_quaternion_ptr(0),m_instance_colors_ptr(0),m_instance_scale_ptr(0) - { - } - -}; - -static GLuint instancingShader; // The instancing renderer - -GLuint cube_vbo; - -static GLuint m_texturehandle; - -static bool done = false; -static GLint angle_loc = 0; -static GLint ModelViewMatrix; -static GLint ProjectionMatrix; - - - -GLInstancingRenderer::GLInstancingRenderer() -{ - - m_data = new InternalDataRenderer; - - m_data->m_instance_positions_ptr = (GLfloat*)new float[MAX_CONVEX_BODIES_CL*4]; - m_data->m_instance_quaternion_ptr = (GLfloat*)new float[MAX_CONVEX_BODIES_CL*4]; - m_data->m_instance_colors_ptr = (GLfloat*)new float[MAX_CONVEX_BODIES_CL*4]; - m_data->m_instance_scale_ptr = (GLfloat*)new float[MAX_CONVEX_BODIES_CL*3]; - -} - -GLInstancingRenderer::~GLInstancingRenderer() -{ - delete m_data; -} - - -static GLint uniform_texture_diffuse = 0; - -//used for dynamic loading from disk (default switched off) -#define MAX_SHADER_LENGTH 8192 -static GLubyte shaderText[MAX_SHADER_LENGTH]; - -static const char* vertexShader= \ -"#version 330\n" -"precision highp float;\n" -"\n" -"\n" -"\n" -"layout (location = 0) in vec4 position;\n" -"layout (location = 1) in vec4 instance_position;\n" -"layout (location = 2) in vec4 instance_quaternion;\n" -"layout (location = 3) in vec2 uvcoords;\n" -"layout (location = 4) in vec3 vertexnormal;\n" -"layout (location = 5) in vec4 instance_color;\n" -"layout (location = 6) in vec3 instance_scale;\n" -"\n" -"\n" -"uniform float angle = 0.0;\n" -"uniform mat4 ModelViewMatrix;\n" -"uniform mat4 ProjectionMatrix;\n" -"\n" -"out Fragment\n" -"{\n" -" vec4 color;\n" -"} fragment;\n" -"\n" -"out Vert\n" -"{\n" -" vec2 texcoord;\n" -"} vert;\n" -"\n" -"\n" -"vec4 quatMul ( in vec4 q1, in vec4 q2 )\n" -"{\n" -" vec3 im = q1.w * q2.xyz + q1.xyz * q2.w + cross ( q1.xyz, q2.xyz );\n" -" vec4 dt = q1 * q2;\n" -" float re = dot ( dt, vec4 ( -1.0, -1.0, -1.0, 1.0 ) );\n" -" return vec4 ( im, re );\n" -"}\n" -"\n" -"vec4 quatFromAxisAngle(vec4 axis, in float angle)\n" -"{\n" -" float cah = cos(angle*0.5);\n" -" float sah = sin(angle*0.5);\n" -" float d = inversesqrt(dot(axis,axis));\n" -" vec4 q = vec4(axis.x*sah*d,axis.y*sah*d,axis.z*sah*d,cah);\n" -" return q;\n" -"}\n" -"//\n" -"// vector rotation via quaternion\n" -"//\n" -"vec4 quatRotate3 ( in vec3 p, in vec4 q )\n" -"{\n" -" vec4 temp = quatMul ( q, vec4 ( p, 0.0 ) );\n" -" return quatMul ( temp, vec4 ( -q.x, -q.y, -q.z, q.w ) );\n" -"}\n" -"vec4 quatRotate ( in vec4 p, in vec4 q )\n" -"{\n" -" vec4 temp = quatMul ( q, p );\n" -" return quatMul ( temp, vec4 ( -q.x, -q.y, -q.z, q.w ) );\n" -"}\n" -"\n" -"out vec3 lightDir,normal,ambient;\n" -"\n" -"void main(void)\n" -"{\n" -" vec4 q = instance_quaternion;\n" -" ambient = vec3(0.3,.3,0.3);\n" -" \n" -" \n" -" vec4 local_normal = (quatRotate3( vertexnormal,q));\n" -" vec3 light_pos = vec3(-0.8,1,-0.6);\n" -" normal = local_normal.xyz;\n"//normalize(ModelViewMatrix * local_normal).xyz;\n" -"\n" -" lightDir = normalize(light_pos);//gl_LightSource[0].position.xyz));\n" -"// lightDir = normalize(vec3(gl_LightSource[0].position));\n" -" \n" -" vec4 axis = vec4(1,1,1,0);\n" -" vec4 localcoord = quatRotate3( position.xyz*instance_scale,q);\n" -" vec4 vertexPos = ProjectionMatrix * ModelViewMatrix *(instance_position+localcoord);\n" -"\n" -" gl_Position = vertexPos;\n" -" \n" -" fragment.color = instance_color;\n" -" vert.texcoord = uvcoords;\n" -"}\n" -; - - -static const char* fragmentShader= \ -"#version 330\n" -"precision highp float;\n" -"\n" -"in Fragment\n" -"{\n" -" vec4 color;\n" -"} fragment;\n" -"\n" -"in Vert\n" -"{\n" -" vec2 texcoord;\n" -"} vert;\n" -"\n" -"uniform sampler2D Diffuse;\n" -"\n" -"in vec3 lightDir,normal,ambient;\n" -"\n" -"out vec4 color;\n" -"\n" -"void main_textured(void)\n" -"{\n" -" color = texture2D(Diffuse,vert.texcoord);//fragment.color;\n" -"}\n" -"\n" -"void main(void)\n" -"{\n" -" vec4 texel = fragment.color*texture2D(Diffuse,vert.texcoord);//fragment.color;\n" -" vec3 ct,cf;\n" -" float intensity,at,af;\n" -" intensity = max(dot(lightDir,normalize(normal)),.2);\n" -" cf = intensity*vec3(1.0,1.0,1.0)+ambient;" -" af = 1.0;\n" -" \n" -" ct = texel.rgb;\n" -" at = texel.a;\n" -" \n" -" color = vec4(ct * cf, at * af); \n" -"}\n" -; - - -// Load the shader from the source text -void gltLoadShaderSrc(const char *szShaderSrc, GLuint shader) -{ - GLchar *fsStringPtr[1]; - - fsStringPtr[0] = (GLchar *)szShaderSrc; - glShaderSource(shader, 1, (const GLchar **)fsStringPtr, NULL); -} - - -GLuint gltLoadShaderPair(const char *szVertexProg, const char *szFragmentProg) -{ - // Temporary Shader objects - GLuint hVertexShader; - GLuint hFragmentShader; - GLuint hReturn = 0; - GLint testVal; - - // Create shader objects - hVertexShader = glCreateShader(GL_VERTEX_SHADER); - hFragmentShader = glCreateShader(GL_FRAGMENT_SHADER); - - gltLoadShaderSrc(vertexShader, hVertexShader); - gltLoadShaderSrc(fragmentShader, hFragmentShader); - - // Compile them - glCompileShader(hVertexShader); - glCompileShader(hFragmentShader); - - // Check for errors - glGetShaderiv(hVertexShader, GL_COMPILE_STATUS, &testVal); - if(testVal == GL_FALSE) - { - char temp[256] = ""; - glGetShaderInfoLog( hVertexShader, 256, NULL, temp); - fprintf( stderr, "Compile failed:\n%s\n", temp); - assert(0); - exit(0); - glDeleteShader(hVertexShader); - glDeleteShader(hFragmentShader); - return (GLuint)NULL; - } - - glGetShaderiv(hFragmentShader, GL_COMPILE_STATUS, &testVal); - if(testVal == GL_FALSE) - { - char temp[256] = ""; - glGetShaderInfoLog( hFragmentShader, 256, NULL, temp); - fprintf( stderr, "Compile failed:\n%s\n", temp); - assert(0); - exit(0); - glDeleteShader(hVertexShader); - glDeleteShader(hFragmentShader); - return (GLuint)NULL; - } - - // Link them - assuming it works... - hReturn = glCreateProgram(); - glAttachShader(hReturn, hVertexShader); - glAttachShader(hReturn, hFragmentShader); - - glLinkProgram(hReturn); - - // These are no longer needed - glDeleteShader(hVertexShader); - glDeleteShader(hFragmentShader); - - // Make sure link worked too - glGetProgramiv(hReturn, GL_LINK_STATUS, &testVal); - if(testVal == GL_FALSE) - { - glDeleteProgram(hReturn); - return (GLuint)NULL; - } - - return hReturn; -} - - -void GLInstancingRenderer::writeTransforms() -{ - glBindBuffer(GL_ARRAY_BUFFER, cube_vbo); - glFlush(); - - char* orgBase = (char*)glMapBuffer( GL_ARRAY_BUFFER,GL_READ_WRITE); - - int totalNumInstances= 0; - - for (int k=0;km_numGraphicsInstances; - } - - - - for (int k=0;km_numGraphicsInstances;i++) - { - - int srcIndex=i+gfxObj->m_instanceOffset; - - positions[srcIndex*4] = m_data->m_instance_positions_ptr[srcIndex*4]; - positions[srcIndex*4+1] = m_data->m_instance_positions_ptr[srcIndex*4+1]; - positions[srcIndex*4+2] = m_data->m_instance_positions_ptr[srcIndex*4+2]; - positions[srcIndex*4+3] = m_data->m_instance_positions_ptr[srcIndex*4+3]; - - orientations[srcIndex*4]=m_data->m_instance_quaternion_ptr[srcIndex*4]; - orientations[srcIndex*4+1]=m_data->m_instance_quaternion_ptr[srcIndex*4+1]; - orientations[srcIndex*4+2]=m_data->m_instance_quaternion_ptr[srcIndex*4+2]; - orientations[srcIndex*4+3]=m_data->m_instance_quaternion_ptr[srcIndex*4+3]; - - colors[srcIndex*4]=m_data->m_instance_colors_ptr[srcIndex*4]; - colors[srcIndex*4+1]=m_data->m_instance_colors_ptr[srcIndex*4+1]; - colors[srcIndex*4+2]=m_data->m_instance_colors_ptr[srcIndex*4+2]; - colors[srcIndex*4+3]=m_data->m_instance_colors_ptr[srcIndex*4+3]; - - scaling[srcIndex*3]=m_data->m_instance_scale_ptr[srcIndex*3]; - scaling[srcIndex*3+1]=m_data->m_instance_scale_ptr[srcIndex*3+1]; - scaling[srcIndex*3+2]=m_data->m_instance_scale_ptr[srcIndex*3+2]; - - } - } - - glUnmapBuffer( GL_ARRAY_BUFFER); - //if this glFinish is removed, the animation is not always working/blocks - //@todo: figure out why - glFlush(); -} - -int GLInstancingRenderer::registerGraphicsInstance(int shapeIndex, const float* position, const float* quaternion, const float* color, const float* scaling) -{ - btGraphicsInstance* gfxObj = m_graphicsInstances[shapeIndex]; - - int index = gfxObj->m_numGraphicsInstances + gfxObj->m_instanceOffset; - - - - m_data->m_instance_positions_ptr[index*4]=position[0]; - m_data->m_instance_positions_ptr[index*4+1]=position[1]; - m_data->m_instance_positions_ptr[index*4+2]=position[2]; - m_data->m_instance_positions_ptr[index*4+3]=1; - - m_data->m_instance_quaternion_ptr[index*4]=quaternion[0]; - m_data->m_instance_quaternion_ptr[index*4+1]=quaternion[1]; - m_data->m_instance_quaternion_ptr[index*4+2]=quaternion[2]; - m_data->m_instance_quaternion_ptr[index*4+3]=quaternion[3]; - - m_data->m_instance_colors_ptr[index*4]=color[0]; - m_data->m_instance_colors_ptr[index*4+1]=color[1]; - m_data->m_instance_colors_ptr[index*4+2]=color[2]; - m_data->m_instance_colors_ptr[index*4+3]=color[3]; - - m_data->m_instance_scale_ptr[index*3] = scaling[0]; - m_data->m_instance_scale_ptr[index*3+1] = scaling[1]; - m_data->m_instance_scale_ptr[index*3+2] = scaling[2]; - - gfxObj->m_numGraphicsInstances++; - return gfxObj->m_numGraphicsInstances; -} - - -int GLInstancingRenderer::registerShape(const float* vertices, int numvertices, const int* indices, int numIndices) -{ - btGraphicsInstance* gfxObj = new btGraphicsInstance; - - if (m_graphicsInstances.size()) - { - btGraphicsInstance* prevObj = m_graphicsInstances[m_graphicsInstances.size()-1]; - gfxObj->m_instanceOffset = prevObj->m_instanceOffset + prevObj->m_numGraphicsInstances; - gfxObj->m_vertexArrayOffset = prevObj->m_vertexArrayOffset + prevObj->m_numVertices; - } else - { - gfxObj->m_instanceOffset = 0; - } - - m_graphicsInstances.push_back(gfxObj); - gfxObj->m_numIndices = numIndices; - gfxObj->m_numVertices = numvertices; - - - glBindBuffer(GL_ARRAY_BUFFER, cube_vbo); - char* dest= (char*)glMapBuffer( GL_ARRAY_BUFFER,GL_WRITE_ONLY);//GL_WRITE_ONLY - int vertexStrideInBytes = 9*sizeof(float); - int sz = numvertices*vertexStrideInBytes; - memcpy(dest+vertexStrideInBytes*gfxObj->m_vertexArrayOffset,vertices,sz); - glUnmapBuffer( GL_ARRAY_BUFFER); - - glGenBuffers(1, &gfxObj->m_index_vbo); - - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, gfxObj->m_index_vbo); - int indexBufferSizeInBytes = gfxObj->m_numIndices*sizeof(int); - - glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexBufferSizeInBytes, NULL, GL_STATIC_DRAW); - glBufferSubData(GL_ELEMENT_ARRAY_BUFFER,0,indexBufferSizeInBytes,indices); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - - glGenVertexArrays(1, &gfxObj->m_cube_vao); - glBindVertexArray(gfxObj->m_cube_vao); - glBindBuffer(GL_ARRAY_BUFFER, cube_vbo); - glBindVertexArray(0); - glBindBuffer(GL_ARRAY_BUFFER,0); - glBindVertexArray(0); - - - return m_graphicsInstances.size()-1; -} - - - - -void GLInstancingRenderer::InitShaders() -{ - - int POSITION_BUFFER_SIZE = (MAX_CONVEX_BODIES_CL*sizeof(float)*4); - int ORIENTATION_BUFFER_SIZE = (MAX_CONVEX_BODIES_CL*sizeof(float)*4); - int COLOR_BUFFER_SIZE = (MAX_CONVEX_BODIES_CL*sizeof(float)*4); - int SCALE_BUFFER_SIZE = (MAX_CONVEX_BODIES_CL*sizeof(float)*3); - - - instancingShader = gltLoadShaderPair(vertexShader,fragmentShader); - - glLinkProgram(instancingShader); - glUseProgram(instancingShader); - angle_loc = glGetUniformLocation(instancingShader, "angle"); - ModelViewMatrix = glGetUniformLocation(instancingShader, "ModelViewMatrix"); - ProjectionMatrix = glGetUniformLocation(instancingShader, "ProjectionMatrix"); - uniform_texture_diffuse = glGetUniformLocation(instancingShader, "Diffuse"); - - GLuint offset = 0; - - - glGenBuffers(1, &cube_vbo); - glBindBuffer(GL_ARRAY_BUFFER, cube_vbo); - - - int size = SHAPE_BUFFER_SIZE + POSITION_BUFFER_SIZE+ORIENTATION_BUFFER_SIZE+COLOR_BUFFER_SIZE+SCALE_BUFFER_SIZE; - VBOsize = size; - - glBufferData(GL_ARRAY_BUFFER, size, 0, GL_DYNAMIC_DRAW);//GL_STATIC_DRAW); - - glBindBuffer(GL_ARRAY_BUFFER,0); - glBindVertexArray(0); - - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - - -} - - -void myinit() -{ - GLint err = glGetError(); - - // GLfloat light_ambient[] = { btScalar(0.2), btScalar(0.2), btScalar(0.2), btScalar(1.0) }; - GLfloat light_ambient[] = { btScalar(1.0), btScalar(1.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 )}; - /* light_position is NOT default value */ - GLfloat light_position0[] = { btScalar(10000.0), btScalar(10000.0), btScalar(10000.0), btScalar(0.0 )}; - GLfloat light_position1[] = { btScalar(-1.0), btScalar(-10.0), btScalar(-1.0), btScalar(0.0) }; - - glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient); - glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse); - glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular); - glLightfv(GL_LIGHT0, GL_POSITION, light_position0); - - glLightfv(GL_LIGHT1, GL_AMBIENT, light_ambient); - glLightfv(GL_LIGHT1, GL_DIFFUSE, light_diffuse); - glLightfv(GL_LIGHT1, GL_SPECULAR, light_specular); - glLightfv(GL_LIGHT1, GL_POSITION, light_position1); - - glEnable(GL_LIGHTING); - glEnable(GL_LIGHT0); - glEnable(GL_LIGHT1); - - - // glShadeModel(GL_FLAT);//GL_SMOOTH); - glShadeModel(GL_SMOOTH); - - glEnable(GL_DEPTH_TEST); - glDepthFunc(GL_LESS); - - glClearColor(float(0.7),float(0.7),float(0.7),float(0)); - glEnable(GL_LIGHTING); - glEnable(GL_LIGHT0); - - - static bool m_textureenabled = true; - static bool m_textureinitialized = false; - - - if(m_textureenabled) - { - if(!m_textureinitialized) - { - glActiveTexture(GL_TEXTURE0); - - GLubyte* image=new GLubyte[256*256*3]; - for(int y=0;y<256;++y) - { - const int t=y>>5; - GLubyte* pi=image+y*256*3; - for(int x=0;x<256;++x) - { - if (x<2||y<2||x>253||y>253) - { - pi[0]=0; - pi[1]=0; - pi[2]=0; - } else - { - pi[0]=255; - pi[1]=255; - pi[2]=255; - } - - /* - const int s=x>>5; - const GLubyte b=180; - GLubyte c=b+((s+t&1)&1)*(255-b); - pi[0]=c; - pi[1]=c; - pi[2]=c; - */ - - pi+=3; - } - } - - glGenTextures(1,(GLuint*)&m_texturehandle); - glBindTexture(GL_TEXTURE_2D,m_texturehandle); - glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE); - glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR); - glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); - glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT); - glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT); - gluBuild2DMipmaps(GL_TEXTURE_2D,3,256,256,GL_RGB,GL_UNSIGNED_BYTE,image); - delete[] image; - m_textureinitialized=true; - } - // glMatrixMode(GL_TEXTURE); - // glLoadIdentity(); - // glMatrixMode(GL_MODELVIEW); - - glEnable(GL_TEXTURE_2D); - glBindTexture(GL_TEXTURE_2D,m_texturehandle); - - } else - { - glDisable(GL_TEXTURE_2D); - } - - glEnable(GL_COLOR_MATERIAL); - - err = glGetError(); - assert(err==GL_NO_ERROR); - - // glEnable(GL_CULL_FACE); - // glCullFace(GL_BACK); -} - -void updateCamera() -{ - - - - btVector3 m_cameraUp(0,1,0); - int m_forwardAxis=2; - - - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - - - //m_azi+=0.0f; - - btScalar rele = m_ele * btScalar(0.01745329251994329547);// rads per deg - btScalar razi = m_azi * btScalar(0.01745329251994329547);// rads per deg - - - btQuaternion rot(m_cameraUp,razi); - - - btVector3 eyePos(0,0,0); - eyePos[m_forwardAxis] = -m_cameraDistance; - - btVector3 forward(eyePos[0],eyePos[1],eyePos[2]); - if (forward.length2() < SIMD_EPSILON) - { - forward.setValue(1.f,0.f,0.f); - } - btVector3 right = m_cameraUp.cross(forward); - btQuaternion roll(right,-rele); - - eyePos = btMatrix3x3(rot) * btMatrix3x3(roll) * eyePos; - - m_cameraPosition[0] = eyePos.getX(); - m_cameraPosition[1] = eyePos.getY(); - m_cameraPosition[2] = eyePos.getZ(); - m_cameraPosition += m_cameraTargetPosition; - - - float m_frustumZNear=1; - float m_frustumZFar=1000; - - if (m_glutScreenWidth == 0 && m_glutScreenHeight == 0) - return; - - float aspect; - btVector3 extents; - - if (m_glutScreenWidth > m_glutScreenHeight) - { - aspect = m_glutScreenWidth / (float)m_glutScreenHeight; - extents.setValue(aspect * 1.0f, 1.0f,0); - } else - { - aspect = m_glutScreenHeight / (float)m_glutScreenWidth; - extents.setValue(1.0f, aspect*1.f,0); - } - - - if (m_ortho) - { - // reset matrix - glLoadIdentity(); - extents *= m_cameraDistance; - btVector3 lower = m_cameraTargetPosition - extents; - btVector3 upper = m_cameraTargetPosition + extents; - glOrtho(lower.getX(), upper.getX(), lower.getY(), upper.getY(),-1000,1000); - - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - } else - { - if (m_glutScreenWidth > m_glutScreenHeight) - { - glFrustum (-aspect * m_frustumZNear, aspect * m_frustumZNear, -m_frustumZNear, m_frustumZNear, m_frustumZNear, m_frustumZFar); - } else - { - glFrustum (-aspect * m_frustumZNear, aspect * m_frustumZNear, -m_frustumZNear, m_frustumZNear, m_frustumZNear, m_frustumZFar); - } - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - gluLookAt(m_cameraPosition[0], m_cameraPosition[1], m_cameraPosition[2], - m_cameraTargetPosition[0], m_cameraTargetPosition[1], m_cameraTargetPosition[2], - m_cameraUp.getX(),m_cameraUp.getY(),m_cameraUp.getZ()); - } - -} - - -void GLInstancingRenderer::RenderScene(void) -{ - BT_PROFILE("GlutDisplayFunc"); - - myinit(); - - updateCamera(); - - //render coordinate system - glBegin(GL_LINES); - glColor3f(1,0,0); - glVertex3f(0,0,0); - glVertex3f(1,0,0); - glColor3f(0,1,0); - glVertex3f(0,0,0); - glVertex3f(0,1,0); - glColor3f(0,0,1); - glVertex3f(0,0,0); - glVertex3f(0,0,1); - glEnd(); - - //do a finish, to make sure timings are clean - // glFinish(); - - - - // glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ARRAY_BUFFER, cube_vbo); - glFlush(); - - //updatePos(); - -// simulationLoop(); - - //useCPU = true; - - int totalNumInstances = 0; - - for (int i=0;im_numGraphicsInstances; - } - - int curOffset = 0; - - for (int i=0;im_instanceOffset*4*sizeof(float); - - int POSITION_BUFFER_SIZE = (totalNumInstances*sizeof(float)*4); - int ORIENTATION_BUFFER_SIZE = (totalNumInstances*sizeof(float)*4); - int COLOR_BUFFER_SIZE = (totalNumInstances*sizeof(float)*4); - int SCALE_BUFFER_SIZE = (totalNumInstances*sizeof(float)*3); - - glBindVertexArray(gfxObj->m_cube_vao); - - - int vertexStride = 9*sizeof(float); - int vertexBase = gfxObj->m_vertexArrayOffset*vertexStride; - - glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 9*sizeof(float), (GLvoid*)vertexBase); - glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, (GLvoid *)(curOffset*4*sizeof(float)+SHAPE_BUFFER_SIZE)); - glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, 0, (GLvoid *)(curOffset*4*sizeof(float)+SHAPE_BUFFER_SIZE+POSITION_BUFFER_SIZE)); - int uvoffset = 7*sizeof(float)+vertexBase; - int normaloffset = 4*sizeof(float)+vertexBase; - - glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, 9*sizeof(float), (GLvoid *)uvoffset); - glVertexAttribPointer(4, 3, GL_FLOAT, GL_FALSE, 9*sizeof(float), (GLvoid *)normaloffset); - glVertexAttribPointer(5, 4, GL_FLOAT, GL_FALSE, 0, (GLvoid *)(curOffset*4*sizeof(float)+SHAPE_BUFFER_SIZE+POSITION_BUFFER_SIZE+ORIENTATION_BUFFER_SIZE)); - glVertexAttribPointer(6, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid *)(curOffset*3*sizeof(float)+SHAPE_BUFFER_SIZE+POSITION_BUFFER_SIZE+ORIENTATION_BUFFER_SIZE+COLOR_BUFFER_SIZE)); - - glEnableVertexAttribArray(0); - glEnableVertexAttribArray(1); - glEnableVertexAttribArray(2); - glEnableVertexAttribArray(3); - glEnableVertexAttribArray(4); - glEnableVertexAttribArray(5); - glEnableVertexAttribArray(6); - - glVertexAttribDivisor(0, 0); - glVertexAttribDivisor(1, 1); - glVertexAttribDivisor(2, 1); - glVertexAttribDivisor(3, 0); - glVertexAttribDivisor(4, 0); - glVertexAttribDivisor(5, 1); - glVertexAttribDivisor(6, 1); - - glUseProgram(instancingShader); - glUniform1f(angle_loc, 0); - GLfloat pm[16]; - glGetFloatv(GL_PROJECTION_MATRIX, pm); - glUniformMatrix4fv(ProjectionMatrix, 1, false, &pm[0]); - - GLfloat mvm[16]; - glGetFloatv(GL_MODELVIEW_MATRIX, mvm); - glUniformMatrix4fv(ModelViewMatrix, 1, false, &mvm[0]); - - glUniform1i(uniform_texture_diffuse, 0); - - glFlush(); - - if (gfxObj->m_numGraphicsInstances) - { - int indexCount = gfxObj->m_numIndices; - int indexOffset = 0; - - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, gfxObj->m_index_vbo); - { - BT_PROFILE("glDrawElementsInstanced"); - glDrawElementsInstanced(GL_TRIANGLES, indexCount, GL_UNSIGNED_INT, (void*)indexOffset, gfxObj->m_numGraphicsInstances); - } - } - curOffset+= gfxObj->m_numGraphicsInstances; - } - glUseProgram(0); - glBindBuffer(GL_ARRAY_BUFFER,0); - glBindVertexArray(0); - - - GLint err = glGetError(); - assert(err==GL_NO_ERROR); -} - - -void GLInstancingRenderer::CleanupShaders() -{ - - delete []m_data->m_instance_positions_ptr; - delete []m_data->m_instance_quaternion_ptr; - delete []m_data->m_instance_colors_ptr; - delete []m_data->m_instance_scale_ptr; -} \ No newline at end of file diff --git a/Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline2/GLInstancingRenderer.h b/Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline2/GLInstancingRenderer.h deleted file mode 100644 index b5924385b..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline2/GLInstancingRenderer.h +++ /dev/null @@ -1,45 +0,0 @@ -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Erwin Coumans - -#ifndef GL_INSTANCING_RENDERER_H -#define GL_INSTANCING_RENDERER_H - -#include "LinearMath/btAlignedObjectArray.h" - -class GLInstancingRenderer -{ - - btAlignedObjectArray m_graphicsInstances; - - struct InternalDataRenderer* m_data; - -public: - GLInstancingRenderer(); - virtual ~GLInstancingRenderer(); - - void InitShaders(); - void RenderScene(void); - void CleanupShaders(); - - ///vertices must be in the format x,y,z, nx,ny,nz, u,v - int registerShape(const float* vertices, int numvertices, const int* indices, int numIndices); - - ///position x,y,z, quaternion x,y,z,w, color r,g,b,a, scaling x,y,z - int registerGraphicsInstance(int shapeIndex, const float* position, const float* quaternion, const float* color, const float* scaling); - - void writeTransforms(); -}; - -#endif //GL_INSTANCING_RENDERER_H diff --git a/Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline2/GlutRenderer.cpp b/Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline2/GlutRenderer.cpp deleted file mode 100644 index 3cb02c278..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline2/GlutRenderer.cpp +++ /dev/null @@ -1,107 +0,0 @@ -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Erwin Coumans - - -#include -#include "GlutRenderer.h" -#include - - -GlutRenderer* GlutRenderer::gDemoApplication; - - - -void GlutRenderer::runMainLoop() -{ - glutMainLoop(); - -} - - -static void glutKeyboardCallback(unsigned char key, int x, int y) { GlutRenderer::gDemoApplication->keyboardCallback(key,x,y); } -static void glutKeyboardUpCallback(unsigned char key, int x, int y){ GlutRenderer::gDemoApplication->keyboardUpCallback(key,x,y);} -static void glutSpecialKeyboardCallback(int key, int x, int y){ GlutRenderer::gDemoApplication->specialKeyboard(key,x,y);} -static void glutSpecialKeyboardUpCallback(int key, int x, int y){ GlutRenderer::gDemoApplication->specialKeyboardUp(key,x,y);} -static void glutReshapeCallback(int w, int h){ GlutRenderer::gDemoApplication->resize(w,h);} -static void glutIdleCallback(){ glutPostRedisplay (); } -static void glutMouseFuncCallback(int button, int state, int x, int y){ GlutRenderer::gDemoApplication->mouseFunc(button,state,x,y);} -static void glutMotionFuncCallback(int x,int y){ GlutRenderer::gDemoApplication->mouseMotionFunc(x,y);} -static void glutDisplayCallback(void){ GlutRenderer::gDemoApplication->displayCallback();} - - -void GlutRenderer::resize(int width, int height) -{ - m_glutScreenWidth = width; - m_glutScreenHeight = height; -} - -void GlutRenderer::mouseFunc(int button, int state, int x, int y) -{ -} -void GlutRenderer::mouseMotionFunc(int x,int y) -{ -} - -void GlutRenderer::renderScene() -{ - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - glutSwapBuffers(); - glutPostRedisplay(); - - GLint err = glGetError(); - assert(err==GL_NO_ERROR); -} - -void GlutRenderer::displayCallback() -{ - updateScene(); - - renderScene(); -} - -GlutRenderer::GlutRenderer(int argc, char* argv[]) -{ - glutInit(&argc, argv); - gDemoApplication = this; -} - -void GlutRenderer::initGraphics(int width, int height) -{ - m_glutScreenWidth = width; - m_glutScreenHeight = height; - - glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA); - - glutInitWindowSize(m_glutScreenWidth, m_glutScreenHeight); - glutCreateWindow("GPU rigid body pipeline2"); - glutKeyboardFunc(glutKeyboardCallback); - glutKeyboardUpFunc(glutKeyboardUpCallback); - glutSpecialFunc(glutSpecialKeyboardCallback); - glutSpecialUpFunc(glutSpecialKeyboardUpCallback); - glutReshapeFunc(glutReshapeCallback); - glutIdleFunc(glutIdleCallback); - glutMouseFunc(glutMouseFuncCallback); - glutPassiveMotionFunc(glutMotionFuncCallback); - glutMotionFunc(glutMotionFuncCallback); - glutDisplayFunc( glutDisplayCallback ); - - GLenum err = glewInit(); - if (GLEW_OK != err) - { - printf("Error: %s\n", glewGetErrorString(err)); - } - - glClearColor(0.6f,0.6f,1.f,1.f); -} \ No newline at end of file diff --git a/Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline2/GlutRenderer.h b/Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline2/GlutRenderer.h deleted file mode 100644 index 3596ad490..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline2/GlutRenderer.h +++ /dev/null @@ -1,59 +0,0 @@ -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Erwin Coumans - -#ifndef GLUT_RENDERER_H -#define GLUT_RENDERER_H - -#include "btGlutInclude.h" -#include "LinearMath/btVector3.h" - -struct GlutRenderer -{ - static GlutRenderer* gDemoApplication; - int m_glutScreenWidth; - int m_glutScreenHeight; - - btVector3 m_cameraPosition; - btVector3 m_cameraTargetPosition; - btScalar m_cameraDistance; - btVector3 m_cameraUp; - float m_azimuth; - float m_elevation; - - - GlutRenderer(int argc, char* argv[]); - - virtual void initGraphics(int width, int height); - virtual void cleanup() {} - - void runMainLoop(); - - virtual void updateScene(){}; - - virtual void renderScene(); - - virtual void keyboardCallback(unsigned char key, int x, int y) {}; - virtual void keyboardUpCallback(unsigned char key, int x, int y) {} - virtual void specialKeyboard(int key, int x, int y){} - virtual void specialKeyboardUp(int key, int x, int y){} - virtual void resize(int w, int h); - virtual void mouseFunc(int button, int state, int x, int y); - virtual void mouseMotionFunc(int x,int y); - virtual void displayCallback(); - - -}; - -#endif //GLUT_RENDERER_H diff --git a/Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline2/NVIDIA/premake4.lua b/Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline2/NVIDIA/premake4.lua deleted file mode 100644 index 8ccc57e5d..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline2/NVIDIA/premake4.lua +++ /dev/null @@ -1,64 +0,0 @@ - - hasCL = findOpenCL_NVIDIA() - - if (hasCL) then - - project "OpenCL_gpu_rigidbody_pipeline2_NVIDIA" - - initOpenCL_NVIDIA() - - language "C++" - - kind "ConsoleApp" - targetdir "../../../bin" - - initOpenGL() - initGlew() - - - includedirs { - "../../primitives", - "../../../bullet2" - } - - files { - "../main.cpp", - "../CLPhysicsDemo.cpp", - "../CLPhysicsDemo.h", - "../GLInstancingRenderer.cpp", - "../GLInstancingRenderer.h", - "../GlutRenderer.cpp", - "../GlutRenderer.h", - "../Win32OpenGLRenderManager.cpp", - "../Win32OpenGLRenderManager.h", - "../../gpu_rigidbody_pipeline/btConvexUtility.cpp", - "../../gpu_rigidbody_pipeline/btConvexUtility.h", - "../../gpu_rigidbody_pipeline/btGpuNarrowPhaseAndSolver.cpp", - "../../gpu_rigidbody_pipeline/btGpuNarrowPhaseAndSolver.h", - "../../../dynamics/basic_demo/ConvexHeightFieldShape.cpp", - "../../../dynamics/basic_demo/ConvexHeightFieldShape.h", - "../../../bullet2/LinearMath/btConvexHullComputer.cpp", - "../../../bullet2/LinearMath/btConvexHullComputer.h", - "../../broadphase_benchmark/findPairsOpenCL.cpp", - "../../broadphase_benchmark/findPairsOpenCL.h", - "../../broadphase_benchmark/btGridBroadphaseCL.cpp", - "../../broadphase_benchmark/btGridBroadphaseCL.h", - "../../3dGridBroadphase/Shared/bt3dGridBroadphaseOCL.cpp", - "../../3dGridBroadphase/Shared/bt3dGridBroadphaseOCL.h", - "../../3dGridBroadphase/Shared/btGpu3DGridBroadphase.cpp", - "../../3dGridBroadphase/Shared/btGpu3DGridBroadphase.h", - "../../../bullet2/LinearMath/btAlignedAllocator.cpp", - "../../../bullet2/LinearMath/btQuickprof.cpp", - "../../../bullet2/LinearMath/btQuickprof.h", - "../../../bullet2/BulletCollision/BroadphaseCollision/btBroadphaseProxy.cpp", - "../../../bullet2/BulletCollision/BroadphaseCollision/btOverlappingPairCache.cpp", - "../../../bullet2/BulletCollision/BroadphaseCollision/btSimpleBroadphase.cpp", - "../../basic_initialize/btOpenCLUtils.cpp", - "../../basic_initialize/btOpenCLUtils.h", - "../../opengl_interop/btOpenCLGLInteropBuffer.cpp", - "../../opengl_interop/btOpenCLGLInteropBuffer.h", - "../../opengl_interop/btStopwatch.cpp", - "../../opengl_interop/btStopwatch.h" - } - - end diff --git a/Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline2/OpenGLInclude.h b/Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline2/OpenGLInclude.h deleted file mode 100644 index 2b3060bd3..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline2/OpenGLInclude.h +++ /dev/null @@ -1,41 +0,0 @@ -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Erwin Coumans - - -#ifndef __OPENGL_INCLUDE_H -#define __OPENGL_INCLUDE_H - -#include - -//think different -#if defined(__APPLE__) && !defined (VMDMESA) -#include -#include -#include -#else - - -#ifdef _WINDOWS -#include -#include -#include -#else -#include - -#endif //_WINDOWS -#endif //APPLE - -#endif //__OPENGL_INCLUDE_H - diff --git a/Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline2/ShapeData.h b/Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline2/ShapeData.h deleted file mode 100644 index e77affe61..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline2/ShapeData.h +++ /dev/null @@ -1,210 +0,0 @@ -#ifndef SHAPE_DATA_H -#define SHAPE_DATA_H - -static float barrel_vertices[] = { -0.0f,-0.5f,0.0f, 1.0f, 0.0f,-1.0f,0.0f, 0.5f, 0.5f, -0.282362f,-0.5f,-0.205148f, 1.0f, 0.0f,-1.0f,0.0f, 0.5f, 0.5f, -0.349018f,-0.5f,0.0f, 1.0f, 0.0f,-1.0f,0.0f, 0.5f, 0.5f, -0.107853f,-0.5f,-0.331936f, 1.0f, 0.0f,-1.0f,0.0f, 0.5f, 0.5f, --0.107853f,-0.5f,-0.331936f, 1.0f, 0.0f,-1.0f,0.0f, 0.5f, 0.5f, -0.107853f,-0.5f,-0.331936f, 1.0f, 0.0f,-1.0f,0.0f, 0.5f, 0.5f, --0.282362f,-0.5f,-0.205148f, 1.0f, 0.0f,-1.0f,0.0f, 0.5f, 0.5f, --0.349018f,-0.5f,0.0f, 1.0f, 0.0f,-1.0f,0.0f, 0.5f, 0.5f, --0.282362f,-0.5f,0.205148f, 1.0f, 0.0f,-1.0f,0.0f, 0.5f, 0.5f, --0.107853f,-0.5f,0.331936f, 1.0f, 0.0f,-1.0f,0.0f, 0.5f, 0.5f, -0.107853f,-0.5f,0.331936f, 1.0f, 0.0f,-1.0f,0.0f, 0.5f, 0.5f, -0.282362f,-0.5f,0.205148f, 1.0f, 0.0f,-1.0f,0.0f, 0.5f, 0.5f, -0.0f,0.5f,0.0f, 1.0f, 0.0f,1.0f,0.0f, 0.5f, 0.5f, -0.349018f,0.5f,0.0f, 1.0f, 0.0f,1.0f,0.0f, 0.5f, 0.5f, -0.282362f,0.5f,-0.205148f, 1.0f, 0.0f,1.0f,0.0f, 0.5f, 0.5f, -0.107853f,0.5f,-0.331936f, 1.0f, 0.0f,1.0f,0.0f, 0.5f, 0.5f, -0.107853f,0.5f,-0.331936f, 1.0f, 0.0f,1.0f,0.0f, 0.5f, 0.5f, --0.107853f,0.5f,-0.331936f, 1.0f, 0.0f,1.0f,0.0f, 0.5f, 0.5f, --0.282362f,0.5f,-0.205148f, 1.0f, 0.0f,1.0f,0.0f, 0.5f, 0.5f, --0.349018f,0.5f,0.0f, 1.0f, 0.0f,1.0f,0.0f, 0.5f, 0.5f, --0.282362f,0.5f,0.205148f, 1.0f, 0.0f,1.0f,0.0f, 0.5f, 0.5f, --0.107853f,0.5f,0.331936f, 1.0f, 0.0f,1.0f,0.0f, 0.5f, 0.5f, -0.107853f,0.5f,0.331936f, 1.0f, 0.0f,1.0f,0.0f, 0.5f, 0.5f, -0.282362f,0.5f,0.205148f, 1.0f, 0.0f,1.0f,0.0f, 0.5f, 0.5f, -0.349018f,-0.5f,0.0f, 1.0f, 0.957307f,-0.289072f,0.0f, 0.5f, 0.5f, -0.404509f,0.0f,-0.293893f, 1.0f, 0.809017f,0.0f,-0.587785f, 0.5f, 0.5f, -0.5f,0.0f,0.0f, 1.0f, 1.0f,0.0f,0.0f, 0.5f, 0.5f, -0.282362f,-0.5f,-0.205148f, 1.0f, 0.774478f,-0.289072f,-0.562691f, 0.5f, 0.5f, -0.154508f,0.0f,-0.475528f, 1.0f, 0.309017f,0.0f,-0.951057f, 0.5f, 0.5f, -0.107853f,-0.5f,-0.331936f, 1.0f, 0.295824f,-0.289072f,-0.910453f, 0.5f, 0.5f, -0.107853f,-0.5f,-0.331936f, 1.0f, 0.295824f,-0.289072f,-0.910453f, 0.5f, 0.5f, --0.154509f,0.0f,-0.475528f, 1.0f, -0.309017f,0.0f,-0.951057f, 0.5f, 0.5f, -0.154508f,0.0f,-0.475528f, 1.0f, 0.309017f,0.0f,-0.951057f, 0.5f, 0.5f, --0.107853f,-0.5f,-0.331936f, 1.0f, -0.295824f,-0.289072f,-0.910453f, 0.5f, 0.5f, --0.404509f,0.0f,-0.293893f, 1.0f, -0.809017f,0.0f,-0.587785f, 0.5f, 0.5f, --0.282362f,-0.5f,-0.205148f, 1.0f, -0.774478f,-0.289072f,-0.562691f, 0.5f, 0.5f, --0.5f,0.0f,0.0f, 1.0f, -1.0f,0.0f,0.0f, 0.5f, 0.5f, --0.349018f,-0.5f,0.0f, 1.0f, -0.957307f,-0.289072f,0.0f, 0.5f, 0.5f, --0.404508f,0.0f,0.293893f, 1.0f, -0.809017f,0.0f,0.587785f, 0.5f, 0.5f, --0.282362f,-0.5f,0.205148f, 1.0f, -0.774478f,-0.289072f,0.562691f, 0.5f, 0.5f, --0.154509f,0.0f,0.475528f, 1.0f, -0.309017f,0.0f,0.951056f, 0.5f, 0.5f, --0.107853f,-0.5f,0.331936f, 1.0f, -0.295824f,-0.289072f,0.910453f, 0.5f, 0.5f, -0.154509f,0.0f,0.475528f, 1.0f, 0.309017f,0.0f,0.951056f, 0.5f, 0.5f, -0.107853f,-0.5f,0.331936f, 1.0f, 0.295824f,-0.289072f,0.910453f, 0.5f, 0.5f, -0.404509f,0.0f,0.293892f, 1.0f, 0.809017f,0.0f,0.587785f, 0.5f, 0.5f, -0.282362f,-0.5f,0.205148f, 1.0f, 0.774478f,-0.289072f,0.562691f, 0.5f, 0.5f, -0.282362f,0.5f,-0.205148f, 1.0f, 0.774478f,0.289072f,-0.562691f, 0.5f, 0.5f, -0.349018f,0.5f,0.0f, 1.0f, 0.957307f,0.289072f,0.0f, 0.5f, 0.5f, -0.107853f,0.5f,-0.331936f, 1.0f, 0.295824f,0.289072f,-0.910453f, 0.5f, 0.5f, --0.107853f,0.5f,-0.331936f, 1.0f, -0.295824f,0.289072f,-0.910453f, 0.5f, 0.5f, -0.107853f,0.5f,-0.331936f, 1.0f, 0.295824f,0.289072f,-0.910453f, 0.5f, 0.5f, --0.282362f,0.5f,-0.205148f, 1.0f, -0.774478f,0.289072f,-0.562691f, 0.5f, 0.5f, --0.349018f,0.5f,0.0f, 1.0f, -0.957307f,0.289072f,0.0f, 0.5f, 0.5f, --0.282362f,0.5f,0.205148f, 1.0f, -0.774478f,0.289072f,0.562691f, 0.5f, 0.5f, --0.107853f,0.5f,0.331936f, 1.0f, -0.295824f,0.289072f,0.910453f, 0.5f, 0.5f, -0.107853f,0.5f,0.331936f, 1.0f, 0.295824f,0.289072f,0.910453f, 0.5f, 0.5f, -0.282362f,0.5f,0.205148f, 1.0f, 0.774478f,0.289072f,0.562691f, 0.5f, 0.5f -}; - - - -static int barrel_indices[] = { -0,1,2, -0,3,1, -0,4,5, -0,6,4, -0,7,6, -0,8,7, -0,9,8, -0,10,9, -0,11,10, -0,2,11, -12,13,14, -12,14,15, -12,16,17, -12,17,18, -12,18,19, -12,19,20, -12,20,21, -12,21,22, -12,22,23, -12,23,13, -24,25,26, -24,27,25, -27,28,25, -27,29,28, -30,31,32, -30,33,31, -33,34,31, -33,35,34, -35,36,34, -35,37,36, -37,38,36, -37,39,38, -39,40,38, -39,41,40, -41,42,40, -41,43,42, -43,44,42, -43,45,44, -45,26,44, -45,24,26, -26,46,47, -26,25,46, -25,48,46, -25,28,48, -32,49,50, -32,31,49, -31,51,49, -31,34,51, -34,52,51, -34,36,52, -36,53,52, -36,38,53, -38,54,53, -38,40,54, -40,55,54, -40,42,55, -42,56,55, -42,44,56, -44,47,56, -44,26,47, -}; - - -///position xyz, unused w, normal, uv -static const float cube_vertices[] = -{ - -0.5f, -0.5f, 0.5f, 0.0f, 0,0,1, 0,0,//0 - 0.5f, -0.5f, 0.5f, 0.0f, 0,0,1, 1,0,//1 - 0.5f, 0.5f, 0.5f, 0.0f, 0,0,1, 1,1,//2 - -0.5f, 0.5f, 0.5f, 0.0f, 0,0,1, 0,1 ,//3 - - -0.5f, -0.5f, -0.5f, 0.5f, 0,0,-1, 0,0,//4 - 0.5f, -0.5f, -0.5f, 0.5f, 0,0,-1, 1,0,//5 - 0.5f, 0.5f, -0.5f, 0.5f, 0,0,-1, 1,1,//6 - -0.5f, 0.5f, -0.5f, 0.5f, 0,0,-1, 0,1,//7 - - -0.5f, -0.5f, -0.5f, 0.5f, -1,0,0, 0,0, - -0.5f, 0.5f, -0.5f, 0.5f, -1,0,0, 1,0, - -0.5f, 0.5f, 0.5f, 0.5f, -1,0,0, 1,1, - -0.5f, -0.5f, 0.5f, 0.5f, -1,0,0, 0,1, - - 0.5f, -0.5f, -0.5f, 0.5f, 1,0,0, 0,0, - 0.5f, 0.5f, -0.5f, 0.5f, 1,0,0, 1,0, - 0.5f, 0.5f, 0.5f, 0.5f, 1,0,0, 1,1, - 0.5f, -0.5f, 0.5f, 0.5f, 1,0,0, 0,1, - - -0.5f, -0.5f, -0.5f, 0.5f, 0,-1,0, 0,0, - -0.5f, -0.5f, 0.5f, 0.5f, 0,-1,0, 1,0, - 0.5f, -0.5f, 0.5f, 0.5f, 0,-1,0, 1,1, - 0.5f,-0.5f, -0.5f, 0.5f, 0,-1,0, 0,1, - - -0.5f, 0.5f, -0.5f, 0.5f, 0,1,0, 0,0, - -0.5f, 0.5f, 0.5f, 0.5f, 0,1,0, 1,0, - 0.5f, 0.5f, 0.5f, 0.5f, 0,1,0, 1,1, - 0.5f,0.5f, -0.5f, 0.5f, 0,1,0, 0,1, -}; - - -///position xyz, unused w, normal, uv -static const float cube_vertices2[] = -{ - -1.5f, -0.5f, 0.5f, 0.0f, 0,0,1, 0,0,//0 - 1.5f, -0.5f, 0.5f, 0.0f, 0,0,1, 1,0,//1 - 1.5f, 0.5f, 0.5f, 0.0f, 0,0,1, 1,1,//2 - -1.5f, 0.5f, 0.5f, 0.0f, 0,0,1, 0,1 ,//3 - - -1.5f, -0.5f, -0.5f, 0.5f, 0,0,-1, 0,0,//4 - 1.5f, -0.5f, -0.5f, 0.5f, 0,0,-1, 1,0,//5 - 1.5f, 0.5f, -0.5f, 0.5f, 0,0,-1, 1,1,//6 - -1.5f, 0.5f, -0.5f, 0.5f, 0,0,-1, 0,1,//7 - - -1.5f, -0.5f, -0.5f, 0.5f, -1,0,0, 0,0, - -1.5f, 0.5f, -0.5f, 0.5f, -1,0,0, 1,0, - -1.5f, 0.5f, 0.5f, 0.5f, -1,0,0, 1,1, - -1.5f, -0.5f, 0.5f, 0.5f, -1,0,0, 0,1, - - 1.5f, -0.5f, -0.5f, 0.5f, 1,0,0, 0,0, - 1.5f, 0.5f, -0.5f, 0.5f, 1,0,0, 1,0, - 1.5f, 0.5f, 0.5f, 0.5f, 1,0,0, 1,1, - 1.5f, -0.5f, 0.5f, 0.5f, 1,0,0, 0,1, - - -1.5f, -0.5f, -0.5f, 0.5f, 0,-1,0, 0,0, - -1.5f, -0.5f, 0.5f, 0.5f, 0,-1,0, 1,0, - 1.5f, -0.5f, 0.5f, 0.5f, 0,-1,0, 1,1, - 1.5f, -0.5f, -0.5f, 0.5f, 0,-1,0, 0,1, - - -1.5f, 0.5f, -0.5f, 0.5f, 0,1,0, 0,0, - -1.5f, 0.5f, 0.5f, 0.5f, 0,1,0, 1,0, - 1.5f, 0.5f, 0.5f, 0.5f, 0,1,0, 1,1, - 1.5f, 0.5f, -0.5f, 0.5f, 0,1,0, 0,1, -}; - - -static const int cube_indices[]= -{ - 0,1,2,0,2,3,//ground face - 4,5,6,4,6,7,//top face - 8,9,10,8,10,11, - 12,13,14,12,14,15, - 16,17,18,16,18,19, - 20,21,22,20,22,23 -}; - -#endif //SHAPE_DATA_H diff --git a/Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline2/Win32OpenGLRenderManager.cpp b/Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline2/Win32OpenGLRenderManager.cpp deleted file mode 100644 index c3b9f250a..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline2/Win32OpenGLRenderManager.cpp +++ /dev/null @@ -1,465 +0,0 @@ -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Erwin Coumans - - -#include "Win32OpenGLRenderManager.h" - -#include -#include - -static InternalData2* sData = 0; - -struct InternalData2 -{ - HWND m_hWnd;; - int m_width; - int m_height; - HDC m_hDC; - HGLRC m_hRC; - bool m_OpenGLInitialized; - int m_oldScreenWidth; - int m_oldHeight; - int m_oldBitsPerPel; - bool m_quit; - - - InternalData2() - { - m_hWnd = 0; - m_width = 0; - m_height = 0; - m_hDC = 0; - m_hRC = 0; - m_OpenGLInitialized = false; - m_oldScreenWidth = 0; - m_oldHeight = 0; - m_oldBitsPerPel = 0; - m_quit = false; - } -}; - - -void Win32OpenGLWindow::enableOpenGL() -{ - - - - PIXELFORMATDESCRIPTOR pfd; - int format; - - // get the device context (DC) - m_data->m_hDC = GetDC( m_data->m_hWnd ); - - // set the pixel format for the DC - ZeroMemory( &pfd, sizeof( pfd ) ); - pfd.nSize = sizeof( pfd ); - pfd.nVersion = 1; - pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; - pfd.iPixelType = PFD_TYPE_RGBA; - pfd.cColorBits = 24; - pfd.cDepthBits = 16; - pfd.cStencilBits = 1; - pfd.iLayerType = PFD_MAIN_PLANE; - format = ChoosePixelFormat( m_data->m_hDC, &pfd ); - SetPixelFormat( m_data->m_hDC, format, &pfd ); - - // create and enable the render context (RC) - m_data->m_hRC = wglCreateContext( m_data->m_hDC ); - wglMakeCurrent( m_data->m_hDC, m_data->m_hRC ); - m_data->m_OpenGLInitialized = true; - - -} - - -void Win32OpenGLWindow::disableOpenGL() -{ - m_data->m_OpenGLInitialized = false; - - wglMakeCurrent( NULL, NULL ); - wglDeleteContext( m_data->m_hRC ); - ReleaseDC( m_data->m_hWnd, m_data->m_hDC ); -} - -void Win32OpenGLWindow::pumpMessage() -{ - MSG msg; - // check for messages - if ( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) ) - { - - // handle or dispatch messages - if ( msg.message == WM_QUIT ) - { - m_data->m_quit = TRUE; - } - else - { - TranslateMessage( &msg ); - DispatchMessage( &msg ); - } - -// gDemoApplication->displayCallback(); - - - }; -} - - - -LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) -{ - switch (message) - { - case WM_PAINT: - { - PAINTSTRUCT ps; - BeginPaint(hWnd, &ps); - EndPaint(hWnd, &ps); - } - return 0; - - case WM_ERASEBKGND: - return 0; - - case WM_DESTROY: - PostQuitMessage(0); - return 0; - - case WM_KEYDOWN: - { - switch ( wParam ) - { - case 'Q': - case VK_ESCAPE: - { - PostQuitMessage(0); - } - return 0; - } - break; - } - - case WM_SIZE: // Size Action Has Taken Place - - switch (wParam) // Evaluate Size Action - { - case SIZE_MINIMIZED: // Was Window Minimized? - return 0; // Return - - case SIZE_MAXIMIZED: // Was Window Maximized? - - sData->m_width = LOWORD (lParam); - sData->m_height = HIWORD (lParam); - //if (sOpenGLInitialized) - //{ - // //gDemoApplication->reshape(sWidth,sHeight); - //} - glViewport(0, 0, sData->m_width, sData->m_height); - return 0; // Return - - case SIZE_RESTORED: // Was Window Restored? - sData->m_width = LOWORD (lParam); - sData->m_height = HIWORD (lParam); - //if (sOpenGLInitialized) - //{ - // gDemoApplication->reshape(sWidth,sHeight); - //} - glViewport(0, 0, sData->m_width, sData->m_height); - return 0; // Return - } - break; - - default:{ - - } - }; - - return DefWindowProc(hWnd, message, wParam, lParam); -} - - - - -void Win32OpenGLWindow::init(int width,int height, bool fullscreen,int colorBitsPerPixel, void* windowHandle) -{ - // get handle to exe file - HINSTANCE hInstance = GetModuleHandle(0); - - // create the window if we need to and we do not use the null device - if (!windowHandle) - { - const char* ClassName = "DeviceWin32"; - - // Register Class - WNDCLASSEX wcex; - wcex.cbSize = sizeof(WNDCLASSEX); - wcex.style = CS_HREDRAW | CS_VREDRAW; - wcex.lpfnWndProc = WndProc; - wcex.cbClsExtra = 0; - wcex.cbWndExtra = 0; - wcex.hInstance = hInstance; - wcex.hIcon = LoadIcon( NULL, IDI_APPLICATION ); //(HICON)LoadImage(hInstance, "bullet_ico.ico", IMAGE_ICON, 0,0, LR_LOADTRANSPARENT);//LR_LOADFROMFILE); - wcex.hCursor = LoadCursor(NULL, IDC_ARROW); - wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); - wcex.lpszMenuName = 0; - wcex.lpszClassName = ClassName; - wcex.hIconSm = 0; - - // if there is an icon, load it - wcex.hIcon = (HICON)LoadImage(hInstance, "irrlicht.ico", IMAGE_ICON, 0,0, LR_LOADFROMFILE); - - RegisterClassEx(&wcex); - - // calculate client size - - RECT clientSize; - clientSize.top = 0; - clientSize.left = 0; - clientSize.right = width; - clientSize.bottom = height; - - DWORD style = WS_POPUP; - - if (!fullscreen) - style = WS_SYSMENU | WS_BORDER | WS_CAPTION | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_SIZEBOX; - - AdjustWindowRect(&clientSize, style, FALSE); - - m_data->m_width = clientSize.right - clientSize.left; - m_data->m_height = clientSize.bottom - clientSize.top; - - int windowLeft = (GetSystemMetrics(SM_CXSCREEN) - m_data->m_width) / 2; - int windowTop = (GetSystemMetrics(SM_CYSCREEN) - m_data->m_height) / 2; - - if (fullscreen) - { - windowLeft = 0; - windowTop = 0; - } - - // create window - - m_data->m_hWnd = CreateWindow( ClassName, "", style, windowLeft, windowTop, - m_data->m_width, m_data->m_height, NULL, NULL, hInstance, NULL); - - ShowWindow(m_data->m_hWnd, SW_SHOW); - UpdateWindow(m_data->m_hWnd); - - MoveWindow(m_data->m_hWnd, windowLeft, windowTop, m_data->m_width, m_data->m_height, TRUE); - } - else if (windowHandle) - { - // attach external window - m_data->m_hWnd = static_cast(windowHandle); - RECT r; - GetWindowRect(m_data->m_hWnd, &r); - m_data->m_width = r.right - r.left; - m_data->m_height = r.bottom - r.top; - //sFullScreen = false; - //sExternalWindow = true; - } - - - if (fullscreen) - { - DEVMODE dm; - memset(&dm, 0, sizeof(dm)); - dm.dmSize = sizeof(dm); - // use default values from current setting - EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dm); - m_data->m_oldScreenWidth = dm.dmPelsWidth; - m_data->m_oldHeight = dm.dmPelsHeight; - m_data->m_oldBitsPerPel = dm.dmBitsPerPel; - - dm.dmPelsWidth = width; - dm.dmPelsHeight = height; - if (colorBitsPerPixel) - { - dm.dmBitsPerPel = colorBitsPerPixel; - } - dm.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY; - - LONG res = ChangeDisplaySettings(&dm, CDS_FULLSCREEN); - if (res != DISP_CHANGE_SUCCESSFUL) - { // try again without forcing display frequency - dm.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT; - res = ChangeDisplaySettings(&dm, CDS_FULLSCREEN); - } - - } - - //VideoDriver = video::createOpenGLDriver(CreationParams, FileSystem, this); - enableOpenGL(); - - - const wchar_t* text= L"OpenCL rigid body demo"; - - DWORD dwResult; - -#ifdef _WIN64 - SetWindowTextW(m_data->m_hWnd, text); -#else - SendMessageTimeoutW(m_data->m_hWnd, WM_SETTEXT, 0, - reinterpret_cast(text), - SMTO_ABORTIFHUNG, 2000, &dwResult); -#endif - - -} - - -void Win32OpenGLWindow::switchFullScreen(bool fullscreen,int width,int height,int colorBitsPerPixel) -{ - LONG res; - DEVMODE dm; - memset(&dm, 0, sizeof(dm)); - dm.dmSize = sizeof(dm); - // use default values from current setting - EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dm); - - dm.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY; - - if (fullscreen && !m_data->m_oldScreenWidth) - { - m_data->m_oldScreenWidth = dm.dmPelsWidth; - m_data->m_oldHeight = dm.dmPelsHeight; - m_data->m_oldBitsPerPel = dm.dmBitsPerPel; - - if (width && height) - { - dm.dmPelsWidth = width; - dm.dmPelsHeight = height; - } else - { - dm.dmPelsWidth = m_data->m_width; - dm.dmPelsHeight = m_data->m_height; - } - if (colorBitsPerPixel) - { - dm.dmBitsPerPel = colorBitsPerPixel; - } - } else - { - if (m_data->m_oldScreenWidth) - { - dm.dmPelsWidth = m_data->m_oldScreenWidth; - dm.dmPelsHeight= m_data->m_oldHeight; - dm.dmBitsPerPel = m_data->m_oldBitsPerPel; - } - } - - if (fullscreen) - { - res = ChangeDisplaySettings(&dm, CDS_FULLSCREEN); - } else - { - res = ChangeDisplaySettings(&dm, 0); - } -} - - - -Win32OpenGLWindow::Win32OpenGLWindow() -{ - m_data = new InternalData2(); - sData = m_data; -} - -Win32OpenGLWindow::~Win32OpenGLWindow() -{ - delete m_data; - sData = 0; -} - -void Win32OpenGLWindow::init() -{ - init(640,480,false); -} - - -void Win32OpenGLWindow::exit() -{ - disableOpenGL(); - DestroyWindow(this->m_data->m_hWnd); -} - - - - - -void Win32OpenGLWindow::startRendering() -{ - pumpMessage(); - - //glClearColor(1.f,0.f,0.f,1.f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); //clear buffers - - //glCullFace(GL_BACK); - //glFrontFace(GL_CCW); - glEnable(GL_DEPTH_TEST); - - - float aspect; - //btVector3 extents; - - if (m_data->m_width > m_data->m_height) - { - aspect = (float)m_data->m_width / (float)m_data->m_height; - //extents.setValue(aspect * 1.0f, 1.0f,0); - } else - { - aspect = (float)m_data->m_height / (float)m_data->m_width; - //extents.setValue(1.0f, aspect*1.f,0); - } - - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - - if (m_data->m_width > m_data->m_height) - { - glFrustum (-aspect, aspect, -1.0, 1.0, 1.0, 10000.0); - } else - { - glFrustum (-1.0, 1.0, -aspect, aspect, 1.0, 10000.0); - } - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - -} - - -void Win32OpenGLWindow::renderAllObjects() -{ -} - -void Win32OpenGLWindow::endRendering() -{ - SwapBuffers( m_data->m_hDC ); -} - -float Win32OpenGLWindow::getTimeInSeconds() -{ - return 0.f; -} - -void Win32OpenGLWindow::setDebugMessage(int x,int y,const char* message) -{ -} - -bool Win32OpenGLWindow::requestedExit() -{ - return m_data->m_quit; -} \ No newline at end of file diff --git a/Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline2/Win32OpenGLRenderManager.h b/Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline2/Win32OpenGLRenderManager.h deleted file mode 100644 index 861c6f5b6..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline2/Win32OpenGLRenderManager.h +++ /dev/null @@ -1,70 +0,0 @@ -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Erwin Coumans - - -#ifndef _WIN32_OPENGL_RENDER_MANAGER_H -#define _WIN32_OPENGL_RENDER_MANAGER_H - - -#define RM_DECLARE_HANDLE(name) typedef struct name##__ { int unused; } *name - -RM_DECLARE_HANDLE(RenderObjectHandle); - -struct InternalData2; - -class Win32OpenGLWindow -{ - protected: - - struct InternalData2* m_data; - - void enableOpenGL(); - - void disableOpenGL(); - - void pumpMessage(); - - - -public: - - Win32OpenGLWindow(); - - virtual ~Win32OpenGLWindow(); - - virtual void init(); //default implementation uses default settings for width/height/fullscreen - - void init(int width,int height, bool fullscreen=false, int colorBitsPerPixel=0, void* windowHandle=0); - - void switchFullScreen(bool fullscreen,int width=0,int height=0,int colorBitsPerPixel=0); - - virtual void exit(); - - - virtual void startRendering(); - - virtual void renderAllObjects(); - - virtual void endRendering(); - - virtual float getTimeInSeconds(); - - virtual void setDebugMessage(int x,int y,const char* message); - - virtual bool requestedExit(); - -}; - -#endif //_WIN32_OPENGL_RENDER_MANAGER_H diff --git a/Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline2/main.cpp b/Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline2/main.cpp deleted file mode 100644 index b4de1789f..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline2/main.cpp +++ /dev/null @@ -1,224 +0,0 @@ -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Erwin Coumans - -// -//#include "vld.h" -#include - -#include "GLInstancingRenderer.h" - - -#include "GLInstancingRenderer.h" -#include "../opengl_interop/btOpenCLGLInteropBuffer.h" -#include "Win32OpenGLRenderManager.h" -#include "CLPhysicsDemo.h" -#include "../broadphase_benchmark/btGridBroadphaseCl.h" -#include "../../opencl/gpu_rigidbody_pipeline/btGpuNarrowPhaseAndSolver.h" -#include "ShapeData.h" -#include "LinearMath/btQuickprof.h" - -int NUM_OBJECTS_X = 32; -int NUM_OBJECTS_Y = 24; -int NUM_OBJECTS_Z = 32; - - -float X_GAP = 2.f; -float Y_GAP = 2.f; -float Z_GAP = 2.f; - -extern int numPairsOut; - - -void createScene(GLInstancingRenderer& renderer,CLPhysicsDemo& physicsSim) -{ - int strideInBytes = sizeof(float)*9; - - int barrelShapeIndex = -1; - int cubeShapeIndex = -1; - - float position[4]={0,0,0,0}; - float orn[4] = {0,0,0,1}; - float color[4] = {1,1,1,1}; - int index=0; -#if 1 - { - int numVertices = sizeof(barrel_vertices)/strideInBytes; - int numIndices = sizeof(barrel_indices)/sizeof(int); - barrelShapeIndex = renderer.registerShape(&barrel_vertices[0],numVertices,barrel_indices,numIndices); - } - - - float barrelScaling[4] = {2,2,2,1}; - - - int barrelCollisionShapeIndex = physicsSim.registerCollisionShape(&barrel_vertices[0],strideInBytes, sizeof(barrel_vertices)/strideInBytes,&barrelScaling[0]); - - - - for (int i=0;iinit(1024,768); - GLenum err = glewInit(); - window->startRendering(); - window->endRendering(); - - GLInstancingRenderer render; - - - - - - CLPhysicsDemo demo(window); - - bool useInterop = true; - demo.init(-1,-1,useInterop); - - render.InitShaders(); - - if (useInterop) - demo.setupInterop(); - - createScene(render, demo); - - - printf("num objects = %d\n", NUM_OBJECTS_X*NUM_OBJECTS_Y*NUM_OBJECTS_Z); - - - render.writeTransforms(); - - - while (!window->requestedExit()) - { - CProfileManager::Reset(); - - demo.stepSimulation(); - - - window->startRendering(); - render.RenderScene(); - window->endRendering(); - - CProfileManager::Increment_Frame_Counter(); - - static bool printStats = true; - - if (printStats) - { - static int count = 10; - count--; - if (count<0) - { - CProfileManager::dumpAll(); - //printf("total broadphase pairs= %d\n", gFpIO.m_numOverlap); - printf("numPairsOut (culled) = %d\n", numPairsOut); - printStats = false; - } - } - - } - - - demo.cleanup(); - - render.CleanupShaders(); - window->exit(); - delete window; - - - - return 0; -} \ No newline at end of file diff --git a/Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline2/premake4.lua b/Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline2/premake4.lua deleted file mode 100644 index e78f276dc..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/gpu_rigidbody_pipeline2/premake4.lua +++ /dev/null @@ -1,5 +0,0 @@ - -include "AMD" --- include "Intel" --- include "NVIDIA" - \ No newline at end of file diff --git a/Extras/RigidBodyGpuPipeline/opencl/integration/AMD/premake4.lua b/Extras/RigidBodyGpuPipeline/opencl/integration/AMD/premake4.lua deleted file mode 100644 index a8b029e81..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/integration/AMD/premake4.lua +++ /dev/null @@ -1,34 +0,0 @@ - - hasCL = findOpenCL_AMD() - - if (hasCL) then - - project "OpenCL_integration_AMD" - - initOpenCL_AMD() - - language "C++" - - kind "ConsoleApp" - targetdir "../../../bin" - - initOpenGL() - initGlut() - initGlew() - - includedirs { - "../../../rendering/BulletMath", - "../../primitives" - } - - files { - "../main.cpp", - "../../basic_initialize/btOpenCLUtils.cpp", - "../../basic_initialize/btOpenCLUtils.h", - "../../opengl_interop/btOpenCLGLInteropBuffer.cpp", - "../../opengl_interop/btOpenCLGLInteropBuffer.h", - "../../opengl_interop/btStopwatch.cpp", - "../../opengl_interop/btStopwatch.h" - } - - end \ No newline at end of file diff --git a/Extras/RigidBodyGpuPipeline/opencl/integration/Intel/premake4.lua b/Extras/RigidBodyGpuPipeline/opencl/integration/Intel/premake4.lua deleted file mode 100644 index 27c08660d..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/integration/Intel/premake4.lua +++ /dev/null @@ -1,36 +0,0 @@ - - hasCL = findOpenCL_Intel() - - if (hasCL) then - - project "OpenCL_integration_Intel" - - initOpenCL_Intel() - - language "C++" - - kind "ConsoleApp" - targetdir "../../../bin" - - - initOpenGL() - initGlut() - initGlew() - - - includedirs { - "../../../rendering/BulletMath", - "../../primitives" - } - - files { - "../main.cpp", - "../../basic_initialize/btOpenCLUtils.cpp", - "../../basic_initialize/btOpenCLUtils.h", - "../../opengl_interop/btOpenCLGLInteropBuffer.cpp", - "../../opengl_interop/btOpenCLGLInteropBuffer.h", - "../../opengl_interop/btStopwatch.cpp", - "../../opengl_interop/btStopwatch.h" - } - - end \ No newline at end of file diff --git a/Extras/RigidBodyGpuPipeline/opencl/integration/NVIDIA/premake4.lua b/Extras/RigidBodyGpuPipeline/opencl/integration/NVIDIA/premake4.lua deleted file mode 100644 index b6b5272f1..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/integration/NVIDIA/premake4.lua +++ /dev/null @@ -1,35 +0,0 @@ - - hasCL = findOpenCL_NVIDIA() - - if (hasCL) then - - project "OpenCL_integration_NVIDIA" - - initOpenCL_NVIDIA() - - language "C++" - - kind "ConsoleApp" - targetdir "../../../bin" - - initOpenGL() - initGlut() - initGlew() - - - includedirs { - "../../../rendering/BulletMath", - "../../primitives" - } - - files { - "../main.cpp", - "../../basic_initialize/btOpenCLUtils.cpp", - "../../basic_initialize/btOpenCLUtils.h", - "../../opengl_interop/btOpenCLGLInteropBuffer.cpp", - "../../opengl_interop/btOpenCLGLInteropBuffer.h", - "../../opengl_interop/btStopwatch.cpp", - "../../opengl_interop/btStopwatch.h" - } - - end \ No newline at end of file diff --git a/Extras/RigidBodyGpuPipeline/opencl/integration/integrateKernel.cl b/Extras/RigidBodyGpuPipeline/opencl/integration/integrateKernel.cl deleted file mode 100644 index fbb16be97..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/integration/integrateKernel.cl +++ /dev/null @@ -1,73 +0,0 @@ -MSTRINGIFY( - -float4 quatMult(float4 q1, float4 q2) -{ - float4 q; - q.x = q1.w * q2.x + q1.x * q2.w + q1.y * q2.z - q1.z * q2.y; - q.y = q1.w * q2.y + q1.y * q2.w + q1.z * q2.x - q1.x * q2.z; - q.z = q1.w * q2.z + q1.z * q2.w + q1.x * q2.y - q1.y * q2.x; - q.w = q1.w * q2.w - q1.x * q2.x - q1.y * q2.y - q1.z * q2.z; - return q; -} - -float4 quatNorm(float4 q) -{ - float len = native_sqrt(dot(q, q)); - if(len > 0.f) - { - q *= 1.f / len; - } - else - { - q.x = q.y = q.z = 0.f; - q.w = 1.f; - } - return q; -} - - - -__kernel void - interopKernel( const int startOffset, const int numNodes, __global float4 *g_vertexBuffer, - __global float4 *linVel, - __global float4 *pAngVel) -{ - int nodeID = get_global_id(0); - float timeStep = 0.0166666; - - float BT_GPU_ANGULAR_MOTION_THRESHOLD = (0.25f * 3.14159254); - - if( nodeID < numNodes ) - { - g_vertexBuffer[nodeID + startOffset/4] += linVel[nodeID]*timeStep; - - // g_vertexBuffer[nodeID + startOffset/4+numNodes] += angVel[nodeID]; - - float4 axis; - float4 angvel = pAngVel[nodeID]; - float fAngle = native_sqrt(dot(angvel, angvel)); - //limit the angular motion - if(fAngle*timeStep > BT_GPU_ANGULAR_MOTION_THRESHOLD) - { - fAngle = BT_GPU_ANGULAR_MOTION_THRESHOLD / timeStep; - } - if(fAngle < 0.001f) - { - // use Taylor's expansions of sync function - axis = angvel * (0.5f*timeStep-(timeStep*timeStep*timeStep)*0.020833333333f * fAngle * fAngle); - } - else - { - // sync(fAngle) = sin(c*fAngle)/t - axis = angvel * ( native_sin(0.5f * fAngle * timeStep) / fAngle); - } - float4 dorn = axis; - dorn.w = native_cos(fAngle * timeStep * 0.5f); - float4 orn0 = g_vertexBuffer[nodeID + startOffset/4+numNodes]; - float4 predictedOrn = quatMult(dorn, orn0); - predictedOrn = quatNorm(predictedOrn); - g_vertexBuffer[nodeID + startOffset/4+numNodes]=predictedOrn; - } -} - -); \ No newline at end of file diff --git a/Extras/RigidBodyGpuPipeline/opencl/integration/main.cpp b/Extras/RigidBodyGpuPipeline/opencl/integration/main.cpp deleted file mode 100644 index 26e44b6bf..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/integration/main.cpp +++ /dev/null @@ -1,1106 +0,0 @@ - -//starts crashing when more than 32700 objects on my Geforce 260, unless _USE_SUB_DATA is defined (still unstable though) -//runs fine with fewer objects - -#define NUM_OBJECTS_X 327 -#define NUM_OBJECTS_Y 20 -#define NUM_OBJECTS_Z 20 -//#define NUM_OBJECTS_Z 20 - -//#define _USE_SUB_DATA - -//#define NUM_OBJECTS_X 100 -//#define NUM_OBJECTS_Y 100 -//#define NUM_OBJECTS_Z 100 - -///RECREATE_CL_AND_SHADERS_ON_RESIZE will delete and re-create OpenCL and GLSL shaders/buffers at each resize -//#define RECREATE_CL_AND_SHADERS_ON_RESIZE - -/// -/// OpenCL - OpenGL interop example. Updating transforms of many cubes on GPU, without going through main memory/using the PCIe bus -/// Create all OpenGL resources AFTER create OpenCL context! -/// - - -#include -#include - -#include "btGlutInclude.h" -#include "../opengl_interop/btStopwatch.h" - - -#include "btVector3.h" -#include "btQuaternion.h" -#include "btMatrix3x3.h" -static float angle(0); - -#include - -#ifdef _WIN32 -#include -#endif - -//OpenCL stuff -#include "../basic_initialize/btOpenCLUtils.h" -#include "../opengl_interop/btOpenCLGLInteropBuffer.h" - -cl_context g_cxMainContext; -cl_command_queue g_cqCommandQue; -cl_device_id g_device; -static const size_t workGroupSize = 128; -cl_mem gLinVelMem; -cl_mem gAngVelMem; - - -btOpenCLGLInteropBuffer* g_interopBuffer = 0; -cl_kernel g_interopKernel; - -////for Adl -#include - -adl::DeviceCL* g_deviceCL=0; - - - -bool useCPU = false; -bool printStats = false; -bool runOpenCLKernels = true; - -#define MSTRINGIFY(A) #A -static char* interopKernelString = -#include "integrateKernel.cl" - -btStopwatch gStopwatch; -int m_glutScreenWidth = 640; -int m_glutScreenHeight= 480; - -bool m_ortho = false; - -static GLuint instancingShader; // The instancing renderer -static GLuint cube_vao; -static GLuint cube_vbo; -static GLuint index_vbo; -static GLuint m_texturehandle; - -static bool done = false; -static GLint angle_loc = 0; -static GLint ModelViewMatrix; -static GLint ProjectionMatrix; - - -static GLint uniform_texture_diffuse = 0; - -//used for dynamic loading from disk (default switched off) -#define MAX_SHADER_LENGTH 8192 -static GLubyte shaderText[MAX_SHADER_LENGTH]; - -static const char* vertexShader= \ -"#version 330\n" -"precision highp float;\n" -"\n" -"\n" -"\n" -"layout (location = 0) in vec4 position;\n" -"layout (location = 1) in vec4 instance_position;\n" -"layout (location = 2) in vec4 instance_quaternion;\n" -"layout (location = 3) in vec2 uvcoords;\n" -"layout (location = 4) in vec3 vertexnormal;\n" -"\n" -"\n" -"uniform float angle = 0.0;\n" -"uniform mat4 ModelViewMatrix;\n" -"uniform mat4 ProjectionMatrix;\n" -"\n" -"out Fragment\n" -"{\n" -" vec4 color;\n" -"} fragment;\n" -"\n" -"out Vert\n" -"{\n" -" vec2 texcoord;\n" -"} vert;\n" -"\n" -"\n" -"vec4 quatMul ( in vec4 q1, in vec4 q2 )\n" -"{\n" -" vec3 im = q1.w * q2.xyz + q1.xyz * q2.w + cross ( q1.xyz, q2.xyz );\n" -" vec4 dt = q1 * q2;\n" -" float re = dot ( dt, vec4 ( -1.0, -1.0, -1.0, 1.0 ) );\n" -" return vec4 ( im, re );\n" -"}\n" -"\n" -"vec4 quatFromAxisAngle(vec4 axis, in float angle)\n" -"{\n" -" float cah = cos(angle*0.5);\n" -" float sah = sin(angle*0.5);\n" -" float d = inversesqrt(dot(axis,axis));\n" -" vec4 q = vec4(axis.x*sah*d,axis.y*sah*d,axis.z*sah*d,cah);\n" -" return q;\n" -"}\n" -"//\n" -"// vector rotation via quaternion\n" -"//\n" -"vec4 quatRotate3 ( in vec3 p, in vec4 q )\n" -"{\n" -" vec4 temp = quatMul ( q, vec4 ( p, 0.0 ) );\n" -" return quatMul ( temp, vec4 ( -q.x, -q.y, -q.z, q.w ) );\n" -"}\n" -"vec4 quatRotate ( in vec4 p, in vec4 q )\n" -"{\n" -" vec4 temp = quatMul ( q, p );\n" -" return quatMul ( temp, vec4 ( -q.x, -q.y, -q.z, q.w ) );\n" -"}\n" -"\n" -"out vec3 lightDir,normal,ambient;\n" -"\n" -"void main(void)\n" -"{\n" -" vec4 q = instance_quaternion;\n" -" ambient = vec3(0.2,0.2,0.2);\n" -" \n" -" \n" -" vec4 local_normal = (quatRotate3( vertexnormal,q));\n" -" vec3 light_pos = vec3(1000,1000,1000);\n" -" normal = normalize(ModelViewMatrix * local_normal).xyz;\n" -"\n" -" lightDir = normalize(light_pos);//gl_LightSource[0].position.xyz));\n" -"// lightDir = normalize(vec3(gl_LightSource[0].position));\n" -" \n" -" vec4 axis = vec4(1,1,1,0);\n" -" vec4 localcoord = quatRotate3( position.xyz,q);\n" -" vec4 vertexPos = ProjectionMatrix * ModelViewMatrix *(instance_position+localcoord);\n" -"\n" -" gl_Position = vertexPos;\n" -" \n" -"// fragment.color = instance_color;\n" -" vert.texcoord = uvcoords;\n" -"}\n" -; - - -static const char* fragmentShader= \ -"#version 330\n" -"precision highp float;\n" -"\n" -"in Fragment\n" -"{\n" -" vec4 color;\n" -"} fragment;\n" -"\n" -"in Vert\n" -"{\n" -" vec2 texcoord;\n" -"} vert;\n" -"\n" -"uniform sampler2D Diffuse;\n" -"\n" -"in vec3 lightDir,normal,ambient;\n" -"\n" -"out vec4 color;\n" -"\n" -"void main_textured(void)\n" -"{\n" -" color = texture2D(Diffuse,vert.texcoord);//fragment.color;\n" -"}\n" -"\n" -"void main(void)\n" -"{\n" -" vec4 texel = texture2D(Diffuse,vert.texcoord);//fragment.color;\n" -" vec3 ct,cf;\n" -" float intensity,at,af;\n" -" intensity = max(dot(lightDir,normalize(normal)),0.0);\n" -" cf = intensity*vec3(1.0,1.0,1.0);//intensity * (gl_FrontMaterial.diffuse).rgb+ambient;//gl_FrontMaterial.ambient.rgb;\n" -" af = 1.0;\n" -" \n" -" ct = texel.rgb;\n" -" at = texel.a;\n" -" \n" -" color = vec4(ct * cf, at * af); \n" -"}\n" -; - - -// Load the shader from the source text -void gltLoadShaderSrc(const char *szShaderSrc, GLuint shader) -{ - GLchar *fsStringPtr[1]; - - fsStringPtr[0] = (GLchar *)szShaderSrc; - glShaderSource(shader, 1, (const GLchar **)fsStringPtr, NULL); -} - - -//////////////////////////////////////////////////////////////// -// Load the shader from the specified file. Returns false if the -// shader could not be loaded -bool gltLoadShaderFile(const char *szFile, GLuint shader) -{ - GLint shaderLength = 0; - FILE *fp; - - // Open the shader file - fp = fopen(szFile, "r"); - if(fp != NULL) - { - // See how long the file is - while (fgetc(fp) != EOF) - shaderLength++; - - // Allocate a block of memory to send in the shader - assert(shaderLength < MAX_SHADER_LENGTH); // make me bigger! - if(shaderLength > MAX_SHADER_LENGTH) - { - fclose(fp); - return false; - } - - // Go back to beginning of file - rewind(fp); - - // Read the whole file in - if (shaderText != NULL) - fread(shaderText, 1, shaderLength, fp); - - // Make sure it is null terminated and close the file - shaderText[shaderLength] = '\0'; - fclose(fp); - } - else - return false; - - // printf(shaderText); - // Load the string - gltLoadShaderSrc((const char *)shaderText, shader); - - return true; -} - - -///////////////////////////////////////////////////////////////// -// Load a pair of shaders, compile, and link together. Specify the complete -// file path for each shader. Note, there is no support for -// just loading say a vertex program... you have to do both. -GLuint gltLoadShaderPair(const char *szVertexProg, const char *szFragmentProg, bool loadFromFile) -{ - // Temporary Shader objects - GLuint hVertexShader; - GLuint hFragmentShader; - GLuint hReturn = 0; - GLint testVal; - - // Create shader objects - hVertexShader = glCreateShader(GL_VERTEX_SHADER); - hFragmentShader = glCreateShader(GL_FRAGMENT_SHADER); - - if (loadFromFile) - { - - if(gltLoadShaderFile(szVertexProg, hVertexShader) == false) - { - glDeleteShader(hVertexShader); - glDeleteShader(hFragmentShader); - return (GLuint)NULL; - } - - if(gltLoadShaderFile(szFragmentProg, hFragmentShader) == false) - { - glDeleteShader(hVertexShader); - glDeleteShader(hFragmentShader); - return (GLuint)NULL; - } - } else - { - gltLoadShaderSrc(vertexShader, hVertexShader); - gltLoadShaderSrc(fragmentShader, hFragmentShader); - } - // Compile them - glCompileShader(hVertexShader); - glCompileShader(hFragmentShader); - - // Check for errors - glGetShaderiv(hVertexShader, GL_COMPILE_STATUS, &testVal); - if(testVal == GL_FALSE) - { - char temp[256] = ""; - glGetShaderInfoLog( hVertexShader, 256, NULL, temp); - fprintf( stderr, "Compile failed:\n%s\n", temp); - assert(0); - exit(0); - glDeleteShader(hVertexShader); - glDeleteShader(hFragmentShader); - return (GLuint)NULL; - } - - glGetShaderiv(hFragmentShader, GL_COMPILE_STATUS, &testVal); - if(testVal == GL_FALSE) - { - char temp[256] = ""; - glGetShaderInfoLog( hFragmentShader, 256, NULL, temp); - fprintf( stderr, "Compile failed:\n%s\n", temp); - assert(0); - exit(0); - glDeleteShader(hVertexShader); - glDeleteShader(hFragmentShader); - return (GLuint)NULL; - } - - // Link them - assuming it works... - hReturn = glCreateProgram(); - glAttachShader(hReturn, hVertexShader); - glAttachShader(hReturn, hFragmentShader); - - glLinkProgram(hReturn); - - // These are no longer needed - glDeleteShader(hVertexShader); - glDeleteShader(hFragmentShader); - - // Make sure link worked too - glGetProgramiv(hReturn, GL_LINK_STATUS, &testVal); - if(testVal == GL_FALSE) - { - glDeleteProgram(hReturn); - return (GLuint)NULL; - } - - return hReturn; -} - -///position xyz, unused w, normal, uv -static const GLfloat cube_vertices[] = -{ - -1.0f, -1.0f, 1.0f, 0.0f, 0,0,1, 0,0,//0 - 1.0f, -1.0f, 1.0f, 0.0f, 0,0,1, 1,0,//1 - 1.0f, 1.0f, 1.0f, 0.0f, 0,0,1, 1,1,//2 - -1.0f, 1.0f, 1.0f, 0.0f, 0,0,1, 0,1 ,//3 - - -1.0f, -1.0f, -1.0f, 1.0f, 0,0,-1, 0,0,//4 - 1.0f, -1.0f, -1.0f, 1.0f, 0,0,-1, 1,0,//5 - 1.0f, 1.0f, -1.0f, 1.0f, 0,0,-1, 1,1,//6 - -1.0f, 1.0f, -1.0f, 1.0f, 0,0,-1, 0,1,//7 - - -1.0f, -1.0f, -1.0f, 1.0f, -1,0,0, 0,0, - -1.0f, 1.0f, -1.0f, 1.0f, -1,0,0, 1,0, - -1.0f, 1.0f, 1.0f, 1.0f, -1,0,0, 1,1, - -1.0f, -1.0f, 1.0f, 1.0f, -1,0,0, 0,1, - - 1.0f, -1.0f, -1.0f, 1.0f, 1,0,0, 0,0, - 1.0f, 1.0f, -1.0f, 1.0f, 1,0,0, 1,0, - 1.0f, 1.0f, 1.0f, 1.0f, 1,0,0, 1,1, - 1.0f, -1.0f, 1.0f, 1.0f, 1,0,0, 0,1, - - -1.0f, -1.0f, -1.0f, 1.0f, 0,-1,0, 0,0, - -1.0f, -1.0f, 1.0f, 1.0f, 0,-1,0, 1,0, - 1.0f, -1.0f, 1.0f, 1.0f, 0,-1,0, 1,1, - 1.0f,-1.0f, -1.0f, 1.0f, 0,-1,0, 0,1, - - -1.0f, 1.0f, -1.0f, 1.0f, 0,1,0, 0,0, - -1.0f, 1.0f, 1.0f, 1.0f, 0,1,0, 1,0, - 1.0f, 1.0f, 1.0f, 1.0f, 0,1,0, 1,1, - 1.0f,1.0f, -1.0f, 1.0f, 0,1,0, 0,1, -}; - -static const int cube_indices[]= -{ - 0,1,2,0,2,3,//ground face - 4,5,6,4,6,7,//top face - 8,9,10,8,10,11, - 12,13,14,12,14,15, - 16,17,18,16,18,19, - 20,21,22,20,22,23 -}; - - - - - -void DeleteCL() -{ - clReleaseContext(g_cxMainContext); - clReleaseCommandQueue(g_cqCommandQue); -} - -void InitCL() -{ - void* glCtx=0; - void* glDC = 0; - -#ifdef _WIN32 - glCtx = wglGetCurrentContext(); -#else //!_WIN32 - GLXContext glCtx = glXGetCurrentContext(); -#endif //!_WIN32 - glDC = wglGetCurrentDC(); - - int ciErrNum = 0; - cl_device_type deviceType = CL_DEVICE_TYPE_ALL;//GPU; - g_cxMainContext = btOpenCLUtils::createContextFromType(deviceType, &ciErrNum, glCtx, glDC); - oclCHECKERROR(ciErrNum, CL_SUCCESS); - - int numDev = btOpenCLUtils::getNumDevices(g_cxMainContext); - - if (numDev>0) - { - g_device= btOpenCLUtils::getDevice(g_cxMainContext,0); - btOpenCLDeviceInfo clInfo; - btOpenCLUtils::getDeviceInfo(g_device,clInfo); - btOpenCLUtils::printDeviceInfo(g_device); - // create a command-queue - g_cqCommandQue = clCreateCommandQueue(g_cxMainContext, g_device, 0, &ciErrNum); - oclCHECKERROR(ciErrNum, CL_SUCCESS); - //normally you would create and execute kernels using this command queue - - } - - -} - -#define NUM_OBJECTS (NUM_OBJECTS_X*NUM_OBJECTS_Y*NUM_OBJECTS_Z) -#define POSITION_BUFFER_SIZE (NUM_OBJECTS*sizeof(float)*4) -#define ORIENTATION_BUFFER_SIZE (NUM_OBJECTS*sizeof(float)*4) - - -GLfloat* instance_positions_ptr = 0; -GLfloat* instance_quaternion_ptr = 0; - -void DeleteShaders() -{ - glDeleteVertexArrays(1, &cube_vao); - glDeleteBuffers(1,&index_vbo); - glDeleteBuffers(1,&cube_vbo); - glDeleteProgram(instancingShader); -} - -void writeTransforms() -{ - - - glFlush(); - char* bla = (char*)glMapBuffer( GL_ARRAY_BUFFER,GL_READ_WRITE);//GL_WRITE_ONLY - - float* positions = (float*)(bla+sizeof(cube_vertices)); - float* orientations = (float*)(bla+sizeof(cube_vertices) + POSITION_BUFFER_SIZE); - // positions[0]+=0.001f; - - static int offset=0; - //offset++; - - static btVector3 axis(1,0,0); - angle += 0.01f; - int index=0; - btQuaternion orn(axis,angle); - for (int i=0;i m_glutScreenHeight) - { - aspect = m_glutScreenWidth / (float)m_glutScreenHeight; - extents.setValue(aspect * 1.0f, 1.0f,0); - } else - { - aspect = m_glutScreenHeight / (float)m_glutScreenWidth; - extents.setValue(1.0f, aspect*1.f,0); - } - - - if (m_ortho) - { - // reset matrix - glLoadIdentity(); - extents *= m_cameraDistance; - btVector3 lower = m_cameraTargetPosition - extents; - btVector3 upper = m_cameraTargetPosition + extents; - glOrtho(lower.getX(), upper.getX(), lower.getY(), upper.getY(),-1000,1000); - - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - } else - { - if (m_glutScreenWidth > m_glutScreenHeight) - { - glFrustum (-aspect * m_frustumZNear, aspect * m_frustumZNear, -m_frustumZNear, m_frustumZNear, m_frustumZNear, m_frustumZFar); - } else - { - glFrustum (-aspect * m_frustumZNear, aspect * m_frustumZNear, -m_frustumZNear, m_frustumZNear, m_frustumZNear, m_frustumZFar); - } - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - gluLookAt(m_cameraPosition[0], m_cameraPosition[1], m_cameraPosition[2], - m_cameraTargetPosition[0], m_cameraTargetPosition[1], m_cameraTargetPosition[2], - m_cameraUp.getX(),m_cameraUp.getY(),m_cameraUp.getZ()); - } - -} - - - -void myinit() -{ - - - // GLfloat light_ambient[] = { btScalar(0.2), btScalar(0.2), btScalar(0.2), btScalar(1.0) }; - GLfloat light_ambient[] = { btScalar(1.0), btScalar(1.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 )}; - /* light_position is NOT default value */ - GLfloat light_position0[] = { btScalar(1000.0), btScalar(1000.0), btScalar(1000.0), btScalar(0.0 )}; - GLfloat light_position1[] = { btScalar(-1.0), btScalar(-10.0), btScalar(-1.0), btScalar(0.0) }; - - glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient); - glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse); - glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular); - glLightfv(GL_LIGHT0, GL_POSITION, light_position0); - - glLightfv(GL_LIGHT1, GL_AMBIENT, light_ambient); - glLightfv(GL_LIGHT1, GL_DIFFUSE, light_diffuse); - glLightfv(GL_LIGHT1, GL_SPECULAR, light_specular); - glLightfv(GL_LIGHT1, GL_POSITION, light_position1); - - glEnable(GL_LIGHTING); - glEnable(GL_LIGHT0); - glEnable(GL_LIGHT1); - - - // glShadeModel(GL_FLAT);//GL_SMOOTH); - glShadeModel(GL_SMOOTH); - - glEnable(GL_DEPTH_TEST); - glDepthFunc(GL_LESS); - - glClearColor(float(0.7),float(0.7),float(0.7),float(0)); - glEnable(GL_LIGHTING); - glEnable(GL_LIGHT0); - - - static bool m_textureenabled = true; - static bool m_textureinitialized = false; - - - if(m_textureenabled) - { - if(!m_textureinitialized) - { - glActiveTexture(GL_TEXTURE0); - - GLubyte* image=new GLubyte[256*256*3]; - for(int y=0;y<256;++y) - { - const int t=y>>5; - GLubyte* pi=image+y*256*3; - for(int x=0;x<256;++x) - { - const int s=x>>5; - const GLubyte b=180; - GLubyte c=b+((s+t&1)&1)*(255-b); - pi[0]=255; - pi[1]=c; - pi[2]=c; - pi+=3; - } - } - - glGenTextures(1,(GLuint*)&m_texturehandle); - glBindTexture(GL_TEXTURE_2D,m_texturehandle); - glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE); - glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR); - glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR_MIPMAP_LINEAR); - glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT); - glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT); - gluBuild2DMipmaps(GL_TEXTURE_2D,3,256,256,GL_RGB,GL_UNSIGNED_BYTE,image); - delete[] image; - m_textureinitialized=true; - } - // glMatrixMode(GL_TEXTURE); - // glLoadIdentity(); - // glMatrixMode(GL_MODELVIEW); - - glEnable(GL_TEXTURE_2D); - glBindTexture(GL_TEXTURE_2D,m_texturehandle); - - } else - { - glDisable(GL_TEXTURE_2D); - } - - glEnable(GL_COLOR_MATERIAL); - - - // glEnable(GL_CULL_FACE); - // glCullFace(GL_BACK); -} - -//#pragma optimize( "g", off ) - -void updatePos() -{ - - - if (useCPU) - { - int index=0; - for (int i=0;igetCLBUffer(); - cl_int ciErrNum = CL_SUCCESS; - ciErrNum = clEnqueueAcquireGLObjects(g_cqCommandQue, 1, &clBuffer, 0, 0, NULL); - oclCHECKERROR(ciErrNum, CL_SUCCESS); - if (runOpenCLKernels) - { - int numObjects = NUM_OBJECTS; - int offset = (sizeof(cube_vertices) )/4; - - ciErrNum = clSetKernelArg(g_interopKernel, 0, sizeof(int), &offset); - ciErrNum = clSetKernelArg(g_interopKernel, 1, sizeof(int), &numObjects); - ciErrNum = clSetKernelArg(g_interopKernel, 2, sizeof(cl_mem), (void*)&clBuffer ); - - ciErrNum = clSetKernelArg(g_interopKernel, 3, sizeof(cl_mem), (void*)&gLinVelMem); - ciErrNum = clSetKernelArg(g_interopKernel, 4, sizeof(cl_mem), (void*)&gAngVelMem); - - size_t numWorkItems = workGroupSize*((NUM_OBJECTS + (workGroupSize-1)) / workGroupSize); - ciErrNum = clEnqueueNDRangeKernel(g_cqCommandQue, g_interopKernel, 1, NULL, &numWorkItems, &workGroupSize,0 ,0 ,0); - oclCHECKERROR(ciErrNum, CL_SUCCESS); - } - - ciErrNum = clEnqueueReleaseGLObjects(g_cqCommandQue, 1, &clBuffer, 0, 0, 0); - oclCHECKERROR(ciErrNum, CL_SUCCESS); - clFinish(g_cqCommandQue); - - } - -} -//#pragma optimize( "g", on ) - -void RenderScene(void) -{ - -#if 0 - float modelview[20]={0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9}; - // get the current modelview matrix - glGetFloatv(GL_MODELVIEW_MATRIX , modelview); - float projection[20]={0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9}; - glGetFloatv(GL_PROJECTION_MATRIX, projection); -#endif - - myinit(); - - updateCamera(); - - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - //render coordinate system - glBegin(GL_LINES); - glColor3f(1,0,0); - glVertex3f(0,0,0); - glVertex3f(1,0,0); - glColor3f(0,1,0); - glVertex3f(0,0,0); - glVertex3f(0,1,0); - glColor3f(0,0,1); - glVertex3f(0,0,0); - glVertex3f(0,0,1); - glEnd(); - - //do a finish, to make sure timings are clean - // glFinish(); - - float start = gStopwatch.getTimeMilliseconds(); - - // glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ARRAY_BUFFER, cube_vbo); - glFlush(); - updatePos(); - - float stop = gStopwatch.getTimeMilliseconds(); - gStopwatch.reset(); - - if (printStats) - { - printf("updatePos=%f ms on ",stop-start); - - if (useCPU) - { - printf("CPU \n"); - } else - { - printf("OpenCL "); - if (runOpenCLKernels) - printf("running the kernels"); - else - printf("without running the kernels"); - printf("\n"); - } - } - - glBindVertexArray(cube_vao); - - glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 9*sizeof(float), 0); - glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, (GLvoid *)(sizeof(cube_vertices))); - glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, 0, (GLvoid *)(sizeof(cube_vertices)+POSITION_BUFFER_SIZE)); - int uvoffset = 7*sizeof(float); - int normaloffset = 4*sizeof(float); - - glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, 9*sizeof(float), (GLvoid *)uvoffset); - glVertexAttribPointer(4, 3, GL_FLOAT, GL_FALSE, 9*sizeof(float), (GLvoid *)normaloffset); - - glEnableVertexAttribArray(0); - glEnableVertexAttribArray(1); - glEnableVertexAttribArray(2); - glEnableVertexAttribArray(3); - glEnableVertexAttribArray(4); - - glVertexAttribDivisor(1, 1); - glVertexAttribDivisor(2, 1); - glVertexAttribDivisor(3, 0); - glVertexAttribDivisor(4, 0); - - glUseProgram(instancingShader); - glUniform1f(angle_loc, 0); - GLfloat pm[16]; - glGetFloatv(GL_PROJECTION_MATRIX, pm); - glUniformMatrix4fv(ProjectionMatrix, 1, false, &pm[0]); - - GLfloat mvm[16]; - glGetFloatv(GL_MODELVIEW_MATRIX, mvm); - glUniformMatrix4fv(ModelViewMatrix, 1, false, &mvm[0]); - - glUniform1i(uniform_texture_diffuse, 0); - - glFlush(); - int numInstances = NUM_OBJECTS; - int indexCount = sizeof(cube_indices)/sizeof(int); - int indexOffset = 0; - - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_vbo); - glDrawElementsInstanced(GL_TRIANGLES, indexCount, GL_UNSIGNED_INT, (void*)indexOffset, numInstances); - - glUseProgram(0); - glBindBuffer(GL_ARRAY_BUFFER,0); - glBindVertexArray(0); - - glutSwapBuffers(); - glutPostRedisplay(); - - GLint err = glGetError(); - assert(err==GL_NO_ERROR); -} - - -void ChangeSize(int w, int h) -{ - m_glutScreenWidth = w; - m_glutScreenHeight = h; - -#ifdef RECREATE_CL_AND_SHADERS_ON_RESIZE - delete g_interopBuffer; - clReleaseKernel(g_interopKernel); - DeleteCL(); - DeleteShaders(); -#endif //RECREATE_CL_AND_SHADERS_ON_RESIZE - - // Set Viewport to window dimensions - glViewport(0, 0, w, h); - -#ifdef RECREATE_CL_AND_SHADERS_ON_RESIZE - InitCL(); - InitShaders(); - - g_interopBuffer = new btOpenCLGLInteropBuffer(g_cxMainContext,g_cqCommandQue,cube_vbo); - clFinish(g_cqCommandQue); - g_interopKernel = btOpenCLUtils::compileCLKernelFromString(g_cxMainContext, interopKernelString, "interopKernel" ); -#endif //RECREATE_CL_AND_SHADERS_ON_RESIZE - -} - -void Keyboard(unsigned char key, int x, int y) -{ - switch (key) - { - case 27: - done = true; - break; - case 'O': - case 'o': - { - m_ortho = !m_ortho; - break; - } - case 'c': - case 'C': - { - useCPU = !useCPU; - if (useCPU) - printf("using CPU\n"); - else - printf("using OpenCL\n"); - break; - } - case 's': - case 'S': - { - printStats = !printStats; - break; - } - case 'k': - case 'K': - { - runOpenCLKernels=!runOpenCLKernels; - break; - } - case 'q': - case 'Q': - exit(0); - default: - break; - } -} - -// Cleanup -void ShutdownRC(void) -{ - glDeleteBuffers(1, &cube_vbo); - glDeleteVertexArrays(1, &cube_vao); -} - -int main(int argc, char* argv[]) -{ - // printf("vertexShader = \n%s\n",vertexShader); - // printf("fragmentShader = \n%s\n",fragmentShader); - - glutInit(&argc, argv); - - glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA); - - - glutInitWindowSize(m_glutScreenWidth, m_glutScreenHeight); - char buf[1024]; - sprintf(buf,"OpenCL - OpenGL interop, transforms %d cubes on the GPU (use c to toggle CPU/CL)", NUM_OBJECTS); - glutCreateWindow(buf); - - glutReshapeFunc(ChangeSize); - - glutKeyboardFunc(Keyboard); - glutDisplayFunc(RenderScene); - - GLenum err = glewInit(); - if (GLEW_OK != err) - { - /* Problem: glewInit failed, something is seriously wrong. */ - fprintf(stderr, "Error: %s\n", glewGetErrorString(err)); - } - - //ChangeSize(m_glutScreenWidth,m_glutScreenHeight); - - InitCL(); - - -#define CUSTOM_CL_INITIALIZATION -#ifdef CUSTOM_CL_INITIALIZATION - g_deviceCL = new adl::DeviceCL(); - g_deviceCL->m_deviceIdx = g_device; - g_deviceCL->m_context = g_cxMainContext; - g_deviceCL->m_commandQueue = g_cqCommandQue; - -#else - DeviceUtils::Config cfg; - cfg.m_type = DeviceUtils::Config::DEVICE_CPU; - g_deviceCL = DeviceUtils::allocate( TYPE_CL, cfg ); -#endif - - int size = NUM_OBJECTS; - adl::Buffer linvelBuf( g_deviceCL, size ); - adl::Buffer angvelBuf( g_deviceCL, size ); - - gLinVelMem = (cl_mem)linvelBuf.m_ptr; - gAngVelMem = (cl_mem)angvelBuf.m_ptr; - - btVector3* linVelHost= new btVector3[size]; - btVector3* angVelHost = new btVector3[size]; - - for (int i=0;i -#include -#include -#endif - -#if defined (SUNOS) || defined (__SUNOS__) -#include -#endif - -#if defined(WIN32) || defined(_WIN32) - -#define BT_USE_WINDOWS_TIMERS -#define WIN32_LEAN_AND_MEAN -#define NOWINRES -#define NOMCX -#define NOIME - -#ifdef _XBOX - #include -#else //_XBOX - #include -#endif //_XBOX - -#include - - -#else //_WIN32 -#include -#endif //_WIN32 - -#define mymin(a,b) (a > b ? a : b) - -struct btStopwatchData -{ - -#ifdef BT_USE_WINDOWS_TIMERS - LARGE_INTEGER mClockFrequency; - DWORD mStartTick; - LONGLONG mPrevElapsedTime; - LARGE_INTEGER mStartTime; -#else -#ifdef __CELLOS_LV2__ - uint64_t mStartTime; -#else - struct timeval mStartTime; -#endif -#endif //__CELLOS_LV2__ - -}; - - -btStopwatch::btStopwatch() -{ - m_data = new btStopwatchData; -#ifdef BT_USE_WINDOWS_TIMERS - QueryPerformanceFrequency(&m_data->mClockFrequency); -#endif - reset(); -} - -btStopwatch::~btStopwatch() -{ - delete m_data; -} - -btStopwatch::btStopwatch(const btStopwatch& other) -{ - m_data = new btStopwatchData; - *m_data = *other.m_data; -} - -btStopwatch& btStopwatch::operator=(const btStopwatch& other) -{ - *m_data = *other.m_data; - return *this; -} - - - /// Resets the initial reference time. -void btStopwatch::reset() -{ -#ifdef BT_USE_WINDOWS_TIMERS - QueryPerformanceCounter(&m_data->mStartTime); - m_data->mStartTick = GetTickCount(); - m_data->mPrevElapsedTime = 0; -#else -#ifdef __CELLOS_LV2__ - - typedef uint64_t ClockSize; - ClockSize newTime; - //__asm __volatile__( "mftb %0" : "=r" (newTime) : : "memory"); - SYS_TIMEBASE_GET( newTime ); - m_data->mStartTime = newTime; -#else - gettimeofday(&m_data->mStartTime, 0); -#endif -#endif -} - -/// Returns the time in ms since the last call to reset or since -/// the btStopwatch was created. -float btStopwatch::getTimeMilliseconds() -{ - return getTimeMicroseconds()/1000.f; -} - - /// Returns the time in us since the last call to reset or since - /// the stopwatch was created. -unsigned long int btStopwatch::getTimeMicroseconds() -{ -#ifdef BT_USE_WINDOWS_TIMERS - LARGE_INTEGER currentTime; - QueryPerformanceCounter(¤tTime); - LONGLONG elapsedTime = currentTime.QuadPart - m_data->mStartTime.QuadPart; - - // Compute the number of millisecond ticks elapsed. - unsigned long msecTicks = (unsigned long)(1000 * elapsedTime / m_data->mClockFrequency.QuadPart); - - // Check for unexpected leaps in the Win32 performance counter. - // (This is caused by unexpected data across the PCI to ISA - // bridge, aka south bridge. See Microsoft KB274323.) - unsigned long elapsedTicks = GetTickCount() - m_data->mStartTick; - signed long msecOff = (signed long)(msecTicks - elapsedTicks); - if (msecOff < -100 || msecOff > 100) - { - // Adjust the starting time forwards. - LONGLONG msecAdjustment = mymin(msecOff * - m_data->mClockFrequency.QuadPart / 1000, elapsedTime - - m_data->mPrevElapsedTime); - m_data->mStartTime.QuadPart += msecAdjustment; - elapsedTime -= msecAdjustment; - } - - // Store the current elapsed time for adjustments next time. - m_data->mPrevElapsedTime = elapsedTime; - - // Convert to microseconds. - unsigned long usecTicks = (unsigned long)(1000000 * elapsedTime / - m_data->mClockFrequency.QuadPart); - - return usecTicks; -#else - -#ifdef __CELLOS_LV2__ - uint64_t freq=sys_time_get_timebase_frequency(); - double dFreq=((double) freq)/ 1000000.0; - typedef uint64_t ClockSize; - ClockSize newTime; - //__asm __volatile__( "mftb %0" : "=r" (newTime) : : "memory"); - SYS_TIMEBASE_GET( newTime ); - - return (unsigned long int)((double(newTime-m_data->mStartTime)) / dFreq); -#else - - struct timeval currentTime; - gettimeofday(¤tTime, 0); - return (currentTime.tv_sec - m_data->mStartTime.tv_sec) * 1000000 + (currentTime.tv_usec - m_data->mStartTime.tv_usec); -#endif//__CELLOS_LV2__ -#endif -} - - - diff --git a/Extras/RigidBodyGpuPipeline/opencl/opengl_interop/btStopwatch.h b/Extras/RigidBodyGpuPipeline/opencl/opengl_interop/btStopwatch.h deleted file mode 100644 index 19e8d3722..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/opengl_interop/btStopwatch.h +++ /dev/null @@ -1,45 +0,0 @@ -/* -Stopwatch for timing and profiling for the Bullet Physics Library, http://bulletphysics.org -Copyright (c) 2003-2011 Erwin Coumans - -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_STOPWATCH_H -#define BT_STOPWATCH_H - -///The btStopwatch is a portable basic clock that measures real-time, use for profiling etc. -class btStopwatch -{ -public: - btStopwatch(); - - btStopwatch(const btStopwatch& other); - btStopwatch& operator=(const btStopwatch& other); - - ~btStopwatch(); - - /// Resets the initial reference time. - void reset(); - - /// Returns the time in ms since the last call to reset or since - /// the btStopwatch was created. - float getTimeMilliseconds(); - - /// Returns the time in us since the last call to reset or since - /// the Clock was created. - unsigned long int getTimeMicroseconds(); -private: - struct btStopwatchData* m_data; -}; - - -#endif //BT_STOPWATCH_H \ No newline at end of file diff --git a/Extras/RigidBodyGpuPipeline/opencl/opengl_interop/interopKernel.cl b/Extras/RigidBodyGpuPipeline/opencl/opengl_interop/interopKernel.cl deleted file mode 100644 index e65da56dc..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/opengl_interop/interopKernel.cl +++ /dev/null @@ -1,13 +0,0 @@ -MSTRINGIFY( - -__kernel void -interopKernel( const int startOffset, const int numNodes, __global float *g_vertexBuffer) -{ - int nodeID = get_global_id(0); - if( nodeID < numNodes ) - { - g_vertexBuffer[nodeID*4 + startOffset+1] += 0.01; - } -} - -); \ No newline at end of file diff --git a/Extras/RigidBodyGpuPipeline/opencl/opengl_interop/main.cpp b/Extras/RigidBodyGpuPipeline/opencl/opengl_interop/main.cpp deleted file mode 100644 index 9ee3921b5..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/opengl_interop/main.cpp +++ /dev/null @@ -1,1057 +0,0 @@ - -//starts crashing when more than 32700 objects on my Geforce 260, unless _USE_SUB_DATA is defined (still unstable though) -//runs fine with fewer objects - -#define NUM_OBJECTS_X 327 -#define NUM_OBJECTS_Y 10 -#define NUM_OBJECTS_Z 10 -//#define NUM_OBJECTS_Z 20 - -//#define _USE_SUB_DATA - -//#define NUM_OBJECTS_X 100 -//#define NUM_OBJECTS_Y 100 -//#define NUM_OBJECTS_Z 100 - -///RECREATE_CL_AND_SHADERS_ON_RESIZE will delete and re-create OpenCL and GLSL shaders/buffers at each resize -//#define RECREATE_CL_AND_SHADERS_ON_RESIZE - -/// -/// OpenCL - OpenGL interop example. Updating transforms of many cubes on GPU, without going through main memory/using the PCIe bus -/// Create all OpenGL resources AFTER create OpenCL context! -/// - - -#include -#include - -#include "btGlutInclude.h" -#include "btStopwatch.h" - - -#include "btVector3.h" -#include "btQuaternion.h" -#include "btMatrix3x3.h" -static float angle(0); - -#include - -#ifdef _WIN32 -#include -#endif - -//OpenCL stuff -#include "../basic_initialize/btOpenCLUtils.h" -#include "btOpenCLGLInteropBuffer.h" - -cl_context g_cxMainContext; -cl_command_queue g_cqCommandQue; -cl_device_id g_device; -static const size_t workGroupSize = 128; - - -btOpenCLGLInteropBuffer* g_interopBuffer = 0; -cl_kernel g_interopKernel; - -bool useCPU = false; -bool printStats = false; -bool runOpenCLKernels = true; - -#define MSTRINGIFY(A) #A -static char* interopKernelString = -#include "interopKernel.cl" - -btStopwatch gStopwatch; -int m_glutScreenWidth = 640; -int m_glutScreenHeight= 480; - -bool m_ortho = false; - -static GLuint instancingShader; // The instancing renderer -static GLuint cube_vao; -static GLuint cube_vbo; -static GLuint index_vbo; -static GLuint m_texturehandle; - -static bool done = false; -static GLint angle_loc = 0; -static GLint ModelViewMatrix; -static GLint ProjectionMatrix; - - -static GLint uniform_texture_diffuse = 0; - -//used for dynamic loading from disk (default switched off) -#define MAX_SHADER_LENGTH 8192 -static GLubyte shaderText[MAX_SHADER_LENGTH]; - -static const char* vertexShader= \ -"#version 330\n" -"precision highp float;\n" -"\n" -"\n" -"\n" -"layout (location = 0) in vec4 position;\n" -"layout (location = 1) in vec4 instance_position;\n" -"layout (location = 2) in vec4 instance_quaternion;\n" -"layout (location = 3) in vec2 uvcoords;\n" -"layout (location = 4) in vec3 vertexnormal;\n" -"\n" -"\n" -"uniform float angle = 0.0;\n" -"uniform mat4 ModelViewMatrix;\n" -"uniform mat4 ProjectionMatrix;\n" -"\n" -"out Fragment\n" -"{\n" -" vec4 color;\n" -"} fragment;\n" -"\n" -"out Vert\n" -"{\n" -" vec2 texcoord;\n" -"} vert;\n" -"\n" -"\n" -"vec4 quatMul ( in vec4 q1, in vec4 q2 )\n" -"{\n" -" vec3 im = q1.w * q2.xyz + q1.xyz * q2.w + cross ( q1.xyz, q2.xyz );\n" -" vec4 dt = q1 * q2;\n" -" float re = dot ( dt, vec4 ( -1.0, -1.0, -1.0, 1.0 ) );\n" -" return vec4 ( im, re );\n" -"}\n" -"\n" -"vec4 quatFromAxisAngle(vec4 axis, in float angle)\n" -"{\n" -" float cah = cos(angle*0.5);\n" -" float sah = sin(angle*0.5);\n" -" float d = inversesqrt(dot(axis,axis));\n" -" vec4 q = vec4(axis.x*sah*d,axis.y*sah*d,axis.z*sah*d,cah);\n" -" return q;\n" -"}\n" -"//\n" -"// vector rotation via quaternion\n" -"//\n" -"vec4 quatRotate3 ( in vec3 p, in vec4 q )\n" -"{\n" -" vec4 temp = quatMul ( q, vec4 ( p, 0.0 ) );\n" -" return quatMul ( temp, vec4 ( -q.x, -q.y, -q.z, q.w ) );\n" -"}\n" -"vec4 quatRotate ( in vec4 p, in vec4 q )\n" -"{\n" -" vec4 temp = quatMul ( q, p );\n" -" return quatMul ( temp, vec4 ( -q.x, -q.y, -q.z, q.w ) );\n" -"}\n" -"\n" -"out vec3 lightDir,normal,ambient;\n" -"\n" -"void main(void)\n" -"{\n" -" vec4 q = instance_quaternion;\n" -" ambient = vec3(0.2,0.2,0.2);\n" -" \n" -" \n" -" vec4 local_normal = (quatRotate3( vertexnormal,q));\n" -" vec3 light_pos = vec3(1000,1000,1000);\n" -" normal = normalize(ModelViewMatrix * local_normal).xyz;\n" -"\n" -" lightDir = normalize(light_pos);//gl_LightSource[0].position.xyz));\n" -"// lightDir = normalize(vec3(gl_LightSource[0].position));\n" -" \n" -" vec4 axis = vec4(1,1,1,0);\n" -" vec4 localcoord = quatRotate3( position.xyz,q);\n" -" vec4 vertexPos = ProjectionMatrix * ModelViewMatrix *(instance_position+localcoord);\n" -"\n" -" gl_Position = vertexPos;\n" -" \n" -"// fragment.color = instance_color;\n" -" vert.texcoord = uvcoords;\n" -"}\n" -; - - -static const char* fragmentShader= \ -"#version 330\n" -"precision highp float;\n" -"\n" -"in Fragment\n" -"{\n" -" vec4 color;\n" -"} fragment;\n" -"\n" -"in Vert\n" -"{\n" -" vec2 texcoord;\n" -"} vert;\n" -"\n" -"uniform sampler2D Diffuse;\n" -"\n" -"in vec3 lightDir,normal,ambient;\n" -"\n" -"out vec4 color;\n" -"\n" -"void main_textured(void)\n" -"{\n" -" color = texture2D(Diffuse,vert.texcoord);//fragment.color;\n" -"}\n" -"\n" -"void main(void)\n" -"{\n" -" vec4 texel = texture2D(Diffuse,vert.texcoord);//fragment.color;\n" -" vec3 ct,cf;\n" -" float intensity,at,af;\n" -" intensity = max(dot(lightDir,normalize(normal)),0.0);\n" -" cf = intensity*vec3(1.0,1.0,1.0);//intensity * (gl_FrontMaterial.diffuse).rgb+ambient;//gl_FrontMaterial.ambient.rgb;\n" -" af = 1.0;\n" -" \n" -" ct = texel.rgb;\n" -" at = texel.a;\n" -" \n" -" color = vec4(ct * cf, at * af); \n" -"}\n" -; - - -// Load the shader from the source text -void gltLoadShaderSrc(const char *szShaderSrc, GLuint shader) -{ - GLchar *fsStringPtr[1]; - - fsStringPtr[0] = (GLchar *)szShaderSrc; - glShaderSource(shader, 1, (const GLchar **)fsStringPtr, NULL); -} - - -//////////////////////////////////////////////////////////////// -// Load the shader from the specified file. Returns false if the -// shader could not be loaded -bool gltLoadShaderFile(const char *szFile, GLuint shader) -{ - GLint shaderLength = 0; - FILE *fp; - - // Open the shader file - fp = fopen(szFile, "r"); - if(fp != NULL) - { - // See how long the file is - while (fgetc(fp) != EOF) - shaderLength++; - - // Allocate a block of memory to send in the shader - assert(shaderLength < MAX_SHADER_LENGTH); // make me bigger! - if(shaderLength > MAX_SHADER_LENGTH) - { - fclose(fp); - return false; - } - - // Go back to beginning of file - rewind(fp); - - // Read the whole file in - if (shaderText != NULL) - fread(shaderText, 1, shaderLength, fp); - - // Make sure it is null terminated and close the file - shaderText[shaderLength] = '\0'; - fclose(fp); - } - else - return false; - - // printf(shaderText); - // Load the string - gltLoadShaderSrc((const char *)shaderText, shader); - - return true; -} - - -///////////////////////////////////////////////////////////////// -// Load a pair of shaders, compile, and link together. Specify the complete -// file path for each shader. Note, there is no support for -// just loading say a vertex program... you have to do both. -GLuint gltLoadShaderPair(const char *szVertexProg, const char *szFragmentProg, bool loadFromFile) -{ - // Temporary Shader objects - GLuint hVertexShader; - GLuint hFragmentShader; - GLuint hReturn = 0; - GLint testVal; - - // Create shader objects - hVertexShader = glCreateShader(GL_VERTEX_SHADER); - hFragmentShader = glCreateShader(GL_FRAGMENT_SHADER); - - if (loadFromFile) - { - - if(gltLoadShaderFile(szVertexProg, hVertexShader) == false) - { - glDeleteShader(hVertexShader); - glDeleteShader(hFragmentShader); - return (GLuint)NULL; - } - - if(gltLoadShaderFile(szFragmentProg, hFragmentShader) == false) - { - glDeleteShader(hVertexShader); - glDeleteShader(hFragmentShader); - return (GLuint)NULL; - } - } else - { - gltLoadShaderSrc(vertexShader, hVertexShader); - gltLoadShaderSrc(fragmentShader, hFragmentShader); - } - // Compile them - glCompileShader(hVertexShader); - glCompileShader(hFragmentShader); - - // Check for errors - glGetShaderiv(hVertexShader, GL_COMPILE_STATUS, &testVal); - if(testVal == GL_FALSE) - { - char temp[256] = ""; - glGetShaderInfoLog( hVertexShader, 256, NULL, temp); - fprintf( stderr, "Compile failed:\n%s\n", temp); - assert(0); - exit(0); - glDeleteShader(hVertexShader); - glDeleteShader(hFragmentShader); - return (GLuint)NULL; - } - - glGetShaderiv(hFragmentShader, GL_COMPILE_STATUS, &testVal); - if(testVal == GL_FALSE) - { - char temp[256] = ""; - glGetShaderInfoLog( hFragmentShader, 256, NULL, temp); - fprintf( stderr, "Compile failed:\n%s\n", temp); - assert(0); - exit(0); - glDeleteShader(hVertexShader); - glDeleteShader(hFragmentShader); - return (GLuint)NULL; - } - - // Link them - assuming it works... - hReturn = glCreateProgram(); - glAttachShader(hReturn, hVertexShader); - glAttachShader(hReturn, hFragmentShader); - - glLinkProgram(hReturn); - - // These are no longer needed - glDeleteShader(hVertexShader); - glDeleteShader(hFragmentShader); - - // Make sure link worked too - glGetProgramiv(hReturn, GL_LINK_STATUS, &testVal); - if(testVal == GL_FALSE) - { - glDeleteProgram(hReturn); - return (GLuint)NULL; - } - - return hReturn; -} - -///position xyz, unused w, normal, uv -static const GLfloat cube_vertices[] = -{ - -1.0f, -1.0f, 1.0f, 0.0f, 0,0,1, 0,0,//0 - 1.0f, -1.0f, 1.0f, 0.0f, 0,0,1, 1,0,//1 - 1.0f, 1.0f, 1.0f, 0.0f, 0,0,1, 1,1,//2 - -1.0f, 1.0f, 1.0f, 0.0f, 0,0,1, 0,1 ,//3 - - -1.0f, -1.0f, -1.0f, 1.0f, 0,0,-1, 0,0,//4 - 1.0f, -1.0f, -1.0f, 1.0f, 0,0,-1, 1,0,//5 - 1.0f, 1.0f, -1.0f, 1.0f, 0,0,-1, 1,1,//6 - -1.0f, 1.0f, -1.0f, 1.0f, 0,0,-1, 0,1,//7 - - -1.0f, -1.0f, -1.0f, 1.0f, -1,0,0, 0,0, - -1.0f, 1.0f, -1.0f, 1.0f, -1,0,0, 1,0, - -1.0f, 1.0f, 1.0f, 1.0f, -1,0,0, 1,1, - -1.0f, -1.0f, 1.0f, 1.0f, -1,0,0, 0,1, - - 1.0f, -1.0f, -1.0f, 1.0f, 1,0,0, 0,0, - 1.0f, 1.0f, -1.0f, 1.0f, 1,0,0, 1,0, - 1.0f, 1.0f, 1.0f, 1.0f, 1,0,0, 1,1, - 1.0f, -1.0f, 1.0f, 1.0f, 1,0,0, 0,1, - - -1.0f, -1.0f, -1.0f, 1.0f, 0,-1,0, 0,0, - -1.0f, -1.0f, 1.0f, 1.0f, 0,-1,0, 1,0, - 1.0f, -1.0f, 1.0f, 1.0f, 0,-1,0, 1,1, - 1.0f,-1.0f, -1.0f, 1.0f, 0,-1,0, 0,1, - - -1.0f, 1.0f, -1.0f, 1.0f, 0,1,0, 0,0, - -1.0f, 1.0f, 1.0f, 1.0f, 0,1,0, 1,0, - 1.0f, 1.0f, 1.0f, 1.0f, 0,1,0, 1,1, - 1.0f,1.0f, -1.0f, 1.0f, 0,1,0, 0,1, -}; - -static const int cube_indices[]= -{ - 0,1,2,0,2,3,//ground face - 4,5,6,4,6,7,//top face - 8,9,10,8,10,11, - 12,13,14,12,14,15, - 16,17,18,16,18,19, - 20,21,22,20,22,23 -}; - - - - - -void DeleteCL() -{ - clReleaseContext(g_cxMainContext); - clReleaseCommandQueue(g_cqCommandQue); -} - -void InitCL() -{ - void* glCtx=0; - void* glDC = 0; - -#ifdef _WIN32 - glCtx = wglGetCurrentContext(); -#else //!_WIN32 - GLXContext glCtx = glXGetCurrentContext(); -#endif //!_WIN32 - glDC = wglGetCurrentDC(); - - int ciErrNum = 0; - cl_device_type deviceType = CL_DEVICE_TYPE_ALL;//CPU; - g_cxMainContext = btOpenCLUtils::createContextFromType(deviceType, &ciErrNum, glCtx, glDC); - oclCHECKERROR(ciErrNum, CL_SUCCESS); - - int numDev = btOpenCLUtils::getNumDevices(g_cxMainContext); - - if (numDev>0) - { - g_device= btOpenCLUtils::getDevice(g_cxMainContext,0); - btOpenCLDeviceInfo clInfo; - btOpenCLUtils::getDeviceInfo(g_device,clInfo); - btOpenCLUtils::printDeviceInfo(g_device); - // create a command-queue - g_cqCommandQue = clCreateCommandQueue(g_cxMainContext, g_device, 0, &ciErrNum); - oclCHECKERROR(ciErrNum, CL_SUCCESS); - //normally you would create and execute kernels using this command queue - - } - - -} - -#define NUM_OBJECTS (NUM_OBJECTS_X*NUM_OBJECTS_Y*NUM_OBJECTS_Z) -#define POSITION_BUFFER_SIZE (NUM_OBJECTS*sizeof(float)*4) -#define ORIENTATION_BUFFER_SIZE (NUM_OBJECTS*sizeof(float)*4) - - -GLfloat* instance_positions_ptr = 0; -GLfloat* instance_quaternion_ptr = 0; - -void DeleteShaders() -{ - glDeleteVertexArrays(1, &cube_vao); - glDeleteBuffers(1,&index_vbo); - glDeleteBuffers(1,&cube_vbo); - glDeleteProgram(instancingShader); -} - -void writeTransforms() -{ - - - glFlush(); - char* bla = (char*)glMapBuffer( GL_ARRAY_BUFFER,GL_READ_WRITE);//GL_WRITE_ONLY - - float* positions = (float*)(bla+sizeof(cube_vertices)); - float* orientations = (float*)(bla+sizeof(cube_vertices) + POSITION_BUFFER_SIZE); - // positions[0]+=0.001f; - - static int offset=0; - //offset++; - - static btVector3 axis(1,0,0); - angle += 0.01f; - int index=0; - btQuaternion orn(axis,angle); - for (int i=0;i m_glutScreenHeight) - { - aspect = m_glutScreenWidth / (float)m_glutScreenHeight; - extents.setValue(aspect * 1.0f, 1.0f,0); - } else - { - aspect = m_glutScreenHeight / (float)m_glutScreenWidth; - extents.setValue(1.0f, aspect*1.f,0); - } - - - if (m_ortho) - { - // reset matrix - glLoadIdentity(); - extents *= m_cameraDistance; - btVector3 lower = m_cameraTargetPosition - extents; - btVector3 upper = m_cameraTargetPosition + extents; - glOrtho(lower.getX(), upper.getX(), lower.getY(), upper.getY(),-1000,1000); - - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - } else - { - if (m_glutScreenWidth > m_glutScreenHeight) - { - glFrustum (-aspect * m_frustumZNear, aspect * m_frustumZNear, -m_frustumZNear, m_frustumZNear, m_frustumZNear, m_frustumZFar); - } else - { - glFrustum (-aspect * m_frustumZNear, aspect * m_frustumZNear, -m_frustumZNear, m_frustumZNear, m_frustumZNear, m_frustumZFar); - } - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - gluLookAt(m_cameraPosition[0], m_cameraPosition[1], m_cameraPosition[2], - m_cameraTargetPosition[0], m_cameraTargetPosition[1], m_cameraTargetPosition[2], - m_cameraUp.getX(),m_cameraUp.getY(),m_cameraUp.getZ()); - } - -} - - - -void myinit() -{ - - - // GLfloat light_ambient[] = { btScalar(0.2), btScalar(0.2), btScalar(0.2), btScalar(1.0) }; - GLfloat light_ambient[] = { btScalar(1.0), btScalar(1.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 )}; - /* light_position is NOT default value */ - GLfloat light_position0[] = { btScalar(1000.0), btScalar(1000.0), btScalar(1000.0), btScalar(0.0 )}; - GLfloat light_position1[] = { btScalar(-1.0), btScalar(-10.0), btScalar(-1.0), btScalar(0.0) }; - - glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient); - glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse); - glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular); - glLightfv(GL_LIGHT0, GL_POSITION, light_position0); - - glLightfv(GL_LIGHT1, GL_AMBIENT, light_ambient); - glLightfv(GL_LIGHT1, GL_DIFFUSE, light_diffuse); - glLightfv(GL_LIGHT1, GL_SPECULAR, light_specular); - glLightfv(GL_LIGHT1, GL_POSITION, light_position1); - - glEnable(GL_LIGHTING); - glEnable(GL_LIGHT0); - glEnable(GL_LIGHT1); - - - // glShadeModel(GL_FLAT);//GL_SMOOTH); - glShadeModel(GL_SMOOTH); - - glEnable(GL_DEPTH_TEST); - glDepthFunc(GL_LESS); - - glClearColor(float(0.7),float(0.7),float(0.7),float(0)); - glEnable(GL_LIGHTING); - glEnable(GL_LIGHT0); - - - static bool m_textureenabled = true; - static bool m_textureinitialized = false; - - - if(m_textureenabled) - { - if(!m_textureinitialized) - { - glActiveTexture(GL_TEXTURE0); - - GLubyte* image=new GLubyte[256*256*3]; - for(int y=0;y<256;++y) - { - const int t=y>>5; - GLubyte* pi=image+y*256*3; - for(int x=0;x<256;++x) - { - const int s=x>>5; - const GLubyte b=180; - GLubyte c=b+((s+t&1)&1)*(255-b); - pi[0]=255; - pi[1]=c; - pi[2]=c; - pi+=3; - } - } - - glGenTextures(1,(GLuint*)&m_texturehandle); - glBindTexture(GL_TEXTURE_2D,m_texturehandle); - glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE); - glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR); - glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR_MIPMAP_LINEAR); - glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT); - glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT); - gluBuild2DMipmaps(GL_TEXTURE_2D,3,256,256,GL_RGB,GL_UNSIGNED_BYTE,image); - delete[] image; - m_textureinitialized=true; - } - // glMatrixMode(GL_TEXTURE); - // glLoadIdentity(); - // glMatrixMode(GL_MODELVIEW); - - glEnable(GL_TEXTURE_2D); - glBindTexture(GL_TEXTURE_2D,m_texturehandle); - - } else - { - glDisable(GL_TEXTURE_2D); - } - - glEnable(GL_COLOR_MATERIAL); - - - // glEnable(GL_CULL_FACE); - // glCullFace(GL_BACK); -} - -//#pragma optimize( "g", off ) - -void updatePos() -{ - - - if (useCPU) - { - int index=0; - for (int i=0;igetCLBUffer(); - cl_int ciErrNum = CL_SUCCESS; - ciErrNum = clEnqueueAcquireGLObjects(g_cqCommandQue, 1, &clBuffer, 0, 0, NULL); - oclCHECKERROR(ciErrNum, CL_SUCCESS); - if (runOpenCLKernels) - { - int numObjects = NUM_OBJECTS; - int offset = (sizeof(cube_vertices) )/4; - - ciErrNum = clSetKernelArg(g_interopKernel, 0, sizeof(int), &offset); - ciErrNum = clSetKernelArg(g_interopKernel, 1, sizeof(int), &numObjects); - ciErrNum = clSetKernelArg(g_interopKernel, 2, sizeof(cl_mem), (void*)&clBuffer ); - size_t numWorkItems = workGroupSize*((NUM_OBJECTS + (workGroupSize-1)) / workGroupSize); - ciErrNum = clEnqueueNDRangeKernel(g_cqCommandQue, g_interopKernel, 1, NULL, &numWorkItems, &workGroupSize,0 ,0 ,0); - oclCHECKERROR(ciErrNum, CL_SUCCESS); - } - ciErrNum = clEnqueueReleaseGLObjects(g_cqCommandQue, 1, &clBuffer, 0, 0, 0); - oclCHECKERROR(ciErrNum, CL_SUCCESS); - clFinish(g_cqCommandQue); - - } - -} -//#pragma optimize( "g", on ) - -void RenderScene(void) -{ - -#if 0 - float modelview[20]={0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9}; - // get the current modelview matrix - glGetFloatv(GL_MODELVIEW_MATRIX , modelview); - float projection[20]={0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9}; - glGetFloatv(GL_PROJECTION_MATRIX, projection); -#endif - - myinit(); - - updateCamera(); - - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - //render coordinate system - glBegin(GL_LINES); - glColor3f(1,0,0); - glVertex3f(0,0,0); - glVertex3f(1,0,0); - glColor3f(0,1,0); - glVertex3f(0,0,0); - glVertex3f(0,1,0); - glColor3f(0,0,1); - glVertex3f(0,0,0); - glVertex3f(0,0,1); - glEnd(); - - //do a finish, to make sure timings are clean - // glFinish(); - - float start = gStopwatch.getTimeMilliseconds(); - - // glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ARRAY_BUFFER, cube_vbo); - glFlush(); - updatePos(); - - float stop = gStopwatch.getTimeMilliseconds(); - gStopwatch.reset(); - - if (printStats) - { - printf("updatePos=%f ms on ",stop-start); - - if (useCPU) - { - printf("CPU \n"); - } else - { - printf("OpenCL "); - if (runOpenCLKernels) - printf("running the kernels"); - else - printf("without running the kernels"); - printf("\n"); - } - } - - glBindVertexArray(cube_vao); - - glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 9*sizeof(float), 0); - glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, (GLvoid *)(sizeof(cube_vertices))); - glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, 0, (GLvoid *)(sizeof(cube_vertices)+POSITION_BUFFER_SIZE)); - int uvoffset = 7*sizeof(float); - int normaloffset = 4*sizeof(float); - - glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, 9*sizeof(float), (GLvoid *)uvoffset); - glVertexAttribPointer(4, 3, GL_FLOAT, GL_FALSE, 9*sizeof(float), (GLvoid *)normaloffset); - - glEnableVertexAttribArray(0); - glEnableVertexAttribArray(1); - glEnableVertexAttribArray(2); - glEnableVertexAttribArray(3); - glEnableVertexAttribArray(4); - - glVertexAttribDivisor(1, 1); - glVertexAttribDivisor(2, 1); - glVertexAttribDivisor(3, 0); - glVertexAttribDivisor(4, 0); - - glUseProgram(instancingShader); - glUniform1f(angle_loc, 0); - GLfloat pm[16]; - glGetFloatv(GL_PROJECTION_MATRIX, pm); - glUniformMatrix4fv(ProjectionMatrix, 1, false, &pm[0]); - - GLfloat mvm[16]; - glGetFloatv(GL_MODELVIEW_MATRIX, mvm); - glUniformMatrix4fv(ModelViewMatrix, 1, false, &mvm[0]); - - glUniform1i(uniform_texture_diffuse, 0); - - glFlush(); - int numInstances = NUM_OBJECTS; - int indexCount = sizeof(cube_indices)/sizeof(int); - int indexOffset = 0; - - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_vbo); - glDrawElementsInstanced(GL_TRIANGLES, indexCount, GL_UNSIGNED_INT, (void*)indexOffset, numInstances); - - glUseProgram(0); - glBindBuffer(GL_ARRAY_BUFFER,0); - glBindVertexArray(0); - - glutSwapBuffers(); - glutPostRedisplay(); - - GLint err = glGetError(); - assert(err==GL_NO_ERROR); -} - - -void ChangeSize(int w, int h) -{ - m_glutScreenWidth = w; - m_glutScreenHeight = h; - -#ifdef RECREATE_CL_AND_SHADERS_ON_RESIZE - delete g_interopBuffer; - clReleaseKernel(g_interopKernel); - DeleteCL(); - DeleteShaders(); -#endif //RECREATE_CL_AND_SHADERS_ON_RESIZE - - // Set Viewport to window dimensions - glViewport(0, 0, w, h); - -#ifdef RECREATE_CL_AND_SHADERS_ON_RESIZE - InitCL(); - InitShaders(); - - g_interopBuffer = new btOpenCLGLInteropBuffer(g_cxMainContext,g_cqCommandQue,cube_vbo); - clFinish(g_cqCommandQue); - g_interopKernel = btOpenCLUtils::compileCLKernelFromString(g_cxMainContext, interopKernelString, "interopKernel" ); -#endif //RECREATE_CL_AND_SHADERS_ON_RESIZE - -} - -void Keyboard(unsigned char key, int x, int y) -{ - switch (key) - { - case 27: - done = true; - break; - case 'O': - case 'o': - { - m_ortho = !m_ortho; - break; - } - case 'c': - case 'C': - { - useCPU = !useCPU; - if (useCPU) - printf("using CPU\n"); - else - printf("using OpenCL\n"); - break; - } - case 's': - case 'S': - { - printStats = !printStats; - break; - } - case 'k': - case 'K': - { - runOpenCLKernels=!runOpenCLKernels; - break; - } - case 'q': - case 'Q': - exit(0); - default: - break; - } -} - -// Cleanup -void ShutdownRC(void) -{ - glDeleteBuffers(1, &cube_vbo); - glDeleteVertexArrays(1, &cube_vao); -} - -int main(int argc, char* argv[]) -{ - // printf("vertexShader = \n%s\n",vertexShader); - // printf("fragmentShader = \n%s\n",fragmentShader); - - glutInit(&argc, argv); - - glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA); - - - glutInitWindowSize(m_glutScreenWidth, m_glutScreenHeight); - char buf[1024]; - sprintf(buf,"OpenCL - OpenGL interop, transforms %d cubes on the GPU (use c to toggle CPU/CL)", NUM_OBJECTS); - glutCreateWindow(buf); - - glutReshapeFunc(ChangeSize); - - glutKeyboardFunc(Keyboard); - glutDisplayFunc(RenderScene); - - GLenum err = glewInit(); - if (GLEW_OK != err) - { - /* Problem: glewInit failed, something is seriously wrong. */ - fprintf(stderr, "Error: %s\n", glewGetErrorString(err)); - } - - //ChangeSize(m_glutScreenWidth,m_glutScreenHeight); - - InitCL(); - - - InitShaders(); - - g_interopBuffer = new btOpenCLGLInteropBuffer(g_cxMainContext,g_cqCommandQue,cube_vbo); - clFinish(g_cqCommandQue); - - - g_interopKernel = btOpenCLUtils::compileCLKernelFromString(g_cxMainContext, g_device,interopKernelString, "interopKernel" ); - - glutMainLoop(); - ShutdownRC(); - - return 0; -} diff --git a/Extras/RigidBodyGpuPipeline/opencl/opengl_interop/premake4.lua b/Extras/RigidBodyGpuPipeline/opencl/opengl_interop/premake4.lua deleted file mode 100644 index 422952b33..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/opengl_interop/premake4.lua +++ /dev/null @@ -1,5 +0,0 @@ - - include "AMD" - include "Intel" --- include "NVIDIA" - \ No newline at end of file diff --git a/Extras/RigidBodyGpuPipeline/opencl/primitives/Adl/Adl.cpp b/Extras/RigidBodyGpuPipeline/opencl/primitives/Adl/Adl.cpp deleted file mode 100644 index fdd5ed3e9..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/primitives/Adl/Adl.cpp +++ /dev/null @@ -1,19 +0,0 @@ -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Takahiro Harada - - -#include - -//KernelManager* KernelManager::s_kManager = NULL; diff --git a/Extras/RigidBodyGpuPipeline/opencl/primitives/Adl/Adl.h b/Extras/RigidBodyGpuPipeline/opencl/primitives/Adl/Adl.h deleted file mode 100644 index 5d51abe4e..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/primitives/Adl/Adl.h +++ /dev/null @@ -1,235 +0,0 @@ -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Takahiro Harada - - -#ifndef ADL_H -#define ADL_H - -#pragma warning( disable : 4996 ) -#include -#include -#include - -#ifndef max -#define max(a,b) (((a) > (b)) ? (a) : (b)) -#endif - -#ifndef min -#define min(a,b) (((a) < (b)) ? (a) : (b)) -#endif - -namespace adl -{ - -enum DeviceType -{ - TYPE_CL = 0, - TYPE_DX11 = 1, - TYPE_HOST, -}; - - -struct Device; - -struct BufferBase -{ - enum BufferType - { - BUFFER, - - // for dx - BUFFER_CONST, - BUFFER_STAGING, - BUFFER_APPEND, - BUFFER_RAW, - BUFFER_W_COUNTER, - BUFFER_INDEX, - BUFFER_VERTEX, - - // for cl - BUFFER_ZERO_COPY, - - }; -}; - -class DeviceUtils -{ - public: - struct Config - { - enum DeviceType - { - DEVICE_GPU, - DEVICE_CPU, - }; - - // for CL - enum DeviceVendor - { - VD_AMD, - VD_INTEL, - VD_NV, - }; - - Config() : m_type(DEVICE_GPU), m_deviceIdx(0), m_vendor(VD_AMD){} - - DeviceType m_type; - int m_deviceIdx; - DeviceVendor m_vendor; - }; - - __inline - static - int getNDevices( DeviceType type ); - __inline - static Device* allocate( DeviceType type, Config& cfg ); - __inline - static void deallocate( Device* deviceData ); - __inline - static void waitForCompletion( const Device* deviceData ); -}; - -//========================== -// DeviceData -//========================== -struct Kernel; - -struct Device -{ - typedef DeviceUtils::Config Config; - - Device( DeviceType type ) : m_type( type ), m_memoryUsage(0) - { - } - - virtual void* getContext() const { return 0; } - virtual void initialize(const Config& cfg){} - virtual void release(){} - virtual void waitForCompletion() const {} - virtual void getDeviceName( char nameOut[128] ) const {} - virtual Kernel* getKernel(const char* fileName, const char* funcName, const char* option = NULL, const char* src = NULL, bool cacheKernel = true ) const { ADLASSERT(0); return 0;} - virtual unsigned int getUsedMemory() const { return m_memoryUsage; } - - DeviceType m_type; - unsigned int m_memoryUsage; -}; - -//========================== -// Buffer -//========================== - -template -struct HostBuffer; -// overload each deviceDatas -template -struct Buffer : public BufferBase -{ - __inline - Buffer(); - __inline - Buffer(const Device* device, int nElems, BufferType type = BUFFER ); - __inline - virtual ~Buffer(); - - __inline - void setRawPtr( const Device* device, T* ptr, int size, BufferType type = BUFFER ); - __inline - void allocate(const Device* device, int nElems, BufferType type = BUFFER ); - __inline - void write(T* hostSrcPtr, int nElems, int dstOffsetNElems = 0); - __inline - void read(T* hostDstPtr, int nElems, int srcOffsetNElems = 0) const; - __inline - void write(Buffer& src, int nElems); - __inline - void read(Buffer& dst, int nElems) const; -// __inline -// Buffer& operator = (const Buffer& buffer); - __inline - int getSize() const { return m_size; } - - DeviceType getType() const { ADLASSERT( m_device ); return m_device->m_type; } - - - const Device* m_device; - int m_size; - T* m_ptr; - // for DX11 - void* m_uav; - void* m_srv; - bool m_allocated; // todo. move this to a bit -}; - -class BufferUtils -{ -public: - template - __inline - static - typename Buffer* map(const Device* device, const Buffer* in, int copySize = -1); - - template - __inline - static - void unmap( Buffer* native, const Buffer* orig, int copySize = -1 ); -}; - -//========================== -// HostBuffer -//========================== -struct DeviceHost; - -template -struct HostBuffer : public Buffer -{ - __inline - HostBuffer():Buffer(){} - __inline - HostBuffer(const Device* device, int nElems, BufferType type = BUFFER ) : Buffer(device, nElems, type) {} -// HostBuffer(const Device* deviceData, T* rawPtr, int nElems); - - - __inline - T& operator[](int idx); - __inline - const T& operator[](int idx) const; - __inline - T* begin() { return m_ptr; } - - __inline - HostBuffer& operator = (const Buffer& device); -}; - -}; - -#include -#if defined(ADL_ENABLE_CL) - #include -#endif -#if defined(ADL_ENABLE_DX11) - #include -#endif - -#include -#include -#include - - -#include - -#include -#include - -#endif diff --git a/Extras/RigidBodyGpuPipeline/opencl/primitives/Adl/Adl.inl b/Extras/RigidBodyGpuPipeline/opencl/primitives/Adl/Adl.inl deleted file mode 100644 index d732e86d6..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/primitives/Adl/Adl.inl +++ /dev/null @@ -1,344 +0,0 @@ -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Takahiro Harada - - -namespace adl -{ - -int DeviceUtils::getNDevices( DeviceType type ) -{ - switch( type ) - { -#if defined(ADL_ENABLE_CL) - case TYPE_CL: - return DeviceCL::getNDevices(); -#endif -#if defined(ADL_ENABLE_DX11) - case TYPE_DX11: - return DeviceDX11::getNDevices(); -#endif - default: - return 1; - }; -} - -Device* DeviceUtils::allocate( DeviceType type, Config& cfg ) -{ - Device* deviceData; - switch( type ) - { -#if defined(ADL_ENABLE_CL) - case TYPE_CL: - deviceData = new DeviceCL(); - break; -#endif -#if defined(ADL_ENABLE_DX11) - case TYPE_DX11: - deviceData = new DeviceDX11(); - break; -#endif - case TYPE_HOST: - deviceData = new DeviceHost(); - break; - default: - ADLASSERT( 0 ); - break; - }; - deviceData->initialize( cfg ); - return deviceData; -} - -void DeviceUtils::deallocate( Device* deviceData ) -{ - ADLASSERT( deviceData->getUsedMemory() == 0 ); - deviceData->release(); - delete deviceData; -} - -void DeviceUtils::waitForCompletion( const Device* deviceData ) -{ - deviceData->waitForCompletion(); -} - -#if defined(ADL_ENABLE_DX11) - #if defined(ADL_ENABLE_CL) - #define SELECT_DEVICEDATA( type, func ) \ - switch( type ) \ - { \ - case TYPE_CL: ((DeviceCL*)m_device)->func; break; \ - case TYPE_DX11: ((DeviceDX11*)m_device)->func; break; \ - case TYPE_HOST: ((DeviceHost*)m_device)->func; break; \ - default: ADLASSERT(0); break; \ - } - - #define SELECT_DEVICEDATA1( deviceData, func ) \ - switch( deviceData->m_type ) \ - { \ - case TYPE_CL: ((DeviceCL*)deviceData)->func; break; \ - case TYPE_DX11: ((DeviceDX11*)deviceData)->func; break; \ - case TYPE_HOST: ((DeviceHost*)deviceData)->func; break; \ - default: ADLASSERT(0); break; \ - } - #else - #define SELECT_DEVICEDATA( type, func ) \ - switch( type ) \ - { \ - case TYPE_DX11: ((DeviceDX11*)m_device)->func; break; \ - case TYPE_HOST: ((DeviceHost*)m_device)->func; break; \ - default: ADLASSERT(0); break; \ - } - - #define SELECT_DEVICEDATA1( deviceData, func ) \ - switch( deviceData->m_type ) \ - { \ - case TYPE_DX11: ((DeviceDX11*)deviceData)->func; break; \ - case TYPE_HOST: ((DeviceHost*)deviceData)->func; break; \ - default: ADLASSERT(0); break; \ - } - #endif -#else - #if defined(ADL_ENABLE_CL) - #define SELECT_DEVICEDATA( type, func ) \ - switch( type ) \ - { \ - case TYPE_CL: ((DeviceCL*)m_device)->func; break; \ - case TYPE_HOST: ((DeviceHost*)m_device)->func; break; \ - default: ADLASSERT(0); break; \ - } - - #define SELECT_DEVICEDATA1( deviceData, func ) \ - switch( deviceData->m_type ) \ - { \ - case TYPE_CL: ((DeviceCL*)deviceData)->func; break; \ - case TYPE_HOST: ((DeviceHost*)deviceData)->func; break; \ - default: ADLASSERT(0); break; \ - } - #else - #define SELECT_DEVICEDATA( type, func ) \ - switch( type ) \ - { \ - case TYPE_HOST: ((DeviceHost*)m_device)->func; break; \ - default: ADLASSERT(0); break; \ - } - - #define SELECT_DEVICEDATA1( deviceData, func ) \ - switch( deviceData->m_type ) \ - { \ - case TYPE_HOST: ((DeviceHost*)deviceData)->func; break; \ - default: ADLASSERT(0); break; \ - } - #endif -#endif - -template -Buffer::Buffer() -{ - m_device = 0; - m_size = 0; - m_ptr = 0; - - m_uav = 0; - m_srv = 0; - - m_allocated = false; -} - -template -Buffer::Buffer(const Device* deviceData, int nElems, BufferType type ) -{ - m_device = 0; - allocate( deviceData, nElems, type ); -} - -template -Buffer::~Buffer() -{ - if( m_allocated ) - { - if( m_device ) - SELECT_DEVICEDATA( m_device->m_type, deallocate( this ) ); - } - - m_device = 0; - m_ptr = 0; - m_size = 0; -} - -template -void Buffer::setRawPtr( const Device* device, T* ptr, int size, BufferType type ) -{ - ADLASSERT( m_device == 0 ); - ADLASSERT( type == BUFFER ); // todo. implement - ADLASSERT( device->m_type != TYPE_DX11 ); // todo. implement set srv, uav - - m_device = device; - m_ptr = ptr; - m_size = size; -} - -template -void Buffer::allocate(const Device* deviceData, int nElems, BufferType type ) -{ - ADLASSERT( m_device == 0 ); - m_device = deviceData; - m_size = 0; - m_ptr = 0; - - m_uav = 0; - m_srv = 0; - - SELECT_DEVICEDATA( m_device->m_type, allocate( this, nElems, type ) ); - m_allocated = true; -} - -template -void Buffer::write(T* hostPtr, int nElems, int offsetNElems) -{ - ADLASSERT( nElems+offsetNElems <= m_size ); - SELECT_DEVICEDATA( m_device->m_type, copy(this, hostPtr, nElems, offsetNElems) ); -} - -template -void Buffer::read(T* hostPtr, int nElems, int offsetNElems) const -{ - SELECT_DEVICEDATA( m_device->m_type, copy(hostPtr,this, nElems, offsetNElems) ); -} - -template -void Buffer::write(Buffer& src, int nElems) -{ - ADLASSERT( nElems <= m_size ); - SELECT_DEVICEDATA( m_device->m_type, copy(this, &src, nElems) ); -} - -template -void Buffer::read(Buffer& dst, int nElems) const -{ - SELECT_DEVICEDATA( m_device->m_type, copy(&dst, this, nElems) ); -} -/* -template -Buffer& Buffer::operator = ( const Buffer& buffer ) -{ -// ADLASSERT( buffer.m_size <= m_size ); - - SELECT_DEVICEDATA( m_device->m_type, copy(this, &buffer, min2( m_size, buffer.m_size) ) ); - - return *this; -} -*/ - -template -__inline -static -typename Buffer* BufferUtils::map(const Device* device, const Buffer* in, int copySize) -{ - Buffer* native; - ADLASSERT( device->m_type == TYPE ); - - if( in->getType() == TYPE ) - native = (Buffer*)in; - else - { - ADLASSERT( copySize <= in->getSize() ); - copySize = (copySize==-1)? in->getSize() : copySize; - - native = new Buffer( device, copySize ); - if( COPY ) - { - if( in->getType() == TYPE_HOST ) - native->write( in->m_ptr, copySize ); - else if( native->getType() == TYPE_HOST ) - { - in->read( native->m_ptr, copySize ); - DeviceUtils::waitForCompletion( in->m_device ); - } - else - { - T* tmp = new T[copySize]; - in->read( tmp, copySize ); - DeviceUtils::waitForCompletion( in->m_device ); - native->write( tmp, copySize ); - DeviceUtils::waitForCompletion( native->m_device ); - delete [] tmp; - } - } - } - return native; -} - -template -__inline -static -void BufferUtils::unmap( Buffer* native, const Buffer* orig, int copySize ) -{ - if( native != orig ) - { - if( COPY ) - { - copySize = (copySize==-1)? orig->getSize() : copySize; - ADLASSERT( copySize <= orig->getSize() ); - if( orig->getType() == TYPE_HOST ) - { - native->read( orig->m_ptr, copySize ); - DeviceUtils::waitForCompletion( native->m_device ); - } - else if( native->getType() == TYPE_HOST ) - { - Buffer* dst = (Buffer*)orig; - dst->write( native->m_ptr, copySize ); - DeviceUtils::waitForCompletion( dst->m_device ); - } - else - { - T* tmp = new T[copySize]; - native->read( tmp, copySize ); - DeviceUtils::waitForCompletion( native->m_device ); - Buffer* dst = (Buffer*)orig; - dst->write( tmp, copySize ); - DeviceUtils::waitForCompletion( dst->m_device ); - delete [] tmp; - } - } - delete native; - } -} - - -template -T& HostBuffer::operator[](int idx) -{ - return m_ptr[idx]; -} - -template -const T& HostBuffer::operator[](int idx) const -{ - return m_ptr[idx]; -} - -template -HostBuffer& HostBuffer::operator = ( const Buffer& device ) -{ - ADLASSERT( device.m_size <= m_size ); - - SELECT_DEVICEDATA1( device.m_device, copy( m_ptr, &device, device.m_size ) ); - - return *this; -} - -#undef SELECT_DEVICEDATA - -}; diff --git a/Extras/RigidBodyGpuPipeline/opencl/primitives/Adl/AdlConfig.h b/Extras/RigidBodyGpuPipeline/opencl/primitives/Adl/AdlConfig.h deleted file mode 100644 index 141c874c9..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/primitives/Adl/AdlConfig.h +++ /dev/null @@ -1,27 +0,0 @@ -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Takahiro Harada - - - -//ADL_ENABLE_CL and ADL_ENABLE_DX11 can be set in the build system using C/C++ preprocessor defines -//#define ADL_ENABLE_CL -//#define ADL_ENABLE_DX11 - -//#define ADL_CL_FORCE_UNCACHE_KERNEL -#define ADL_CL_DUMP_MEMORY_LOG - -//load the kernels from string instead of loading them from file -#define ADL_LOAD_KERNEL_FROM_STRING -#define ADL_DUMP_DX11_ERROR diff --git a/Extras/RigidBodyGpuPipeline/opencl/primitives/Adl/AdlError.h b/Extras/RigidBodyGpuPipeline/opencl/primitives/Adl/AdlError.h deleted file mode 100644 index 6d08e95a8..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/primitives/Adl/AdlError.h +++ /dev/null @@ -1,80 +0,0 @@ -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Takahiro Harada - - -#ifndef ADL_ERROR_H -#define ADL_ERROR_H - -#if defined(ADL_DUMP_DX11_ERROR) - #include -#endif -#ifdef _DEBUG - #include - #include - #include -#endif - - -namespace adl -{ - -#ifdef _DEBUG - #define ADLASSERT(x) if(!(x)){__debugbreak(); } -#else - #define ADLASSERT(x) if(x){} -#endif - -#ifdef _DEBUG - #define COMPILE_TIME_ASSERT(x) {int compileTimeAssertFailed[x]; compileTimeAssertFailed[0];} -#else - #define COMPILE_TIME_ASSERT(x) -#endif - -#ifdef _DEBUG - __inline - void debugPrintf(const char *fmt, ...) - { - va_list arg; - va_start(arg, fmt); -#if defined(ADL_DUMP_DX11_ERROR) - const int size = 1024*10; - char buf[size]; - vsprintf_s( buf, size, fmt, arg ); -#ifdef UNICODE - WCHAR wbuf[size]; - int sizeWide = MultiByteToWideChar(0,0,buf,-1,wbuf,0); - MultiByteToWideChar(0,0,buf,-1,wbuf,sizeWide); - -// swprintf_s( wbuf, 256, L"%s", buf ); - OutputDebugString( wbuf ); -#else - OutputDebugString( buf ); -#endif -#else - vprintf(fmt, arg); -#endif - va_end(arg); - } -#else - __inline - void debugPrintf(const char *fmt, ...) - { - } -#endif - -}; - -#endif - diff --git a/Extras/RigidBodyGpuPipeline/opencl/primitives/Adl/AdlKernel.h b/Extras/RigidBodyGpuPipeline/opencl/primitives/Adl/AdlKernel.h deleted file mode 100644 index 1a785c1be..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/primitives/Adl/AdlKernel.h +++ /dev/null @@ -1,142 +0,0 @@ -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Takahiro Harada - - -#ifndef ADL_KERNEL_H -#define ADL_KERNEL_H - -#include -#include -#include - -namespace adl -{ - -//========================== -// Kernel -//========================== -struct Kernel -{ - DeviceType m_type; - void* m_kernel; -}; - -//========================== -// KernelManager -//========================== -class KernelManager -{ - public: - typedef std::map KMap; - - __inline - ~KernelManager(); - - __inline -// static - Kernel* query(const Device* dd, const char* fileName, const char* funcName, const char* option = NULL, const char* src = NULL, - bool cacheKernel = true); - - public: - KMap m_map; -}; - -//========================== -// Launcher -//========================== -class Launcher -{ - public: - struct BufferInfo - { - BufferInfo(){} - template - BufferInfo(Buffer* buff, bool isReadOnly = false): m_buffer(buff), m_isReadOnly(isReadOnly){} - - void* m_buffer; - bool m_isReadOnly; - }; - - __inline - Launcher(const Device* dd, char* fileName, char* funcName, char* option = NULL); - __inline - Launcher(const Device* dd, Kernel* kernel); - __inline - void setBuffers( BufferInfo* buffInfo, int n ); - template - __inline - void setConst( Buffer& constBuff, const T& consts ); - __inline - void launch1D( int numThreads, int localSize = 64 ); - __inline - void launch2D( int numThreadsX, int numThreadsY, int localSizeX = 8, int localSizeY = 8 ); - - public: - enum - { - CONST_BUFFER_SIZE = 512, - }; - - const Device* m_deviceData; - Kernel* m_kernel; - int m_idx; - int m_idxRw; -}; - -template -class KernelBuilder -{ - public: - - __inline - KernelBuilder(): m_ptr(0){} - - __inline - void setFromFile( const Device* deviceData, const char* fileName, const char* option = NULL, bool addExtension = false, - bool cacheKernel = true); - - __inline - void setFromSrc( const Device* deviceData, const char* src, const char* option = NULL ); - - __inline - void setFromSrcCached( const Device* deviceData, const char* src, const char* fileName, const char* option ); - - - __inline - void createKernel( const char* funcName, Kernel& kernelOut ); - - __inline - ~KernelBuilder(); - // todo. implemement in kernel destructor? - __inline - static void deleteKernel( Kernel& kernel ); - - private: - enum - { - MAX_PATH_LENGTH = 260, - }; - const Device* m_deviceData; -#ifdef UNICODE - wchar_t m_path[MAX_PATH_LENGTH]; -#else - char m_path[MAX_PATH_LENGTH]; -#endif - void* m_ptr; -}; - -}; - -#endif //ADL_KERNEL_H diff --git a/Extras/RigidBodyGpuPipeline/opencl/primitives/Adl/AdlKernel.inl b/Extras/RigidBodyGpuPipeline/opencl/primitives/Adl/AdlKernel.inl deleted file mode 100644 index 9752b8cf6..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/primitives/Adl/AdlKernel.inl +++ /dev/null @@ -1,223 +0,0 @@ -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Takahiro Harada - - - -#ifdef ADL_ENABLE_CL - #include -#endif -#ifdef ADL_ENABLE_DX11 - #include -#endif - -namespace adl -{ - -//========================== -// KernelManager -//========================== -Kernel* KernelManager::query(const Device* dd, const char* fileName, const char* funcName, const char* option, const char* src, - bool cacheKernel) -{ - printf("compiling kernel %s",funcName); - const int charSize = 1024*2; - KernelManager* s_kManager = this; - - char fullFineName[charSize]; - switch( dd->m_type ) - { - case TYPE_CL: -#if defined(ADL_ENABLE_CL) - sprintf_s(fullFineName,charSize,"%s.cl", fileName); - break; -#endif -#if defined(ADL_ENABLE_DX11) - case TYPE_DX11: - sprintf_s(fullFineName,charSize,"%s.hlsl", fileName); - break; -#endif - default: - ADLASSERT(0); - break; - }; - - char mapName[charSize]; - { - if( option ) - sprintf_s(mapName, charSize, "%d%s%s%s", (int)dd->getContext(), fullFineName, funcName, option); - else - sprintf_s(mapName, charSize, "%d%s%s", (int)dd->getContext(), fullFineName, funcName); - } - - std::string str(mapName); - - KMap::iterator iter = s_kManager->m_map.find( str ); - - Kernel* kernelOut; - if( iter == s_kManager->m_map.end() ) - { - kernelOut = new Kernel(); - - switch( dd->m_type ) - { -#if defined(ADL_ENABLE_CL) - case TYPE_CL: - { - KernelBuilder builder; - if( src ) - if (cacheKernel) - { - builder.setFromSrcCached( dd, src, fileName, option ); - } else - { - builder.setFromSrc( dd, src, option ); - } - else - builder.setFromFile( dd, fileName, option, true, cacheKernel ); - builder.createKernel( funcName, *kernelOut ); - } - break; -#endif -#if defined(ADL_ENABLE_DX11) - case TYPE_DX11: - { - KernelBuilder builder; - if( src ) - builder.setFromSrc( dd, src, option ); - else - builder.setFromFile( dd, fileName, option, true, cacheKernel ); - builder.createKernel( funcName, *kernelOut ); - } - break; -#endif - default: - ADLASSERT(0); - break; - }; - s_kManager->m_map.insert( KMap::value_type(str,kernelOut) ); - } - else - { - kernelOut = iter->second; - } - - printf(" ready\n"); - return kernelOut; -} - -KernelManager::~KernelManager() -{ - for(KMap::iterator iter = m_map.begin(); iter != m_map.end(); iter++) - { - Kernel* k = iter->second; - switch( k->m_type ) - { -#if defined(ADL_ENABLE_CL) - case TYPE_CL: - KernelBuilder::deleteKernel( *k ); - delete k; - break; -#endif -#if defined(ADL_ENABLE_DX11) - case TYPE_DX11: - KernelBuilder::deleteKernel( *k ); - delete k; - break; -#endif - default: - ADLASSERT(0); - break; - }; - } -} - -//========================== -// Launcher -//========================== - -#if defined(ADL_ENABLE_DX11) - #if defined(ADL_ENABLE_CL) - #define SELECT_LAUNCHER( type, func ) \ - switch( type ) \ - { \ - case TYPE_CL: LauncherCL::func; break; \ - case TYPE_DX11: LauncherDX11::func; break; \ - default: ADLASSERT(0); break; \ - }; - #else - #define SELECT_LAUNCHER( type, func ) \ - switch( type ) \ - { \ - case TYPE_DX11: LauncherDX11::func; break; \ - default: ADLASSERT(0); break; \ - }; - #endif -#else - #if defined(ADL_ENABLE_CL) - #define SELECT_LAUNCHER( type, func ) \ - switch( type ) \ - { \ - case TYPE_CL: LauncherCL::func; break; \ - default: ADLASSERT(0); break; \ - }; - #else - #define SELECT_LAUNCHER( type, func ) \ - switch( type ) \ - { \ - default: ADLASSERT(0); break; \ - }; - #endif -#endif - -Launcher::Launcher(const Device *dd, char *fileName, char *funcName, char *option) -{ - m_kernel = dd->getKernel( fileName, funcName, option ); - m_deviceData = dd; - m_idx = 0; - m_idxRw = 0; -} - -Launcher::Launcher(const Device* dd, Kernel* kernel) -{ - m_kernel = kernel; - m_deviceData = dd; - m_idx = 0; - m_idxRw = 0; -} - -void Launcher::setBuffers( BufferInfo* buffInfo, int n ) -{ - SELECT_LAUNCHER( m_deviceData->m_type, setBuffers( this, buffInfo, n ) ); -} - -template -void Launcher::setConst( Buffer& constBuff, const T& consts ) -{ - SELECT_LAUNCHER( m_deviceData->m_type, setConst( this, constBuff, consts ) ); -} - -void Launcher::launch1D( int numThreads, int localSize ) -{ - SELECT_LAUNCHER( m_deviceData->m_type, launch2D( this, numThreads, 1, localSize, 1 ) ); -} - -void Launcher::launch2D( int numThreadsX, int numThreadsY, int localSizeX, int localSizeY ) -{ - SELECT_LAUNCHER( m_deviceData->m_type, launch2D( this, numThreadsX, numThreadsY, localSizeX, localSizeY ) ); -} - -#undef SELECT_LAUNCHER - -}; \ No newline at end of file diff --git a/Extras/RigidBodyGpuPipeline/opencl/primitives/Adl/AdlStopwatch.h b/Extras/RigidBodyGpuPipeline/opencl/primitives/Adl/AdlStopwatch.h deleted file mode 100644 index 034f044a1..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/primitives/Adl/AdlStopwatch.h +++ /dev/null @@ -1,81 +0,0 @@ -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Takahiro Harada - - - -#include - -namespace adl -{ - -struct StopwatchBase -{ - __inline - StopwatchBase(): m_device(0){} - __inline - StopwatchBase( const Device* deviceData ){ init(deviceData); } - __inline - virtual ~StopwatchBase(){} - - __inline - virtual void init( const Device* deviceData ) = 0; - __inline - virtual void start() = 0; - __inline - virtual void split() = 0; - __inline - virtual void stop() = 0; - __inline - virtual float getMs(int index=0) = 0; - __inline - virtual void getMs( float* times, int capacity ) = 0; - __inline - int getNIntervals() const{ return m_idx-1;} - - enum - { - CAPACITY = 64, - }; - - const Device* m_device; - int m_idx; -}; - -struct Stopwatch -{ - __inline - Stopwatch( const Device* deviceData = NULL ) { m_impl=0; if(deviceData) init(deviceData);} - __inline - ~Stopwatch(); - - __inline - void init( const Device* deviceData ); - __inline - void start(){if(!m_impl) init(0); m_impl->start();} - __inline - void split(){m_impl->split();} - __inline - void stop(){m_impl->stop();} - __inline - float getMs(){ return m_impl->getMs();} - __inline - void getMs( float* times, int capacity ){m_impl->getMs(times, capacity);} - __inline - int getNIntervals() const{return m_impl->getNIntervals();} - - StopwatchBase* m_impl; -}; - -}; diff --git a/Extras/RigidBodyGpuPipeline/opencl/primitives/Adl/AdlStopwatch.inl b/Extras/RigidBodyGpuPipeline/opencl/primitives/Adl/AdlStopwatch.inl deleted file mode 100644 index a825ec2c9..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/primitives/Adl/AdlStopwatch.inl +++ /dev/null @@ -1,59 +0,0 @@ -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Takahiro Harada - - -namespace adl -{ - -void Stopwatch::init( const Device* deviceData ) -{ - ADLASSERT( m_impl == 0 ); - - if( deviceData ) - { - switch( deviceData->m_type ) - { -#if defined(ADL_ENABLE_CL) - case TYPE_CL: - m_impl = new StopwatchHost;//StopwatchCL - break; -#endif -#if defined(ADL_ENABLE_DX11) - case TYPE_DX11: - m_impl = new StopwatchHost;//StopwatchDX11; - break; -#endif - case TYPE_HOST: - m_impl = new StopwatchHost; - break; - default: - ADLASSERT(0); - break; - }; - } - else - { - m_impl = new StopwatchHost; - } - m_impl->init( deviceData ); -} - -Stopwatch::~Stopwatch() -{ - if( m_impl == 0 ) return; - delete m_impl; -} - -}; \ No newline at end of file diff --git a/Extras/RigidBodyGpuPipeline/opencl/primitives/Adl/CL/AdlCL.inl b/Extras/RigidBodyGpuPipeline/opencl/primitives/Adl/CL/AdlCL.inl deleted file mode 100644 index 1b603a9c4..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/primitives/Adl/CL/AdlCL.inl +++ /dev/null @@ -1,384 +0,0 @@ -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Takahiro Harada - - - -#pragma comment(lib,"OpenCL.lib") -#include -#include -#include - -namespace adl -{ - -struct DeviceCL : public Device -{ - typedef DeviceUtils::Config Config; - - - __inline - DeviceCL() : Device( TYPE_CL ), m_kernelManager(0){} - __inline - void* getContext() const { return m_context; } - __inline - void initialize(const Config& cfg); - __inline - void release(); - - template - __inline - void allocate(Buffer* buf, int nElems, BufferBase::BufferType type); - - template - __inline - void deallocate(Buffer* buf); - - template - __inline - void copy(Buffer* dst, const Buffer* src, int nElems,int srcOffsetNElems = 0,int dstOffsetNElems = 0); - - template - __inline - void copy(T* dst, const Buffer* src, int nElems, int srcOffsetNElems = 0); - - template - __inline - void copy(Buffer* dst, const T* src, int nElems, int dstOffsetNElems = 0); - - __inline - void waitForCompletion() const; - - __inline - void getDeviceName( char nameOut[128] ) const; - - __inline - static - int getNDevices(); - - __inline - Kernel* getKernel(const char* fileName, const char* funcName, const char* option = NULL, const char* src = NULL, bool cacheKernel = true )const; - - - enum - { - MAX_NUM_DEVICES = 6, - }; - - cl_context m_context; - cl_command_queue m_commandQueue; - - cl_device_id m_deviceIdx; - - KernelManager* m_kernelManager; -}; - -//=== -//=== - -void DeviceCL::initialize(const Config& cfg) -{ -// DeviceUtils::create( cfg, (DeviceCL*)this ); - { -// dd = new DeviceCL(); - - DeviceCL* deviceData = (DeviceCL*)this; - -// cl_device_type deviceType = (driverType == DRIVER_HARDWARE)? CL_DEVICE_TYPE_GPU:CL_DEVICE_TYPE_CPU; - cl_device_type deviceType = (cfg.m_type== Config::DEVICE_GPU)? CL_DEVICE_TYPE_GPU: CL_DEVICE_TYPE_CPU; -// int numContextQueuePairsToCreate = 1; - bool enableProfiling = false; -#ifdef _DEBUG - enableProfiling = true; -#endif - cl_int status; - - cl_platform_id platform; - { - cl_uint nPlatforms = 0; - status = clGetPlatformIDs(0, NULL, &nPlatforms); - ADLASSERT( status == CL_SUCCESS ); - - cl_platform_id pIdx[5]; - status = clGetPlatformIDs(nPlatforms, pIdx, NULL); - ADLASSERT( status == CL_SUCCESS ); - - cl_uint atiIdx = -1; - cl_uint intelIdx = -1; - cl_uint nvIdx = -1; - - for(cl_uint i=0; i0) - { - if( strcmp( buff, "NVIDIA Corporation" )==0 ) nvIdx = i; - if( strcmp( buff, "Advanced Micro Devices, Inc." )==0 ) atiIdx = i; - if( strcmp( buff, "Intel(R) Corporation" )==0 ) intelIdx = i; - } - } - - if( deviceType == CL_DEVICE_TYPE_GPU ) - { - switch( cfg.m_vendor ) - { - case DeviceUtils::Config::VD_AMD: - if( atiIdx == -1 && nvIdx != -1 ) goto USE_NV_GPU; -USE_AMD_GPU: - ADLASSERT(atiIdx != -1 ); - platform = pIdx[atiIdx]; - break; - case DeviceUtils::Config::VD_NV: - if( atiIdx != -1 && nvIdx == -1 ) goto USE_AMD_GPU; -USE_NV_GPU: - ADLASSERT(nvIdx != -1 ); - platform = pIdx[nvIdx]; - break; - default: - ADLASSERT(0); - break; - }; - } - else if( deviceType == CL_DEVICE_TYPE_CPU ) - { - switch( cfg.m_vendor ) - { - case DeviceUtils::Config::VD_AMD: - ADLASSERT(atiIdx != -1 ); - platform = pIdx[atiIdx]; - break; - case DeviceUtils::Config::VD_INTEL: - ADLASSERT(intelIdx != -1 ); - platform = pIdx[intelIdx]; - break; - default: - ADLASSERT(0); - break; - }; - } - } - - cl_uint numDevice; - status = clGetDeviceIDs( platform, deviceType, 0, NULL, &numDevice ); - -// ADLASSERT( cfg.m_deviceIdx < (int)numDevice ); - - debugPrintf("CL: %d %s Devices ", numDevice, (deviceType==CL_DEVICE_TYPE_GPU)? "GPU":"CPU"); - -// numContextQueuePairsToCreate = min( (int)numDevice, numContextQueuePairsToCreate ); -// numContextQueuePairsToCreate = ( (int)numDevice < numContextQueuePairsToCreate )? numDevice : numContextQueuePairsToCreate; - - cl_device_id deviceIds[ MAX_NUM_DEVICES ]; - - status = clGetDeviceIDs( platform, deviceType, numDevice, deviceIds, NULL ); - ADLASSERT( status == CL_SUCCESS ); - - { int i = min( (int)numDevice-1, cfg.m_deviceIdx ); - m_deviceIdx = deviceIds[i]; - deviceData->m_context = clCreateContext( NULL, 1, &deviceData->m_deviceIdx, NULL, NULL, &status ); - ADLASSERT( status == CL_SUCCESS ); - - char buff[512]; - status = clGetDeviceInfo( deviceData->m_deviceIdx, CL_DEVICE_NAME, sizeof(buff), &buff, NULL ); - ADLASSERT( status == CL_SUCCESS ); - - debugPrintf("[%s]\n", buff); - - deviceData->m_commandQueue = clCreateCommandQueue( deviceData->m_context, deviceData->m_deviceIdx, (enableProfiling)?CL_QUEUE_PROFILING_ENABLE:NULL, NULL ); - - ADLASSERT( status == CL_SUCCESS ); - - // status = clSetCommandQueueProperty( commandQueue, CL_QUEUE_PROFILING_ENABLE, CL_TRUE, 0 ); - // CLASSERT( status == CL_SUCCESS ); - - if(0) - { - cl_bool image_support; - clGetDeviceInfo(deviceData->m_deviceIdx, CL_DEVICE_IMAGE_SUPPORT, sizeof(image_support), &image_support, NULL); - debugPrintf(" CL_DEVICE_IMAGE_SUPPORT : %s\n", image_support?"Yes":"No"); - } - } - } - - m_kernelManager = new KernelManager; -} - -void DeviceCL::release() -{ - clReleaseCommandQueue( m_commandQueue ); - clReleaseContext( m_context ); - - if( m_kernelManager ) delete m_kernelManager; -} - -template -void DeviceCL::allocate(Buffer* buf, int nElems, BufferBase::BufferType type) -{ - buf->m_device = this; - buf->m_size = nElems; - buf->m_ptr = 0; - - if( type == BufferBase::BUFFER_CONST ) return; - -#if defined(ADL_CL_DUMP_MEMORY_LOG) - char deviceName[256]; - getDeviceName( deviceName ); - printf( "adlCLMemoryLog %s : %3.2fMB Allocation: %3.2fKB ", deviceName, m_memoryUsage/1024.f/1024.f, sizeof(T)*nElems/1024.f ); - fflush( stdout ); -#endif - - int sz=sizeof(T)*nElems; - - cl_int status = 0; - if( type == BufferBase::BUFFER_ZERO_COPY ) - buf->m_ptr = (T*)clCreateBuffer( m_context, CL_MEM_READ_WRITE | CL_MEM_ALLOC_HOST_PTR, sz, 0, &status ); - else if( type == BufferBase::BUFFER_RAW ) - buf->m_ptr = (T*)clCreateBuffer( m_context, CL_MEM_WRITE_ONLY, sz, 0, &status ); - else - buf->m_ptr = (T*)clCreateBuffer( m_context, CL_MEM_READ_WRITE, sz, 0, &status ); - - m_memoryUsage += buf->m_size*sizeof(T); -#if defined(ADL_CL_DUMP_MEMORY_LOG) - printf( "%s\n", (status==CL_SUCCESS)? "Succeed": "Failed" ); - fflush( stdout ); -#endif - ADLASSERT( status == CL_SUCCESS ); -} - -template -void DeviceCL::deallocate(Buffer* buf) -{ - if( buf->m_ptr ) - { - m_memoryUsage -= buf->m_size*sizeof(T); - clReleaseMemObject( (cl_mem)buf->m_ptr ); - } - buf->m_device = 0; - buf->m_size = 0; - buf->m_ptr = 0; -} - -template -void DeviceCL::copy(Buffer* dst, const Buffer* src, int nElems,int srcOffsetNElems,int dstOffsetNElems ) -{ - if( dst->m_device->m_type == TYPE_CL && src->m_device->m_type == TYPE_CL ) - { - cl_int status = 0; - status = clEnqueueCopyBuffer( m_commandQueue, (cl_mem)src->m_ptr, (cl_mem)dst->m_ptr, sizeof(T)*srcOffsetNElems, sizeof(T)*dstOffsetNElems, sizeof(T)*nElems, 0, 0, 0 ); - ADLASSERT( status == CL_SUCCESS ); - } - else if( src->m_device->m_type == TYPE_HOST ) - { - ADLASSERT( dst->getType() == TYPE_CL ); - dst->write( src->m_ptr, nElems ); - } - else if( dst->m_device->m_type == TYPE_HOST ) - { - ADLASSERT( src->getType() == TYPE_CL ); - src->read( dst->m_ptr, nElems ); - } - else - { - ADLASSERT( 0 ); - } -} - -template -void DeviceCL::copy(T* dst, const Buffer* src, int nElems, int srcOffsetNElems ) -{ - cl_int status = 0; - status = clEnqueueReadBuffer( m_commandQueue, (cl_mem)src->m_ptr, 0, sizeof(T)*srcOffsetNElems, sizeof(T)*nElems, - dst, 0,0,0 ); - ADLASSERT( status == CL_SUCCESS ); -} - -template -void DeviceCL::copy(Buffer* dst, const T* src, int nElems, int dstOffsetNElems ) -{ - cl_int status = 0; - int sz=sizeof(T)*nElems; - status = clEnqueueWriteBuffer( m_commandQueue, (cl_mem)dst->m_ptr, 0, sizeof(T)*dstOffsetNElems, sz, - src, 0,0,0 ); - ADLASSERT( status == CL_SUCCESS ); -} - -void DeviceCL::waitForCompletion() const -{ - clFinish( m_commandQueue ); -} - -int DeviceCL::getNDevices() -{ - cl_device_type deviceType = CL_DEVICE_TYPE_GPU; - cl_int status; - - cl_platform_id platform; - { - cl_uint nPlatforms = 0; - status = clGetPlatformIDs(0, NULL, &nPlatforms); - ADLASSERT( status == CL_SUCCESS ); - - cl_platform_id pIdx[5]; - status = clGetPlatformIDs(nPlatforms, pIdx, NULL); - ADLASSERT( status == CL_SUCCESS ); - - cl_uint nvIdx = -1; - cl_uint atiIdx = -1; - for(cl_uint i=0; iquery( this, fileName, funcName, option, src, cacheKernel ); -} - -}; diff --git a/Extras/RigidBodyGpuPipeline/opencl/primitives/Adl/CL/AdlKernelUtilsCL.inl b/Extras/RigidBodyGpuPipeline/opencl/primitives/Adl/CL/AdlKernelUtilsCL.inl deleted file mode 100644 index 513478a35..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/primitives/Adl/CL/AdlKernelUtilsCL.inl +++ /dev/null @@ -1,541 +0,0 @@ -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Takahiro Harada - - - - - -namespace adl -{ - -struct KernelCL : public Kernel -{ - cl_kernel& getKernel() { return (cl_kernel&)m_kernel; } -}; - -static const char* strip(const char* name, const char* pattern) -{ - size_t const patlen = strlen(pattern); - size_t patcnt = 0; - const char * oriptr; - const char * patloc; - // find how many times the pattern occurs in the original string - for (oriptr = name; patloc = strstr(oriptr, pattern); oriptr = patloc + patlen) - { - patcnt++; - } - return oriptr; -} - -static bool isFileUpToDate(const char* binaryFileName,const char* srcFileName) - -{ - bool fileUpToDate = false; - - bool binaryFileValid=false; - FILETIME modtimeBinary; - - int nameLength = (int)strlen(binaryFileName)+1; -#ifdef UNICODE - WCHAR* fName = new WCHAR[nameLength]; - MultiByteToWideChar(CP_ACP,0,binaryFileName,-1, fName, nameLength); - HANDLE binaryFileHandle = CreateFile(fName,GENERIC_READ,0,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0); - delete [] fName; -#else - HANDLE binaryFileHandle = CreateFile(binaryFileName,GENERIC_READ,0,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0); -#endif - if (binaryFileHandle ==INVALID_HANDLE_VALUE) - { - DWORD errorCode; - errorCode = GetLastError(); - switch (errorCode) - { - case ERROR_FILE_NOT_FOUND: - { - debugPrintf("\nCached file not found %s\n", binaryFileName); - break; - } - case ERROR_PATH_NOT_FOUND: - { - debugPrintf("\nCached file path not found %s\n", binaryFileName); - break; - } - default: - { - debugPrintf("\nFailed reading cached file with errorCode = %d\n", errorCode); - } - } - } else - { - if (GetFileTime(binaryFileHandle, NULL, NULL, &modtimeBinary)==0) - { - DWORD errorCode; - errorCode = GetLastError(); - debugPrintf("\nGetFileTime errorCode = %d\n", errorCode); - } else - { - binaryFileValid = true; - } - CloseHandle(binaryFileHandle); - } - - if (binaryFileValid) - { -#ifdef UNICODE - int nameLength = (int)strlen(srcFileName)+1; - WCHAR* fName = new WCHAR[nameLength]; - MultiByteToWideChar(CP_ACP,0,srcFileName,-1, fName, nameLength); - HANDLE srcFileHandle = CreateFile(fName,GENERIC_READ,0,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0); - delete [] fName; -#else - HANDLE srcFileHandle = CreateFile(srcFileName,GENERIC_READ,0,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0); -#endif - if (srcFileHandle!=INVALID_HANDLE_VALUE) - { - FILETIME modtimeSrc; - if (GetFileTime(srcFileHandle, NULL, NULL, &modtimeSrc)==0) - { - DWORD errorCode; - errorCode = GetLastError(); - debugPrintf("\nGetFileTime errorCode = %d\n", errorCode); - } - if ( ( modtimeSrc.dwHighDateTime < modtimeBinary.dwHighDateTime) - ||(( modtimeSrc.dwHighDateTime == modtimeBinary.dwHighDateTime)&&(modtimeSrc.dwLowDateTime <= modtimeBinary.dwLowDateTime))) - { - fileUpToDate=true; - } else - { - debugPrintf("\nCached binary file found (%s), but out-of-date\n",binaryFileName); - } - CloseHandle(srcFileHandle); - } - else - { -#ifdef _DEBUG - DWORD errorCode; - errorCode = GetLastError(); - switch (errorCode) - { - case ERROR_FILE_NOT_FOUND: - { - debugPrintf("\nSrc file not found %s\n", srcFileName); - break; - } - case ERROR_PATH_NOT_FOUND: - { - debugPrintf("\nSrc path not found %s\n", srcFileName); - break; - } - default: - { - debugPrintf("\nnSrc file reading errorCode = %d\n", errorCode); - } - } - ADLASSERT(0); -#else - //if we cannot find the source, assume it is OK in release builds - fileUpToDate = true; -#endif - } - } - - - return fileUpToDate; -} - -template<> -void KernelBuilder::setFromFile( const Device* deviceData, const char* fileName, const char* option, bool addExtension, - bool cacheKernel) -{ - m_deviceData = deviceData; - - char fileNameWithExtension[256]; - - if( addExtension ) - sprintf_s( fileNameWithExtension, "%s.cl", fileName ); - else - sprintf_s( fileNameWithExtension, "%s", fileName ); - - class File - { - public: - __inline - bool open(const char* fileNameWithExtension) - { - size_t size; - char* str; - - // Open file stream - std::fstream f(fileNameWithExtension, (std::fstream::in | std::fstream::binary)); - - // Check if we have opened file stream - if (f.is_open()) { - size_t sizeFile; - // Find the stream size - f.seekg(0, std::fstream::end); - size = sizeFile = (size_t)f.tellg(); - f.seekg(0, std::fstream::beg); - - str = new char[size + 1]; - if (!str) { - f.close(); - return NULL; - } - - // Read file - f.read(str, sizeFile); - f.close(); - str[size] = '\0'; - - m_source = str; - - delete[] str; - - return true; - } - - return false; - } - const std::string& getSource() const {return m_source;} - - private: - std::string m_source; - }; - - cl_program& program = (cl_program&)m_ptr; - cl_int status = 0; - - bool cacheBinary = cacheKernel; -#if defined(ADL_CL_FORCE_UNCACHE_KERNEL) - cacheBinary = false; -#endif - - char binaryFileName[512]; - { - char deviceName[256]; - deviceData->getDeviceName(deviceName); - char driverVersion[256]; - const DeviceCL* dd = (const DeviceCL*) deviceData; - clGetDeviceInfo(dd->m_deviceIdx, CL_DRIVER_VERSION, 256, &driverVersion, NULL); - const char* strippedFileName = strip(fileName,"\\"); - strippedFileName = strip(strippedFileName,"/"); - - sprintf_s(binaryFileName,"cache/%s.%s.%s.bin",strippedFileName, deviceName,driverVersion ); - } - - bool upToDate = isFileUpToDate(binaryFileName,fileNameWithExtension); - - if( cacheBinary && upToDate) - { - FILE* file = fopen(binaryFileName, "rb"); - - if( file ) - { - fseek( file, 0L, SEEK_END ); - size_t binarySize = ftell( file ); - - rewind( file ); - char* binary = new char[binarySize]; - fread( binary, sizeof(char), binarySize, file ); - fclose( file ); - - if (binarySize) - { - const DeviceCL* dd = (const DeviceCL*) deviceData; - program = clCreateProgramWithBinary( dd->m_context, 1, &dd->m_deviceIdx, &binarySize, (const unsigned char**)&binary, 0, &status ); - ADLASSERT( status == CL_SUCCESS ); - status = clBuildProgram( program, 1, &dd->m_deviceIdx, option, 0, 0 ); - ADLASSERT( status == CL_SUCCESS ); - if( status != CL_SUCCESS ) - { - char *build_log; - size_t ret_val_size; - clGetProgramBuildInfo(program, dd->m_deviceIdx, CL_PROGRAM_BUILD_LOG, 0, NULL, &ret_val_size); - build_log = new char[ret_val_size+1]; - clGetProgramBuildInfo(program, dd->m_deviceIdx, CL_PROGRAM_BUILD_LOG, ret_val_size, build_log, NULL); - - build_log[ret_val_size] = '\0'; - - debugPrintf("%s\n", build_log); - - delete build_log; - ADLASSERT(0); - } - - } - } - } - if( !m_ptr ) - { - File kernelFile; - ADLASSERT( kernelFile.open( fileNameWithExtension ) ); - const char* source = kernelFile.getSource().c_str(); - setFromSrc( m_deviceData, source, option ); - - if( cacheBinary ) - { // write to binary - size_t binarySize; - status = clGetProgramInfo( program, CL_PROGRAM_BINARY_SIZES, sizeof(size_t), &binarySize, 0 ); - ADLASSERT( status == CL_SUCCESS ); - - char* binary = new char[binarySize]; - - status = clGetProgramInfo( program, CL_PROGRAM_BINARIES, sizeof(char*), &binary, 0 ); - ADLASSERT( status == CL_SUCCESS ); - - { - FILE* file = fopen(binaryFileName, "wb"); - if (file) - { - fwrite( binary, sizeof(char), binarySize, file ); - fclose( file ); - } - } - - delete [] binary; - } - } -} - - - -template<> -void KernelBuilder::setFromSrcCached( const Device* deviceData, const char* src, const char* fileName, const char* option ) -{ - m_deviceData = deviceData; - - bool cacheBinary = true; - cl_program& program = (cl_program&)m_ptr; - cl_int status = 0; - - char binaryFileName[512]; - { - char deviceName[256]; - deviceData->getDeviceName(deviceName); - char driverVersion[256]; - const DeviceCL* dd = (const DeviceCL*) deviceData; - clGetDeviceInfo(dd->m_deviceIdx, CL_DRIVER_VERSION, 256, &driverVersion, NULL); - - const char* strippedFileName = strip(fileName,"\\"); - strippedFileName = strip(strippedFileName,"/"); - - sprintf_s(binaryFileName,"cache/%s.%s.%s.bin",strippedFileName, deviceName,driverVersion ); - } - - - char fileNameWithExtension[256]; - sprintf_s(fileNameWithExtension,"%s.cl",fileName, ".cl"); - - bool upToDate = isFileUpToDate(binaryFileName,fileNameWithExtension); - - - if( cacheBinary ) - { - - bool fileUpToDate = isFileUpToDate(binaryFileName,fileNameWithExtension); - - if( fileUpToDate) - { - FILE* file = fopen(binaryFileName, "rb"); - if (file) - { - fseek( file, 0L, SEEK_END ); - size_t binarySize = ftell( file ); - rewind( file ); - char* binary = new char[binarySize]; - fread( binary, sizeof(char), binarySize, file ); - fclose( file ); - - const DeviceCL* dd = (const DeviceCL*) deviceData; - program = clCreateProgramWithBinary( dd->m_context, 1, &dd->m_deviceIdx, &binarySize, (const unsigned char**)&binary, 0, &status ); - ADLASSERT( status == CL_SUCCESS ); - status = clBuildProgram( program, 1, &dd->m_deviceIdx, option, 0, 0 ); - ADLASSERT( status == CL_SUCCESS ); - - if( status != CL_SUCCESS ) - { - char *build_log; - size_t ret_val_size; - clGetProgramBuildInfo(program, dd->m_deviceIdx, CL_PROGRAM_BUILD_LOG, 0, NULL, &ret_val_size); - build_log = new char[ret_val_size+1]; - clGetProgramBuildInfo(program, dd->m_deviceIdx, CL_PROGRAM_BUILD_LOG, ret_val_size, build_log, NULL); - - build_log[ret_val_size] = '\0'; - - debugPrintf("%s\n", build_log); - - delete build_log; - ADLASSERT(0); - } - delete[] binary; - } - } - } - - - if( !m_ptr ) - { - - setFromSrc( deviceData, src, option ); - - if( cacheBinary ) - { // write to binary - cl_uint numAssociatedDevices; - status = clGetProgramInfo( program, CL_PROGRAM_NUM_DEVICES, sizeof(cl_uint), &numAssociatedDevices, 0 ); - ADLASSERT( status == CL_SUCCESS ); - if (numAssociatedDevices==1) - { - - - size_t binarySize; - status = clGetProgramInfo( program, CL_PROGRAM_BINARY_SIZES, sizeof(size_t), &binarySize, 0 ); - ADLASSERT( status == CL_SUCCESS ); - - char* binary = new char[binarySize]; - - status = clGetProgramInfo( program, CL_PROGRAM_BINARIES, sizeof(char*), &binary, 0 ); - ADLASSERT( status == CL_SUCCESS ); - - { - FILE* file = fopen(binaryFileName, "wb"); - if (file) - { - fwrite( binary, sizeof(char), binarySize, file ); - fclose( file ); - } - } - - delete [] binary; - } - } - } -} - - -template<> -void KernelBuilder::setFromSrc( const Device* deviceData, const char* src, const char* option ) -{ - ADLASSERT( deviceData->m_type == TYPE_CL ); - m_deviceData = deviceData; - const DeviceCL* dd = (const DeviceCL*) deviceData; - - cl_program& program = (cl_program&)m_ptr; - cl_int status = 0; - size_t srcSize[] = {strlen( src )}; - program = clCreateProgramWithSource( dd->m_context, 1, &src, srcSize, &status ); - ADLASSERT( status == CL_SUCCESS ); - status = clBuildProgram( program, 1, &dd->m_deviceIdx, option, NULL, NULL ); - if( status != CL_SUCCESS ) - { - char *build_log; - size_t ret_val_size; - clGetProgramBuildInfo(program, dd->m_deviceIdx, CL_PROGRAM_BUILD_LOG, 0, NULL, &ret_val_size); - build_log = new char[ret_val_size+1]; - clGetProgramBuildInfo(program, dd->m_deviceIdx, CL_PROGRAM_BUILD_LOG, ret_val_size, build_log, NULL); - - build_log[ret_val_size] = '\0'; - - debugPrintf("%s\n", build_log); - printf("%s\n", build_log); - - ADLASSERT(0); - delete build_log; - - } -} - -template<> -KernelBuilder::~KernelBuilder() -{ - cl_program program = (cl_program)m_ptr; - clReleaseProgram( program ); -} - -template<> -void KernelBuilder::createKernel( const char* funcName, Kernel& kernelOut ) -{ - KernelCL* clKernel = (KernelCL*)&kernelOut; - - cl_program program = (cl_program)m_ptr; - cl_int status = 0; - clKernel->getKernel() = clCreateKernel(program, funcName, &status ); - ADLASSERT( status == CL_SUCCESS ); - - kernelOut.m_type = TYPE_CL; -} - -template<> -void KernelBuilder::deleteKernel( Kernel& kernel ) -{ - KernelCL* clKernel = (KernelCL*)&kernel; - clReleaseKernel( clKernel->getKernel() ); -} - - - -class LauncherCL -{ - public: - typedef Launcher::BufferInfo BufferInfo; - - __inline - static void setBuffers( Launcher* launcher, BufferInfo* buffInfo, int n ); - template - __inline - static void setConst( Launcher* launcher, Buffer& constBuff, const T& consts ); - __inline - static void launch2D( Launcher* launcher, int numThreadsX, int numThreadsY, int localSizeX, int localSizeY ); -}; - -void LauncherCL::setBuffers( Launcher* launcher, BufferInfo* buffInfo, int n ) -{ - KernelCL* clKernel = (KernelCL*)launcher->m_kernel; - for(int i=0; i* buff = (Buffer*)buffInfo[i].m_buffer; - cl_int status = clSetKernelArg( clKernel->getKernel(), launcher->m_idx++, sizeof(cl_mem), &buff->m_ptr ); - ADLASSERT( status == CL_SUCCESS ); - } -} - -template -void LauncherCL::setConst( Launcher* launcher, Buffer& constBuff, const T& consts ) -{ - KernelCL* clKernel = (KernelCL*)launcher->m_kernel; - int sz=sizeof(T); - cl_int status = clSetKernelArg( clKernel->getKernel(), launcher->m_idx++, sz, &consts ); - ADLASSERT( status == CL_SUCCESS ); -} - -void LauncherCL::launch2D( Launcher* launcher, int numThreadsX, int numThreadsY, int localSizeX, int localSizeY ) -{ - KernelCL* clKernel = (KernelCL*)launcher->m_kernel; - const DeviceCL* ddcl = (const DeviceCL*)launcher->m_deviceData; - size_t gRange[3] = {1,1,1}; - size_t lRange[3] = {1,1,1}; - lRange[0] = localSizeX; - lRange[1] = localSizeY; - gRange[0] = max((size_t)1, (numThreadsX/lRange[0])+(!(numThreadsX%lRange[0])?0:1)); - gRange[0] *= lRange[0]; - gRange[1] = max((size_t)1, (numThreadsY/lRange[1])+(!(numThreadsY%lRange[1])?0:1)); - gRange[1] *= lRange[1]; - - cl_int status = clEnqueueNDRangeKernel( ddcl->m_commandQueue, - clKernel->getKernel(), 2, NULL, gRange, lRange, 0,0,0 ); - ADLASSERT( status == CL_SUCCESS ); -} - - -}; \ No newline at end of file diff --git a/Extras/RigidBodyGpuPipeline/opencl/primitives/Adl/DX11/AdlDX11.inl b/Extras/RigidBodyGpuPipeline/opencl/primitives/Adl/DX11/AdlDX11.inl deleted file mode 100644 index 66abde98e..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/primitives/Adl/DX11/AdlDX11.inl +++ /dev/null @@ -1,512 +0,0 @@ -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Takahiro Harada - - -#include -#include -#include -#include -#include -#pragma comment(lib,"d3dx11.lib") -#pragma comment(lib,"d3d11.lib") -#pragma comment(lib,"DXGI.lib") - -namespace adl -{ - -#define u32 unsigned int - -struct DeviceDX11 : public Device -{ - typedef DeviceUtils::Config Config; - - - __inline - DeviceDX11() : Device( TYPE_DX11 ), m_kernelManager(0){} - __inline - void* getContext() const { return m_context; } - __inline - void initialize(const Config& cfg); - __inline - void release(); - - template - __inline - void allocate(Buffer* buf, int nElems, BufferBase::BufferType type); - - template - __inline - void deallocate(Buffer* buf); - - template - __inline - void copy(Buffer* dst, const Buffer* src, int nElems); - - template - __inline - void copy(T* dst, const Buffer* src, int nElems, int srcOffsetNElems = 0); - - template - __inline - void copy(Buffer* dst, const T* src, int nElems, int dstOffsetNElems = 0); - - __inline - void waitForCompletion() const; - - __inline - void getDeviceName( char nameOut[128] ) const; - - __inline - static - int getNDevices(); - - __inline - Kernel* getKernel(const char* fileName, const char* funcName, const char* option = NULL, const char* src = NULL, bool cacheKernel = true )const; - - - ID3D11DeviceContext* m_context; - ID3D11Device* m_device; - IDXGISwapChain* m_swapChain; - - KernelManager* m_kernelManager; -}; - -template -struct BufferDX11 : public Buffer -{ - ID3D11Buffer* getBuffer() { return (ID3D11Buffer*)m_ptr; } - ID3D11UnorderedAccessView* getUAV() { return (ID3D11UnorderedAccessView*)m_uav; } - ID3D11ShaderResourceView* getSRV() { return (ID3D11ShaderResourceView*)m_srv; } - - ID3D11Buffer** getBufferPtr() { return (ID3D11Buffer**)&m_ptr; } - ID3D11UnorderedAccessView** getUAVPtr() { return (ID3D11UnorderedAccessView**)&m_uav; } - ID3D11ShaderResourceView** getSRVPtr() { return (ID3D11ShaderResourceView**)&m_srv; } -}; - -#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } } - - -void DeviceDX11::initialize(const Config& cfg) -{ - DeviceDX11* deviceData = this; - - HRESULT hr = S_OK; - UINT createDeviceFlg = 0; -#ifdef _DEBUG - createDeviceFlg |= D3D11_CREATE_DEVICE_DEBUG; -#endif - D3D_FEATURE_LEVEL fl[] = { - D3D_FEATURE_LEVEL_11_0, - D3D_FEATURE_LEVEL_10_1, - D3D_FEATURE_LEVEL_10_0 - }; - -typedef HRESULT (WINAPI * LPD3D11CREATEDEVICE)( IDXGIAdapter*, D3D_DRIVER_TYPE, HMODULE, u32, D3D_FEATURE_LEVEL*, UINT, u32, ID3D11Device**, D3D_FEATURE_LEVEL*, ID3D11DeviceContext** ); - - HMODULE moduleD3D11 = 0; -#ifdef UNICODE - moduleD3D11 = LoadLibrary( L"d3d11.dll" ); -#else - moduleD3D11 = LoadLibrary( "d3d11.dll" ); -#endif - ADLASSERT( moduleD3D11 ); - - LPD3D11CREATEDEVICE _DynamicD3D11CreateDevice; - _DynamicD3D11CreateDevice = ( LPD3D11CREATEDEVICE )GetProcAddress( moduleD3D11, "D3D11CreateDevice" ); - - D3D_DRIVER_TYPE type = D3D_DRIVER_TYPE_HARDWARE; - // http://msdn.microsoft.com/en-us/library/ff476082(v=VS.85).aspx - // If you set the pAdapter parameter to a non-NULL value, you must also set the DriverType parameter to the D3D_DRIVER_TYPE_UNKNOWN value. If you set the pAdapter parameter to a non-NULL value and the DriverType parameter to the D3D_DRIVER_TYPE_HARDWARE value, D3D11CreateDevice returns an HRESULT of E_INVALIDARG. - type = D3D_DRIVER_TYPE_UNKNOWN; -/* - // Create a hardware Direct3D 11 device - hr = _DynamicD3D11CreateDevice( NULL, - type, NULL, createDeviceFlg, - fl, _countof(fl), D3D11_SDK_VERSION, &deviceData->m_device, NULL, &deviceData->m_context ); -*/ - IDXGIAdapter* adapter = NULL; - {// get adapter of the index - IDXGIFactory* factory = NULL; - int targetAdapterIdx = cfg.m_deviceIdx;//min( cfg.m_deviceIdx, getNDevices()-1 ); - CreateDXGIFactory( __uuidof(IDXGIFactory), (void**)&factory ); - - u32 i = 0; - while( factory->EnumAdapters( i, &adapter ) != DXGI_ERROR_NOT_FOUND ) - { - if( i== targetAdapterIdx ) break; - i++; - } - factory->Release(); - } - - // Create a hardware Direct3D 11 device - hr = D3D11CreateDevice( adapter, - type, - NULL, createDeviceFlg, - fl, _countof(fl), D3D11_SDK_VERSION, &deviceData->m_device, NULL, &deviceData->m_context ); - - ADLASSERT( hr == S_OK ); - - // Check if the hardware device supports Compute Shader 4.0 - D3D11_FEATURE_DATA_D3D10_X_HARDWARE_OPTIONS hwopts; - deviceData->m_device->CheckFeatureSupport(D3D11_FEATURE_D3D10_X_HARDWARE_OPTIONS, &hwopts, sizeof(hwopts)); - - if( !hwopts.ComputeShaders_Plus_RawAndStructuredBuffers_Via_Shader_4_x ) - { - SAFE_RELEASE( deviceData->m_context ); - SAFE_RELEASE( deviceData->m_device ); - - debugPrintf("DX11 GPU is not present\n"); - ADLASSERT( 0 ); - } - - m_kernelManager = new KernelManager; -} - -void DeviceDX11::release() -{ - SAFE_RELEASE( m_context ); - SAFE_RELEASE( m_device ); - - if( m_kernelManager ) delete m_kernelManager; -} - -template -void DeviceDX11::allocate(Buffer* buf, int nElems, BufferBase::BufferType type) -{ - ADLASSERT( type != BufferBase::BUFFER_ZERO_COPY ); - - DeviceDX11* deviceData = this; - buf->m_device = deviceData; - buf->m_size = nElems; - BufferDX11* dBuf = (BufferDX11*)buf; - -// if( type & BufferBase::BUFFER ) - { - HRESULT hr = S_OK; - - if( type == BufferBase::BUFFER_CONST ) - { - ADLASSERT( nElems == 1 ); - D3D11_BUFFER_DESC constant_buffer_desc; - ZeroMemory( &constant_buffer_desc, sizeof(constant_buffer_desc) ); -// constant_buffer_desc.ByteWidth = NEXTMULTIPLEOF( sizeof(T), 16 ); - constant_buffer_desc.ByteWidth = (((sizeof(T))/(16) + (((sizeof(T))%(16)==0)?0:1))*(16)); -// constant_buffer_desc.Usage = D3D11_USAGE_DYNAMIC; -// constant_buffer_desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; -// constant_buffer_desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; - constant_buffer_desc.Usage = D3D11_USAGE_DEFAULT; - constant_buffer_desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; - constant_buffer_desc.CPUAccessFlags = 0; - - hr = deviceData->m_device->CreateBuffer( &constant_buffer_desc, NULL, dBuf->getBufferPtr() ); - ADLASSERT( hr == S_OK ); - return; - } - - D3D11_BUFFER_DESC buffer_desc; - ZeroMemory(&buffer_desc, sizeof(buffer_desc)); - buffer_desc.ByteWidth = nElems * sizeof(T); - - if( type != BufferBase::BUFFER_RAW ) - { - buffer_desc.StructureByteStride = sizeof(T); -// buffer_desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; - } - - if( type == BufferBase::BUFFER_STAGING ) - { - buffer_desc.Usage = D3D11_USAGE_STAGING; - buffer_desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; - } - else if( type == BufferBase::BUFFER_INDEX ) - { - buffer_desc.Usage = D3D11_USAGE_DEFAULT; - buffer_desc.BindFlags = D3D11_BIND_INDEX_BUFFER; - } - else if( type == BufferBase::BUFFER_VERTEX ) - { - buffer_desc.Usage = D3D11_USAGE_DEFAULT; - buffer_desc.BindFlags = D3D11_BIND_VERTEX_BUFFER; - } - else - { - buffer_desc.Usage = D3D11_USAGE_DEFAULT; - - buffer_desc.BindFlags = D3D11_BIND_UNORDERED_ACCESS | D3D11_BIND_SHADER_RESOURCE; - buffer_desc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED; - -// check this - if(type == BufferBase::BUFFER_RAW) - { -// buffer_desc.BindFlags |= D3D11_BIND_INDEX_BUFFER | D3D11_BIND_VERTEX_BUFFER; - buffer_desc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_ALLOW_RAW_VIEWS | D3D11_RESOURCE_MISC_DRAWINDIRECT_ARGS; // need this to be used for DispatchIndirect - } - } - hr = deviceData->m_device->CreateBuffer(&buffer_desc, NULL, dBuf->getBufferPtr()); - - ADLASSERT( hr == S_OK ); - - if( type == BufferBase::BUFFER_INDEX ) return; - - if( type == BufferBase::BUFFER || - type == BufferBase::BUFFER_RAW || - type == BufferBase::BUFFER_W_COUNTER ) - { - // Create UAVs for all CS buffers - D3D11_UNORDERED_ACCESS_VIEW_DESC uavbuffer_desc; - ZeroMemory(&uavbuffer_desc, sizeof(uavbuffer_desc)); - uavbuffer_desc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER; - - if( type == BufferBase::BUFFER_RAW ) - { - uavbuffer_desc.Format = DXGI_FORMAT_R32_TYPELESS; - uavbuffer_desc.Buffer.Flags = D3D11_BUFFER_UAV_FLAG_RAW; - uavbuffer_desc.Buffer.NumElements = buffer_desc.ByteWidth / 4; - } - else - { - uavbuffer_desc.Format = DXGI_FORMAT_UNKNOWN; - uavbuffer_desc.Buffer.NumElements = nElems; - } - - if( type == BufferBase::BUFFER_W_COUNTER ) - { - uavbuffer_desc.Buffer.Flags = D3D11_BUFFER_UAV_FLAG_COUNTER; - } - - hr = deviceData->m_device->CreateUnorderedAccessView(dBuf->getBuffer(), &uavbuffer_desc, dBuf->getUAVPtr()); - ADLASSERT( hr == S_OK ); - - // Create SRVs for all CS buffers - D3D11_SHADER_RESOURCE_VIEW_DESC srvbuffer_desc; - ZeroMemory(&srvbuffer_desc, sizeof(srvbuffer_desc)); - if( type == BufferBase::BUFFER_RAW ) - { - ADLASSERT( sizeof(T) <= 16 ); - srvbuffer_desc.Format = DXGI_FORMAT_R32_UINT; - srvbuffer_desc.Buffer.ElementWidth = nElems; -// if ( buffer_desc.MiscFlags & D3D11_RESOURCE_MISC_BUFFER_ALLOW_RAW_VIEWS ) -// { -// srvbuffer_desc.Format = DXGI_FORMAT_R32_TYPELESS; -// srvbuffer_desc.BufferEx.Flags = D3D11_BUFFEREX_SRV_FLAG_RAW; -// srvbuffer_desc.BufferEx.NumElements = buffer_desc.ByteWidth / 4; - } - else - { - srvbuffer_desc.Format = DXGI_FORMAT_UNKNOWN; - srvbuffer_desc.Buffer.ElementWidth = nElems; - } - srvbuffer_desc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER; - - hr = deviceData->m_device->CreateShaderResourceView(dBuf->getBuffer(), &srvbuffer_desc, dBuf->getSRVPtr()); - ADLASSERT( hr == S_OK ); - } - else if( type == BufferBase::BUFFER_APPEND ) - { - D3D11_UNORDERED_ACCESS_VIEW_DESC desc; - ZeroMemory( &desc, sizeof(desc) ); - desc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER; - desc.Buffer.FirstElement = 0; - - desc.Buffer.Flags = D3D11_BUFFER_UAV_FLAG_APPEND; - - desc.Format = DXGI_FORMAT_UNKNOWN; // Format must be must be DXGI_FORMAT_UNKNOWN, when creating a View of a Structured Buffer - desc.Buffer.NumElements = buffer_desc.ByteWidth / buffer_desc.StructureByteStride; - - hr = deviceData->m_device->CreateUnorderedAccessView( dBuf->getBuffer(), &desc, dBuf->getUAVPtr() ); - ADLASSERT( hr == S_OK ); - } - } -// else -// { -// ADLASSERT(0); -// } -} - -template -void DeviceDX11::deallocate(Buffer* buf) -{ - BufferDX11* dBuf = (BufferDX11*)buf; - - if( dBuf->getBuffer() ) - { - dBuf->getBuffer()->Release(); - dBuf->m_ptr = NULL; - } - if( dBuf->getUAV() ) - { - dBuf->getUAV()->Release(); - dBuf->m_uav = NULL; - } - if( dBuf->getSRV() ) - { - dBuf->getSRV()->Release(); - dBuf->m_srv = NULL; - } - buf->m_device = 0; -} - -template -void DeviceDX11::copy(Buffer* dst, const Buffer* src, int nElems) -{ - if( dst->m_device->m_type == TYPE_DX11 || src->m_device->m_type == TYPE_DX11 ) - { - DeviceDX11* deviceData = this; - BufferDX11* dDst = (BufferDX11*)dst; - BufferDX11* dSrc = (BufferDX11*)src; - - D3D11_MAPPED_SUBRESOURCE MappedVelResource = {0}; - - D3D11_BOX destRegion; - destRegion.left = 0*sizeof(T); - destRegion.front = 0; - destRegion.top = 0; - destRegion.bottom = 1; - destRegion.back = 1; - destRegion.right = (0+nElems)*sizeof(T); - - deviceData->m_context->CopySubresourceRegion( - dDst->getBuffer(), - 0, 0, 0, 0, - dSrc->getBuffer(), - 0, - &destRegion ); - - } - else if( src->m_device->m_type == TYPE_HOST ) - { - ADLASSERT( dst->getType() == TYPE_DX11 ); - dst->write( src->m_ptr, nElems ); - } - else if( dst->m_device->m_type == TYPE_HOST ) - { - ADLASSERT( src->getType() == TYPE_DX11 ); - src->read( dst->m_ptr, nElems ); - } - else - { - ADLASSERT( 0 ); - } -} - -template -void DeviceDX11::copy(T* dst, const Buffer* src, int nElems, int srcOffsetNElems) -{ - DeviceDX11* deviceData = this; - BufferDX11* dSrc = (BufferDX11*)src; - Buffer sBuf( deviceData, nElems, BufferBase::BUFFER_STAGING ); - BufferDX11* dStagingBuf = (BufferDX11*)&sBuf; - - - ID3D11Buffer *StagingBuffer = dStagingBuf->getBuffer(); - D3D11_MAPPED_SUBRESOURCE MappedVelResource = {0}; - - D3D11_BOX destRegion; - destRegion.left = srcOffsetNElems*sizeof(T); - destRegion.front = 0; - destRegion.top = 0; - destRegion.bottom = 1; - destRegion.back = 1; - destRegion.right = (srcOffsetNElems+nElems)*sizeof(T); - - deviceData->m_context->CopySubresourceRegion( - StagingBuffer, - 0, 0, 0, 0, - dSrc->getBuffer(), - 0, - &destRegion); - - deviceData->m_context->Map(StagingBuffer, 0, D3D11_MAP_READ, 0, &MappedVelResource); - memcpy(dst, MappedVelResource.pData, nElems*sizeof(T)); - deviceData->m_context->Unmap(StagingBuffer, 0); -} - -template -void DeviceDX11::copy(Buffer* dst, const T* src, int nElems, int dstOffsetNElems) -{ - BufferDX11* dBuf = (BufferDX11*)dst; - - DeviceDX11* deviceData = this; - - D3D11_BOX destRegion; - destRegion.left = dstOffsetNElems*sizeof(T); - destRegion.front = 0; - destRegion.top = 0; - destRegion.bottom = 1; - destRegion.back = 1; - destRegion.right = (dstOffsetNElems+nElems)*sizeof(T); - deviceData->m_context->UpdateSubresource(dBuf->getBuffer(), 0, &destRegion, src, 0, 0); -} - -void DeviceDX11::waitForCompletion() const -{ - const DeviceDX11* deviceData = this; - - ID3D11Query* syncQuery; - D3D11_QUERY_DESC qDesc; - qDesc.Query = D3D11_QUERY_EVENT; - qDesc.MiscFlags = 0; - deviceData->m_device->CreateQuery( &qDesc, &syncQuery ); - deviceData->m_context->End( syncQuery ); - while( deviceData->m_context->GetData( syncQuery, 0,0,0 ) == S_FALSE ){} - syncQuery->Release(); -} - -int DeviceDX11::getNDevices() -{ - IDXGIFactory1* factory = NULL; - IDXGIAdapter1* adapter = NULL; - CreateDXGIFactory1( __uuidof(IDXGIFactory1), (void**)&factory ); - - u32 i = 0; - while( factory->EnumAdapters1( i, &adapter ) != DXGI_ERROR_NOT_FOUND ) - { - i++; - } - - factory->Release(); - return i; -} - -void DeviceDX11::getDeviceName( char nameOut[128] ) const -{ - IDXGIAdapter* adapter;// = getAdapterFromDevice( this ); - { - IDXGIDevice* pDXGIDevice; - - ADLASSERT( m_device->QueryInterface(__uuidof(IDXGIDevice), (void **)&pDXGIDevice) == S_OK ); - ADLASSERT( pDXGIDevice->GetParent(__uuidof(IDXGIAdapter), (void **)&adapter) == S_OK ); - - pDXGIDevice->Release(); - } - DXGI_ADAPTER_DESC adapterDesc; - adapter->GetDesc( &adapterDesc ); - -// wcstombs( nameOut, adapterDesc.Description, 128 ); - size_t i; - wcstombs_s( &i, nameOut, 128, adapterDesc.Description, 128 ); -} - -Kernel* DeviceDX11::getKernel(const char* fileName, const char* funcName, const char* option, const char* src, bool cacheKernel ) const -{ - return m_kernelManager->query( this, fileName, funcName, option, src, cacheKernel ); -} - -#undef u32 - -#undef SAFE_RELEASE - -}; diff --git a/Extras/RigidBodyGpuPipeline/opencl/primitives/Adl/DX11/AdlKernelUtilsDX11.inl b/Extras/RigidBodyGpuPipeline/opencl/primitives/Adl/DX11/AdlKernelUtilsDX11.inl deleted file mode 100644 index d4e29999d..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/primitives/Adl/DX11/AdlKernelUtilsDX11.inl +++ /dev/null @@ -1,348 +0,0 @@ -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Takahiro Harada - - - -namespace adl -{ - -#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } } - -struct KernelDX11 : public Kernel -{ - ID3D11ComputeShader* getKernel() { return (ID3D11ComputeShader*)m_kernel; } - ID3D11ComputeShader** getKernelPtr() { return (ID3D11ComputeShader**)&m_kernel; } -}; - - -__inline -#ifdef UNICODE -HRESULT FindDXSDKShaderFileCch( __in_ecount(cchDest) WCHAR* strDestPath, - int cchDest, - __in LPCWSTR strFilename ) -#else -HRESULT FindDXSDKShaderFileCch( __in_ecount(cchDest) CHAR* strDestPath, - int cchDest, - __in LPCSTR strFilename ) -#endif -{ - if( NULL == strFilename || strFilename[0] == 0 || NULL == strDestPath || cchDest < 10 ) - return E_INVALIDARG; - - // Get the exe name, and exe path -#ifdef UNICODE - WCHAR strExePath[MAX_PATH] = -#else - CHAR strExePath[MAX_PATH] = -#endif - { - 0 - }; -#ifdef UNICODE - WCHAR strExeName[MAX_PATH] = -#else - CHAR strExeName[MAX_PATH] = -#endif - { - 0 - }; -#ifdef UNICODE - WCHAR* strLastSlash = NULL; -#else - CHAR* strLastSlash = NULL; -#endif - GetModuleFileName( NULL, strExePath, MAX_PATH ); - strExePath[MAX_PATH - 1] = 0; -#ifdef UNICODE - strLastSlash = wcsrchr( strExePath, TEXT( '\\' ) ); -#else - strLastSlash = strrchr( strExePath, TEXT( '\\' ) ); -#endif - if( strLastSlash ) - { -#ifdef UNICODE - wcscpy_s( strExeName, MAX_PATH, &strLastSlash[1] ); -#else - -#endif - // Chop the exe name from the exe path - *strLastSlash = 0; - - // Chop the .exe from the exe name -#ifdef UNICODE - strLastSlash = wcsrchr( strExeName, TEXT( '.' ) ); -#else - strLastSlash = strrchr( strExeName, TEXT( '.' ) ); -#endif - if( strLastSlash ) - *strLastSlash = 0; - } - - // Search in directories: - // .\ - // %EXE_DIR%\..\..\%EXE_NAME% -#ifdef UNICODE - wcscpy_s( strDestPath, cchDest, strFilename ); -#else - strcpy_s( strDestPath, cchDest, strFilename ); -#endif - if( GetFileAttributes( strDestPath ) != 0xFFFFFFFF ) - return S_OK; - -// swprintf_s( strDestPath, cchDest, L"%s\\..\\..\\%s\\%s", strExePath, strExeName, strFilename ); -#ifdef UNICODE - swprintf_s( strDestPath, cchDest, L"%s\\..\\%s\\%s", strExePath, strExeName, strFilename ); -#else - sprintf_s( strDestPath, cchDest, "%s\\..\\%s\\%s", strExePath, strExeName, strFilename ); -#endif - if( GetFileAttributes( strDestPath ) != 0xFFFFFFFF ) - return S_OK; - - // On failure, return the file as the path but also return an error code -#ifdef UNICODE - wcscpy_s( strDestPath, cchDest, strFilename ); -#else - strcpy_s( strDestPath, cchDest, strFilename ); -#endif - - ADLASSERT( 0 ); - - return E_FAIL; -} - - - - -template<> -void KernelBuilder::setFromFile( const Device* deviceData, const char* fileName, const char* option, bool addExtension, - bool cacheKernel) -{ - char fileNameWithExtension[256]; - - if( addExtension ) - sprintf_s( fileNameWithExtension, "%s.hlsl", fileName ); - else - sprintf_s( fileNameWithExtension, "%s", fileName ); - - m_deviceData = deviceData; - - int nameLength = (int)strlen(fileNameWithExtension)+1; -#ifdef UNICODE - WCHAR* wfileNameWithExtension = new WCHAR[nameLength]; -#else - CHAR* wfileNameWithExtension = new CHAR[nameLength]; -#endif - memset(wfileNameWithExtension,0,nameLength); -#ifdef UNICODE - MultiByteToWideChar(CP_ACP,0,fileNameWithExtension,-1, wfileNameWithExtension, nameLength); -#else - sprintf_s(wfileNameWithExtension, nameLength, "%s", fileNameWithExtension); -#endif -// swprintf_s(wfileNameWithExtension, nameLength*2, L"%s", fileNameWithExtension); - - HRESULT hr; - - // Finds the correct path for the shader file. - // This is only required for this sample to be run correctly from within the Sample Browser, - // in your own projects, these lines could be removed safely - hr = FindDXSDKShaderFileCch( m_path, MAX_PATH, wfileNameWithExtension ); - - delete [] wfileNameWithExtension; - - ADLASSERT( hr == S_OK ); -} - -template<> -void KernelBuilder::setFromSrc( const Device* deviceData, const char* src, const char* option ) -{ - m_deviceData = deviceData; - m_ptr = (void*)src; - m_path[0] = '0'; -} - -template<> -KernelBuilder::~KernelBuilder() -{ - -} - -template<> -void KernelBuilder::createKernel( const char* funcName, Kernel& kernelOut ) -{ - const DeviceDX11* deviceData = (const DeviceDX11*)m_deviceData; - KernelDX11* dxKernel = (KernelDX11*)&kernelOut; - HRESULT hr; - - DWORD dwShaderFlags = D3DCOMPILE_ENABLE_STRICTNESS; -#if defined( DEBUG ) || defined( _DEBUG ) - // Set the D3DCOMPILE_DEBUG flag to embed debug information in the shaders. - // Setting this flag improves the shader debugging experience, but still allows - // the shaders to be optimized and to run exactly the way they will run in - // the release configuration of this program. - dwShaderFlags |= D3DCOMPILE_DEBUG; -#endif - - const D3D_SHADER_MACRO defines[] = - { -#ifdef USE_STRUCTURED_BUFFERS - "USE_STRUCTURED_BUFFERS", "1", -#endif - -#ifdef TEST_DOUBLE - "TEST_DOUBLE", "1", -#endif - NULL, NULL - }; - - // We generally prefer to use the higher CS shader profile when possible as CS 5.0 is better performance on 11-class hardware - LPCSTR pProfile = ( deviceData->m_device->GetFeatureLevel() >= D3D_FEATURE_LEVEL_11_0 ) ? "cs_5_0" : "cs_4_0"; - - ID3DBlob* pErrorBlob = NULL; - ID3DBlob* pBlob = NULL; - if( m_path[0] == '0' ) - { - char* src = (char*)m_ptr; - hr = D3DX11CompileFromMemory( src, strlen(src), 0, defines, NULL, funcName, pProfile, - dwShaderFlags, NULL, NULL, &pBlob, &pErrorBlob, NULL ); - } - else - { - hr = D3DX11CompileFromFile( m_path, defines, NULL, funcName, pProfile, - dwShaderFlags, NULL, NULL, &pBlob, &pErrorBlob, NULL ); - } - - if ( FAILED(hr) ) - { - debugPrintf("%s", (char*)pErrorBlob->GetBufferPointer()); - } - ADLASSERT( hr == S_OK ); - - hr = deviceData->m_device->CreateComputeShader( pBlob->GetBufferPointer(), pBlob->GetBufferSize(), NULL, - dxKernel->getKernelPtr() ); - -#if defined(DEBUG) || defined(PROFILE) - if ( kernelOut.m_kernel ) - kernelOut.m_kernel->SetPrivateData( WKPDID_D3DDebugObjectName, lstrlenA(pFunctionName), pFunctionName ); -#endif - - SAFE_RELEASE( pErrorBlob ); - SAFE_RELEASE( pBlob ); - - kernelOut.m_type = TYPE_DX11; -} - -template<> -void KernelBuilder::deleteKernel( Kernel& kernel ) -{ - KernelDX11* dxKernel = (KernelDX11*)&kernel; - - if( kernel.m_kernel ) - { - dxKernel->getKernel()->Release(); - kernel.m_kernel = NULL; - } -} - - - -class LauncherDX11 -{ - public: - typedef Launcher::BufferInfo BufferInfo; - - __inline - static void setBuffers( Launcher* launcher, BufferInfo* buffInfo, int n ); - template - __inline - static void setConst( Launcher* launcher, Buffer& constBuff, const T& consts ); - __inline - static void launch2D( Launcher* launcher, int numThreadsX, int numThreadsY, int localSizeX, int localSizeY ); -}; - -void LauncherDX11::setBuffers( Launcher* launcher, BufferInfo* buffInfo, int n ) -{ - KernelDX11* dxKernel = (KernelDX11*)launcher->m_kernel; - const DeviceDX11* dddx = (const DeviceDX11*)launcher->m_deviceData; - - for(int i=0; i* dBuf = (BufferDX11*)buffInfo[i].m_buffer; - if( buffInfo[i].m_isReadOnly ) - { - dddx->m_context->CSSetShaderResources( launcher->m_idx++, 1, dBuf->getSRVPtr() ); - } - else - { - // todo. cannot initialize append buffer with proper counter value which is the last arg - dddx->m_context->CSSetUnorderedAccessViews( launcher->m_idxRw++, 1, dBuf->getUAVPtr(), 0 ); - } - } -} - -template -void LauncherDX11::setConst( Launcher* launcher, Buffer& constBuff, const T& consts ) -{ - KernelDX11* dxKernel = (KernelDX11*)launcher->m_kernel; - const DeviceDX11* dddx = (const DeviceDX11*)launcher->m_deviceData; - BufferDX11* dBuf = (BufferDX11*)&constBuff; -/* - D3D11_MAPPED_SUBRESOURCE MappedResource; - dddx->m_context->Map( dBuf->getBuffer(), 0, D3D11_MAP_WRITE_DISCARD, 0, &MappedResource ); - memcpy( MappedResource.pData, &consts, sizeof(T) ); - dddx->m_context->Unmap( dBuf->getBuffer(), 0 ); -*/ - - dddx->m_context->UpdateSubresource( dBuf->getBuffer(), 0, NULL, &consts, 0, 0 ); - - dddx->m_context->CSSetConstantBuffers( 0, 1, dBuf->getBufferPtr() ); -} - -void LauncherDX11::launch2D( Launcher* launcher, int numThreadsX, int numThreadsY, int localSizeX, int localSizeY ) -{ - KernelDX11* dxKernel = (KernelDX11*)launcher->m_kernel; - const DeviceDX11* dddx = (const DeviceDX11*)launcher->m_deviceData; - - dddx->m_context->CSSetShader( dxKernel->getKernel(), NULL, 0 ); - - int nx, ny, nz; - nx = max( 1, (numThreadsX/localSizeX)+(!(numThreadsX%localSizeX)?0:1) ); - ny = max( 1, (numThreadsY/localSizeY)+(!(numThreadsY%localSizeY)?0:1) ); - nz = 1; - - dddx->m_context->Dispatch( nx, ny, nz ); - - // set 0 to registers - { - dddx->m_context->CSSetShader( NULL, NULL, 0 ); - - if( launcher->m_idxRw ) - { - ID3D11UnorderedAccessView* aUAViewsNULL[ 16 ] = { 0 }; - dddx->m_context->CSSetUnorderedAccessViews( 0, - min( (unsigned int)launcher->m_idxRw, sizeof(aUAViewsNULL)/sizeof(*aUAViewsNULL) ), aUAViewsNULL, NULL ); - } - - if( launcher->m_idx ) - { - ID3D11ShaderResourceView* ppSRVNULL[16] = { 0 }; - dddx->m_context->CSSetShaderResources( 0, - min( (unsigned int)launcher->m_idx, sizeof(ppSRVNULL)/sizeof(*ppSRVNULL) ), ppSRVNULL ); - } - } -} - -#undef SAFE_RELEASE - -}; diff --git a/Extras/RigidBodyGpuPipeline/opencl/primitives/Adl/DX11/AdlStopwatchDX11.inl b/Extras/RigidBodyGpuPipeline/opencl/primitives/Adl/DX11/AdlStopwatchDX11.inl deleted file mode 100644 index 15b79aac5..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/primitives/Adl/DX11/AdlStopwatchDX11.inl +++ /dev/null @@ -1,131 +0,0 @@ -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Takahiro Harada - - - -namespace adl -{ - -struct StopwatchDX11 : public StopwatchBase -{ - public: - __inline - StopwatchDX11() : StopwatchBase(){} - __inline - ~StopwatchDX11(); - - __inline - void init( const Device* deviceData ); - __inline - void start(); - __inline - void split(); - __inline - void stop(); - __inline - float getMs(int index=0); - __inline - void getMs( float* times, int capacity ); - - public: - ID3D11Query* m_tQuery[CAPACITY+1]; - ID3D11Query* m_fQuery; - UINT64 m_t[CAPACITY]; -}; - -void StopwatchDX11::init( const Device* deviceData ) -{ - ADLASSERT( deviceData->m_type == TYPE_DX11 ); - m_device = deviceData; - { - D3D11_QUERY_DESC qDesc; - qDesc.Query = D3D11_QUERY_TIMESTAMP_DISJOINT; - qDesc.MiscFlags = 0; - ((const DeviceDX11*)m_device)->m_device->CreateQuery( &qDesc, &m_fQuery ); - } - for(int i=0; im_device->CreateQuery( &qDesc, &m_tQuery[i] ); - } -} - -StopwatchDX11::~StopwatchDX11() -{ - m_fQuery->Release(); - for(int i=0; iRelease(); - } -} - -void StopwatchDX11::start() -{ - m_idx = 0; - ((const DeviceDX11*)m_device)->m_context->Begin( m_fQuery ); - ((const DeviceDX11*)m_device)->m_context->End( m_tQuery[m_idx++] ); -} - -void StopwatchDX11::split() -{ - if( m_idx < CAPACITY ) - ((const DeviceDX11*)m_device)->m_context->End( m_tQuery[m_idx++] ); -} - -void StopwatchDX11::stop() -{ - ((const DeviceDX11*)m_device)->m_context->End( m_tQuery[m_idx++] ); - ((const DeviceDX11*)m_device)->m_context->End( m_fQuery ); -} - -float StopwatchDX11::getMs(int index) -{ - D3D11_QUERY_DATA_TIMESTAMP_DISJOINT d; -// m_deviceData->m_context->End( m_fQuery ); - while( ((const DeviceDX11*)m_device)->m_context->GetData( m_fQuery, &d,sizeof(D3D11_QUERY_DATA_TIMESTAMP_DISJOINT),0 ) == S_FALSE ) {} - - while( ((const DeviceDX11*)m_device)->m_context->GetData( m_tQuery[0], &m_t[index],sizeof(UINT64),0 ) == S_FALSE ){} - while( ((const DeviceDX11*)m_device)->m_context->GetData( m_tQuery[1], &m_t[index+1],sizeof(UINT64),0 ) == S_FALSE ){} - - ADLASSERT( d.Disjoint == false ); - - float elapsedMs = (m_t[index+1] - m_t[index])/(float)d.Frequency*1000; - return elapsedMs; - -} - -void StopwatchDX11::getMs( float* times, int capacity ) -{ - ADLASSERT( capacity <= CAPACITY ); - - D3D11_QUERY_DATA_TIMESTAMP_DISJOINT d; - while( ((const DeviceDX11*)m_device)->m_context->GetData( m_fQuery, &d,sizeof(D3D11_QUERY_DATA_TIMESTAMP_DISJOINT),0 ) == S_FALSE ) {} - - for(int i=0; im_context->GetData( m_tQuery[i], &m_t[i],sizeof(UINT64),0 ) == S_FALSE ){} - } - - ADLASSERT( d.Disjoint == false ); - - for(int i=0; i - __inline - void allocate(Buffer* buf, int nElems, BufferBase::BufferType type); - - template - __inline - void deallocate(Buffer* buf); - - template - __inline - void copy(Buffer* dst, const Buffer* src, int nElems); - - template - __inline - void copy(T* dst, const Buffer* src, int nElems, int offsetNElems = 0); - - template - __inline - void copy(Buffer* dst, const T* src, int nElems, int offsetNElems = 0); - - __inline - void waitForCompletion() const; -}; - -void DeviceHost::initialize(const Config& cfg) -{ - -} - -void DeviceHost::release() -{ - -} - -template -void DeviceHost::allocate(Buffer* buf, int nElems, BufferBase::BufferType type) -{ - buf->m_device = this; - - if( type == BufferBase::BUFFER_CONST ) return; - - buf->m_ptr = new T[nElems]; - ADLASSERT( buf->m_ptr ); - buf->m_size = nElems; -} - -template -void DeviceHost::deallocate(Buffer* buf) -{ - if( buf->m_ptr ) delete [] buf->m_ptr; -} - -template -void DeviceHost::copy(Buffer* dst, const Buffer* src, int nElems) -{ - copy( dst, src->m_ptr, nElems ); -} - -template -void DeviceHost::copy(T* dst, const Buffer* src, int nElems, int srcOffsetNElems) -{ - ADLASSERT( src->getType() == TYPE_HOST ); - memcpy( dst, src->m_ptr+srcOffsetNElems, nElems*sizeof(T) ); -} - -template -void DeviceHost::copy(Buffer* dst, const T* src, int nElems, int dstOffsetNElems) -{ - ADLASSERT( dst->getType() == TYPE_HOST ); - memcpy( dst->m_ptr+dstOffsetNElems, src, nElems*sizeof(T) ); -} - -void DeviceHost::waitForCompletion() const -{ - -} - -}; diff --git a/Extras/RigidBodyGpuPipeline/opencl/primitives/Adl/Host/AdlStopwatchHost.inl b/Extras/RigidBodyGpuPipeline/opencl/primitives/Adl/Host/AdlStopwatchHost.inl deleted file mode 100644 index bb6eb571c..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/primitives/Adl/Host/AdlStopwatchHost.inl +++ /dev/null @@ -1,119 +0,0 @@ -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Takahiro Harada - -#ifdef _WIN32 - #include -#else - #include -#endif - -namespace adl -{ - -class StopwatchHost : public StopwatchBase -{ - public: - __inline - StopwatchHost(); - __inline - void init( const Device* deviceData ); - __inline - void start(); - __inline - void split(); - __inline - void stop(); - __inline - float getMs(int index=0); - __inline - void getMs( float* times, int capacity ); - - private: -#ifdef _WIN32 - LARGE_INTEGER m_frequency; - LARGE_INTEGER m_t[CAPACITY]; -#else - struct timeval mStartTime; - timeval m_t[CAPACITY]; -#endif -}; - -__inline -StopwatchHost::StopwatchHost() - : StopwatchBase() -{ -} - -__inline -void StopwatchHost::init( const Device* deviceData ) -{ - m_device = deviceData; -#ifdef _WIN32 - QueryPerformanceFrequency( &m_frequency ); -#else - gettimeofday(&mStartTime, 0); -#endif -} - -__inline -void StopwatchHost::start() -{ - m_idx = 0; -#ifdef _WIN32 - QueryPerformanceCounter(&m_t[m_idx++]); -#else - gettimeofday(&m_t[m_idx++], 0); -#endif -} - -__inline -void StopwatchHost::split() -{ -#ifdef _WIN32 - QueryPerformanceCounter(&m_t[m_idx++]); -#else - gettimeofday(&m_t[m_idx++], 0); -#endif -} - -__inline -void StopwatchHost::stop() -{ - split(); -} - -__inline -float StopwatchHost::getMs(int index) -{ -#ifdef _WIN32 - return (float)(1000*(m_t[index+1].QuadPart - m_t[index].QuadPart))/m_frequency.QuadPart; -#else - return (m_t[index+1].tv_sec - m_t[index].tv_sec) * 1000 + - (m_t[index+1].tv_usec - m_t[index].tv_usec) / 1000; -#endif -} - -__inline -void StopwatchHost::getMs(float* times, int capacity) -{ - for(int i=0; i -#include - -namespace adl -{ - -class CopyBase -{ - public: - enum Option - { - PER_WI_1, - PER_WI_2, - PER_WI_4, - }; -}; - -template -class Copy : public CopyBase -{ - public: - typedef Launcher::BufferInfo BufferInfo; - - struct Data - { - const Device* m_device; - Kernel* m_copy1F4Kernel; - Kernel* m_copy2F4Kernel; - Kernel* m_copy4F4Kernel; - Kernel* m_copyF1Kernel; - Kernel* m_copyF2Kernel; - Buffer* m_constBuffer; - }; - - static - Data* allocate(const Device* deviceData); - - static - void deallocate(Data* data); - - static - void execute( Data* data, Buffer& dst, Buffer& src, int n, Option option = PER_WI_1); - - static - void execute( Data* data, Buffer& dst, Buffer& src, int n); - - static - void execute( Data* data, Buffer& dst, Buffer& src, int n); -}; - - -#include -#include - -}; diff --git a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Copy/Copy.inl b/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Copy/Copy.inl deleted file mode 100644 index ee6d3f0ef..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Copy/Copy.inl +++ /dev/null @@ -1,151 +0,0 @@ -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Takahiro Harada - - - -#define PATH "..\\..\\opencl\\primitives\\AdlPrimitives\\Copy\\CopyKernels" -#define KERNEL0 "Copy1F4Kernel" -#define KERNEL1 "Copy2F4Kernel" -#define KERNEL2 "Copy4F4Kernel" -#define KERNEL3 "CopyF1Kernel" -#define KERNEL4 "CopyF2Kernel" - -#include -#include - - -template -typename Copy::Data* Copy::allocate( const Device* device ) -{ - ADLASSERT( TYPE == device->m_type ); - - - const char* src[] = -#if defined(ADL_LOAD_KERNEL_FROM_STRING) - {copyKernelsCL, copyKernelsDX11}; -// ADLASSERT(0); -#else - {0,0}; -#endif - - Data* data = new Data; - data->m_device = device; - data->m_copy1F4Kernel = device->getKernel( PATH, KERNEL0, 0, src[TYPE] ); - data->m_copy2F4Kernel = device->getKernel( PATH, KERNEL1, 0, src[TYPE] ); - data->m_copy4F4Kernel = device->getKernel( PATH, KERNEL2, 0, src[TYPE] ); - data->m_copyF1Kernel = device->getKernel( PATH, KERNEL3, 0, src[TYPE] ); - data->m_copyF2Kernel = device->getKernel( PATH, KERNEL4, 0, src[TYPE] ); - data->m_constBuffer = new Buffer( device, 1, BufferBase::BUFFER_CONST ); - - return data; -} - -template -void Copy::deallocate( Data* data ) -{ - delete data->m_constBuffer; - delete data; -} - -template -void Copy::execute( Data* data, Buffer& dst, Buffer& src, int n, Option option ) -{ - ADLASSERT( TYPE == dst.getType() ); - ADLASSERT( TYPE == src.getType() ); - - int4 constBuffer; - constBuffer.x = n; - - switch (option) - { - case PER_WI_1: - { - BufferInfo bInfo[] = { BufferInfo( &dst ), BufferInfo( &src, true ) }; - - Launcher launcher( data->m_device, data->m_copy1F4Kernel ); - launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(Launcher::BufferInfo) ); - launcher.setConst( *data->m_constBuffer, constBuffer ); - launcher.launch1D( n/1 ); - } - break; - case PER_WI_2: - { - ADLASSERT( n%2 == 0 ); - BufferInfo bInfo[] = { BufferInfo( &dst ), BufferInfo( &src, true ) }; - - Launcher launcher( data->m_device, data->m_copy2F4Kernel ); - launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(Launcher::BufferInfo) ); - launcher.setConst( *data->m_constBuffer, constBuffer ); - launcher.launch1D( n/2 ); - } - break; - case PER_WI_4: - { - ADLASSERT( n%4 == 0 ); - BufferInfo bInfo[] = { BufferInfo( &dst ), BufferInfo( &src, true ) }; - - Launcher launcher( data->m_device, data->m_copy4F4Kernel ); - launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(Launcher::BufferInfo) ); - launcher.setConst( *data->m_constBuffer, constBuffer ); - launcher.launch1D( n/4 ); - } - break; - default: - ADLASSERT(0); - break; - }; -} - -template -void Copy::execute( Data* data, Buffer& dst, Buffer& src, int n ) -{ - ADLASSERT( TYPE == dst.getType() ); - ADLASSERT( TYPE == src.getType() ); - - int4 constBuffer; - constBuffer.x = n; - - BufferInfo bInfo[] = { BufferInfo( &dst ), BufferInfo( &src, true ) }; - - Launcher launcher( data->m_device, data->m_copyF2Kernel ); - launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(Launcher::BufferInfo) ); - launcher.setConst( *data->m_constBuffer, constBuffer ); - launcher.launch1D( n/1 ); -} - -template -void Copy::execute( Data* data, Buffer& dst, Buffer& src, int n ) -{ - ADLASSERT( TYPE == dst.getType() ); - ADLASSERT( TYPE == src.getType() ); - - int4 constBuffer; - constBuffer.x = n; - - BufferInfo bInfo[] = { BufferInfo( &dst ), BufferInfo( &src, true ) }; - - Launcher launcher( data->m_device, data->m_copyF1Kernel ); - launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(Launcher::BufferInfo) ); - launcher.setConst( *data->m_constBuffer, constBuffer ); - launcher.launch1D( n/1 ); -} - - -#undef PATH -#undef KERNEL0 -#undef KERNEL1 -#undef KERNEL2 -#undef KERNEL3 -#undef KERNEL4 diff --git a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Copy/CopyHost.inl b/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Copy/CopyHost.inl deleted file mode 100644 index 2f8562a29..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Copy/CopyHost.inl +++ /dev/null @@ -1,85 +0,0 @@ -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Takahiro Harada - - -template<> -class Copy : public CopyBase -{ - public: - typedef Launcher::BufferInfo BufferInfo; - - struct Data - { - }; - - static - Data* allocate(const Device* deviceData) - { - ADLASSERT( TYPE_HOST == deviceData->m_type ); - return 0; - } - - static - void deallocate(Data* data) - { - return; - } - - static - void execute( Data* data, Buffer& dst, Buffer& src, int n, Option option = PER_WI_1) - { - ADLASSERT( TYPE_HOST == dst.getType() ); - ADLASSERT( TYPE_HOST == src.getType() ); - - HostBuffer& dstH = (HostBuffer&)dst; - HostBuffer& srcH = (HostBuffer&)src; - - for(int i=0; i& dst, Buffer& src, int n) - { - ADLASSERT( TYPE_HOST == dst.getType() ); - ADLASSERT( TYPE_HOST == src.getType() ); - - HostBuffer& dstH = (HostBuffer&)dst; - HostBuffer& srcH = (HostBuffer&)src; - - for(int i=0; i& dst, Buffer& src, int n) - { - ADLASSERT( TYPE_HOST == dst.getType() ); - ADLASSERT( TYPE_HOST == src.getType() ); - - HostBuffer& dstH = (HostBuffer&)dst; - HostBuffer& srcH = (HostBuffer&)src; - - for(int i=0; i dst : register( u0 ); -StructuredBuffer src : register( t0 ); - -[numthreads(WG_SIZE, 1, 1)] -void Copy1F4Kernel( DEFAULT_ARGS ) -{ - int gIdx = GET_GLOBAL_IDX; - - if( gIdx < m_n ) - { - float4 a0 = src[gIdx]; - - dst[ gIdx ] = a0; - } -} - -[numthreads(WG_SIZE, 1, 1)] -void Copy2F4Kernel( DEFAULT_ARGS ) -{ - int gIdx = GET_GLOBAL_IDX; - - if( 2*gIdx <= m_n ) - { - float4 a0 = src[gIdx*2+0]; - float4 a1 = src[gIdx*2+1]; - - dst[ gIdx*2+0 ] = a0; - dst[ gIdx*2+1 ] = a1; - } -} - -[numthreads(WG_SIZE, 1, 1)] -void Copy4F4Kernel( DEFAULT_ARGS ) -{ - int gIdx = GET_GLOBAL_IDX; - - if( 4*gIdx <= m_n ) - { - int idx0 = gIdx*4+0; - int idx1 = gIdx*4+1; - int idx2 = gIdx*4+2; - int idx3 = gIdx*4+3; - - float4 a0 = src[idx0]; - float4 a1 = src[idx1]; - float4 a2 = src[idx2]; - float4 a3 = src[idx3]; - - dst[ idx0 ] = a0; - dst[ idx1 ] = a1; - dst[ idx2 ] = a2; - dst[ idx3 ] = a3; - } -} - -RWStructuredBuffer dstF1 : register( u0 ); -StructuredBuffer srcF1 : register( t0 ); - -[numthreads(WG_SIZE, 1, 1)] -void CopyF1Kernel( DEFAULT_ARGS ) -{ - int gIdx = GET_GLOBAL_IDX; - - if( gIdx < m_n ) - { - float a0 = srcF1[gIdx]; - - dstF1[ gIdx ] = a0; - } - -} - -RWStructuredBuffer dstF2 : register( u0 ); -StructuredBuffer srcF2 : register( t0 ); - -[numthreads(WG_SIZE, 1, 1)] -void CopyF2Kernel( DEFAULT_ARGS ) -{ - int gIdx = GET_GLOBAL_IDX; - - if( gIdx < m_n ) - { - float2 a0 = srcF2[gIdx]; - - dstF2[ gIdx ] = a0; - } -} diff --git a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Copy/CopyKernelsCL.h b/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Copy/CopyKernelsCL.h deleted file mode 100644 index 3b6789201..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Copy/CopyKernelsCL.h +++ /dev/null @@ -1,119 +0,0 @@ -static const char* copyKernelsCL= \ -"/*\n" -" 2011 Takahiro Harada\n" -"*/\n" -"\n" -"#pragma OPENCL EXTENSION cl_amd_printf : enable\n" -"#pragma OPENCL EXTENSION cl_khr_local_int32_base_atomics : enable\n" -"\n" -"typedef unsigned int u32;\n" -"#define GET_GROUP_IDX get_group_id(0)\n" -"#define GET_LOCAL_IDX get_local_id(0)\n" -"#define GET_GLOBAL_IDX get_global_id(0)\n" -"#define GET_GROUP_SIZE get_local_size(0)\n" -"#define GROUP_LDS_BARRIER barrier(CLK_LOCAL_MEM_FENCE)\n" -"#define GROUP_MEM_FENCE mem_fence(CLK_LOCAL_MEM_FENCE)\n" -"#define AtomInc(x) atom_inc(&(x))\n" -"#define AtomInc1(x, out) out = atom_inc(&(x))\n" -"\n" -"#define make_uint4 (uint4)\n" -"#define make_uint2 (uint2)\n" -"#define make_int2 (int2)\n" -"\n" -"typedef struct\n" -"{\n" -" int m_n;\n" -" int m_padding[3];\n" -"} ConstBuffer;\n" -"\n" -"\n" -"\n" -"__kernel\n" -"__attribute__((reqd_work_group_size(64,1,1)))\n" -"void Copy1F4Kernel(__global float4* dst, __global float4* src, \n" -" ConstBuffer cb)\n" -"{\n" -" int gIdx = GET_GLOBAL_IDX;\n" -"\n" -" if( gIdx < cb.m_n )\n" -" {\n" -" float4 a0 = src[gIdx];\n" -"\n" -" dst[ gIdx ] = a0;\n" -" }\n" -"}\n" -"\n" -"__kernel\n" -"__attribute__((reqd_work_group_size(64,1,1)))\n" -"void Copy2F4Kernel(__global float4* dst, __global float4* src, \n" -" ConstBuffer cb)\n" -"{\n" -" int gIdx = GET_GLOBAL_IDX;\n" -"\n" -" if( 2*gIdx <= cb.m_n )\n" -" {\n" -" float4 a0 = src[gIdx*2+0];\n" -" float4 a1 = src[gIdx*2+1];\n" -"\n" -" dst[ gIdx*2+0 ] = a0;\n" -" dst[ gIdx*2+1 ] = a1;\n" -" }\n" -"}\n" -"\n" -"__kernel\n" -"__attribute__((reqd_work_group_size(64,1,1)))\n" -"void Copy4F4Kernel(__global float4* dst, __global float4* src, \n" -" ConstBuffer cb)\n" -"{\n" -" int gIdx = GET_GLOBAL_IDX;\n" -"\n" -" if( 4*gIdx <= cb.m_n )\n" -" {\n" -" int idx0 = gIdx*4+0;\n" -" int idx1 = gIdx*4+1;\n" -" int idx2 = gIdx*4+2;\n" -" int idx3 = gIdx*4+3;\n" -"\n" -" float4 a0 = src[idx0];\n" -" float4 a1 = src[idx1];\n" -" float4 a2 = src[idx2];\n" -" float4 a3 = src[idx3];\n" -"\n" -" dst[ idx0 ] = a0;\n" -" dst[ idx1 ] = a1;\n" -" dst[ idx2 ] = a2;\n" -" dst[ idx3 ] = a3;\n" -" }\n" -"}\n" -"\n" -"__kernel\n" -"__attribute__((reqd_work_group_size(64,1,1)))\n" -"void CopyF1Kernel(__global float* dstF1, __global float* srcF1, \n" -" ConstBuffer cb)\n" -"{\n" -" int gIdx = GET_GLOBAL_IDX;\n" -"\n" -" if( gIdx < cb.m_n )\n" -" {\n" -" float a0 = srcF1[gIdx];\n" -"\n" -" dstF1[ gIdx ] = a0;\n" -" }\n" -"}\n" -"\n" -"__kernel\n" -"__attribute__((reqd_work_group_size(64,1,1)))\n" -"void CopyF2Kernel(__global float2* dstF2, __global float2* srcF2, \n" -" ConstBuffer cb)\n" -"{\n" -" int gIdx = GET_GLOBAL_IDX;\n" -"\n" -" if( gIdx < cb.m_n )\n" -" {\n" -" float2 a0 = srcF2[gIdx];\n" -"\n" -" dstF2[ gIdx ] = a0;\n" -" }\n" -"}\n" -"\n" -; diff --git a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Copy/CopyKernelsDX11.h b/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Copy/CopyKernelsDX11.h deleted file mode 100644 index 6abcda4a9..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Copy/CopyKernelsDX11.h +++ /dev/null @@ -1,120 +0,0 @@ -static const char* copyKernelsDX11= \ -"/*\n" -" 2011 Takahiro Harada\n" -"*/\n" -"\n" -"typedef uint u32;\n" -"\n" -"#define GET_GROUP_IDX groupIdx.x\n" -"#define GET_LOCAL_IDX localIdx.x\n" -"#define GET_GLOBAL_IDX globalIdx.x\n" -"#define GROUP_LDS_BARRIER GroupMemoryBarrierWithGroupSync()\n" -"#define GROUP_MEM_FENCE\n" -"#define DEFAULT_ARGS uint3 globalIdx : SV_DispatchThreadID, uint3 localIdx : SV_GroupThreadID, uint3 groupIdx : SV_GroupID\n" -"#define AtomInc(x) InterlockedAdd(x, 1)\n" -"#define AtomInc1(x, out) InterlockedAdd(x, 1, out)\n" -"\n" -"#define make_uint4 uint4\n" -"#define make_uint2 uint2\n" -"#define make_int2 int2\n" -"\n" -"#define WG_SIZE 64\n" -"\n" -"#define GET_GROUP_SIZE WG_SIZE\n" -"\n" -"\n" -"\n" -"cbuffer CB : register( b0 )\n" -"{\n" -" int m_n;\n" -" int m_padding[3];\n" -"};\n" -"\n" -"RWStructuredBuffer dst : register( u0 );\n" -"StructuredBuffer src : register( t0 );\n" -"\n" -"[numthreads(WG_SIZE, 1, 1)]\n" -"void Copy1F4Kernel( DEFAULT_ARGS )\n" -"{\n" -" int gIdx = GET_GLOBAL_IDX;\n" -"\n" -" if( gIdx < m_n )\n" -" {\n" -" float4 a0 = src[gIdx];\n" -"\n" -" dst[ gIdx ] = a0;\n" -" }\n" -"}\n" -"\n" -"[numthreads(WG_SIZE, 1, 1)]\n" -"void Copy2F4Kernel( DEFAULT_ARGS )\n" -"{\n" -" int gIdx = GET_GLOBAL_IDX;\n" -"\n" -" if( 2*gIdx <= m_n )\n" -" {\n" -" float4 a0 = src[gIdx*2+0];\n" -" float4 a1 = src[gIdx*2+1];\n" -"\n" -" dst[ gIdx*2+0 ] = a0;\n" -" dst[ gIdx*2+1 ] = a1;\n" -" }\n" -"}\n" -"\n" -"[numthreads(WG_SIZE, 1, 1)]\n" -"void Copy4F4Kernel( DEFAULT_ARGS )\n" -"{\n" -" int gIdx = GET_GLOBAL_IDX;\n" -"\n" -" if( 4*gIdx <= m_n )\n" -" {\n" -" int idx0 = gIdx*4+0;\n" -" int idx1 = gIdx*4+1;\n" -" int idx2 = gIdx*4+2;\n" -" int idx3 = gIdx*4+3;\n" -"\n" -" float4 a0 = src[idx0];\n" -" float4 a1 = src[idx1];\n" -" float4 a2 = src[idx2];\n" -" float4 a3 = src[idx3];\n" -"\n" -" dst[ idx0 ] = a0;\n" -" dst[ idx1 ] = a1;\n" -" dst[ idx2 ] = a2;\n" -" dst[ idx3 ] = a3;\n" -" }\n" -"}\n" -"\n" -"RWStructuredBuffer dstF1 : register( u0 );\n" -"StructuredBuffer srcF1 : register( t0 );\n" -"\n" -"[numthreads(WG_SIZE, 1, 1)]\n" -"void CopyF1Kernel( DEFAULT_ARGS )\n" -"{\n" -" int gIdx = GET_GLOBAL_IDX;\n" -"\n" -" if( gIdx < m_n )\n" -" {\n" -" float a0 = srcF1[gIdx];\n" -"\n" -" dstF1[ gIdx ] = a0;\n" -" }\n" -"\n" -"}\n" -"\n" -"RWStructuredBuffer dstF2 : register( u0 );\n" -"StructuredBuffer srcF2 : register( t0 );\n" -"\n" -"[numthreads(WG_SIZE, 1, 1)]\n" -"void CopyF2Kernel( DEFAULT_ARGS )\n" -"{\n" -" int gIdx = GET_GLOBAL_IDX;\n" -"\n" -" if( gIdx < m_n )\n" -" {\n" -" float2 a0 = srcF2[gIdx];\n" -"\n" -" dstF2[ gIdx ] = a0;\n" -" }\n" -"}\n" -; diff --git a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Fill/Fill.h b/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Fill/Fill.h deleted file mode 100644 index 35957e83d..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Fill/Fill.h +++ /dev/null @@ -1,77 +0,0 @@ -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Takahiro Harada - -#pragma once - -#include -#include - -namespace adl -{ - -class FillBase -{ - public: - enum Option - { - - }; -}; - -template -class Fill -{ - public: - typedef Launcher::BufferInfo BufferInfo; - - struct ConstData - { - int4 m_data; - int m_offset; - int m_n; - int m_padding[2]; - }; - - struct Data - { - const Device* m_device; - Kernel* m_fillIntKernel; - Kernel* m_fillInt2Kernel; - Kernel* m_fillInt4Kernel; - Buffer* m_constBuffer; - }; - - static - Data* allocate(const Device* deviceData); - - static - void deallocate(Data* data); - - static - void execute(Data* data, Buffer& src, const int& value, int n, int offset = 0); - - static - void execute(Data* data, Buffer& src, const int2& value, int n, int offset = 0); - - static - void execute(Data* data, Buffer& src, const int4& value, int n, int offset = 0); - -}; - - -#include -#include - -}; diff --git a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Fill/Fill.inl b/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Fill/Fill.inl deleted file mode 100644 index 913db9b66..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Fill/Fill.inl +++ /dev/null @@ -1,123 +0,0 @@ -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Takahiro Harada - - -//#define PATH "..\\..\\AdlPrimitives\\Fill\\FillKernels" -#define PATH "..\\..\\opencl\\primitives\\AdlPrimitives\\Fill\\FillKernels" -#define KERNEL0 "FillIntKernel" -#define KERNEL1 "FillInt2Kernel" -#define KERNEL2 "FillInt4Kernel" - -#include -#include - - -template -typename Fill::Data* Fill::allocate( const Device* device ) -{ - ADLASSERT( TYPE == device->m_type ); - - const char* src[] = -#if defined(ADL_LOAD_KERNEL_FROM_STRING) - {fillKernelsCL, fillKernelsDX11}; -#else - {0,0}; -#endif - - Data* data = new Data; - data->m_device = device; - data->m_fillIntKernel = device->getKernel( PATH, KERNEL0, 0, src[TYPE] ); - data->m_fillInt2Kernel = device->getKernel( PATH, KERNEL1, 0, src[TYPE] ); - data->m_fillInt4Kernel = device->getKernel( PATH, KERNEL2, 0, src[TYPE] ); - data->m_constBuffer = new Buffer( device, 1, BufferBase::BUFFER_CONST ); - - return data; -} - -template -void Fill::deallocate( Data* data ) -{ - delete data->m_constBuffer; - delete data; -} - -template -void Fill::execute(Data* data, Buffer& src, const int& value, int n, int offset) -{ - ADLASSERT( n>0 ); - ConstData constBuffer; - { - constBuffer.m_offset = offset; - constBuffer.m_n = n; - constBuffer.m_data = make_int4( value ); - } - - { - BufferInfo bInfo[] = { BufferInfo( &src ) }; - - Launcher launcher( data->m_device, data->m_fillIntKernel ); - launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(Launcher::BufferInfo) ); - launcher.setConst( *data->m_constBuffer, constBuffer ); - launcher.launch1D( n ); - } -} - -template -void Fill::execute(Data* data, Buffer& src, const int2& value, int n, int offset) -{ - ADLASSERT( n>0 ); - ConstData constBuffer; - { - constBuffer.m_offset = offset; - constBuffer.m_n = n; - constBuffer.m_data = make_int4( value.x, value.y, 0, 0 ); - } - - { - BufferInfo bInfo[] = { BufferInfo( &src ) }; - - Launcher launcher( data->m_device, data->m_fillInt2Kernel ); - launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(Launcher::BufferInfo) ); - launcher.setConst( *data->m_constBuffer, constBuffer ); - launcher.launch1D( n ); - } -} - -template -void Fill::execute(Data* data, Buffer& src, const int4& value, int n, int offset) -{ - ADLASSERT( n>0 ); - ConstData constBuffer; - { - constBuffer.m_offset = offset; - constBuffer.m_n = n; - constBuffer.m_data = value; - } - - { - BufferInfo bInfo[] = { BufferInfo( &src ) }; - - Launcher launcher( data->m_device, data->m_fillInt4Kernel ); - launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(Launcher::BufferInfo) ); - launcher.setConst( *data->m_constBuffer, constBuffer ); - launcher.launch1D( n ); - } -} - -#undef PATH -#undef KERNEL0 -#undef KERNEL1 -#undef KERNEL2 - diff --git a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Fill/FillHost.inl b/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Fill/FillHost.inl deleted file mode 100644 index c6205fa98..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Fill/FillHost.inl +++ /dev/null @@ -1,99 +0,0 @@ -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Takahiro Harada - -template<> -class Fill -{ - public: - struct Data - { - }; - - static - Data* allocate(const Device* deviceData) - { - return 0; - } - - static - void deallocate(Data* data) - { - - } - - template - static - void executeImpl(Data* data, Buffer& src, const T& value, int n, int offset = 0) - { - ADLASSERT( src.getType() == TYPE_HOST ); - ADLASSERT( src.m_size >= offset+n ); - HostBuffer& hSrc = (HostBuffer&)src; - - for(int idx=offset; idx& src, const int& value, int n, int offset = 0) - { - executeImpl( data, src, value, n, offset ); - } - - static - void execute(Data* data, Buffer& src, const int2& value, int n, int offset = 0) - { - executeImpl( data, src, value, n, offset ); - } - - static - void execute(Data* data, Buffer& src, const int4& value, int n, int offset = 0) - { - executeImpl( data, src, value, n, offset ); - } - -/* - static - void execute(Data* data, Buffer& src, int value, int n, int offset = 0) - { - ADLASSERT( src.getType() == TYPE_HOST ); - ADLASSERT( src.m_size <= offset+n ); - HostBuffer& hSrc = (HostBuffer&)src; - - for(int idx=offset; idx& src, const int2& value, int n, int offset = 0) - { - ADLASSERT( src.getType() == TYPE_HOST ); - ADLASSERT( src.m_size <= offset+n ); - - } - - static - void execute(Data* data, Buffer& src, const int4& value, int n, int offset = 0) - { - ADLASSERT( src.getType() == TYPE_HOST ); - ADLASSERT( src.m_size <= offset+n ); - - } -*/ -}; - diff --git a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Fill/FillKernels.cl b/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Fill/FillKernels.cl deleted file mode 100644 index 11a31b0c5..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Fill/FillKernels.cl +++ /dev/null @@ -1,81 +0,0 @@ -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Takahiro Harada - - -#pragma OPENCL EXTENSION cl_amd_printf : enable -#pragma OPENCL EXTENSION cl_khr_local_int32_base_atomics : enable - -typedef unsigned int u32; -#define GET_GROUP_IDX get_group_id(0) -#define GET_LOCAL_IDX get_local_id(0) -#define GET_GLOBAL_IDX get_global_id(0) -#define GET_GROUP_SIZE get_local_size(0) -#define GROUP_LDS_BARRIER barrier(CLK_LOCAL_MEM_FENCE) -#define GROUP_MEM_FENCE mem_fence(CLK_LOCAL_MEM_FENCE) -#define AtomInc(x) atom_inc(&(x)) -#define AtomInc1(x, out) out = atom_inc(&(x)) - -#define make_uint4 (uint4) -#define make_uint2 (uint2) -#define make_int2 (int2) - -typedef struct -{ - int4 m_data; - int m_offset; - int m_n; - int m_padding[2]; -} ConstBuffer; - - -__kernel -__attribute__((reqd_work_group_size(64,1,1))) -void FillIntKernel(__global int* dstInt, - ConstBuffer cb) -{ - int gIdx = GET_GLOBAL_IDX; - - if( gIdx < cb.m_n ) - { - dstInt[ cb.m_offset+gIdx ] = cb.m_data.x; - } -} - -__kernel -__attribute__((reqd_work_group_size(64,1,1))) -void FillInt2Kernel(__global int2* dstInt2, - ConstBuffer cb) -{ - int gIdx = GET_GLOBAL_IDX; - - if( gIdx < cb.m_n ) - { - dstInt2[ cb.m_offset+gIdx ] = make_int2( cb.m_data.x, cb.m_data.y ); - } -} - -__kernel -__attribute__((reqd_work_group_size(64,1,1))) -void FillInt4Kernel(__global int4* dstInt4, - ConstBuffer cb) -{ - int gIdx = GET_GLOBAL_IDX; - - if( gIdx < cb.m_n ) - { - dstInt4[ cb.m_offset+gIdx ] = cb.m_data; - } -} - diff --git a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Fill/FillKernels.hlsl b/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Fill/FillKernels.hlsl deleted file mode 100644 index ead907d5e..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Fill/FillKernels.hlsl +++ /dev/null @@ -1,79 +0,0 @@ -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Takahiro Harada - - -typedef uint u32; - -#define GET_GROUP_IDX groupIdx.x -#define GET_LOCAL_IDX localIdx.x -#define GET_GLOBAL_IDX globalIdx.x -#define GROUP_LDS_BARRIER GroupMemoryBarrierWithGroupSync() -#define GROUP_MEM_FENCE -#define DEFAULT_ARGS uint3 globalIdx : SV_DispatchThreadID, uint3 localIdx : SV_GroupThreadID, uint3 groupIdx : SV_GroupID -#define AtomInc(x) InterlockedAdd(x, 1) -#define AtomInc1(x, out) InterlockedAdd(x, 1, out) - -#define make_uint4 uint4 -#define make_uint2 uint2 -#define make_int2 int2 - - -cbuffer CB : register( b0 ) -{ - int4 m_data; - int m_offset; - int m_n; - int m_padding[2]; -}; - - -RWStructuredBuffer dstInt : register( u0 ); - -[numthreads(64, 1, 1)] -void FillIntKernel( DEFAULT_ARGS ) -{ - int gIdx = GET_GLOBAL_IDX; - - if( gIdx < m_n ) - { - dstInt[ m_offset+gIdx ] = m_data.x; - } -} - -RWStructuredBuffer dstInt2 : register( u0 ); - -[numthreads(64, 1, 1)] -void FillInt2Kernel( DEFAULT_ARGS ) -{ - int gIdx = GET_GLOBAL_IDX; - - if( gIdx < m_n ) - { - dstInt2[ m_offset+gIdx ] = make_int2( m_data.x, m_data.y ); - } -} - -RWStructuredBuffer dstInt4 : register( u0 ); - -[numthreads(64, 1, 1)] -void FillInt4Kernel( DEFAULT_ARGS ) -{ - int gIdx = GET_GLOBAL_IDX; - - if( gIdx < m_n ) - { - dstInt4[ m_offset+gIdx ] = m_data; - } -} diff --git a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Fill/FillKernelsCL.h b/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Fill/FillKernelsCL.h deleted file mode 100644 index e2899ffbc..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Fill/FillKernelsCL.h +++ /dev/null @@ -1,71 +0,0 @@ -static const char* fillKernelsCL= \ -"/*\n" -" 2011 Takahiro Harada\n" -"*/\n" -"\n" -"#pragma OPENCL EXTENSION cl_amd_printf : enable\n" -"#pragma OPENCL EXTENSION cl_khr_local_int32_base_atomics : enable\n" -"\n" -"typedef unsigned int u32;\n" -"#define GET_GROUP_IDX get_group_id(0)\n" -"#define GET_LOCAL_IDX get_local_id(0)\n" -"#define GET_GLOBAL_IDX get_global_id(0)\n" -"#define GET_GROUP_SIZE get_local_size(0)\n" -"#define GROUP_LDS_BARRIER barrier(CLK_LOCAL_MEM_FENCE)\n" -"#define GROUP_MEM_FENCE mem_fence(CLK_LOCAL_MEM_FENCE)\n" -"#define AtomInc(x) atom_inc(&(x))\n" -"#define AtomInc1(x, out) out = atom_inc(&(x))\n" -"\n" -"#define make_uint4 (uint4)\n" -"#define make_uint2 (uint2)\n" -"#define make_int2 (int2)\n" -"\n" -"typedef struct\n" -"{\n" -" int4 m_data;\n" -" int m_offset;\n" -" int m_n;\n" -" int m_padding[2];\n" -"} ConstBuffer;\n" -"\n" -"\n" -"__kernel\n" -"__attribute__((reqd_work_group_size(64,1,1)))\n" -"void FillIntKernel(__global int* dstInt, \n" -" ConstBuffer cb)\n" -"{\n" -" int gIdx = GET_GLOBAL_IDX;\n" -"\n" -" if( gIdx < cb.m_n )\n" -" {\n" -" dstInt[ cb.m_offset+gIdx ] = cb.m_data.x;\n" -" }\n" -"}\n" -"\n" -"__kernel\n" -"__attribute__((reqd_work_group_size(64,1,1)))\n" -"void FillInt2Kernel(__global int2* dstInt2, \n" -" ConstBuffer cb)\n" -"{\n" -" int gIdx = GET_GLOBAL_IDX;\n" -"\n" -" if( gIdx < cb.m_n )\n" -" {\n" -" dstInt2[ cb.m_offset+gIdx ] = make_int2( cb.m_data.x, cb.m_data.y );\n" -" }\n" -"}\n" -"\n" -"__kernel\n" -"__attribute__((reqd_work_group_size(64,1,1)))\n" -"void FillInt4Kernel(__global int4* dstInt4, \n" -" ConstBuffer cb)\n" -"{\n" -" int gIdx = GET_GLOBAL_IDX;\n" -"\n" -" if( gIdx < cb.m_n )\n" -" {\n" -" dstInt4[ cb.m_offset+gIdx ] = cb.m_data;\n" -" }\n" -"}\n" -"\n" -; diff --git a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Fill/FillKernelsDX11.h b/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Fill/FillKernelsDX11.h deleted file mode 100644 index 1cdc6ab61..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Fill/FillKernelsDX11.h +++ /dev/null @@ -1,69 +0,0 @@ -static const char* fillKernelsDX11= \ -"/*\n" -" 2011 Takahiro Harada\n" -"*/\n" -"\n" -"typedef uint u32;\n" -"\n" -"#define GET_GROUP_IDX groupIdx.x\n" -"#define GET_LOCAL_IDX localIdx.x\n" -"#define GET_GLOBAL_IDX globalIdx.x\n" -"#define GROUP_LDS_BARRIER GroupMemoryBarrierWithGroupSync()\n" -"#define GROUP_MEM_FENCE\n" -"#define DEFAULT_ARGS uint3 globalIdx : SV_DispatchThreadID, uint3 localIdx : SV_GroupThreadID, uint3 groupIdx : SV_GroupID\n" -"#define AtomInc(x) InterlockedAdd(x, 1)\n" -"#define AtomInc1(x, out) InterlockedAdd(x, 1, out)\n" -"\n" -"#define make_uint4 uint4\n" -"#define make_uint2 uint2\n" -"#define make_int2 int2\n" -"\n" -"\n" -"cbuffer CB : register( b0 )\n" -"{\n" -" int4 m_data;\n" -" int m_offset;\n" -" int m_n;\n" -" int m_padding[2];\n" -"};\n" -"\n" -"\n" -"RWStructuredBuffer dstInt : register( u0 );\n" -"\n" -"[numthreads(64, 1, 1)]\n" -"void FillIntKernel( DEFAULT_ARGS )\n" -"{\n" -" int gIdx = GET_GLOBAL_IDX;\n" -"\n" -" if( gIdx < m_n )\n" -" {\n" -" dstInt[ m_offset+gIdx ] = m_data.x;\n" -" }\n" -"}\n" -"\n" -"RWStructuredBuffer dstInt2 : register( u0 );\n" -"\n" -"[numthreads(64, 1, 1)]\n" -"void FillInt2Kernel( DEFAULT_ARGS )\n" -"{\n" -" int gIdx = GET_GLOBAL_IDX;\n" -"\n" -" if( gIdx < m_n )\n" -" {\n" -" dstInt2[ m_offset+gIdx ] = make_int2( m_data.x, m_data.y );\n" -" }\n" -"}\n" -"\n" -"RWStructuredBuffer dstInt4 : register( u0 );\n" -"\n" -"[numthreads(64, 1, 1)]\n" -"void FillInt4Kernel( DEFAULT_ARGS )\n" -"{\n" -" int gIdx = GET_GLOBAL_IDX;\n" -"\n" -" if( gIdx < m_n )\n" -" {\n" -" dstInt4[ m_offset+gIdx ] = m_data;\n" -" }\n" -"}\n" -; diff --git a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Math/Array.h b/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Math/Array.h deleted file mode 100644 index 5a63eee38..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Math/Array.h +++ /dev/null @@ -1,231 +0,0 @@ -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Takahiro Harada - -#ifndef ARRAY_H -#define ARRAY_H - -#include -#include -#include -#include - -namespace adl -{ - -template -class Array -{ - public: - __inline - Array(); - __inline - Array(int size); - __inline - ~Array(); - __inline - T& operator[] (int idx); - __inline - const T& operator[] (int idx) const; - __inline - void pushBack(const T& elem); - __inline - void popBack(); - __inline - void clear(); - __inline - void setSize(int size); - __inline - int getSize() const; - __inline - T* begin(); - __inline - const T* begin() const; - __inline - T* end(); - __inline - const T* end() const; - __inline - int indexOf(const T& data) const; - __inline - void removeAt(int idx); - __inline - T& expandOne(); - - private: - Array(const Array& a){} - - private: - enum - { - DEFAULT_SIZE = 128, - INCREASE_SIZE = 128, - }; - - T* m_data; - int m_size; - int m_capacity; -}; - -template -Array::Array() -{ - m_size = 0; - m_capacity = DEFAULT_SIZE; -// m_data = new T[ m_capacity ]; - m_data = (T*)_aligned_malloc(sizeof(T)*m_capacity, 16); - for(int i=0; i -Array::Array(int size) -{ - m_size = size; - m_capacity = size; -// m_data = new T[ m_capacity ]; - m_data = (T*)_aligned_malloc(sizeof(T)*m_capacity, 16); - for(int i=0; i -Array::~Array() -{ - if( m_data ) - { -// delete [] m_data; - _aligned_free( m_data ); - m_data = NULL; - } -} - -template -T& Array::operator[](int idx) -{ - ADLASSERT(idx -const T& Array::operator[](int idx) const -{ - ADLASSERT(idx -void Array::pushBack(const T& elem) -{ - if( m_size == m_capacity ) - { - int oldCap = m_capacity; - m_capacity += INCREASE_SIZE; -// T* s = new T[m_capacity]; - T* s = (T*)_aligned_malloc(sizeof(T)*m_capacity, 16); - memcpy( s, m_data, sizeof(T)*oldCap ); -// delete [] m_data; - _aligned_free( m_data ); - m_data = s; - } - m_data[ m_size++ ] = elem; -} - -template -void Array::popBack() -{ - ADLASSERT( m_size>0 ); - m_size--; -} - -template -void Array::clear() -{ - m_size = 0; -} - -template -void Array::setSize(int size) -{ - if( size > m_capacity ) - { - int oldCap = m_capacity; - m_capacity = size; -// T* s = new T[m_capacity]; - T* s = (T*)_aligned_malloc(sizeof(T)*m_capacity, 16); - for(int i=0; i -int Array::getSize() const -{ - return m_size; -} - -template -const T* Array::begin() const -{ - return m_data; -} - -template -T* Array::begin() -{ - return m_data; -} - -template -T* Array::end() -{ - return m_data+m_size; -} - -template -const T* Array::end() const -{ - return m_data+m_size; -} - -template -int Array::indexOf(const T& data) const -{ - for(int i=0; i -void Array::removeAt(int idx) -{ - ADLASSERT(idx -T& Array::expandOne() -{ - setSize( m_size+1 ); - return m_data[ m_size-1 ]; -} - -}; - -#endif - diff --git a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Math/Float2.inl b/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Math/Float2.inl deleted file mode 100644 index 4b2a9e7f7..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Math/Float2.inl +++ /dev/null @@ -1,173 +0,0 @@ -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Takahiro Harada - - -__inline -float2 make_float2(float x, float y) -{ - float2 v; - v.s[0] = x; v.s[1] = y; - return v; -} - -__inline -float2 make_float2(float x) -{ - return make_float2(x,x); -} - -__inline -float2 make_float2(const int2& x) -{ - return make_float2((float)x.s[0], (float)x.s[1]); -} - - - - -__inline -float2 operator-(const float2& a) -{ - return make_float2(-a.x, -a.y); -} - -__inline -float2 operator*(const float2& a, const float2& b) -{ - float2 out; - out.s[0] = a.s[0]*b.s[0]; - out.s[1] = a.s[1]*b.s[1]; - return out; -} - -__inline -float2 operator*(float a, const float2& b) -{ - return make_float2(a*b.s[0], a*b.s[1]); -} - -__inline -float2 operator*(const float2& b, float a) -{ - return make_float2(a*b.s[0], a*b.s[1]); -} - -__inline -void operator*=(float2& a, const float2& b) -{ - a.s[0]*=b.s[0]; - a.s[1]*=b.s[1]; -} - -__inline -void operator*=(float2& a, float b) -{ - a.s[0]*=b; - a.s[1]*=b; -} - -__inline -float2 operator/(const float2& a, const float2& b) -{ - float2 out; - out.s[0] = a.s[0]/b.s[0]; - out.s[1] = a.s[1]/b.s[1]; - return out; -} - -__inline -float2 operator/(const float2& b, float a) -{ - return make_float2(b.s[0]/a, b.s[1]/a); -} - -__inline -void operator/=(float2& a, const float2& b) -{ - a.s[0]/=b.s[0]; - a.s[1]/=b.s[1]; -} - -__inline -void operator/=(float2& a, float b) -{ - a.s[0]/=b; - a.s[1]/=b; -} -// - -__inline -float2 operator+(const float2& a, const float2& b) -{ - float2 out; - out.s[0] = a.s[0]+b.s[0]; - out.s[1] = a.s[1]+b.s[1]; - return out; -} - -__inline -float2 operator+(const float2& a, float b) -{ - float2 out; - out.s[0] = a.s[0]+b; - out.s[1] = a.s[1]+b; - return out; -} - -__inline -float2 operator-(const float2& a, const float2& b) -{ - float2 out; - out.s[0] = a.s[0]-b.s[0]; - out.s[1] = a.s[1]-b.s[1]; - return out; -} - -__inline -float2 operator-(const float2& a, float b) -{ - float2 out; - out.s[0] = a.s[0]-b; - out.s[1] = a.s[1]-b; - return out; -} - -__inline -void operator+=(float2& a, const float2& b) -{ - a.s[0]+=b.s[0]; - a.s[1]+=b.s[1]; -} - -__inline -void operator+=(float2& a, float b) -{ - a.s[0]+=b; - a.s[1]+=b; -} - -__inline -void operator-=(float2& a, const float2& b) -{ - a.s[0]-=b.s[0]; - a.s[1]-=b.s[1]; -} - -__inline -void operator-=(float2& a, float b) -{ - a.s[0]-=b; - a.s[1]-=b; -} diff --git a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Math/Float4.inl b/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Math/Float4.inl deleted file mode 100644 index 458a91f65..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Math/Float4.inl +++ /dev/null @@ -1,375 +0,0 @@ -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Takahiro Harada - - -//#define CHECK_ALIGNMENT(a) ADLASSERT((u32(&(a)) & 0xf) == 0); -#define CHECK_ALIGNMENT(a) a; - - -__inline -float4 make_float4(float x, float y, float z, float w = 0.f) -{ - float4 v; - v.x = x; v.y = y; v.z = z; v.w = w; - return v; -} - -__inline -float4 make_float4(float x) -{ - return make_float4(x,x,x,x); -} - -__inline -float4 make_float4(const int4& x) -{ - return make_float4((float)x.s[0], (float)x.s[1], (float)x.s[2], (float)x.s[3]); -} - -__inline -int4 make_int4(int x, int y, int z, int w = 0) -{ - int4 v; - v.s[0] = x; v.s[1] = y; v.s[2] = z; v.s[3] = w; - return v; -} - -__inline -int4 make_int4(int x) -{ - return make_int4(x,x,x,x); -} - -__inline -int4 make_int4(const float4& x) -{ - return make_int4((int)x.x, (int)x.y, (int)x.z, (int)x.w); -} - -__inline -int2 make_int2(int a, int b) -{ - int2 ans; ans.x = a; ans.y = b; - return ans; -} - -__inline -bool operator ==(const int2& a, const int2& b) -{ - return a.x==b.x && a.y==b.y; -} - -__inline -bool operator ==(const int4& a, const int4& b) -{ - return a.x==b.x && a.y==b.y && a.z==b.z && a.w==b.w; -} - -__inline -bool operator ==(const float2& a, const float2& b) -{ - return a.x==b.x && a.y==b.y; -} - -__inline -bool operator ==(const float4& a, const float4& b) -{ - return a.x==b.x && a.y==b.y && a.z==b.z && a.w==b.w; -} - -__inline -float4 operator-(const float4& a) -{ - return make_float4(-a.x, -a.y, -a.z, -a.w); -} - -__inline -float4 operator*(const float4& a, const float4& b) -{ -// ADLASSERT((u32(&a) & 0xf) == 0); - - float4 out; - out.s[0] = a.s[0]*b.s[0]; - out.s[1] = a.s[1]*b.s[1]; - out.s[2] = a.s[2]*b.s[2]; - out.s[3] = a.s[3]*b.s[3]; - return out; -} - -__inline -float4 operator*(float a, const float4& b) -{ - return make_float4(a*b.s[0], a*b.s[1], a*b.s[2], a*b.s[3]); -} - -__inline -float4 operator*(const float4& b, float a) -{ - CHECK_ALIGNMENT(b); - - return make_float4(a*b.s[0], a*b.s[1], a*b.s[2], a*b.s[3]); -} - -__inline -void operator*=(float4& a, const float4& b) -{ - CHECK_ALIGNMENT(a); - - a.s[0]*=b.s[0]; - a.s[1]*=b.s[1]; - a.s[2]*=b.s[2]; - a.s[3]*=b.s[3]; -} - -__inline -void operator*=(float4& a, float b) -{ - CHECK_ALIGNMENT(a); - - a.s[0]*=b; - a.s[1]*=b; - a.s[2]*=b; - a.s[3]*=b; -} -/* -__inline -bool operator ==(const float4& a, const float4& b) -{ - - -} -*/ -// -__inline -float4 operator/(const float4& a, const float4& b) -{ - CHECK_ALIGNMENT(a); - - float4 out; - out.s[0] = a.s[0]/b.s[0]; - out.s[1] = a.s[1]/b.s[1]; - out.s[2] = a.s[2]/b.s[2]; - out.s[3] = a.s[3]/b.s[3]; - return out; -} - -__inline -float4 operator/(const float4& b, float a) -{ - CHECK_ALIGNMENT(b); - - return make_float4(b.s[0]/a, b.s[1]/a, b.s[2]/a, b.s[3]/a); -} - -__inline -void operator/=(float4& a, const float4& b) -{ - a.s[0]/=b.s[0]; - a.s[1]/=b.s[1]; - a.s[2]/=b.s[2]; - a.s[3]/=b.s[3]; -} - -__inline -void operator/=(float4& a, float b) -{ - ADLASSERT((u32(&a) & 0xf) == 0); - - a.s[0]/=b; - a.s[1]/=b; - a.s[2]/=b; - a.s[3]/=b; -} -// - -__inline -float4 operator+(const float4& a, const float4& b) -{ - CHECK_ALIGNMENT(a); - - float4 out; - out.s[0] = a.s[0]+b.s[0]; - out.s[1] = a.s[1]+b.s[1]; - out.s[2] = a.s[2]+b.s[2]; - out.s[3] = a.s[3]+b.s[3]; - return out; -} - -__inline -float4 operator+(const float4& a, float b) -{ - CHECK_ALIGNMENT(a); - - float4 out; - out.s[0] = a.s[0]+b; - out.s[1] = a.s[1]+b; - out.s[2] = a.s[2]+b; - out.s[3] = a.s[3]+b; - return out; -} - -__inline -float4 operator-(const float4& a, const float4& b) -{ - CHECK_ALIGNMENT(a); - - float4 out; - out.s[0] = a.s[0]-b.s[0]; - out.s[1] = a.s[1]-b.s[1]; - out.s[2] = a.s[2]-b.s[2]; - out.s[3] = a.s[3]-b.s[3]; - return out; -} - -__inline -float4 operator-(const float4& a, float b) -{ - CHECK_ALIGNMENT(a); - - float4 out; - out.s[0] = a.s[0]-b; - out.s[1] = a.s[1]-b; - out.s[2] = a.s[2]-b; - out.s[3] = a.s[3]-b; - return out; -} - -__inline -void operator+=(float4& a, const float4& b) -{ - CHECK_ALIGNMENT(a); - - a.s[0]+=b.s[0]; - a.s[1]+=b.s[1]; - a.s[2]+=b.s[2]; - a.s[3]+=b.s[3]; -} - -__inline -void operator+=(float4& a, float b) -{ - CHECK_ALIGNMENT(a); - - a.s[0]+=b; - a.s[1]+=b; - a.s[2]+=b; - a.s[3]+=b; -} - -__inline -void operator-=(float4& a, const float4& b) -{ - CHECK_ALIGNMENT(a); - - a.s[0]-=b.s[0]; - a.s[1]-=b.s[1]; - a.s[2]-=b.s[2]; - a.s[3]-=b.s[3]; -} - -__inline -void operator-=(float4& a, float b) -{ - CHECK_ALIGNMENT(a); - - a.s[0]-=b; - a.s[1]-=b; - a.s[2]-=b; - a.s[3]-=b; -} - - - - - -__inline -float4 cross3(const float4& a, const float4& b) -{ - return make_float4(a.s[1]*b.s[2]-a.s[2]*b.s[1], - a.s[2]*b.s[0]-a.s[0]*b.s[2], - a.s[0]*b.s[1]-a.s[1]*b.s[0], - 0); -} - -__inline -float dot3F4(const float4& a, const float4& b) -{ - return a.x*b.x+a.y*b.y+a.z*b.z; -} - -__inline -float length3(const float4& a) -{ - return sqrtf(dot3F4(a,a)); -} - -__inline -float dot4(const float4& a, const float4& b) -{ - return a.x*b.x+a.y*b.y+a.z*b.z+a.w*b.w; -} - -// for height -__inline -float dot3w1(const float4& point, const float4& eqn) -{ - return point.x*eqn.x+point.y*eqn.y+point.z*eqn.z+eqn.w; -} - -__inline -float4 normalize3(const float4& a) -{ - float length = sqrtf(dot3F4(a, a)); - return 1.f/length * a; -} - -__inline -float4 normalize4(const float4& a) -{ - float length = sqrtf(dot4(a, a)); - return 1.f/length * a; -} - -__inline -float4 createEquation(const float4& a, const float4& b, const float4& c) -{ - float4 eqn; - float4 ab = b-a; - float4 ac = c-a; - eqn = normalize3( cross3(ab, ac) ); - eqn.w = -dot3F4(eqn,a); - return eqn; -} - -__inline -float intersectPlaneLine( const float4& planeEqn, const float4& vec, const float4& orig ) -{ - return (-planeEqn.w - dot3F4(planeEqn, orig))/dot3F4(planeEqn, vec); -} - -template<> -__inline -float4 max2(const float4& a, const float4& b) -{ - return make_float4( max2(a.x,b.x), max2(a.y,b.y), max2(a.z,b.z), max2(a.w,b.w) ); -} - -template<> -__inline -float4 min2(const float4& a, const float4& b) -{ - return make_float4( min2(a.x,b.x), min2(a.y,b.y), min2(a.z,b.z), min2(a.w,b.w) ); -} - diff --git a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Math/Math.h b/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Math/Math.h deleted file mode 100644 index 0126e7289..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Math/Math.h +++ /dev/null @@ -1,224 +0,0 @@ -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Takahiro Harada - - -#ifndef CL_MATH_H -#define CL_MATH_H - -#include -#include -#include -#include - - -#include - -#include -#define pxSort std::sort - -#define PI 3.14159265358979323846f -#define NEXTMULTIPLEOF(num, alignment) (((num)/(alignment) + (((num)%(alignment)==0)?0:1))*(alignment)) - - -#define _MEM_CLASSALIGN16 __declspec(align(16)) -#define _MEM_ALIGNED_ALLOCATOR16 void* operator new(size_t size) { return _aligned_malloc( size, 16 ); } \ - void operator delete(void *p) { _aligned_free( p ); } \ - void* operator new[](size_t size) { return _aligned_malloc( size, 16 ); } \ - void operator delete[](void *p) { _aligned_free( p ); } \ - void* operator new(size_t size, void* p) { return p; } \ - void operator delete(void *p, void* pp) {} - -namespace adl -{ - -template -T nextPowerOf2(T n) -{ - n -= 1; - for(int i=0; i>i); - return n+1; -} - -typedef unsigned int u32; -typedef unsigned short u16; -typedef unsigned char u8; - -_MEM_CLASSALIGN16 -struct float4 -{ - _MEM_ALIGNED_ALLOCATOR16; - union - { - struct - { - float x,y,z,w; - }; - struct - { - float s[4]; - }; - __m128 m_quad; - }; -}; - -_MEM_CLASSALIGN16 -struct int4 -{ - _MEM_ALIGNED_ALLOCATOR16; - union - { - struct - { - int x,y,z,w; - }; - struct - { - int s[4]; - }; - }; -}; - -_MEM_CLASSALIGN16 -struct uint4 -{ - _MEM_ALIGNED_ALLOCATOR16; - union - { - struct - { - u32 x,y,z,w; - }; - struct - { - u32 s[4]; - }; - }; -}; - -struct int2 -{ - union - { - struct - { - int x,y; - }; - struct - { - int s[2]; - }; - }; -}; - -struct float2 -{ - union - { - struct - { - float x,y; - }; - struct - { - float s[2]; - }; - }; -}; - -template -__inline -T max2(const T& a, const T& b) -{ - return (a>b)? a:b; -} - -template -__inline -T min2(const T& a, const T& b) -{ - return (a -#include - - -template -void swap2(T& a, T& b) -{ - T tmp = a; - a = b; - b = tmp; -} - - -__inline -void seedRandom(int seed) -{ - srand( seed ); -} - -template -__inline -T getRandom(const T& minV, const T& maxV) -{ - float r = (rand()%10000)/10000.f; - T range = maxV - minV; - return (T)(minV + r*range); -} - -template<> -__inline -float4 getRandom(const float4& minV, const float4& maxV) -{ - float4 r = make_float4( (rand()%10000)/10000.f, (rand()%10000)/10000.f, (rand()%10000)/10000.f, (rand()%10000)/10000.f ); - float4 range = maxV - minV; - return (minV + r*range); -} - - - -template -T* addByteOffset(void* baseAddr, u32 offset) -{ - return (T*)(((u32)baseAddr)+offset); -} - - -struct Pair32 -{ - Pair32(){} - Pair32(u32 a, u32 b) : m_a(a), m_b(b){} - - u32 m_a; - u32 m_b; -}; - -struct PtrPair -{ - PtrPair(){} - PtrPair(void* a, void* b) : m_a(a), m_b(b){} - template - PtrPair(T* a, T* b) : m_a((void*)a), m_b((void*)b){} - - void* m_a; - void* m_b; -}; - -}; - -#endif diff --git a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Math/MathCL.h b/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Math/MathCL.h deleted file mode 100644 index 6e36881ef..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Math/MathCL.h +++ /dev/null @@ -1,357 +0,0 @@ - -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Takahiro Harada - - -#pragma OPENCL EXTENSION cl_amd_printf : enable -#pragma OPENCL EXTENSION cl_khr_local_int32_base_atomics : enable -#pragma OPENCL EXTENSION cl_khr_global_int32_base_atomics : enable -#pragma OPENCL EXTENSION cl_khr_local_int32_extended_atomics : enable -#pragma OPENCL EXTENSION cl_khr_global_int32_extended_atomics : enable -#pragma OPENCL EXTENSION cl_ext_atomic_counters_32 : enable - -typedef unsigned int u32; -typedef unsigned short u16; -typedef unsigned char u8; - -#define GET_GROUP_IDX get_group_id(0) -#define GET_LOCAL_IDX get_local_id(0) -#define GET_GLOBAL_IDX get_global_id(0) -#define GET_GROUP_SIZE get_local_size(0) -#define GET_NUM_GROUPS get_num_groups(0) -#define GROUP_LDS_BARRIER barrier(CLK_LOCAL_MEM_FENCE) -#define GROUP_MEM_FENCE mem_fence(CLK_LOCAL_MEM_FENCE) -#define AtomInc(x) atom_inc(&(x)) -#define AtomInc1(x, out) out = atom_inc(&(x)) -#define AppendInc(x, out) out = atomic_inc(x) -#define AtomAdd(x, value) atom_add(&(x), value) -#define AtomCmpxhg(x, cmp, value) atom_cmpxchg( &(x), cmp, value ) -#define AtomXhg(x, value) atom_xchg ( &(x), value ) - - -#define SELECT_UINT4( b, a, condition ) select( b,a,condition ) - -#define make_float4 (float4) -#define make_float2 (float2) -#define make_uint4 (uint4) -#define make_int4 (int4) -#define make_uint2 (uint2) -#define make_int2 (int2) - - -#define max2 max -#define min2 min - - -/////////////////////////////////////// -// Vector -/////////////////////////////////////// -__inline -float fastDiv(float numerator, float denominator) -{ - return native_divide(numerator, denominator); -// return numerator/denominator; -} - -__inline -float4 fastDiv4(float4 numerator, float4 denominator) -{ - return native_divide(numerator, denominator); -} - -__inline -float fastSqrtf(float f2) -{ - return native_sqrt(f2); -// return sqrt(f2); -} - -__inline -float fastRSqrt(float f2) -{ - return native_rsqrt(f2); -} - -__inline -float fastLength4(float4 v) -{ - return fast_length(v); -} - -__inline -float4 fastNormalize4(float4 v) -{ - return fast_normalize(v); -} - - -__inline -float sqrtf(float a) -{ -// return sqrt(a); - return native_sqrt(a); -} - -__inline -float4 cross3(float4 a, float4 b) -{ - return cross(a,b); -} - -__inline -float dot3F4(float4 a, float4 b) -{ - float4 a1 = make_float4(a.xyz,0.f); - float4 b1 = make_float4(b.xyz,0.f); - return dot(a1, b1); -} - -__inline -float length3(const float4 a) -{ - return sqrtf(dot3F4(a,a)); -} - -__inline -float dot4(const float4 a, const float4 b) -{ - return dot( a, b ); -} - -// for height -__inline -float dot3w1(const float4 point, const float4 eqn) -{ - return dot3F4(point,eqn) + eqn.w; -} - -__inline -float4 normalize3(const float4 a) -{ - float4 n = make_float4(a.x, a.y, a.z, 0.f); - return fastNormalize4( n ); -// float length = sqrtf(dot3F4(a, a)); -// return 1.f/length * a; -} - -__inline -float4 normalize4(const float4 a) -{ - float length = sqrtf(dot4(a, a)); - return 1.f/length * a; -} - -__inline -float4 createEquation(const float4 a, const float4 b, const float4 c) -{ - float4 eqn; - float4 ab = b-a; - float4 ac = c-a; - eqn = normalize3( cross3(ab, ac) ); - eqn.w = -dot3F4(eqn,a); - return eqn; -} - -/////////////////////////////////////// -// Matrix3x3 -/////////////////////////////////////// - -typedef struct -{ - float4 m_row[3]; -}Matrix3x3; - -__inline -Matrix3x3 mtZero(); - -__inline -Matrix3x3 mtIdentity(); - -__inline -Matrix3x3 mtTranspose(Matrix3x3 m); - -__inline -Matrix3x3 mtMul(Matrix3x3 a, Matrix3x3 b); - -__inline -float4 mtMul1(Matrix3x3 a, float4 b); - -__inline -float4 mtMul3(float4 a, Matrix3x3 b); - -__inline -Matrix3x3 mtZero() -{ - Matrix3x3 m; - m.m_row[0] = (float4)(0.f); - m.m_row[1] = (float4)(0.f); - m.m_row[2] = (float4)(0.f); - return m; -} - -__inline -Matrix3x3 mtIdentity() -{ - Matrix3x3 m; - m.m_row[0] = (float4)(1,0,0,0); - m.m_row[1] = (float4)(0,1,0,0); - m.m_row[2] = (float4)(0,0,1,0); - return m; -} - -__inline -Matrix3x3 mtTranspose(Matrix3x3 m) -{ - Matrix3x3 out; - out.m_row[0] = (float4)(m.m_row[0].x, m.m_row[1].x, m.m_row[2].x, 0.f); - out.m_row[1] = (float4)(m.m_row[0].y, m.m_row[1].y, m.m_row[2].y, 0.f); - out.m_row[2] = (float4)(m.m_row[0].z, m.m_row[1].z, m.m_row[2].z, 0.f); - return out; -} - -__inline -Matrix3x3 mtMul(Matrix3x3 a, Matrix3x3 b) -{ - Matrix3x3 transB; - transB = mtTranspose( b ); - Matrix3x3 ans; - // why this doesn't run when 0ing in the for{} - a.m_row[0].w = 0.f; - a.m_row[1].w = 0.f; - a.m_row[2].w = 0.f; - for(int i=0; i<3; i++) - { -// a.m_row[i].w = 0.f; - ans.m_row[i].x = dot3F4(a.m_row[i],transB.m_row[0]); - ans.m_row[i].y = dot3F4(a.m_row[i],transB.m_row[1]); - ans.m_row[i].z = dot3F4(a.m_row[i],transB.m_row[2]); - ans.m_row[i].w = 0.f; - } - return ans; -} - -__inline -float4 mtMul1(Matrix3x3 a, float4 b) -{ - float4 ans; - ans.x = dot3F4( a.m_row[0], b ); - ans.y = dot3F4( a.m_row[1], b ); - ans.z = dot3F4( a.m_row[2], b ); - ans.w = 0.f; - return ans; -} - -__inline -float4 mtMul3(float4 a, Matrix3x3 b) -{ - float4 colx = make_float4(b.m_row[0].x, b.m_row[1].x, b.m_row[2].x, 0); - float4 coly = make_float4(b.m_row[0].y, b.m_row[1].y, b.m_row[2].y, 0); - float4 colz = make_float4(b.m_row[0].z, b.m_row[1].z, b.m_row[2].z, 0); - - float4 ans; - ans.x = dot3F4( a, colx ); - ans.y = dot3F4( a, coly ); - ans.z = dot3F4( a, colz ); - return ans; -} - -/////////////////////////////////////// -// Quaternion -/////////////////////////////////////// - -typedef float4 Quaternion; - -__inline -Quaternion qtMul(Quaternion a, Quaternion b); - -__inline -Quaternion qtNormalize(Quaternion in); - -__inline -float4 qtRotate(Quaternion q, float4 vec); - -__inline -Quaternion qtInvert(Quaternion q); - -__inline -Matrix3x3 qtGetRotationMatrix(Quaternion q); - - - -__inline -Quaternion qtMul(Quaternion a, Quaternion b) -{ - Quaternion ans; - ans = cross3( a, b ); - ans += a.w*b+b.w*a; -// ans.w = a.w*b.w - (a.x*b.x+a.y*b.y+a.z*b.z); - ans.w = a.w*b.w - dot3F4(a, b); - return ans; -} - -__inline -Quaternion qtNormalize(Quaternion in) -{ - return fastNormalize4(in); -// in /= length( in ); -// return in; -} -__inline -float4 qtRotate(Quaternion q, float4 vec) -{ - Quaternion qInv = qtInvert( q ); - float4 vcpy = vec; - vcpy.w = 0.f; - float4 out = qtMul(qtMul(q,vcpy),qInv); - return out; -} - -__inline -Quaternion qtInvert(Quaternion q) -{ - return (Quaternion)(-q.xyz, q.w); -} - -__inline -float4 qtInvRotate(const Quaternion q, float4 vec) -{ - return qtRotate( qtInvert( q ), vec ); -} - -__inline -Matrix3x3 qtGetRotationMatrix(Quaternion quat) -{ - float4 quat2 = (float4)(quat.x*quat.x, quat.y*quat.y, quat.z*quat.z, 0.f); - Matrix3x3 out; - - out.m_row[0].x=1-2*quat2.y-2*quat2.z; - out.m_row[0].y=2*quat.x*quat.y-2*quat.w*quat.z; - out.m_row[0].z=2*quat.x*quat.z+2*quat.w*quat.y; - out.m_row[0].w = 0.f; - - out.m_row[1].x=2*quat.x*quat.y+2*quat.w*quat.z; - out.m_row[1].y=1-2*quat2.x-2*quat2.z; - out.m_row[1].z=2*quat.y*quat.z-2*quat.w*quat.x; - out.m_row[1].w = 0.f; - - out.m_row[2].x=2*quat.x*quat.z-2*quat.w*quat.y; - out.m_row[2].y=2*quat.y*quat.z+2*quat.w*quat.x; - out.m_row[2].z=1-2*quat2.x-2*quat2.y; - out.m_row[2].w = 0.f; - - return out; -} - - diff --git a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Math/Matrix3x3.h b/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Math/Matrix3x3.h deleted file mode 100644 index d68176835..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Math/Matrix3x3.h +++ /dev/null @@ -1,197 +0,0 @@ -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Takahiro Harada - -#ifndef MATRIX3X3_H -#define MATRIX3X3_H - -#include - -/////////////////////////////////////// -// Matrix3x3 -/////////////////////////////////////// -namespace adl -{ - -typedef -_MEM_CLASSALIGN16 struct -{ - _MEM_ALIGNED_ALLOCATOR16; - float4 m_row[3]; -}Matrix3x3; - -__inline -Matrix3x3 mtZero(); - -__inline -Matrix3x3 mtIdentity(); - -__inline -Matrix3x3 mtDiagonal(float a, float b, float c); - -__inline -Matrix3x3 mtTranspose(const Matrix3x3& m); - -__inline -Matrix3x3 mtMul(const Matrix3x3& a, const Matrix3x3& b); - -__inline -float4 mtMul1(const Matrix3x3& a, const float4& b); - -__inline -Matrix3x3 mtMul2(float a, const Matrix3x3& b); - -__inline -float4 mtMul3(const float4& b, const Matrix3x3& a); - -__inline -Matrix3x3 mtInvert(const Matrix3x3& m); - -__inline -Matrix3x3 mtZero() -{ - Matrix3x3 m; - m.m_row[0] = make_float4(0.f); - m.m_row[1] = make_float4(0.f); - m.m_row[2] = make_float4(0.f); - return m; -} - -__inline -Matrix3x3 mtIdentity() -{ - Matrix3x3 m; - m.m_row[0] = make_float4(1,0,0); - m.m_row[1] = make_float4(0,1,0); - m.m_row[2] = make_float4(0,0,1); - return m; -} - -__inline -Matrix3x3 mtDiagonal(float a, float b, float c) -{ - Matrix3x3 m; - m.m_row[0] = make_float4(a,0,0); - m.m_row[1] = make_float4(0,b,0); - m.m_row[2] = make_float4(0,0,c); - return m; -} - -__inline -Matrix3x3 mtTranspose(const Matrix3x3& m) -{ - Matrix3x3 out; - out.m_row[0] = make_float4(m.m_row[0].s[0], m.m_row[1].s[0], m.m_row[2].s[0], 0.f); - out.m_row[1] = make_float4(m.m_row[0].s[1], m.m_row[1].s[1], m.m_row[2].s[1], 0.f); - out.m_row[2] = make_float4(m.m_row[0].s[2], m.m_row[1].s[2], m.m_row[2].s[2], 0.f); - return out; -} - -__inline -Matrix3x3 mtMul(const Matrix3x3& a, const Matrix3x3& b) -{ - Matrix3x3 transB; - transB = mtTranspose( b ); - Matrix3x3 ans; - for(int i=0; i<3; i++) - { - ans.m_row[i].s[0] = dot3F4(a.m_row[i],transB.m_row[0]); - ans.m_row[i].s[1] = dot3F4(a.m_row[i],transB.m_row[1]); - ans.m_row[i].s[2] = dot3F4(a.m_row[i],transB.m_row[2]); - } - return ans; -} - -__inline -float4 mtMul1(const Matrix3x3& a, const float4& b) -{ - float4 ans; - ans.s[0] = dot3F4( a.m_row[0], b ); - ans.s[1] = dot3F4( a.m_row[1], b ); - ans.s[2] = dot3F4( a.m_row[2], b ); - return ans; -} - -__inline -Matrix3x3 mtMul2(float a, const Matrix3x3& b) -{ - Matrix3x3 ans; - ans.m_row[0] = a*b.m_row[0]; - ans.m_row[1] = a*b.m_row[1]; - ans.m_row[2] = a*b.m_row[2]; - return ans; -} - -__inline -float4 mtMul3(const float4& a, const Matrix3x3& b) -{ - float4 ans; - ans.x = a.x*b.m_row[0].x + a.y*b.m_row[1].x + a.z*b.m_row[2].x; - ans.y = a.x*b.m_row[0].y + a.y*b.m_row[1].y + a.z*b.m_row[2].y; - ans.z = a.x*b.m_row[0].z + a.y*b.m_row[1].z + a.z*b.m_row[2].z; - return ans; -} - -__inline -Matrix3x3 mtInvert(const Matrix3x3& m) -{ - float det = m.m_row[0].s[0]*m.m_row[1].s[1]*m.m_row[2].s[2]+m.m_row[1].s[0]*m.m_row[2].s[1]*m.m_row[0].s[2]+m.m_row[2].s[0]*m.m_row[0].s[1]*m.m_row[1].s[2] - -m.m_row[0].s[0]*m.m_row[2].s[1]*m.m_row[1].s[2]-m.m_row[2].s[0]*m.m_row[1].s[1]*m.m_row[0].s[2]-m.m_row[1].s[0]*m.m_row[0].s[1]*m.m_row[2].s[2]; - - ADLASSERT( det ); - - Matrix3x3 ans; - ans.m_row[0].s[0] = m.m_row[1].s[1]*m.m_row[2].s[2] - m.m_row[1].s[2]*m.m_row[2].s[1]; - ans.m_row[0].s[1] = m.m_row[0].s[2]*m.m_row[2].s[1] - m.m_row[0].s[1]*m.m_row[2].s[2]; - ans.m_row[0].s[2] = m.m_row[0].s[1]*m.m_row[1].s[2] - m.m_row[0].s[2]*m.m_row[1].s[1]; - ans.m_row[0].w = 0.f; - - ans.m_row[1].s[0] = m.m_row[1].s[2]*m.m_row[2].s[0] - m.m_row[1].s[0]*m.m_row[2].s[2]; - ans.m_row[1].s[1] = m.m_row[0].s[0]*m.m_row[2].s[2] - m.m_row[0].s[2]*m.m_row[2].s[0]; - ans.m_row[1].s[2] = m.m_row[0].s[2]*m.m_row[1].s[0] - m.m_row[0].s[0]*m.m_row[1].s[2]; - ans.m_row[1].w = 0.f; - - ans.m_row[2].s[0] = m.m_row[1].s[0]*m.m_row[2].s[1] - m.m_row[1].s[1]*m.m_row[2].s[0]; - ans.m_row[2].s[1] = m.m_row[0].s[1]*m.m_row[2].s[0] - m.m_row[0].s[0]*m.m_row[2].s[1]; - ans.m_row[2].s[2] = m.m_row[0].s[0]*m.m_row[1].s[1] - m.m_row[0].s[1]*m.m_row[1].s[0]; - ans.m_row[2].w = 0.f; - - ans = mtMul2((1.0f/det), ans); - return ans; -} - -__inline -Matrix3x3 mtSet( const float4& a, const float4& b, const float4& c ) -{ - Matrix3x3 m; - m.m_row[0] = a; - m.m_row[1] = b; - m.m_row[2] = c; - return m; -} - -__inline -Matrix3x3 operator+(const Matrix3x3& a, const Matrix3x3& b) -{ - Matrix3x3 out; - out.m_row[0] = a.m_row[0] + b.m_row[0]; - out.m_row[1] = a.m_row[1] + b.m_row[1]; - out.m_row[2] = a.m_row[2] + b.m_row[2]; - return out; -} - -}; - -#endif - diff --git a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Math/Quaternion.h b/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Math/Quaternion.h deleted file mode 100644 index 3eeef4431..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Math/Quaternion.h +++ /dev/null @@ -1,159 +0,0 @@ -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Takahiro Harada - - -#ifndef QUATERNION_H -#define QUATERNION_H - -#include - -namespace adl -{ - -typedef float4 Quaternion; - -__inline -Quaternion qtSet(const float4& axis, float angle); - -__inline -Quaternion qtMul(const Quaternion& a, const Quaternion& b); - -__inline -float4 qtRotate(const Quaternion& q, const float4& vec); - -__inline -float4 qtInvRotate(const Quaternion& q, const float4& vec); - -__inline -Quaternion qtInvert(const Quaternion& q); - -__inline -Matrix3x3 qtGetRotationMatrix(const Quaternion& quat); - -__inline -Quaternion qtNormalize(const Quaternion& q); - -__inline -Quaternion qtGetIdentity() { return make_float4(0,0,0,1); } - -__inline -Quaternion qtSet(const float4& axis, float angle) -{ - float4 nAxis = normalize3( axis ); - - Quaternion q; - q.s[0] = nAxis.s[0]*sin(angle/2); - q.s[1] = nAxis.s[1]*sin(angle/2); - q.s[2] = nAxis.s[2]*sin(angle/2); - q.s[3] = cos(angle/2); - return q; -} - -__inline -Quaternion qtMul(const Quaternion& a, const Quaternion& b) -{ - Quaternion ans; - ans = cross3( a, b ); - ans += a.s[3]*b + b.s[3]*a; - ans.s[3] = a.s[3]*b.s[3] - (a.s[0]*b.s[0]+a.s[1]*b.s[1]+a.s[2]*b.s[2]); - return ans; -} - -__inline -float4 qtRotate(const Quaternion& q, const float4& vec) -{ - Quaternion vecQ = vec; - vecQ.s[3] = 0.f; - Quaternion qInv = qtInvert( q ); - float4 out = qtMul(qtMul(q,vecQ),qInv); - return out; -} - -__inline -float4 qtInvRotate(const Quaternion& q, const float4& vec) -{ - return qtRotate( qtInvert( q ), vec ); -} - -__inline -Quaternion qtInvert(const Quaternion& q) -{ - Quaternion ans; - ans.s[0] = -q.s[0]; - ans.s[1] = -q.s[1]; - ans.s[2] = -q.s[2]; - ans.s[3] = q.s[3]; - return ans; -} - -__inline -Matrix3x3 qtGetRotationMatrix(const Quaternion& quat) -{ - float4 quat2 = make_float4(quat.s[0]*quat.s[0], quat.s[1]*quat.s[1], quat.s[2]*quat.s[2], 0.f); - Matrix3x3 out; - - out.m_row[0].s[0]=1-2*quat2.s[1]-2*quat2.s[2]; - out.m_row[0].s[1]=2*quat.s[0]*quat.s[1]-2*quat.s[3]*quat.s[2]; - out.m_row[0].s[2]=2*quat.s[0]*quat.s[2]+2*quat.s[3]*quat.s[1]; - out.m_row[0].s[3] = 0.f; - - out.m_row[1].s[0]=2*quat.s[0]*quat.s[1]+2*quat.s[3]*quat.s[2]; - out.m_row[1].s[1]=1-2*quat2.s[0]-2*quat2.s[2]; - out.m_row[1].s[2]=2*quat.s[1]*quat.s[2]-2*quat.s[3]*quat.s[0]; - out.m_row[1].s[3] = 0.f; - - out.m_row[2].s[0]=2*quat.s[0]*quat.s[2]-2*quat.s[3]*quat.s[1]; - out.m_row[2].s[1]=2*quat.s[1]*quat.s[2]+2*quat.s[3]*quat.s[0]; - out.m_row[2].s[2]=1-2*quat2.s[0]-2*quat2.s[1]; - out.m_row[2].s[3] = 0.f; - - return out; -} - -__inline -Quaternion qtGetQuaternion(const Matrix3x3* m) -{ - Quaternion q; - q.w = sqrtf( m[0].m_row[0].x + m[0].m_row[1].y + m[0].m_row[2].z + 1 ) * 0.5f; - float inv4w = 1.f/(4.f*q.w); - q.x = (m[0].m_row[2].y-m[0].m_row[1].z)*inv4w; - q.y = (m[0].m_row[0].z-m[0].m_row[2].x)*inv4w; - q.z = (m[0].m_row[1].x-m[0].m_row[0].y)*inv4w; - - return q; -} - -__inline -Quaternion qtNormalize(const Quaternion& q) -{ - return normalize4(q); -} - -__inline -float4 transform(const float4& p, const float4& translation, const Quaternion& orientation) -{ - return qtRotate( orientation, p ) + translation; -} - -__inline -float4 invTransform(const float4& p, const float4& translation, const Quaternion& orientation) -{ - return qtRotate( qtInvert( orientation ), p-translation ); // use qtInvRotate -} - -}; - -#endif - diff --git a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Scan/PrefixScan.h b/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Scan/PrefixScan.h deleted file mode 100644 index db7566ede..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Scan/PrefixScan.h +++ /dev/null @@ -1,73 +0,0 @@ -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Takahiro Harada - -#pragma once - -#include -#include - -namespace adl -{ - -class PrefixScanBase -{ - public: - enum Option - { - INCLUSIVE, - EXCLUSIVE - }; -}; - - -template -class PrefixScan : public PrefixScanBase -{ - public: - typedef Launcher::BufferInfo BufferInfo; - - enum - { - BLOCK_SIZE = 128 - }; - - struct Data - { - Option m_option; - const Device* m_device; - Kernel* m_localScanKernel; - Kernel* m_blockSumKernel; - Kernel* m_propagationKernel; - Buffer* m_workBuffer; - Buffer* m_constBuffer[3];// todo. dx need one for each - int m_maxSize; - }; - - static - Data* allocate(const Device* deviceData, int maxSize, Option option = EXCLUSIVE); - - static - void deallocate(Data* data); - - static - void execute(Data* data, Buffer& src, Buffer& dst, int n, u32* sum = 0); -}; - - - -#include -#include - -}; diff --git a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Scan/PrefixScan.inl b/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Scan/PrefixScan.inl deleted file mode 100644 index 65e8c06a5..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Scan/PrefixScan.inl +++ /dev/null @@ -1,125 +0,0 @@ -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Takahiro Harada - - -#define PATH "..\\..\\opencl\\primitives\\AdlPrimitives\\Scan\\PrefixScanKernels" -#define KERNEL0 "LocalScanKernel" -#define KERNEL1 "TopLevelScanKernel" -#define KERNEL2 "AddOffsetKernel" - -#include -#include - -template -typename PrefixScan::Data* PrefixScan::allocate(const Device* device, int maxSize, Option option) -{ - ADLASSERT( TYPE == device->m_type ); - - ADLASSERT( maxSize <= BLOCK_SIZE*2*2048 ); - - const char* src[] = -#if defined(ADL_LOAD_KERNEL_FROM_STRING) - {prefixScanKernelsCL, prefixScanKernelsDX11}; -#else - {0,0}; -#endif - Data* data = new Data; - data->m_device = device; - data->m_localScanKernel = device->getKernel( PATH, KERNEL0, 0, src[TYPE] ); - data->m_blockSumKernel = device->getKernel( PATH, KERNEL1, 0, src[TYPE] ); - data->m_propagationKernel = device->getKernel( PATH, KERNEL2, 0, src[TYPE] ); - - int bufSize = (NEXTMULTIPLEOF( max2( maxSize/BLOCK_SIZE, (int)BLOCK_SIZE ), BLOCK_SIZE )+1); - data->m_workBuffer = new Buffer( device, bufSize ); - data->m_constBuffer[0] = new Buffer( device, 1, BufferBase::BUFFER_CONST ); - data->m_constBuffer[1] = new Buffer( device, 1, BufferBase::BUFFER_CONST ); - data->m_constBuffer[2] = new Buffer( device, 1, BufferBase::BUFFER_CONST ); - - data->m_maxSize = maxSize; - data->m_option = option; - - return data; -} - -template -void PrefixScan::deallocate(Data* data) -{ - delete data->m_workBuffer; - delete data->m_constBuffer[0]; - delete data->m_constBuffer[1]; - delete data->m_constBuffer[2]; - delete data; -} - -template -void PrefixScan::execute(Data* data, Buffer& src, Buffer& dst, int n, u32* sum) -{ - ADLASSERT( data ); - ADLASSERT( n <= data->m_maxSize ); - ADLASSERT( data->m_option == EXCLUSIVE ); - const u32 numBlocks = u32( (n+BLOCK_SIZE*2-1)/(BLOCK_SIZE*2) ); - - - int4 constBuffer; - constBuffer.x = n; - constBuffer.y = numBlocks; - constBuffer.z = (int)nextPowerOf2( numBlocks ); - - Buffer* srcNative = BufferUtils::map( data->m_device, &src ); - Buffer* dstNative = BufferUtils::map( data->m_device, &dst ); - - { - BufferInfo bInfo[] = { BufferInfo( dstNative ), BufferInfo( srcNative ), BufferInfo( data->m_workBuffer ) }; - - Launcher launcher( data->m_device, data->m_localScanKernel ); - launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(Launcher::BufferInfo) ); - launcher.setConst( *data->m_constBuffer[0], constBuffer ); - launcher.launch1D( numBlocks*BLOCK_SIZE, BLOCK_SIZE ); - } - - { - BufferInfo bInfo[] = { BufferInfo( data->m_workBuffer ) }; - - Launcher launcher( data->m_device, data->m_blockSumKernel ); - launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(Launcher::BufferInfo) ); - launcher.setConst( *data->m_constBuffer[1], constBuffer ); - launcher.launch1D( BLOCK_SIZE, BLOCK_SIZE ); - } - - - if( numBlocks > 1 ) - { - BufferInfo bInfo[] = { BufferInfo( dstNative ), BufferInfo( data->m_workBuffer ) }; - Launcher launcher( data->m_device, data->m_propagationKernel ); - launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(Launcher::BufferInfo) ); - launcher.setConst( *data->m_constBuffer[2], constBuffer ); - launcher.launch1D( (numBlocks-1)*BLOCK_SIZE, BLOCK_SIZE ); - } - - DeviceUtils::waitForCompletion( data->m_device ); - if( sum ) - { - dstNative->read( sum, 1, n-1); - } - DeviceUtils::waitForCompletion( data->m_device ); - - BufferUtils::unmap( srcNative, &src ); - BufferUtils::unmap( dstNative, &dst ); -} - -#undef PATH -#undef KERNEL0 -#undef KERNEL1 -#undef KERNEL2 \ No newline at end of file diff --git a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Scan/PrefixScanHost.inl b/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Scan/PrefixScanHost.inl deleted file mode 100644 index 44987f548..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Scan/PrefixScanHost.inl +++ /dev/null @@ -1,74 +0,0 @@ -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Takahiro Harada - - -template<> -class PrefixScan : public PrefixScanBase -{ - public: - struct Data - { - Option m_option; - }; - - static - Data* allocate(const Device* deviceData, int maxSize, Option option = EXCLUSIVE) - { - ADLASSERT( deviceData->m_type == TYPE_HOST ); - - Data* data = new Data; - data->m_option = option; - return data; - } - - static - void deallocate(Data* data) - { - delete data; - } - - static - void execute(Data* data, Buffer& src, Buffer& dst, int n, u32* sum = 0) - { - ADLASSERT( src.getType() == TYPE_HOST && dst.getType() == TYPE_HOST ); - HostBuffer& hSrc = (HostBuffer&)src; - HostBuffer& hDst = (HostBuffer&)dst; - - u32 s = 0; - if( data->m_option == EXCLUSIVE ) - { - for(int i=0; i>1; nActive>0; nActive>>=1, offset<<=1) - { - GROUP_LDS_BARRIER; - for(int iIdx=lIdx; iIdx>= 1; - for(int nActive=1; nActive>=1 ) - { - GROUP_LDS_BARRIER; - for( int iIdx = lIdx; iIdx dst : register( u0 ); -RWStructuredBuffer src : register( u1 ); -RWStructuredBuffer sumBuffer : register( u2 ); - - -groupshared u32 ldsData[2048]; - -u32 ScanExclusive(u32 n, int lIdx, int lSize) -{ - u32 blocksum; - int offset = 1; - for(int nActive=n>>1; nActive>0; nActive>>=1, offset<<=1) - { - GROUP_LDS_BARRIER; - for(int iIdx=lIdx; iIdx>= 1; - for(int nActive=1; nActive>=1 ) - { - GROUP_LDS_BARRIER; - for( int iIdx = lIdx; iIdx blockSum2 : register( u1 ); - -[numthreads(WG_SIZE, 1, 1)] -void AddOffsetKernel(uint3 globalIdx : SV_DispatchThreadID, uint3 localIdx : SV_GroupThreadID, uint3 groupIdx : SV_GroupID) -{ - const u32 blockSize = WG_SIZE*2; - - int myIdx = GET_GROUP_IDX+1; - int llIdx = GET_LOCAL_IDX; - - u32 iBlockSum = blockSum2[myIdx]; - - int endValue = min((myIdx+1)*(blockSize), m_numElems); - for(int i=myIdx*blockSize+llIdx; i>1; nActive>0; nActive>>=1, offset<<=1)\n" -" {\n" -" GROUP_LDS_BARRIER;\n" -" for(int iIdx=lIdx; iIdx>= 1;\n" -" for(int nActive=1; nActive>=1 )\n" -" {\n" -" GROUP_LDS_BARRIER;\n" -" for( int iIdx = lIdx; iIdx dst : register( u0 );\n" -"RWStructuredBuffer src : register( u1 );\n" -"RWStructuredBuffer sumBuffer : register( u2 );\n" -"\n" -"\n" -"groupshared u32 ldsData[2048];\n" -"\n" -"u32 ScanExclusive(u32 n, int lIdx, int lSize)\n" -"{\n" -" u32 blocksum;\n" -" int offset = 1;\n" -" for(int nActive=n>>1; nActive>0; nActive>>=1, offset<<=1)\n" -" {\n" -" GROUP_LDS_BARRIER;\n" -" for(int iIdx=lIdx; iIdx>= 1;\n" -" for(int nActive=1; nActive>=1 )\n" -" {\n" -" GROUP_LDS_BARRIER;\n" -" for( int iIdx = lIdx; iIdx blockSum2 : register( u1 );\n" -"\n" -"[numthreads(WG_SIZE, 1, 1)]\n" -"void AddOffsetKernel(uint3 globalIdx : SV_DispatchThreadID, uint3 localIdx : SV_GroupThreadID, uint3 groupIdx : SV_GroupID)\n" -"{\n" -" const u32 blockSize = WG_SIZE*2;\n" -"\n" -" int myIdx = GET_GROUP_IDX+1;\n" -" int llIdx = GET_LOCAL_IDX;\n" -"\n" -" u32 iBlockSum = blockSum2[myIdx];\n" -"\n" -" int endValue = min((myIdx+1)*(blockSize), m_numElems);\n" -" for(int i=myIdx*blockSize+llIdx; i -#include -#include -#include - -namespace adl -{ - -class BoundSearchBase -{ - public: - enum Option - { - BOUND_LOWER, - BOUND_UPPER, - COUNT, - }; -}; - -template -class BoundSearch : public BoundSearchBase -{ - public: - typedef Launcher::BufferInfo BufferInfo; - - struct Data - { - const Device* m_device; - Kernel* m_lowerSortDataKernel; - Kernel* m_upperSortDataKernel; - Kernel* m_subtractKernel; - Buffer* m_constBuffer; - Buffer* m_lower; - Buffer* m_upper; - typename Fill::Data* m_fillData; - }; - - static - Data* allocate(const Device* deviceData, int maxSize = 0); - - static - void deallocate(Data* data); - - // src has to be src[i].m_key <= src[i+1].m_key - static - void execute(Data* data, Buffer& src, u32 nSrc, Buffer& dst, u32 nDst, Option option = BOUND_LOWER ); - -// static -// void execute(Data* data, Buffer& src, Buffer& dst, int n, Option option = ); -}; - -#include -#include - -}; diff --git a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Search/BoundSearch.inl b/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Search/BoundSearch.inl deleted file mode 100644 index 33138b4e5..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Search/BoundSearch.inl +++ /dev/null @@ -1,128 +0,0 @@ -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Takahiro Harada - -#define PATH "..\\..\\opencl\\primitives\\AdlPrimitives\\Search\\BoundSearchKernels" -#define KERNEL0 "SearchSortDataLowerKernel" -#define KERNEL1 "SearchSortDataUpperKernel" -#define KERNEL2 "SubtractKernel" - -#include -#include - -template -typename BoundSearch::Data* BoundSearch::allocate(const Device* device, int maxSize) -{ - ADLASSERT( TYPE == device->m_type ); - - const char* src[] = -#if defined(ADL_LOAD_KERNEL_FROM_STRING) - {boundSearchKernelsCL, boundSearchKernelsDX11}; -#else - {0,0}; -#endif - - Data* data = new Data; - - data->m_device = device; - data->m_lowerSortDataKernel = device->getKernel( PATH, KERNEL0, 0, src[TYPE] ); - data->m_upperSortDataKernel = device->getKernel( PATH, KERNEL1, 0, src[TYPE] ); - data->m_constBuffer = new Buffer( device, 1, BufferBase::BUFFER_CONST ); - if( maxSize ) - { - data->m_subtractKernel = device->getKernel( PATH, KERNEL2, 0, src[TYPE] ); - } - data->m_lower = (maxSize == 0)? 0: new Buffer( device, maxSize ); - data->m_upper = (maxSize == 0)? 0: new Buffer( device, maxSize ); - data->m_fillData = (maxSize == 0)? 0: Fill::allocate( device ); - - return data; -} - -template -void BoundSearch::deallocate(Data* data) -{ - delete data->m_constBuffer; - if( data->m_lower ) delete data->m_lower; - if( data->m_upper ) delete data->m_upper; - if( data->m_fillData ) Fill::deallocate( data->m_fillData ); - delete data; -} - -template -void BoundSearch::execute(Data* data, Buffer& src, u32 nSrc, Buffer& dst, u32 nDst, Option option ) -{ - int4 constBuffer; - constBuffer.x = nSrc; - constBuffer.y = nDst; - - Buffer* srcNative = BufferUtils::map( data->m_device, &src ); - Buffer* dstNative = BufferUtils::map( data->m_device, &dst ); - - if( option == BOUND_LOWER ) - { - BufferInfo bInfo[] = { BufferInfo( srcNative, true ), BufferInfo( dstNative ) }; - - Launcher launcher( data->m_device, data->m_lowerSortDataKernel ); - launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(Launcher::BufferInfo) ); - launcher.setConst( *data->m_constBuffer, constBuffer ); - launcher.launch1D( nSrc, 64 ); - } - else if( option == BOUND_UPPER ) - { - BufferInfo bInfo[] = { BufferInfo( srcNative, true ), BufferInfo( dstNative ) }; - - Launcher launcher( data->m_device, data->m_upperSortDataKernel ); - launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(Launcher::BufferInfo) ); - launcher.setConst( *data->m_constBuffer, constBuffer ); - launcher.launch1D( nSrc+1, 64 ); - } - else if( option == COUNT ) - { - ADLASSERT( data->m_lower ); - ADLASSERT( data->m_upper ); - ADLASSERT( data->m_lower->getSize() <= (int)nDst ); - ADLASSERT( data->m_upper->getSize() <= (int)nDst ); - - int zero = 0; - Fill::execute( data->m_fillData, (Buffer&)*data->m_lower, zero, nDst ); - Fill::execute( data->m_fillData, (Buffer&)*data->m_upper, zero, nDst ); - - execute( data, src, nSrc, *data->m_lower, nDst, BOUND_LOWER ); - execute( data, src, nSrc, *data->m_upper, nDst, BOUND_UPPER ); - - { - BufferInfo bInfo[] = { BufferInfo( data->m_upper, true ), BufferInfo( data->m_lower, true ), BufferInfo( dstNative ) }; - - Launcher launcher( data->m_device, data->m_subtractKernel ); - launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(Launcher::BufferInfo) ); - launcher.setConst( *data->m_constBuffer, constBuffer ); - launcher.launch1D( nDst, 64 ); - } - } - else - { - ADLASSERT( 0 ); - } - - BufferUtils::unmap( srcNative, &src ); - BufferUtils::unmap( dstNative, &dst ); -} - - -#undef PATH -#undef KERNEL0 -#undef KERNEL1 -#undef KERNEL2 - diff --git a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Search/BoundSearchHost.inl b/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Search/BoundSearchHost.inl deleted file mode 100644 index b53b3ba48..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Search/BoundSearchHost.inl +++ /dev/null @@ -1,111 +0,0 @@ -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Takahiro Harada - - -template<> -class BoundSearch : public BoundSearchBase -{ - public: - typedef Launcher::BufferInfo BufferInfo; - - struct Data - { - const Device* m_device; - }; - - static - Data* allocate(const Device* deviceData, int maxSize = 0) - { - ADLASSERT( deviceData->m_type == TYPE_HOST ); - Data* data = new Data; - data->m_device = deviceData; - return data; - } - - static - void deallocate(Data* data) - { - delete data; - } - - static - void execute(Data* data, Buffer& rawSrc, u32 nSrc, Buffer& rawDst, u32 nDst, Option option = BOUND_LOWER) - { - ADLASSERT( rawSrc.getType() == TYPE_HOST ); - ADLASSERT( rawDst.getType() == TYPE_HOST ); - - HostBuffer& src = *(HostBuffer*)&rawSrc; - HostBuffer& dst = *(HostBuffer*)&rawDst; - - for(int i=0; i lower( data->m_device, nDst ); - HostBuffer upper( data->m_device, nDst ); - - for(u32 i=0; i& src, Buffer& dst, int n, Option option = ); -}; - - diff --git a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Search/BoundSearchKernels.cl b/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Search/BoundSearchKernels.cl deleted file mode 100644 index 105a17a43..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Search/BoundSearchKernels.cl +++ /dev/null @@ -1,112 +0,0 @@ -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Takahiro Harada - - -typedef unsigned int u32; -#define GET_GROUP_IDX get_group_id(0) -#define GET_LOCAL_IDX get_local_id(0) -#define GET_GLOBAL_IDX get_global_id(0) -#define GET_GROUP_SIZE get_local_size(0) -#define GROUP_LDS_BARRIER barrier(CLK_LOCAL_MEM_FENCE) - -typedef struct -{ - u32 m_key; - u32 m_value; -}SortData; - - - -typedef struct -{ - u32 m_nSrc; - u32 m_nDst; - u32 m_padding[2]; -} ConstBuffer; - - - -__attribute__((reqd_work_group_size(64,1,1))) -__kernel -void SearchSortDataLowerKernel(__global SortData* src, __global u32 *dst, - ConstBuffer cb) -{ - int gIdx = GET_GLOBAL_IDX; - u32 nSrc = cb.m_nSrc; - u32 nDst = cb.m_nDst; - - if( gIdx < nSrc ) - { - SortData first; first.m_key = (u32)(-1); first.m_value = (u32)(-1); - SortData end; end.m_key = nDst; end.m_value = nDst; - - SortData iData = (gIdx==0)? first: src[gIdx-1]; - SortData jData = (gIdx==nSrc)? end: src[gIdx]; - - if( iData.m_key != jData.m_key ) - { -// for(u32 k=iData.m_key+1; k<=min(jData.m_key, nDst-1); k++) - u32 k = jData.m_key; - { - dst[k] = gIdx; - } - } - } -} - - -__attribute__((reqd_work_group_size(64,1,1))) -__kernel -void SearchSortDataUpperKernel(__global SortData* src, __global u32 *dst, - ConstBuffer cb) -{ - int gIdx = GET_GLOBAL_IDX; - u32 nSrc = cb.m_nSrc; - u32 nDst = cb.m_nDst; - - if( gIdx < nSrc+1 ) - { - SortData first; first.m_key = 0; first.m_value = 0; - SortData end; end.m_key = nDst; end.m_value = nDst; - - SortData iData = (gIdx==0)? first: src[gIdx-1]; - SortData jData = (gIdx==nSrc)? end: src[gIdx]; - - if( iData.m_key != jData.m_key ) - { -// for(u32 k=iData.m_key; k src : register( t0 ); -RWStructuredBuffer dst : register( u0 ); - - -[numthreads(64, 1, 1)] -void SearchSortDataLowerKernel( DEFAULT_ARGS ) -{ - int gIdx = GET_GLOBAL_IDX; - u32 nSrc = m_nSrc; - u32 nDst = m_nDst; - - if( gIdx < nSrc ) - { - SortData iData; - SortData jData; - if( gIdx==0 ) iData.m_key = iData.m_value = (u32)-1; - else iData = src[gIdx-1]; - - if( gIdx==nSrc ) jData.m_key = jData.m_value = nDst; - else jData = src[gIdx]; - - if( iData.m_key != jData.m_key ) - { -// for(u32 k=iData.m_key+1; k<=min(jData.m_key, nDst-1); k++) - u32 k = jData.m_key; - { - dst[k] = gIdx; - } - } - } -} - -[numthreads(64, 1, 1)] -void SearchSortDataUpperKernel( DEFAULT_ARGS ) -{ - int gIdx = GET_GLOBAL_IDX; - u32 nSrc = m_nSrc; - u32 nDst = m_nDst; - - if( gIdx < nSrc+1 ) - { - SortData iData; - SortData jData; - if( gIdx==0 ) iData.m_key = iData.m_value = 0; - else iData = src[gIdx-1]; - - if( gIdx==nSrc ) jData.m_key = jData.m_value = nDst; - else jData = src[gIdx]; - - if( iData.m_key != jData.m_key ) - { -// for(u32 k=iData.m_key; k src : register( t0 );\n" -"RWStructuredBuffer dst : register( u0 );\n" -"\n" -"\n" -"[numthreads(64, 1, 1)]\n" -"void SearchSortDataLowerKernel( DEFAULT_ARGS )\n" -"{\n" -" int gIdx = GET_GLOBAL_IDX;\n" -" u32 nSrc = m_nSrc;\n" -" u32 nDst = m_nDst;\n" -"\n" -" if( gIdx < nSrc )\n" -" {\n" -" SortData iData;\n" -" SortData jData;\n" -" if( gIdx==0 ) iData.m_key = iData.m_value = (u32)-1;\n" -" else iData = src[gIdx-1];\n" -"\n" -" if( gIdx==nSrc ) jData.m_key = jData.m_value = nDst;\n" -" else jData = src[gIdx];\n" -"\n" -" if( iData.m_key != jData.m_key )\n" -" {\n" -"// for(u32 k=iData.m_key+1; k<=min(jData.m_key, nDst-1); k++)\n" -" u32 k = jData.m_key;\n" -" {\n" -" dst[k] = gIdx;\n" -" }\n" -" }\n" -" }\n" -"}\n" -"\n" -"[numthreads(64, 1, 1)]\n" -"void SearchSortDataUpperKernel( DEFAULT_ARGS )\n" -"{\n" -" int gIdx = GET_GLOBAL_IDX;\n" -" u32 nSrc = m_nSrc;\n" -" u32 nDst = m_nDst;\n" -"\n" -" if( gIdx < nSrc+1 )\n" -" {\n" -" SortData iData;\n" -" SortData jData;\n" -" if( gIdx==0 ) iData.m_key = iData.m_value = 0;\n" -" else iData = src[gIdx-1];\n" -"\n" -" if( gIdx==nSrc ) jData.m_key = jData.m_value = nDst;\n" -" else jData = src[gIdx];\n" -"\n" -" if( iData.m_key != jData.m_key )\n" -" {\n" -"// for(u32 k=iData.m_key; k -#include -#include -#include - -namespace adl -{ - -class RadixSortBase -{ - public: - enum Option - { - SORT_SIMPLE, - SORT_STANDARD, - SORT_ADVANCED - }; -}; - -template -class RadixSort : public RadixSortBase -{ - public: - struct Data - { - Option m_option; - const Device* m_deviceData; - typename PrefixScan::Data* m_scanData; - int m_maxSize; - }; - - - static - Data* allocate(const Device* deviceData, int maxSize, Option option = SORT_STANDARD); - - static - void deallocate(Data* data); - - static - void execute(Data* data, Buffer& inout, int n, int sortBits = 32); -}; - - -#include -#include - -}; diff --git a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Sort/RadixSort.inl b/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Sort/RadixSort.inl deleted file mode 100644 index f7da098b6..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Sort/RadixSort.inl +++ /dev/null @@ -1,58 +0,0 @@ -/* - 2011 Takahiro Harada -*/ - -#include -#include -#include - - -#define DISPATCH_IMPL(x) \ - switch( data->m_option ) \ - { \ - case SORT_SIMPLE: RadixSortSimple::x; break; \ - case SORT_STANDARD: RadixSortStandard::x; break; \ - case SORT_ADVANCED: RadixSortAdvanced::x; break; \ - default:ADLASSERT(0);break; \ - } - -template -typename RadixSort::Data* RadixSort::allocate(const Device* deviceData, int maxSize, Option option) -{ - ADLASSERT( TYPE == deviceData->m_type ); - - void* dataOut; - switch( option ) - { - case SORT_SIMPLE: - dataOut = RadixSortSimple::allocate( deviceData, maxSize, option ); - break; - case SORT_STANDARD: - dataOut = RadixSortStandard::allocate( deviceData, maxSize, option ); - break; - case SORT_ADVANCED: - dataOut = RadixSortAdvanced::allocate( deviceData, maxSize, option ); - break; - default: - ADLASSERT(0); - break; - } - return (typename RadixSort::Data*)dataOut; -} - -template -void RadixSort::deallocate(Data* data) -{ - DISPATCH_IMPL( deallocate( data ) ); -} - -template -void RadixSort::execute(Data* data, Buffer& inout, int n, int sortBits) -{ - DISPATCH_IMPL( execute( data, inout, n, sortBits ) ); -} - - -#undef DISPATCH_IMPL - - diff --git a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Sort/RadixSort32.h b/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Sort/RadixSort32.h deleted file mode 100644 index c5433e72f..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Sort/RadixSort32.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - 2011 Takahiro Harada -*/ - -#pragma once - -#include -#include -#include -#include - -namespace adl -{ - -class RadixSort32Base -{ - public: -// enum Option -// { -// SORT_SIMPLE, -// SORT_STANDARD, -// SORT_ADVANCED -// }; -}; - -template -class RadixSort32 : public RadixSort32Base -{ - public: - typedef Launcher::BufferInfo BufferInfo; - - enum - { - DATA_ALIGNMENT = 256, - WG_SIZE = 64, - ELEMENTS_PER_WORK_ITEM = (256/WG_SIZE), - BITS_PER_PASS = 4, - - // if you change this, change nPerWI in kernel as well - NUM_WGS = 20*6, // cypress -// NUM_WGS = 24*6, // cayman -// NUM_WGS = 32*4, // nv - }; - - struct ConstData - { - int m_n; - int m_nWGs; - int m_startBit; - int m_nBlocksPerWG; - }; - - struct Data - { - const Device* m_device; - int m_maxSize; - - Kernel* m_streamCountKernel; - Kernel* m_streamCountSortDataKernel; - Kernel* m_prefixScanKernel; - Kernel* m_sortAndScatterKernel; - Kernel* m_sortAndScatterKeyValueKernel; - Kernel* m_sortAndScatterSortDataKernel; - - Buffer* m_workBuffer0; - Buffer* m_workBuffer1; - Buffer* m_workBuffer2; - Buffer* m_workBuffer3; - - Buffer* m_constBuffer[32/BITS_PER_PASS]; - - typename Copy::Data* m_copyData; - }; - - static - Data* allocate(const Device* device, int maxSize); - - static - void deallocate(Data* data); - - static - void execute(Data* data, Buffer& inout, int n, int sortBits = 32); - - static - void execute(Data* data, Buffer& in, Buffer& out, int n, int sortBits = 32); - - static - void execute(Data* data, Buffer& keysIn, Buffer& keysOut, Buffer& valuesIn, Buffer& valuesOut, int n, int sortBits = 32); - - static - void execute(Data* data, Buffer& keyValuesInOut, int n, int sortBits = 32 ); -}; - - -#include -#include - -}; diff --git a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Sort/RadixSort32.inl b/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Sort/RadixSort32.inl deleted file mode 100644 index 468943227..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Sort/RadixSort32.inl +++ /dev/null @@ -1,346 +0,0 @@ -/* - 2011 Takahiro Harada -*/ - -#define PATH "..\\..\\opencl\\primitives\\AdlPrimitives\\Sort\\RadixSort32Kernels" -#define RADIXSORT32_KERNEL0 "StreamCountKernel" -#define RADIXSORT32_KERNEL1 "PrefixScanKernel" -#define RADIXSORT32_KERNEL2 "SortAndScatterKernel" -#define RADIXSORT32_KERNEL3 "SortAndScatterKeyValueKernel" -#define RADIXSORT32_KERNEL4 "SortAndScatterSortDataKernel" -#define RADIXSORT32_KERNEL5 "StreamCountSortDataKernel" - -#include "RadixSort32KernelsCL.h" -#include "RadixSort32KernelsDX11.h" - -// todo. Shader compiler (2010JuneSDK) doesn't allow me to place Barriers in SortAndScatterKernel... -// So it only works on a GPU with 64 wide SIMD. - -template -typename RadixSort32::Data* RadixSort32::allocate( const Device* device, int maxSize ) -{ - ADLASSERT( TYPE == device->m_type ); - - const char* src[] = -#if defined(ADL_LOAD_KERNEL_FROM_STRING) - {radixSort32KernelsCL, radixSort32KernelsDX11}; -#else - {0,0}; -#endif - - Data* data = new Data; - data->m_device = device; - data->m_maxSize = maxSize; - data->m_streamCountKernel = device->getKernel( PATH, RADIXSORT32_KERNEL0, 0, src[TYPE] ); - data->m_streamCountSortDataKernel = device->getKernel( PATH, RADIXSORT32_KERNEL5, 0, src[TYPE] ); - - - - data->m_prefixScanKernel = device->getKernel( PATH, RADIXSORT32_KERNEL1, 0, src[TYPE] ); - data->m_sortAndScatterKernel = device->getKernel( PATH, RADIXSORT32_KERNEL2, 0, src[TYPE] ); - data->m_sortAndScatterKeyValueKernel = device->getKernel( PATH, RADIXSORT32_KERNEL3, 0, src[TYPE] ); - data->m_sortAndScatterSortDataKernel = device->getKernel( PATH, RADIXSORT32_KERNEL4, 0, src[TYPE] ); - - int wtf = NUM_WGS*(1<m_workBuffer0 = new Buffer( device, maxSize ); - data->m_workBuffer1 = new Buffer( device , wtf ); - data->m_workBuffer2 = new Buffer( device, maxSize ); - data->m_workBuffer3 = new Buffer(device,maxSize); - - - for(int i=0; i<32/BITS_PER_PASS; i++) - data->m_constBuffer[i] = new Buffer( device, 1, BufferBase::BUFFER_CONST ); - - data->m_copyData = Copy::allocate( device ); - - return data; -} - -template -void RadixSort32::deallocate( Data* data ) -{ - delete data->m_workBuffer0; - delete data->m_workBuffer1; - delete data->m_workBuffer2; - delete data->m_workBuffer3; - - for(int i=0; i<32/BITS_PER_PASS; i++) - delete data->m_constBuffer[i]; - - Copy::deallocate( data->m_copyData ); - - delete data; -} - -template -void RadixSort32::execute(Data* data, Buffer& inout, int n, int sortBits /* = 32 */ ) -{ - ADLASSERT( n%DATA_ALIGNMENT == 0 ); - ADLASSERT( n <= data->m_maxSize ); -// ADLASSERT( ELEMENTS_PER_WORK_ITEM == 4 ); - ADLASSERT( BITS_PER_PASS == 4 ); - ADLASSERT( WG_SIZE == 64 ); - ADLASSERT( (sortBits&0x3) == 0 ); - - Buffer* src = &inout; - Buffer* dst = data->m_workBuffer0; - Buffer* histogramBuffer = data->m_workBuffer1; - - int nWGs = NUM_WGS; - ConstData cdata; - { - int nBlocks = (n+ELEMENTS_PER_WORK_ITEM*WG_SIZE-1)/(ELEMENTS_PER_WORK_ITEM*WG_SIZE); - - cdata.m_n = n; - cdata.m_nWGs = NUM_WGS; - cdata.m_startBit = 0; - cdata.m_nBlocksPerWG = (nBlocks + cdata.m_nWGs - 1)/cdata.m_nWGs; - - if( nBlocks < NUM_WGS ) - { - cdata.m_nBlocksPerWG = 1; - nWGs = nBlocks; - } - } - - for(int ib=0; ibm_device, data->m_streamCountKernel ); - launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(Launcher::BufferInfo) ); - launcher.setConst( *data->m_constBuffer[ib/4], cdata ); - launcher.launch1D( NUM_WGS*WG_SIZE, WG_SIZE ); - } - {// prefix scan group histogram - BufferInfo bInfo[] = { BufferInfo( histogramBuffer ) }; - Launcher launcher( data->m_device, data->m_prefixScanKernel ); - launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(Launcher::BufferInfo) ); - launcher.setConst( *data->m_constBuffer[ib/4], cdata ); - launcher.launch1D( 128, 128 ); - } - {// local sort and distribute - BufferInfo bInfo[] = { BufferInfo( src, true ), BufferInfo( histogramBuffer, true ), BufferInfo( dst ) }; - Launcher launcher( data->m_device, data->m_sortAndScatterKernel ); - launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(Launcher::BufferInfo) ); - launcher.setConst( *data->m_constBuffer[ib/4], cdata ); - launcher.launch1D( nWGs*WG_SIZE, WG_SIZE ); - } - swap2( src, dst ); - } - - if( src != &inout ) - { - Copy::execute( data->m_copyData, (Buffer&)inout, (Buffer&)*src, n ); - } -} - -template -void RadixSort32::execute(Data* data, Buffer& in, Buffer& out, int n, int sortBits /* = 32 */ ) -{ - ADLASSERT( n%DATA_ALIGNMENT == 0 ); - ADLASSERT( n <= data->m_maxSize ); -// ADLASSERT( ELEMENTS_PER_WORK_ITEM == 4 ); - ADLASSERT( BITS_PER_PASS == 4 ); - ADLASSERT( WG_SIZE == 64 ); - ADLASSERT( (sortBits&0x3) == 0 ); - - Buffer* src = ∈ - Buffer* dst = data->m_workBuffer0; - Buffer* histogramBuffer = data->m_workBuffer1; - - int nWGs = NUM_WGS; - ConstData cdata; - { - int nBlocks = (n+ELEMENTS_PER_WORK_ITEM*WG_SIZE-1)/(ELEMENTS_PER_WORK_ITEM*WG_SIZE); - cdata.m_n = n; - cdata.m_nWGs = NUM_WGS; - cdata.m_startBit = 0; - cdata.m_nBlocksPerWG = (nBlocks + cdata.m_nWGs - 1)/cdata.m_nWGs; - if( nBlocks < NUM_WGS ) - { - cdata.m_nBlocksPerWG = 1; - nWGs = nBlocks; - } - } - - if( sortBits == 4 ) dst = &out; - - for(int ib=0; ibm_device, data->m_streamCountKernel ); - launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(Launcher::BufferInfo) ); - launcher.setConst( *data->m_constBuffer[ib/4], cdata ); - launcher.launch1D( NUM_WGS*WG_SIZE, WG_SIZE ); - } - {// prefix scan group histogram - BufferInfo bInfo[] = { BufferInfo( histogramBuffer ) }; - Launcher launcher( data->m_device, data->m_prefixScanKernel ); - launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(Launcher::BufferInfo) ); - launcher.setConst( *data->m_constBuffer[ib/4], cdata ); - launcher.launch1D( 128, 128 ); - } - {// local sort and distribute - BufferInfo bInfo[] = { BufferInfo( src, true ), BufferInfo( histogramBuffer, true ), BufferInfo( dst ) }; - Launcher launcher( data->m_device, data->m_sortAndScatterKernel ); - launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(Launcher::BufferInfo) ); - launcher.setConst( *data->m_constBuffer[ib/4], cdata ); - launcher.launch1D( nWGs*WG_SIZE, WG_SIZE ); - } - swap2( src, dst ); - } -} - -template -void RadixSort32::execute(Data* data, Buffer& keysIn, Buffer& keysOut, Buffer& valuesIn, Buffer& valuesOut, int n, int sortBits /* = 32 */) -{ - ADLASSERT( n%DATA_ALIGNMENT == 0 ); - ADLASSERT( n <= data->m_maxSize ); -// ADLASSERT( ELEMENTS_PER_WORK_ITEM == 4 ); - ADLASSERT( BITS_PER_PASS == 4 ); - ADLASSERT( WG_SIZE == 64 ); - ADLASSERT( (sortBits&0x3) == 0 ); - - Buffer* src = &keysIn; - Buffer* srcVal = &valuesIn; - Buffer* dst = data->m_workBuffer0; - Buffer* dstVal = data->m_workBuffer2; - Buffer* histogramBuffer = data->m_workBuffer1; - - int nWGs = NUM_WGS; - ConstData cdata; - { - int nBlocks = (n+ELEMENTS_PER_WORK_ITEM*WG_SIZE-1)/(ELEMENTS_PER_WORK_ITEM*WG_SIZE); - cdata.m_n = n; - cdata.m_nWGs = NUM_WGS; - cdata.m_startBit = 0; - cdata.m_nBlocksPerWG = (nBlocks + cdata.m_nWGs - 1)/cdata.m_nWGs; - if( nBlocks < NUM_WGS ) - { - cdata.m_nBlocksPerWG = 1; - nWGs = nBlocks; - } - } - - if( sortBits == 4 ) - { - dst = &keysOut; - dstVal = &valuesOut; - } - - for(int ib=0; ibm_device, data->m_streamCountKernel ); - launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(Launcher::BufferInfo) ); - launcher.setConst( *data->m_constBuffer[ib/4], cdata ); - launcher.launch1D( NUM_WGS*WG_SIZE, WG_SIZE ); - } - {// prefix scan group histogram - BufferInfo bInfo[] = { BufferInfo( histogramBuffer ) }; - Launcher launcher( data->m_device, data->m_prefixScanKernel ); - launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(Launcher::BufferInfo) ); - launcher.setConst( *data->m_constBuffer[ib/4], cdata ); - launcher.launch1D( 128, 128 ); - } - {// local sort and distribute - BufferInfo bInfo[] = { BufferInfo( src, true ), BufferInfo( srcVal, true ), BufferInfo( histogramBuffer, true ), BufferInfo( dst ), BufferInfo( dstVal ) }; - Launcher launcher( data->m_device, data->m_sortAndScatterKeyValueKernel ); - launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(Launcher::BufferInfo) ); - launcher.setConst( *data->m_constBuffer[ib/4], cdata ); - launcher.launch1D( nWGs*WG_SIZE, WG_SIZE ); - } - swap2( src, dst ); - swap2( srcVal, dstVal ); - } -} - -template -void RadixSort32::execute(Data* data, Buffer& keyValuesInOut, int n, int sortBits /* = 32 */) -{ - ADLASSERT( n%DATA_ALIGNMENT == 0 ); - ADLASSERT( n <= data->m_maxSize ); -// ADLASSERT( ELEMENTS_PER_WORK_ITEM == 4 ); - ADLASSERT( BITS_PER_PASS == 4 ); - ADLASSERT( WG_SIZE == 64 ); - ADLASSERT( (sortBits&0x3) == 0 ); - - Buffer* src = &keyValuesInOut; - Buffer* dst = data->m_workBuffer3; - - Buffer* histogramBuffer = data->m_workBuffer1; - - int nWGs = NUM_WGS; - ConstData cdata; - { - int nBlocks = (n+ELEMENTS_PER_WORK_ITEM*WG_SIZE-1)/(ELEMENTS_PER_WORK_ITEM*WG_SIZE); - cdata.m_n = n; - cdata.m_nWGs = NUM_WGS; - cdata.m_startBit = 0; - cdata.m_nBlocksPerWG = (nBlocks + cdata.m_nWGs - 1)/cdata.m_nWGs; - if( nBlocks < NUM_WGS ) - { - cdata.m_nBlocksPerWG = 1; - nWGs = nBlocks; - } - } - - int count=0; - for(int ib=0; ibm_device, data->m_streamCountSortDataKernel); - launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(Launcher::BufferInfo) ); - launcher.setConst( *data->m_constBuffer[ib/4], cdata ); - launcher.launch1D( NUM_WGS*WG_SIZE, WG_SIZE ); - } - {// prefix scan group histogram - BufferInfo bInfo[] = { BufferInfo( histogramBuffer ) }; - Launcher launcher( data->m_device, data->m_prefixScanKernel ); - launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(Launcher::BufferInfo) ); - launcher.setConst( *data->m_constBuffer[ib/4], cdata ); - launcher.launch1D( 128, 128 ); - } - {// local sort and distribute - BufferInfo bInfo[] = { BufferInfo( src, true ), BufferInfo( histogramBuffer, true ), BufferInfo( dst )}; - Launcher launcher( data->m_device, data->m_sortAndScatterSortDataKernel ); - launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(Launcher::BufferInfo) ); - launcher.setConst( *data->m_constBuffer[ib/4], cdata ); - launcher.launch1D( nWGs*WG_SIZE, WG_SIZE ); - } - swap2( src, dst ); - count++; - } - - if (count&1) - { - ADLASSERT(0);//need to copy from workbuffer to keyValuesInOut - - } -} -#undef PATH -#undef RADIXSORT32_KERNEL0 -#undef RADIXSORT32_KERNEL1 -#undef RADIXSORT32_KERNEL2 -#undef RADIXSORT32_KERNEL3 - diff --git a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Sort/RadixSort32Host.inl b/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Sort/RadixSort32Host.inl deleted file mode 100644 index 7e174f48d..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Sort/RadixSort32Host.inl +++ /dev/null @@ -1,163 +0,0 @@ -/* - 2011 Takahiro Harada -*/ - -template<> -class RadixSort32 : public RadixSort32Base -{ - public: - typedef Launcher::BufferInfo BufferInfo; - - enum - { - BITS_PER_PASS = 8, - NUM_TABLES = (1<* m_workBuffer; - }; - - static - Data* allocate(const Device* device, int maxSize) - { - ADLASSERT( device->m_type == TYPE_HOST ); - - Data* data = new Data; - data->m_workBuffer = new HostBuffer( device, maxSize ); - return data; - } - - static - void deallocate(Data* data) - { - delete data->m_workBuffer; - delete data; - } - - static - void execute(Data* data, Buffer& inout, int n, int sortBits = 32) - { - ADLASSERT( inout.getType() == TYPE_HOST ); - - int tables[NUM_TABLES]; - int counter[NUM_TABLES]; - - u32* src = inout.m_ptr; - u32* dst = data->m_workBuffer->m_ptr; - - for(int startBit=0; startBit> startBit) & (NUM_TABLES-1); - tables[tableIdx]++; - } - - // prefix scan - int sum = 0; - for(int i=0; i> startBit) & (NUM_TABLES-1); - - dst[tables[tableIdx] + counter[tableIdx]] = src[i]; - counter[tableIdx] ++; - } - - swap2( src, dst ); - } - - { - if( src != inout.m_ptr ) - { - memcpy( dst, src, sizeof(u32)*n ); - } - } - - } - - static - void execute(Data* data, Buffer& keyInout, const Buffer& valueInout, int n, int sortBits = 32) - { - ADLASSERT( keyInout.getType() == TYPE_HOST ); - - int tables[NUM_TABLES]; - int counter[NUM_TABLES]; - - u32* src = keyInout.m_ptr; - u32* dst = data->m_workBuffer->m_ptr; - - HostBuffer bufVal(valueInout.m_device, valueInout.m_size); - bufVal.write(valueInout.m_ptr, valueInout.m_size); - - u32* srcVal = valueInout.m_ptr; - u32* dstVal = bufVal.m_ptr; - - for(int startBit=0; startBit> startBit) & (NUM_TABLES-1); - tables[tableIdx]++; - } - - // prefix scan - int sum = 0; - for(int i=0; i> startBit) & (NUM_TABLES-1); - int newIdx = tables[tableIdx] + counter[tableIdx]; - dst[newIdx] = src[i]; - dstVal[newIdx] = srcVal[i]; - counter[tableIdx]++; - } - - swap2( src, dst ); - swap2( srcVal, dstVal ); - } - - { - if( src != keyInout.m_ptr ) - { - memcpy( dst, src, sizeof(u32)*n ); - } - - if( srcVal != valueInout.m_ptr ) - { - memcpy( dstVal, srcVal, sizeof(u32)*n ); - } - } - - } -}; - - diff --git a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Sort/RadixSort32Kernels.cl b/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Sort/RadixSort32Kernels.cl deleted file mode 100644 index 44dd9a90f..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Sort/RadixSort32Kernels.cl +++ /dev/null @@ -1,1104 +0,0 @@ -/* -Bullet Continuous Collision Detection and Physics Library -Copyright (c) 2011 Advanced Micro Devices, Inc. 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. -*/ -//Author Takahiro Harada - - -//#pragma OPENCL EXTENSION cl_amd_printf : enable -#pragma OPENCL EXTENSION cl_khr_local_int32_base_atomics : enable -#pragma OPENCL EXTENSION cl_khr_global_int32_base_atomics : enable - -typedef unsigned int u32; -#define GET_GROUP_IDX get_group_id(0) -#define GET_LOCAL_IDX get_local_id(0) -#define GET_GLOBAL_IDX get_global_id(0) -#define GET_GROUP_SIZE get_local_size(0) -#define GROUP_LDS_BARRIER barrier(CLK_LOCAL_MEM_FENCE) -#define GROUP_MEM_FENCE mem_fence(CLK_LOCAL_MEM_FENCE) -#define AtomInc(x) atom_inc(&(x)) -#define AtomInc1(x, out) out = atom_inc(&(x)) -#define AtomAdd(x, value) atom_add(&(x), value) - -#define SELECT_UINT4( b, a, condition ) select( b,a,condition ) - - -#define make_uint4 (uint4) -#define make_uint2 (uint2) -#define make_int2 (int2) - -#define WG_SIZE 64 -#define ELEMENTS_PER_WORK_ITEM (256/WG_SIZE) -#define BITS_PER_PASS 4 -#define NUM_BUCKET (1< 64 ) - { - sorterSharedMemory[idx] += sorterSharedMemory[idx-64]; - GROUP_MEM_FENCE; - } - - sorterSharedMemory[idx-1] += sorterSharedMemory[idx-2]; - GROUP_MEM_FENCE; - } -#else - if( lIdx < 64 ) - { - sorterSharedMemory[idx] += sorterSharedMemory[idx-1]; - GROUP_MEM_FENCE; - sorterSharedMemory[idx] += sorterSharedMemory[idx-2]; - GROUP_MEM_FENCE; - sorterSharedMemory[idx] += sorterSharedMemory[idx-4]; - GROUP_MEM_FENCE; - sorterSharedMemory[idx] += sorterSharedMemory[idx-8]; - GROUP_MEM_FENCE; - sorterSharedMemory[idx] += sorterSharedMemory[idx-16]; - GROUP_MEM_FENCE; - sorterSharedMemory[idx] += sorterSharedMemory[idx-32]; - GROUP_MEM_FENCE; - if( wgSize > 64 ) - { - sorterSharedMemory[idx] += sorterSharedMemory[idx-64]; - GROUP_MEM_FENCE; - } - - sorterSharedMemory[idx-1] += sorterSharedMemory[idx-2]; - GROUP_MEM_FENCE; - } -#endif - } - - GROUP_LDS_BARRIER; - - *totalSum = sorterSharedMemory[wgSize*2-1]; - u32 addValue = sorterSharedMemory[lIdx+wgSize-1]; - return addValue; -} - -//__attribute__((reqd_work_group_size(128,1,1))) -uint4 localPrefixSum128V( uint4 pData, uint lIdx, uint* totalSum, __local u32 sorterSharedMemory[] ) -{ - u32 s4 = prefixScanVectorEx( &pData ); - u32 rank = localPrefixSum( s4, lIdx, totalSum, sorterSharedMemory, 128 ); - return pData + make_uint4( rank, rank, rank, rank ); -} - - -//__attribute__((reqd_work_group_size(64,1,1))) -uint4 localPrefixSum64V( uint4 pData, uint lIdx, uint* totalSum, __local u32 sorterSharedMemory[] ) -{ - u32 s4 = prefixScanVectorEx( &pData ); - u32 rank = localPrefixSum( s4, lIdx, totalSum, sorterSharedMemory, 64 ); - return pData + make_uint4( rank, rank, rank, rank ); -} - -u32 unpack4Key( u32 key, int keyIdx ){ return (key>>(keyIdx*8)) & 0xff;} - -u32 bit8Scan(u32 v) -{ - return (v<<8) + (v<<16) + (v<<24); -} - -//=== - - - - -#define MY_HISTOGRAM(idx) localHistogramMat[(idx)*WG_SIZE+lIdx] - - -__kernel -__attribute__((reqd_work_group_size(WG_SIZE,1,1))) -void StreamCountKernel( __global u32* gSrc, __global u32* histogramOut, ConstBuffer cb ) -{ - __local u32 localHistogramMat[NUM_BUCKET*WG_SIZE]; - - u32 gIdx = GET_GLOBAL_IDX; - u32 lIdx = GET_LOCAL_IDX; - u32 wgIdx = GET_GROUP_IDX; - u32 wgSize = GET_GROUP_SIZE; - const int startBit = cb.m_startBit; - const int n = cb.m_n; - const int nWGs = cb.m_nWGs; - const int nBlocksPerWG = cb.m_nBlocksPerWG; - - for(int i=0; i>startBit) & 0xf; -#if defined(NV_GPU) - MY_HISTOGRAM( localKey )++; -#else - AtomInc( MY_HISTOGRAM( localKey ) ); -#endif - } - } - } - - GROUP_LDS_BARRIER; - - if( lIdx < NUM_BUCKET ) - { - u32 sum = 0; - for(int i=0; i>startBit) & 0xf; -#if defined(NV_GPU) - MY_HISTOGRAM( localKey )++; -#else - AtomInc( MY_HISTOGRAM( localKey ) ); -#endif - } - } - } - - GROUP_LDS_BARRIER; - - if( lIdx < NUM_BUCKET ) - { - u32 sum = 0; - for(int i=0; i>startBit) & mask, (sortData[1]>>startBit) & mask, (sortData[2]>>startBit) & mask, (sortData[3]>>startBit) & mask ); - uint4 prefixSum = SELECT_UINT4( make_uint4(1,1,1,1), make_uint4(0,0,0,0), cmpResult != make_uint4(0,0,0,0) ); - u32 total; - prefixSum = localPrefixSum64V( prefixSum, lIdx, &total, ldsSortData ); - { - uint4 localAddr = make_uint4(lIdx*4+0,lIdx*4+1,lIdx*4+2,lIdx*4+3); - uint4 dstAddr = localAddr - prefixSum + make_uint4( total, total, total, total ); - dstAddr = SELECT_UINT4( prefixSum, dstAddr, cmpResult != make_uint4(0, 0, 0, 0) ); - - GROUP_LDS_BARRIER; - - ldsSortData[dstAddr.x] = sortData[0]; - ldsSortData[dstAddr.y] = sortData[1]; - ldsSortData[dstAddr.z] = sortData[2]; - ldsSortData[dstAddr.w] = sortData[3]; - - GROUP_LDS_BARRIER; - - sortData[0] = ldsSortData[localAddr.x]; - sortData[1] = ldsSortData[localAddr.y]; - sortData[2] = ldsSortData[localAddr.z]; - sortData[3] = ldsSortData[localAddr.w]; - - GROUP_LDS_BARRIER; - } - } -} - -// 2 scan, 2 exchange -void sort4Bits1(u32 sortData[4], int startBit, int lIdx, __local u32* ldsSortData) -{ - for(uint ibit=0; ibit>(startBit+ibit)) & 0x3, - (sortData[1]>>(startBit+ibit)) & 0x3, - (sortData[2]>>(startBit+ibit)) & 0x3, - (sortData[3]>>(startBit+ibit)) & 0x3); - - u32 key4; - u32 sKeyPacked[4] = { 0, 0, 0, 0 }; - { - sKeyPacked[0] |= 1<<(8*b.x); - sKeyPacked[1] |= 1<<(8*b.y); - sKeyPacked[2] |= 1<<(8*b.z); - sKeyPacked[3] |= 1<<(8*b.w); - - key4 = sKeyPacked[0] + sKeyPacked[1] + sKeyPacked[2] + sKeyPacked[3]; - } - - u32 rankPacked; - u32 sumPacked; - { - rankPacked = localPrefixSum( key4, lIdx, &sumPacked, ldsSortData, WG_SIZE ); - } - - GROUP_LDS_BARRIER; - - u32 newOffset[4] = { 0,0,0,0 }; - { - u32 sumScanned = bit8Scan( sumPacked ); - - u32 scannedKeys[4]; - scannedKeys[0] = 1<<(8*b.x); - scannedKeys[1] = 1<<(8*b.y); - scannedKeys[2] = 1<<(8*b.z); - scannedKeys[3] = 1<<(8*b.w); - { // 4 scans at once - u32 sum4 = 0; - for(int ie=0; ie<4; ie++) - { - u32 tmp = scannedKeys[ie]; - scannedKeys[ie] = sum4; - sum4 += tmp; - } - } - - { - u32 sumPlusRank = sumScanned + rankPacked; - { u32 ie = b.x; - scannedKeys[0] += sumPlusRank; - newOffset[0] = unpack4Key( scannedKeys[0], ie ); - } - { u32 ie = b.y; - scannedKeys[1] += sumPlusRank; - newOffset[1] = unpack4Key( scannedKeys[1], ie ); - } - { u32 ie = b.z; - scannedKeys[2] += sumPlusRank; - newOffset[2] = unpack4Key( scannedKeys[2], ie ); - } - { u32 ie = b.w; - scannedKeys[3] += sumPlusRank; - newOffset[3] = unpack4Key( scannedKeys[3], ie ); - } - } - } - - - GROUP_LDS_BARRIER; - - { - ldsSortData[newOffset[0]] = sortData[0]; - ldsSortData[newOffset[1]] = sortData[1]; - ldsSortData[newOffset[2]] = sortData[2]; - ldsSortData[newOffset[3]] = sortData[3]; - - GROUP_LDS_BARRIER; - - u32 dstAddr = 4*lIdx; - sortData[0] = ldsSortData[dstAddr+0]; - sortData[1] = ldsSortData[dstAddr+1]; - sortData[2] = ldsSortData[dstAddr+2]; - sortData[3] = ldsSortData[dstAddr+3]; - - GROUP_LDS_BARRIER; - } - } -} - -#define SET_HISTOGRAM(setIdx, key) ldsSortData[(setIdx)*NUM_BUCKET+key] - -__kernel -__attribute__((reqd_work_group_size(WG_SIZE,1,1))) -void SortAndScatterKernel( __global const u32* restrict gSrc, __global const u32* rHistogram, __global u32* restrict gDst, ConstBuffer cb ) -{ - __local u32 ldsSortData[WG_SIZE*ELEMENTS_PER_WORK_ITEM+16]; - __local u32 localHistogramToCarry[NUM_BUCKET]; - __local u32 localHistogram[NUM_BUCKET*2]; - - u32 gIdx = GET_GLOBAL_IDX; - u32 lIdx = GET_LOCAL_IDX; - u32 wgIdx = GET_GROUP_IDX; - u32 wgSize = GET_GROUP_SIZE; - - const int n = cb.m_n; - const int nWGs = cb.m_nWGs; - const int startBit = cb.m_startBit; - const int nBlocksPerWG = cb.m_nBlocksPerWG; - - if( lIdx < (NUM_BUCKET) ) - { - localHistogramToCarry[lIdx] = rHistogram[lIdx*nWGs + wgIdx]; - } - - GROUP_LDS_BARRIER; - - const int blockSize = ELEMENTS_PER_WORK_ITEM*WG_SIZE; - - int nBlocks = n/blockSize - nBlocksPerWG*wgIdx; - - int addr = blockSize*nBlocksPerWG*wgIdx + ELEMENTS_PER_WORK_ITEM*lIdx; - - for(int iblock=0; iblock>startBit) & 0xf; - - { // create histogram - u32 setIdx = lIdx/16; - if( lIdx < NUM_BUCKET ) - { - localHistogram[lIdx] = 0; - } - ldsSortData[lIdx] = 0; - GROUP_LDS_BARRIER; - - for(int i=0; i>(startBit+ibit)) & 0x3, - (sortData[1]>>(startBit+ibit)) & 0x3, - (sortData[2]>>(startBit+ibit)) & 0x3, - (sortData[3]>>(startBit+ibit)) & 0x3); - - u32 key4; - u32 sKeyPacked[4] = { 0, 0, 0, 0 }; - { - sKeyPacked[0] |= 1<<(8*b.x); - sKeyPacked[1] |= 1<<(8*b.y); - sKeyPacked[2] |= 1<<(8*b.z); - sKeyPacked[3] |= 1<<(8*b.w); - - key4 = sKeyPacked[0] + sKeyPacked[1] + sKeyPacked[2] + sKeyPacked[3]; - } - - u32 rankPacked; - u32 sumPacked; - { - rankPacked = localPrefixSum( key4, lIdx, &sumPacked, ldsSortData, WG_SIZE ); - } - - GROUP_LDS_BARRIER; - - u32 newOffset[4] = { 0,0,0,0 }; - { - u32 sumScanned = bit8Scan( sumPacked ); - - u32 scannedKeys[4]; - scannedKeys[0] = 1<<(8*b.x); - scannedKeys[1] = 1<<(8*b.y); - scannedKeys[2] = 1<<(8*b.z); - scannedKeys[3] = 1<<(8*b.w); - { // 4 scans at once - u32 sum4 = 0; - for(int ie=0; ie<4; ie++) - { - u32 tmp = scannedKeys[ie]; - scannedKeys[ie] = sum4; - sum4 += tmp; - } - } - - { - u32 sumPlusRank = sumScanned + rankPacked; - { u32 ie = b.x; - scannedKeys[0] += sumPlusRank; - newOffset[0] = unpack4Key( scannedKeys[0], ie ); - } - { u32 ie = b.y; - scannedKeys[1] += sumPlusRank; - newOffset[1] = unpack4Key( scannedKeys[1], ie ); - } - { u32 ie = b.z; - scannedKeys[2] += sumPlusRank; - newOffset[2] = unpack4Key( scannedKeys[2], ie ); - } - { u32 ie = b.w; - scannedKeys[3] += sumPlusRank; - newOffset[3] = unpack4Key( scannedKeys[3], ie ); - } - } - } - - - GROUP_LDS_BARRIER; - - { - ldsSortData[newOffset[0]] = sortData[0]; - ldsSortData[newOffset[1]] = sortData[1]; - ldsSortData[newOffset[2]] = sortData[2]; - ldsSortData[newOffset[3]] = sortData[3]; - - ldsSortVal[newOffset[0]] = sortVal[0]; - ldsSortVal[newOffset[1]] = sortVal[1]; - ldsSortVal[newOffset[2]] = sortVal[2]; - ldsSortVal[newOffset[3]] = sortVal[3]; - - GROUP_LDS_BARRIER; - - u32 dstAddr = 4*lIdx; - sortData[0] = ldsSortData[dstAddr+0]; - sortData[1] = ldsSortData[dstAddr+1]; - sortData[2] = ldsSortData[dstAddr+2]; - sortData[3] = ldsSortData[dstAddr+3]; - - sortVal[0] = ldsSortVal[dstAddr+0]; - sortVal[1] = ldsSortVal[dstAddr+1]; - sortVal[2] = ldsSortVal[dstAddr+2]; - sortVal[3] = ldsSortVal[dstAddr+3]; - - GROUP_LDS_BARRIER; - } - } -} - - - -__kernel -__attribute__((reqd_work_group_size(WG_SIZE,1,1))) -void SortAndScatterKeyValueKernel( __global const u32* restrict gSrc, __global const int* restrict gSrcVal, __global const u32* rHistogram, __global u32* restrict gDst, __global int* restrict gDstVal, ConstBuffer cb) -{ - __local u32 ldsSortData[WG_SIZE*ELEMENTS_PER_WORK_ITEM+16]; - __local int ldsSortVal[WG_SIZE*ELEMENTS_PER_WORK_ITEM+16]; - __local u32 localHistogramToCarry[NUM_BUCKET]; - __local u32 localHistogram[NUM_BUCKET*2]; - - u32 gIdx = GET_GLOBAL_IDX; - u32 lIdx = GET_LOCAL_IDX; - u32 wgIdx = GET_GROUP_IDX; - u32 wgSize = GET_GROUP_SIZE; - - const int n = cb.m_n; - const int nWGs = cb.m_nWGs; - const int startBit = cb.m_startBit; - const int nBlocksPerWG = cb.m_nBlocksPerWG; - - if( lIdx < (NUM_BUCKET) ) - { - localHistogramToCarry[lIdx] = rHistogram[lIdx*nWGs + wgIdx]; - } - - GROUP_LDS_BARRIER; - - const int blockSize = ELEMENTS_PER_WORK_ITEM*WG_SIZE; - - int nBlocks = n/blockSize - nBlocksPerWG*wgIdx; - - int addr = blockSize*nBlocksPerWG*wgIdx + ELEMENTS_PER_WORK_ITEM*lIdx; - - for(int iblock=0; iblock>startBit) & 0xf; - - { // create histogram - u32 setIdx = lIdx/16; - if( lIdx < NUM_BUCKET ) - { - localHistogram[lIdx] = 0; - } - ldsSortData[lIdx] = 0; - GROUP_LDS_BARRIER; - - for(int i=0; i>startBit) & 0xf; - - { // create histogram - u32 setIdx = lIdx/16; - if( lIdx < NUM_BUCKET ) - { - localHistogram[lIdx] = 0; - } - ldsSortData[lIdx] = 0; - GROUP_LDS_BARRIER; - - for(int i=0; i gSrc : register( t0 ); -StructuredBuffer gSrcVal : register( t1 ); -StructuredBuffer rHistogram : register( t1 ); -StructuredBuffer rHistogram2 : register( t2 ); -RWStructuredBuffer histogramOut : register( u0 ); -RWStructuredBuffer wHistogram1 : register( u0 ); -RWStructuredBuffer gDst : register( u0 ); -RWStructuredBuffer gDstVal : register( u1 ); - -groupshared u32 localHistogramMat[NUM_BUCKET*WG_SIZE]; -#define MY_HISTOGRAM(idx) localHistogramMat[(idx)*WG_SIZE+lIdx] - - -[numthreads(WG_SIZE, 1, 1)] -void StreamCountKernel( DEFAULT_ARGS ) -{ - u32 gIdx = GET_GLOBAL_IDX; - u32 lIdx = GET_LOCAL_IDX; - u32 wgIdx = GET_GROUP_IDX; - u32 wgSize = GET_GROUP_SIZE; - const int startBit = m_startBit; - - const int n = m_n; - const int nWGs = m_nWGs; - const int nBlocksPerWG = m_nBlocksPerWG; - - for(int i=0; i>startBit) & 0xf; -#if defined(NV_GPU) - MY_HISTOGRAM( localKey )++; -#else - AtomInc( MY_HISTOGRAM( localKey ) ); -#endif - } - } - } - - GROUP_LDS_BARRIER; - - if( lIdx < NUM_BUCKET ) - { - u32 sum = 0; - for(int i=0; i 64 ) - { - ldsSortData[idx] += ldsSortData[idx-64]; - GROUP_MEM_FENCE; - } - - ldsSortData[idx-1] += ldsSortData[idx-2]; - GROUP_MEM_FENCE; - } -#else - if( lIdx < 64 ) - { - ldsSortData[idx] += ldsSortData[idx-1]; - GROUP_MEM_FENCE; - ldsSortData[idx] += ldsSortData[idx-2]; - GROUP_MEM_FENCE; - ldsSortData[idx] += ldsSortData[idx-4]; - GROUP_MEM_FENCE; - ldsSortData[idx] += ldsSortData[idx-8]; - GROUP_MEM_FENCE; - ldsSortData[idx] += ldsSortData[idx-16]; - GROUP_MEM_FENCE; - ldsSortData[idx] += ldsSortData[idx-32]; - GROUP_MEM_FENCE; - if( wgSize > 64 ) - { - ldsSortData[idx] += ldsSortData[idx-64]; - GROUP_MEM_FENCE; - } - - ldsSortData[idx-1] += ldsSortData[idx-2]; - GROUP_MEM_FENCE; - } -#endif - } - - GROUP_LDS_BARRIER; - - totalSum = ldsSortData[wgSize*2-1]; - u32 addValue = ldsSortData[lIdx+wgSize-1]; - return addValue; -} - -//__attribute__((reqd_work_group_size(128,1,1))) -uint4 localPrefixSum128V( uint4 pData, uint lIdx, inout uint totalSum ) -{ - u32 s4 = prefixScanVectorEx( pData ); - u32 rank = localPrefixSum( s4, lIdx, totalSum, 128 ); - return pData + make_uint4( rank, rank, rank, rank ); -} - -//__attribute__((reqd_work_group_size(64,1,1))) -uint4 localPrefixSum64V( uint4 pData, uint lIdx, inout uint totalSum ) -{ - u32 s4 = prefixScanVectorEx( pData ); - u32 rank = localPrefixSum( s4, lIdx, totalSum, 64 ); - return pData + make_uint4( rank, rank, rank, rank ); -} - - - - - -#define nPerLane (nPerWI/4) - -// NUM_BUCKET*nWGs < 128*nPerWI -[numthreads(128, 1, 1)] -void PrefixScanKernel( DEFAULT_ARGS ) -{ - u32 lIdx = GET_LOCAL_IDX; - u32 wgIdx = GET_GROUP_IDX; - const int nWGs = m_nWGs; - - u32 data[nPerWI]; - for(int i=0; i>(keyIdx*8)) & 0xff;} - -u32 bit8Scan(u32 v) -{ - return (v<<8) + (v<<16) + (v<<24); -} - - - - -void sort4Bits1(inout u32 sortData[4], int startBit, int lIdx) -{ -/* - for(uint ibit=0; ibit>(startBit+ibit)) & 0x3, - (sortData[1]>>(startBit+ibit)) & 0x3, - (sortData[2]>>(startBit+ibit)) & 0x3, - (sortData[3]>>(startBit+ibit)) & 0x3); - - u32 key4; - u32 sKeyPacked[4] = { 0, 0, 0, 0 }; - { - sKeyPacked[0] |= 1<<(8*b.x); - sKeyPacked[1] |= 1<<(8*b.y); - sKeyPacked[2] |= 1<<(8*b.z); - sKeyPacked[3] |= 1<<(8*b.w); - - key4 = sKeyPacked[0] + sKeyPacked[1] + sKeyPacked[2] + sKeyPacked[3]; - } - - u32 rankPacked; - u32 sumPacked; - { - rankPacked = localPrefixSum64VSingle( key4, lIdx, sumPacked ); - } - -// GROUP_LDS_BARRIER; - - u32 sum[4] = { unpack4Key( sumPacked,0 ), unpack4Key( sumPacked,1 ), unpack4Key( sumPacked,2 ), unpack4Key( sumPacked,3 ) }; - - { - u32 sum4 = 0; - for(int ie=0; ie<4; ie++) - { - u32 tmp = sum[ie]; - sum[ie] = sum4; - sum4 += tmp; - } - } - - u32 newOffset[4] = { 0,0,0,0 }; - - for(int ie=0; ie<4; ie++) - { - uint4 key = extractKeys( b, ie ); - uint4 scannedKey = key; - prefixScanVectorEx( scannedKey ); - uint offset = sum[ie] + unpack4Key( rankPacked, ie ); - uint4 dstAddress = make_uint4( offset, offset, offset, offset ) + scannedKey; - - newOffset[0] += dstAddress.x*key.x; - newOffset[1] += dstAddress.y*key.y; - newOffset[2] += dstAddress.z*key.z; - newOffset[3] += dstAddress.w*key.w; - } - - - - { - ldsSortData[newOffset[0]] = sortData[0]; - ldsSortData[newOffset[1]] = sortData[1]; - ldsSortData[newOffset[2]] = sortData[2]; - ldsSortData[newOffset[3]] = sortData[3]; - -// GROUP_LDS_BARRIER; - - sortData[0] = ldsSortData[lIdx*4+0]; - sortData[1] = ldsSortData[lIdx*4+1]; - sortData[2] = ldsSortData[lIdx*4+2]; - sortData[3] = ldsSortData[lIdx*4+3]; - -// GROUP_LDS_BARRIER; - } - } -*/ - for(uint ibit=0; ibit>(startBit+ibit)) & 0x3, - (sortData[1]>>(startBit+ibit)) & 0x3, - (sortData[2]>>(startBit+ibit)) & 0x3, - (sortData[3]>>(startBit+ibit)) & 0x3); - - u32 key4; - u32 sKeyPacked[4] = { 0, 0, 0, 0 }; - { - sKeyPacked[0] |= 1<<(8*b.x); - sKeyPacked[1] |= 1<<(8*b.y); - sKeyPacked[2] |= 1<<(8*b.z); - sKeyPacked[3] |= 1<<(8*b.w); - - key4 = sKeyPacked[0] + sKeyPacked[1] + sKeyPacked[2] + sKeyPacked[3]; - } - - u32 rankPacked; - u32 sumPacked; - { - rankPacked = localPrefixSum( key4, lIdx, sumPacked, WG_SIZE ); - } - - GROUP_LDS_BARRIER; - - u32 newOffset[4] = { 0,0,0,0 }; - { - u32 sumScanned = bit8Scan( sumPacked ); - - u32 scannedKeys[4]; - scannedKeys[0] = 1<<(8*b.x); - scannedKeys[1] = 1<<(8*b.y); - scannedKeys[2] = 1<<(8*b.z); - scannedKeys[3] = 1<<(8*b.w); - { // 4 scans at once - u32 sum4 = 0; - for(int ie=0; ie<4; ie++) - { - u32 tmp = scannedKeys[ie]; - scannedKeys[ie] = sum4; - sum4 += tmp; - } - } - - { - u32 sumPlusRank = sumScanned + rankPacked; - { u32 ie = b.x; - scannedKeys[0] += sumPlusRank; - newOffset[0] = unpack4Key( scannedKeys[0], ie ); - } - { u32 ie = b.y; - scannedKeys[1] += sumPlusRank; - newOffset[1] = unpack4Key( scannedKeys[1], ie ); - } - { u32 ie = b.z; - scannedKeys[2] += sumPlusRank; - newOffset[2] = unpack4Key( scannedKeys[2], ie ); - } - { u32 ie = b.w; - scannedKeys[3] += sumPlusRank; - newOffset[3] = unpack4Key( scannedKeys[3], ie ); - } - } - } - - - GROUP_LDS_BARRIER; - - { - ldsSortData[newOffset[0]] = sortData[0]; - ldsSortData[newOffset[1]] = sortData[1]; - ldsSortData[newOffset[2]] = sortData[2]; - ldsSortData[newOffset[3]] = sortData[3]; - - GROUP_LDS_BARRIER; - - u32 dstAddr = 4*lIdx; - sortData[0] = ldsSortData[dstAddr+0]; - sortData[1] = ldsSortData[dstAddr+1]; - sortData[2] = ldsSortData[dstAddr+2]; - sortData[3] = ldsSortData[dstAddr+3]; - - GROUP_LDS_BARRIER; - } - } -} - - -groupshared u32 localHistogramToCarry[NUM_BUCKET]; -groupshared u32 localHistogram[NUM_BUCKET*2]; -#define SET_HISTOGRAM(setIdx, key) ldsSortData[(setIdx)*NUM_BUCKET+key] - - -[numthreads(WG_SIZE, 1, 1)] -void SortAndScatterKernel( DEFAULT_ARGS ) -{ - u32 gIdx = GET_GLOBAL_IDX; - u32 lIdx = GET_LOCAL_IDX; - u32 wgIdx = GET_GROUP_IDX; - u32 wgSize = GET_GROUP_SIZE; - - const int n = m_n; - const int nWGs = m_nWGs; - const int startBit = m_startBit; - const int nBlocksPerWG = m_nBlocksPerWG; - - if( lIdx < (NUM_BUCKET) ) - { - localHistogramToCarry[lIdx] = rHistogram[lIdx*nWGs + wgIdx]; - } - - GROUP_LDS_BARRIER; - - const int blockSize = ELEMENTS_PER_WORK_ITEM*WG_SIZE; - - int nBlocks = n/blockSize - nBlocksPerWG*wgIdx; - - int addr = blockSize*nBlocksPerWG*wgIdx + ELEMENTS_PER_WORK_ITEM*lIdx; - - for(int iblock=0; iblock>startBit) & 0xf; - - { // create histogram - u32 setIdx = lIdx/16; - if( lIdx < NUM_BUCKET ) - { - localHistogram[lIdx] = 0; - } - ldsSortData[lIdx] = 0; - GROUP_LDS_BARRIER; - - for(int i=0; i>startBit) & 0xf; - - { // create histogram - if( lIdx < NUM_BUCKET ) - { - localHistogram[lIdx] = 0; - localHistogram[NUM_BUCKET+lIdx] = 0; - } -// GROUP_LDS_BARRIER; - - AtomInc( localHistogram[NUM_BUCKET+keys[0]] ); - AtomInc( localHistogram[NUM_BUCKET+keys[1]] ); - AtomInc( localHistogram[NUM_BUCKET+keys[2]] ); - AtomInc( localHistogram[NUM_BUCKET+keys[3]] ); - -// GROUP_LDS_BARRIER; - - uint hIdx = NUM_BUCKET+lIdx; - if( lIdx < NUM_BUCKET ) - { - myHistogram = localHistogram[hIdx]; - } -// GROUP_LDS_BARRIER; - -#if defined(USE_2LEVEL_REDUCE) - if( lIdx < NUM_BUCKET ) - { - localHistogram[hIdx] = localHistogram[hIdx-1]; - GROUP_MEM_FENCE; - - u32 u0, u1, u2; - u0 = localHistogram[hIdx-3]; - u1 = localHistogram[hIdx-2]; - u2 = localHistogram[hIdx-1]; - AtomAdd( localHistogram[hIdx], u0 + u1 + u2 ); - GROUP_MEM_FENCE; - u0 = localHistogram[hIdx-12]; - u1 = localHistogram[hIdx-8]; - u2 = localHistogram[hIdx-4]; - AtomAdd( localHistogram[hIdx], u0 + u1 + u2 ); - GROUP_MEM_FENCE; - } -#else - if( lIdx < NUM_BUCKET ) - { - localHistogram[hIdx] = localHistogram[hIdx-1]; - GROUP_MEM_FENCE; - localHistogram[hIdx] += localHistogram[hIdx-1]; - GROUP_MEM_FENCE; - localHistogram[hIdx] += localHistogram[hIdx-2]; - GROUP_MEM_FENCE; - localHistogram[hIdx] += localHistogram[hIdx-4]; - GROUP_MEM_FENCE; - localHistogram[hIdx] += localHistogram[hIdx-8]; - GROUP_MEM_FENCE; - } -#endif - -// GROUP_LDS_BARRIER; - } - - { - for(int ie=0; ie>(startBit+ibit)) & 0x3, - (sortData[1]>>(startBit+ibit)) & 0x3, - (sortData[2]>>(startBit+ibit)) & 0x3, - (sortData[3]>>(startBit+ibit)) & 0x3); - - u32 key4; - u32 sKeyPacked[4] = { 0, 0, 0, 0 }; - { - sKeyPacked[0] |= 1<<(8*b.x); - sKeyPacked[1] |= 1<<(8*b.y); - sKeyPacked[2] |= 1<<(8*b.z); - sKeyPacked[3] |= 1<<(8*b.w); - - key4 = sKeyPacked[0] + sKeyPacked[1] + sKeyPacked[2] + sKeyPacked[3]; - } - - u32 rankPacked; - u32 sumPacked; - { - rankPacked = localPrefixSum( key4, lIdx, sumPacked, WG_SIZE ); - } - - GROUP_LDS_BARRIER; - - u32 newOffset[4] = { 0,0,0,0 }; - { - u32 sumScanned = bit8Scan( sumPacked ); - - u32 scannedKeys[4]; - scannedKeys[0] = 1<<(8*b.x); - scannedKeys[1] = 1<<(8*b.y); - scannedKeys[2] = 1<<(8*b.z); - scannedKeys[3] = 1<<(8*b.w); - { // 4 scans at once - u32 sum4 = 0; - for(int ie=0; ie<4; ie++) - { - u32 tmp = scannedKeys[ie]; - scannedKeys[ie] = sum4; - sum4 += tmp; - } - } - - { - u32 sumPlusRank = sumScanned + rankPacked; - { u32 ie = b.x; - scannedKeys[0] += sumPlusRank; - newOffset[0] = unpack4Key( scannedKeys[0], ie ); - } - { u32 ie = b.y; - scannedKeys[1] += sumPlusRank; - newOffset[1] = unpack4Key( scannedKeys[1], ie ); - } - { u32 ie = b.z; - scannedKeys[2] += sumPlusRank; - newOffset[2] = unpack4Key( scannedKeys[2], ie ); - } - { u32 ie = b.w; - scannedKeys[3] += sumPlusRank; - newOffset[3] = unpack4Key( scannedKeys[3], ie ); - } - } - } - - - GROUP_LDS_BARRIER; - - { - ldsSortData[newOffset[0]] = sortData[0]; - ldsSortData[newOffset[1]] = sortData[1]; - ldsSortData[newOffset[2]] = sortData[2]; - ldsSortData[newOffset[3]] = sortData[3]; - - ldsSortVal[newOffset[0]] = sortVal[0]; - ldsSortVal[newOffset[1]] = sortVal[1]; - ldsSortVal[newOffset[2]] = sortVal[2]; - ldsSortVal[newOffset[3]] = sortVal[3]; - - GROUP_LDS_BARRIER; - - u32 dstAddr = 4*lIdx; - sortData[0] = ldsSortData[dstAddr+0]; - sortData[1] = ldsSortData[dstAddr+1]; - sortData[2] = ldsSortData[dstAddr+2]; - sortData[3] = ldsSortData[dstAddr+3]; - - sortVal[0] = ldsSortVal[dstAddr+0]; - sortVal[1] = ldsSortVal[dstAddr+1]; - sortVal[2] = ldsSortVal[dstAddr+2]; - sortVal[3] = ldsSortVal[dstAddr+3]; - - GROUP_LDS_BARRIER; - } - } -} - - - -[numthreads(WG_SIZE, 1, 1)] -void SortAndScatterKeyValueKernel( DEFAULT_ARGS ) -{ - u32 gIdx = GET_GLOBAL_IDX; - u32 lIdx = GET_LOCAL_IDX; - u32 wgIdx = GET_GROUP_IDX; - u32 wgSize = GET_GROUP_SIZE; - - const int n = m_n; - const int nWGs = m_nWGs; - const int startBit = m_startBit; - const int nBlocksPerWG = m_nBlocksPerWG; - - if( lIdx < (NUM_BUCKET) ) - { - localHistogramToCarry[lIdx] = rHistogram2[lIdx*nWGs + wgIdx]; - } - - GROUP_LDS_BARRIER; - - const int blockSize = ELEMENTS_PER_WORK_ITEM*WG_SIZE; - - int nBlocks = n/blockSize - nBlocksPerWG*wgIdx; - - int addr = blockSize*nBlocksPerWG*wgIdx + ELEMENTS_PER_WORK_ITEM*lIdx; - - for(int iblock=0; iblock>startBit) & 0xf; - - { // create histogram - u32 setIdx = lIdx/16; - if( lIdx < NUM_BUCKET ) - { - localHistogram[lIdx] = 0; - } - ldsSortData[lIdx] = 0; - GROUP_LDS_BARRIER; - - for(int i=0; i 64 )\n" -" {\n" -" sorterSharedMemory[idx] += sorterSharedMemory[idx-64];\n" -" GROUP_MEM_FENCE;\n" -" }\n" -"\n" -" sorterSharedMemory[idx-1] += sorterSharedMemory[idx-2];\n" -" GROUP_MEM_FENCE;\n" -" }\n" -"#else\n" -" if( lIdx < 64 )\n" -" {\n" -" sorterSharedMemory[idx] += sorterSharedMemory[idx-1];\n" -" GROUP_MEM_FENCE;\n" -" sorterSharedMemory[idx] += sorterSharedMemory[idx-2]; \n" -" GROUP_MEM_FENCE;\n" -" sorterSharedMemory[idx] += sorterSharedMemory[idx-4];\n" -" GROUP_MEM_FENCE;\n" -" sorterSharedMemory[idx] += sorterSharedMemory[idx-8];\n" -" GROUP_MEM_FENCE;\n" -" sorterSharedMemory[idx] += sorterSharedMemory[idx-16];\n" -" GROUP_MEM_FENCE;\n" -" sorterSharedMemory[idx] += sorterSharedMemory[idx-32];\n" -" GROUP_MEM_FENCE;\n" -" if( wgSize > 64 )\n" -" {\n" -" sorterSharedMemory[idx] += sorterSharedMemory[idx-64];\n" -" GROUP_MEM_FENCE;\n" -" }\n" -"\n" -" sorterSharedMemory[idx-1] += sorterSharedMemory[idx-2];\n" -" GROUP_MEM_FENCE;\n" -" }\n" -"#endif\n" -" }\n" -"\n" -" GROUP_LDS_BARRIER;\n" -"\n" -" *totalSum = sorterSharedMemory[wgSize*2-1];\n" -" u32 addValue = sorterSharedMemory[lIdx+wgSize-1];\n" -" return addValue;\n" -"}\n" -"\n" -"//__attribute__((reqd_work_group_size(128,1,1)))\n" -"uint4 localPrefixSum128V( uint4 pData, uint lIdx, uint* totalSum, __local u32 sorterSharedMemory[] )\n" -"{\n" -" u32 s4 = prefixScanVectorEx( &pData );\n" -" u32 rank = localPrefixSum( s4, lIdx, totalSum, sorterSharedMemory, 128 );\n" -" return pData + make_uint4( rank, rank, rank, rank );\n" -"}\n" -"\n" -"\n" -"//__attribute__((reqd_work_group_size(64,1,1)))\n" -"uint4 localPrefixSum64V( uint4 pData, uint lIdx, uint* totalSum, __local u32 sorterSharedMemory[] )\n" -"{\n" -" u32 s4 = prefixScanVectorEx( &pData );\n" -" u32 rank = localPrefixSum( s4, lIdx, totalSum, sorterSharedMemory, 64 );\n" -" return pData + make_uint4( rank, rank, rank, rank );\n" -"}\n" -"\n" -"u32 unpack4Key( u32 key, int keyIdx ){ return (key>>(keyIdx*8)) & 0xff;}\n" -"\n" -"u32 bit8Scan(u32 v)\n" -"{\n" -" return (v<<8) + (v<<16) + (v<<24);\n" -"}\n" -"\n" -"//===\n" -"\n" -"\n" -"\n" -"\n" -"#define MY_HISTOGRAM(idx) localHistogramMat[(idx)*WG_SIZE+lIdx]\n" -"\n" -"\n" -"__kernel\n" -"__attribute__((reqd_work_group_size(WG_SIZE,1,1)))\n" -"void StreamCountKernel( __global u32* gSrc, __global u32* histogramOut, ConstBuffer cb )\n" -"{\n" -" __local u32 localHistogramMat[NUM_BUCKET*WG_SIZE];\n" -"\n" -" u32 gIdx = GET_GLOBAL_IDX;\n" -" u32 lIdx = GET_LOCAL_IDX;\n" -" u32 wgIdx = GET_GROUP_IDX;\n" -" u32 wgSize = GET_GROUP_SIZE;\n" -" const int startBit = cb.m_startBit;\n" -" const int n = cb.m_n;\n" -" const int nWGs = cb.m_nWGs;\n" -" const int nBlocksPerWG = cb.m_nBlocksPerWG;\n" -"\n" -" for(int i=0; i>startBit) & 0xf;\n" -"#if defined(NV_GPU)\n" -" MY_HISTOGRAM( localKey )++;\n" -"#else\n" -" AtomInc( MY_HISTOGRAM( localKey ) );\n" -"#endif\n" -" }\n" -" }\n" -" }\n" -"\n" -" GROUP_LDS_BARRIER;\n" -" \n" -" if( lIdx < NUM_BUCKET )\n" -" {\n" -" u32 sum = 0;\n" -" for(int i=0; i>startBit) & 0xf;\n" -"#if defined(NV_GPU)\n" -" MY_HISTOGRAM( localKey )++;\n" -"#else\n" -" AtomInc( MY_HISTOGRAM( localKey ) );\n" -"#endif\n" -" }\n" -" }\n" -" }\n" -"\n" -" GROUP_LDS_BARRIER;\n" -" \n" -" if( lIdx < NUM_BUCKET )\n" -" {\n" -" u32 sum = 0;\n" -" for(int i=0; i>startBit) & mask, (sortData[1]>>startBit) & mask, (sortData[2]>>startBit) & mask, (sortData[3]>>startBit) & mask );\n" -" uint4 prefixSum = SELECT_UINT4( make_uint4(1,1,1,1), make_uint4(0,0,0,0), cmpResult != make_uint4(0,0,0,0) );\n" -" u32 total;\n" -" prefixSum = localPrefixSum64V( prefixSum, lIdx, &total, ldsSortData );\n" -" {\n" -" uint4 localAddr = make_uint4(lIdx*4+0,lIdx*4+1,lIdx*4+2,lIdx*4+3);\n" -" uint4 dstAddr = localAddr - prefixSum + make_uint4( total, total, total, total );\n" -" dstAddr = SELECT_UINT4( prefixSum, dstAddr, cmpResult != make_uint4(0, 0, 0, 0) );\n" -"\n" -" GROUP_LDS_BARRIER;\n" -"\n" -" ldsSortData[dstAddr.x] = sortData[0];\n" -" ldsSortData[dstAddr.y] = sortData[1];\n" -" ldsSortData[dstAddr.z] = sortData[2];\n" -" ldsSortData[dstAddr.w] = sortData[3];\n" -"\n" -" GROUP_LDS_BARRIER;\n" -"\n" -" sortData[0] = ldsSortData[localAddr.x];\n" -" sortData[1] = ldsSortData[localAddr.y];\n" -" sortData[2] = ldsSortData[localAddr.z];\n" -" sortData[3] = ldsSortData[localAddr.w];\n" -"\n" -" GROUP_LDS_BARRIER;\n" -" }\n" -" }\n" -"}\n" -"\n" -"// 2 scan, 2 exchange\n" -"void sort4Bits1(u32 sortData[4], int startBit, int lIdx, __local u32* ldsSortData)\n" -"{\n" -" for(uint ibit=0; ibit>(startBit+ibit)) & 0x3, \n" -" (sortData[1]>>(startBit+ibit)) & 0x3, \n" -" (sortData[2]>>(startBit+ibit)) & 0x3, \n" -" (sortData[3]>>(startBit+ibit)) & 0x3);\n" -"\n" -" u32 key4;\n" -" u32 sKeyPacked[4] = { 0, 0, 0, 0 };\n" -" {\n" -" sKeyPacked[0] |= 1<<(8*b.x);\n" -" sKeyPacked[1] |= 1<<(8*b.y);\n" -" sKeyPacked[2] |= 1<<(8*b.z);\n" -" sKeyPacked[3] |= 1<<(8*b.w);\n" -"\n" -" key4 = sKeyPacked[0] + sKeyPacked[1] + sKeyPacked[2] + sKeyPacked[3];\n" -" }\n" -"\n" -" u32 rankPacked;\n" -" u32 sumPacked;\n" -" {\n" -" rankPacked = localPrefixSum( key4, lIdx, &sumPacked, ldsSortData, WG_SIZE );\n" -" }\n" -"\n" -" GROUP_LDS_BARRIER;\n" -"\n" -" u32 newOffset[4] = { 0,0,0,0 };\n" -" {\n" -" u32 sumScanned = bit8Scan( sumPacked );\n" -"\n" -" u32 scannedKeys[4];\n" -" scannedKeys[0] = 1<<(8*b.x);\n" -" scannedKeys[1] = 1<<(8*b.y);\n" -" scannedKeys[2] = 1<<(8*b.z);\n" -" scannedKeys[3] = 1<<(8*b.w);\n" -" { // 4 scans at once\n" -" u32 sum4 = 0;\n" -" for(int ie=0; ie<4; ie++)\n" -" {\n" -" u32 tmp = scannedKeys[ie];\n" -" scannedKeys[ie] = sum4;\n" -" sum4 += tmp;\n" -" }\n" -" }\n" -"\n" -" {\n" -" u32 sumPlusRank = sumScanned + rankPacked;\n" -" { u32 ie = b.x;\n" -" scannedKeys[0] += sumPlusRank;\n" -" newOffset[0] = unpack4Key( scannedKeys[0], ie );\n" -" }\n" -" { u32 ie = b.y;\n" -" scannedKeys[1] += sumPlusRank;\n" -" newOffset[1] = unpack4Key( scannedKeys[1], ie );\n" -" }\n" -" { u32 ie = b.z;\n" -" scannedKeys[2] += sumPlusRank;\n" -" newOffset[2] = unpack4Key( scannedKeys[2], ie );\n" -" }\n" -" { u32 ie = b.w;\n" -" scannedKeys[3] += sumPlusRank;\n" -" newOffset[3] = unpack4Key( scannedKeys[3], ie );\n" -" }\n" -" }\n" -" }\n" -"\n" -"\n" -" GROUP_LDS_BARRIER;\n" -"\n" -" {\n" -" ldsSortData[newOffset[0]] = sortData[0];\n" -" ldsSortData[newOffset[1]] = sortData[1];\n" -" ldsSortData[newOffset[2]] = sortData[2];\n" -" ldsSortData[newOffset[3]] = sortData[3];\n" -"\n" -" GROUP_LDS_BARRIER;\n" -"\n" -" u32 dstAddr = 4*lIdx;\n" -" sortData[0] = ldsSortData[dstAddr+0];\n" -" sortData[1] = ldsSortData[dstAddr+1];\n" -" sortData[2] = ldsSortData[dstAddr+2];\n" -" sortData[3] = ldsSortData[dstAddr+3];\n" -"\n" -" GROUP_LDS_BARRIER;\n" -" }\n" -" }\n" -"}\n" -"\n" -"#define SET_HISTOGRAM(setIdx, key) ldsSortData[(setIdx)*NUM_BUCKET+key]\n" -"\n" -"__kernel\n" -"__attribute__((reqd_work_group_size(WG_SIZE,1,1)))\n" -"void SortAndScatterKernel( __global const u32* restrict gSrc, __global const u32* rHistogram, __global u32* restrict gDst, ConstBuffer cb )\n" -"{\n" -" __local u32 ldsSortData[WG_SIZE*ELEMENTS_PER_WORK_ITEM+16];\n" -" __local u32 localHistogramToCarry[NUM_BUCKET];\n" -" __local u32 localHistogram[NUM_BUCKET*2];\n" -"\n" -" u32 gIdx = GET_GLOBAL_IDX;\n" -" u32 lIdx = GET_LOCAL_IDX;\n" -" u32 wgIdx = GET_GROUP_IDX;\n" -" u32 wgSize = GET_GROUP_SIZE;\n" -"\n" -" const int n = cb.m_n;\n" -" const int nWGs = cb.m_nWGs;\n" -" const int startBit = cb.m_startBit;\n" -" const int nBlocksPerWG = cb.m_nBlocksPerWG;\n" -"\n" -" if( lIdx < (NUM_BUCKET) )\n" -" {\n" -" localHistogramToCarry[lIdx] = rHistogram[lIdx*nWGs + wgIdx];\n" -" }\n" -"\n" -" GROUP_LDS_BARRIER;\n" -"\n" -" const int blockSize = ELEMENTS_PER_WORK_ITEM*WG_SIZE;\n" -"\n" -" int nBlocks = n/blockSize - nBlocksPerWG*wgIdx;\n" -"\n" -" int addr = blockSize*nBlocksPerWG*wgIdx + ELEMENTS_PER_WORK_ITEM*lIdx;\n" -"\n" -" for(int iblock=0; iblock>startBit) & 0xf;\n" -"\n" -" { // create histogram\n" -" u32 setIdx = lIdx/16;\n" -" if( lIdx < NUM_BUCKET )\n" -" {\n" -" localHistogram[lIdx] = 0;\n" -" }\n" -" ldsSortData[lIdx] = 0;\n" -" GROUP_LDS_BARRIER;\n" -"\n" -" for(int i=0; i>(startBit+ibit)) & 0x3, \n" -" (sortData[1]>>(startBit+ibit)) & 0x3, \n" -" (sortData[2]>>(startBit+ibit)) & 0x3, \n" -" (sortData[3]>>(startBit+ibit)) & 0x3);\n" -"\n" -" u32 key4;\n" -" u32 sKeyPacked[4] = { 0, 0, 0, 0 };\n" -" {\n" -" sKeyPacked[0] |= 1<<(8*b.x);\n" -" sKeyPacked[1] |= 1<<(8*b.y);\n" -" sKeyPacked[2] |= 1<<(8*b.z);\n" -" sKeyPacked[3] |= 1<<(8*b.w);\n" -"\n" -" key4 = sKeyPacked[0] + sKeyPacked[1] + sKeyPacked[2] + sKeyPacked[3];\n" -" }\n" -"\n" -" u32 rankPacked;\n" -" u32 sumPacked;\n" -" {\n" -" rankPacked = localPrefixSum( key4, lIdx, &sumPacked, ldsSortData, WG_SIZE );\n" -" }\n" -"\n" -" GROUP_LDS_BARRIER;\n" -"\n" -" u32 newOffset[4] = { 0,0,0,0 };\n" -" {\n" -" u32 sumScanned = bit8Scan( sumPacked );\n" -"\n" -" u32 scannedKeys[4];\n" -" scannedKeys[0] = 1<<(8*b.x);\n" -" scannedKeys[1] = 1<<(8*b.y);\n" -" scannedKeys[2] = 1<<(8*b.z);\n" -" scannedKeys[3] = 1<<(8*b.w);\n" -" { // 4 scans at once\n" -" u32 sum4 = 0;\n" -" for(int ie=0; ie<4; ie++)\n" -" {\n" -" u32 tmp = scannedKeys[ie];\n" -" scannedKeys[ie] = sum4;\n" -" sum4 += tmp;\n" -" }\n" -" }\n" -"\n" -" {\n" -" u32 sumPlusRank = sumScanned + rankPacked;\n" -" { u32 ie = b.x;\n" -" scannedKeys[0] += sumPlusRank;\n" -" newOffset[0] = unpack4Key( scannedKeys[0], ie );\n" -" }\n" -" { u32 ie = b.y;\n" -" scannedKeys[1] += sumPlusRank;\n" -" newOffset[1] = unpack4Key( scannedKeys[1], ie );\n" -" }\n" -" { u32 ie = b.z;\n" -" scannedKeys[2] += sumPlusRank;\n" -" newOffset[2] = unpack4Key( scannedKeys[2], ie );\n" -" }\n" -" { u32 ie = b.w;\n" -" scannedKeys[3] += sumPlusRank;\n" -" newOffset[3] = unpack4Key( scannedKeys[3], ie );\n" -" }\n" -" }\n" -" }\n" -"\n" -"\n" -" GROUP_LDS_BARRIER;\n" -"\n" -" {\n" -" ldsSortData[newOffset[0]] = sortData[0];\n" -" ldsSortData[newOffset[1]] = sortData[1];\n" -" ldsSortData[newOffset[2]] = sortData[2];\n" -" ldsSortData[newOffset[3]] = sortData[3];\n" -"\n" -" ldsSortVal[newOffset[0]] = sortVal[0];\n" -" ldsSortVal[newOffset[1]] = sortVal[1];\n" -" ldsSortVal[newOffset[2]] = sortVal[2];\n" -" ldsSortVal[newOffset[3]] = sortVal[3];\n" -"\n" -" GROUP_LDS_BARRIER;\n" -"\n" -" u32 dstAddr = 4*lIdx;\n" -" sortData[0] = ldsSortData[dstAddr+0];\n" -" sortData[1] = ldsSortData[dstAddr+1];\n" -" sortData[2] = ldsSortData[dstAddr+2];\n" -" sortData[3] = ldsSortData[dstAddr+3];\n" -"\n" -" sortVal[0] = ldsSortVal[dstAddr+0];\n" -" sortVal[1] = ldsSortVal[dstAddr+1];\n" -" sortVal[2] = ldsSortVal[dstAddr+2];\n" -" sortVal[3] = ldsSortVal[dstAddr+3];\n" -"\n" -" GROUP_LDS_BARRIER;\n" -" }\n" -" }\n" -"}\n" -"\n" -"\n" -"\n" -"__kernel\n" -"__attribute__((reqd_work_group_size(WG_SIZE,1,1)))\n" -"void SortAndScatterKeyValueKernel( __global const u32* restrict gSrc, __global const int* restrict gSrcVal, __global const u32* rHistogram, __global u32* restrict gDst, __global int* restrict gDstVal, ConstBuffer cb)\n" -"{\n" -" __local u32 ldsSortData[WG_SIZE*ELEMENTS_PER_WORK_ITEM+16];\n" -" __local int ldsSortVal[WG_SIZE*ELEMENTS_PER_WORK_ITEM+16];\n" -" __local u32 localHistogramToCarry[NUM_BUCKET];\n" -" __local u32 localHistogram[NUM_BUCKET*2];\n" -"\n" -" u32 gIdx = GET_GLOBAL_IDX;\n" -" u32 lIdx = GET_LOCAL_IDX;\n" -" u32 wgIdx = GET_GROUP_IDX;\n" -" u32 wgSize = GET_GROUP_SIZE;\n" -"\n" -" const int n = cb.m_n;\n" -" const int nWGs = cb.m_nWGs;\n" -" const int startBit = cb.m_startBit;\n" -" const int nBlocksPerWG = cb.m_nBlocksPerWG;\n" -"\n" -" if( lIdx < (NUM_BUCKET) )\n" -" {\n" -" localHistogramToCarry[lIdx] = rHistogram[lIdx*nWGs + wgIdx];\n" -" }\n" -"\n" -" GROUP_LDS_BARRIER;\n" -"\n" -" const int blockSize = ELEMENTS_PER_WORK_ITEM*WG_SIZE;\n" -"\n" -" int nBlocks = n/blockSize - nBlocksPerWG*wgIdx;\n" -"\n" -" int addr = blockSize*nBlocksPerWG*wgIdx + ELEMENTS_PER_WORK_ITEM*lIdx;\n" -"\n" -" for(int iblock=0; iblock>startBit) & 0xf;\n" -"\n" -" { // create histogram\n" -" u32 setIdx = lIdx/16;\n" -" if( lIdx < NUM_BUCKET )\n" -" {\n" -" localHistogram[lIdx] = 0;\n" -" }\n" -" ldsSortData[lIdx] = 0;\n" -" GROUP_LDS_BARRIER;\n" -"\n" -" for(int i=0; i>startBit) & 0xf;\n" -"\n" -" { // create histogram\n" -" u32 setIdx = lIdx/16;\n" -" if( lIdx < NUM_BUCKET )\n" -" {\n" -" localHistogram[lIdx] = 0;\n" -" }\n" -" ldsSortData[lIdx] = 0;\n" -" GROUP_LDS_BARRIER;\n" -"\n" -" for(int i=0; i gSrc : register( t0 );\n" -"StructuredBuffer gSrcVal : register( t1 );\n" -"StructuredBuffer rHistogram : register( t1 );\n" -"StructuredBuffer rHistogram2 : register( t2 );\n" -"RWStructuredBuffer histogramOut : register( u0 );\n" -"RWStructuredBuffer wHistogram1 : register( u0 );\n" -"RWStructuredBuffer gDst : register( u0 );\n" -"RWStructuredBuffer gDstVal : register( u1 );\n" -"\n" -"groupshared u32 localHistogramMat[NUM_BUCKET*WG_SIZE];\n" -"#define MY_HISTOGRAM(idx) localHistogramMat[(idx)*WG_SIZE+lIdx]\n" -"\n" -"\n" -"[numthreads(WG_SIZE, 1, 1)]\n" -"void StreamCountKernel( DEFAULT_ARGS )\n" -"{\n" -" u32 gIdx = GET_GLOBAL_IDX;\n" -" u32 lIdx = GET_LOCAL_IDX;\n" -" u32 wgIdx = GET_GROUP_IDX;\n" -" u32 wgSize = GET_GROUP_SIZE;\n" -" const int startBit = m_startBit;\n" -"\n" -" const int n = m_n;\n" -" const int nWGs = m_nWGs;\n" -" const int nBlocksPerWG = m_nBlocksPerWG;\n" -"\n" -" for(int i=0; i>startBit) & 0xf;\n" -"#if defined(NV_GPU)\n" -" MY_HISTOGRAM( localKey )++;\n" -"#else\n" -" AtomInc( MY_HISTOGRAM( localKey ) );\n" -"#endif\n" -" }\n" -" }\n" -" }\n" -"\n" -" GROUP_LDS_BARRIER;\n" -" \n" -" if( lIdx < NUM_BUCKET )\n" -" {\n" -" u32 sum = 0;\n" -" for(int i=0; i 64 )\n" -" {\n" -" ldsSortData[idx] += ldsSortData[idx-64];\n" -" GROUP_MEM_FENCE;\n" -" }\n" -"\n" -" ldsSortData[idx-1] += ldsSortData[idx-2];\n" -" GROUP_MEM_FENCE;\n" -" }\n" -"#else\n" -" if( lIdx < 64 )\n" -" {\n" -" ldsSortData[idx] += ldsSortData[idx-1];\n" -" GROUP_MEM_FENCE;\n" -" ldsSortData[idx] += ldsSortData[idx-2]; \n" -" GROUP_MEM_FENCE;\n" -" ldsSortData[idx] += ldsSortData[idx-4];\n" -" GROUP_MEM_FENCE;\n" -" ldsSortData[idx] += ldsSortData[idx-8];\n" -" GROUP_MEM_FENCE;\n" -" ldsSortData[idx] += ldsSortData[idx-16];\n" -" GROUP_MEM_FENCE;\n" -" ldsSortData[idx] += ldsSortData[idx-32];\n" -" GROUP_MEM_FENCE;\n" -" if( wgSize > 64 )\n" -" {\n" -" ldsSortData[idx] += ldsSortData[idx-64];\n" -" GROUP_MEM_FENCE;\n" -" }\n" -"\n" -" ldsSortData[idx-1] += ldsSortData[idx-2];\n" -" GROUP_MEM_FENCE;\n" -" }\n" -"#endif\n" -" }\n" -"\n" -" GROUP_LDS_BARRIER;\n" -"\n" -" totalSum = ldsSortData[wgSize*2-1];\n" -" u32 addValue = ldsSortData[lIdx+wgSize-1];\n" -" return addValue;\n" -"}\n" -"\n" -"//__attribute__((reqd_work_group_size(128,1,1)))\n" -"uint4 localPrefixSum128V( uint4 pData, uint lIdx, inout uint totalSum )\n" -"{\n" -" u32 s4 = prefixScanVectorEx( pData );\n" -" u32 rank = localPrefixSum( s4, lIdx, totalSum, 128 );\n" -" return pData + make_uint4( rank, rank, rank, rank );\n" -"}\n" -"\n" -"//__attribute__((reqd_work_group_size(64,1,1)))\n" -"uint4 localPrefixSum64V( uint4 pData, uint lIdx, inout uint totalSum )\n" -"{\n" -" u32 s4 = prefixScanVectorEx( pData );\n" -" u32 rank = localPrefixSum( s4, lIdx, totalSum, 64 );\n" -" return pData + make_uint4( rank, rank, rank, rank );\n" -"}\n" -"\n" -"\n" -"\n" -"\n" -"\n" -"#define nPerLane (nPerWI/4)\n" -"\n" -"// NUM_BUCKET*nWGs < 128*nPerWI\n" -"[numthreads(128, 1, 1)]\n" -"void PrefixScanKernel( DEFAULT_ARGS )\n" -"{\n" -" u32 lIdx = GET_LOCAL_IDX;\n" -" u32 wgIdx = GET_GROUP_IDX;\n" -" const int nWGs = m_nWGs;\n" -"\n" -" u32 data[nPerWI];\n" -" for(int i=0; i>(keyIdx*8)) & 0xff;}\n" -"\n" -"u32 bit8Scan(u32 v)\n" -"{\n" -" return (v<<8) + (v<<16) + (v<<24);\n" -"}\n" -"\n" -"\n" -"\n" -"\n" -"void sort4Bits1(inout u32 sortData[4], int startBit, int lIdx)\n" -"{\n" -"/*\n" -" for(uint ibit=0; ibit>(startBit+ibit)) & 0x3, \n" -" (sortData[1]>>(startBit+ibit)) & 0x3, \n" -" (sortData[2]>>(startBit+ibit)) & 0x3, \n" -" (sortData[3]>>(startBit+ibit)) & 0x3);\n" -"\n" -" u32 key4;\n" -" u32 sKeyPacked[4] = { 0, 0, 0, 0 };\n" -" {\n" -" sKeyPacked[0] |= 1<<(8*b.x);\n" -" sKeyPacked[1] |= 1<<(8*b.y);\n" -" sKeyPacked[2] |= 1<<(8*b.z);\n" -" sKeyPacked[3] |= 1<<(8*b.w);\n" -"\n" -" key4 = sKeyPacked[0] + sKeyPacked[1] + sKeyPacked[2] + sKeyPacked[3];\n" -" }\n" -"\n" -" u32 rankPacked;\n" -" u32 sumPacked;\n" -" {\n" -" rankPacked = localPrefixSum64VSingle( key4, lIdx, sumPacked );\n" -" }\n" -"\n" -"// GROUP_LDS_BARRIER;\n" -"\n" -" u32 sum[4] = { unpack4Key( sumPacked,0 ), unpack4Key( sumPacked,1 ), unpack4Key( sumPacked,2 ), unpack4Key( sumPacked,3 ) };\n" -"\n" -" {\n" -" u32 sum4 = 0;\n" -" for(int ie=0; ie<4; ie++)\n" -" {\n" -" u32 tmp = sum[ie];\n" -" sum[ie] = sum4;\n" -" sum4 += tmp;\n" -" }\n" -" }\n" -"\n" -" u32 newOffset[4] = { 0,0,0,0 };\n" -"\n" -" for(int ie=0; ie<4; ie++)\n" -" {\n" -" uint4 key = extractKeys( b, ie );\n" -" uint4 scannedKey = key;\n" -" prefixScanVectorEx( scannedKey );\n" -" uint offset = sum[ie] + unpack4Key( rankPacked, ie );\n" -" uint4 dstAddress = make_uint4( offset, offset, offset, offset ) + scannedKey;\n" -"\n" -" newOffset[0] += dstAddress.x*key.x;\n" -" newOffset[1] += dstAddress.y*key.y;\n" -" newOffset[2] += dstAddress.z*key.z;\n" -" newOffset[3] += dstAddress.w*key.w;\n" -" }\n" -"\n" -"\n" -"\n" -" {\n" -" ldsSortData[newOffset[0]] = sortData[0];\n" -" ldsSortData[newOffset[1]] = sortData[1];\n" -" ldsSortData[newOffset[2]] = sortData[2];\n" -" ldsSortData[newOffset[3]] = sortData[3];\n" -"\n" -"// GROUP_LDS_BARRIER;\n" -"\n" -" sortData[0] = ldsSortData[lIdx*4+0];\n" -" sortData[1] = ldsSortData[lIdx*4+1];\n" -" sortData[2] = ldsSortData[lIdx*4+2];\n" -" sortData[3] = ldsSortData[lIdx*4+3];\n" -"\n" -"// GROUP_LDS_BARRIER;\n" -" }\n" -" }\n" -"*/\n" -" for(uint ibit=0; ibit>(startBit+ibit)) & 0x3, \n" -" (sortData[1]>>(startBit+ibit)) & 0x3, \n" -" (sortData[2]>>(startBit+ibit)) & 0x3, \n" -" (sortData[3]>>(startBit+ibit)) & 0x3);\n" -"\n" -" u32 key4;\n" -" u32 sKeyPacked[4] = { 0, 0, 0, 0 };\n" -" {\n" -" sKeyPacked[0] |= 1<<(8*b.x);\n" -" sKeyPacked[1] |= 1<<(8*b.y);\n" -" sKeyPacked[2] |= 1<<(8*b.z);\n" -" sKeyPacked[3] |= 1<<(8*b.w);\n" -"\n" -" key4 = sKeyPacked[0] + sKeyPacked[1] + sKeyPacked[2] + sKeyPacked[3];\n" -" }\n" -"\n" -" u32 rankPacked;\n" -" u32 sumPacked;\n" -" {\n" -" rankPacked = localPrefixSum( key4, lIdx, sumPacked, WG_SIZE );\n" -" }\n" -"\n" -" GROUP_LDS_BARRIER;\n" -"\n" -" u32 newOffset[4] = { 0,0,0,0 };\n" -" {\n" -" u32 sumScanned = bit8Scan( sumPacked );\n" -"\n" -" u32 scannedKeys[4];\n" -" scannedKeys[0] = 1<<(8*b.x);\n" -" scannedKeys[1] = 1<<(8*b.y);\n" -" scannedKeys[2] = 1<<(8*b.z);\n" -" scannedKeys[3] = 1<<(8*b.w);\n" -" { // 4 scans at once\n" -" u32 sum4 = 0;\n" -" for(int ie=0; ie<4; ie++)\n" -" {\n" -" u32 tmp = scannedKeys[ie];\n" -" scannedKeys[ie] = sum4;\n" -" sum4 += tmp;\n" -" }\n" -" }\n" -"\n" -" {\n" -" u32 sumPlusRank = sumScanned + rankPacked;\n" -" { u32 ie = b.x;\n" -" scannedKeys[0] += sumPlusRank;\n" -" newOffset[0] = unpack4Key( scannedKeys[0], ie );\n" -" }\n" -" { u32 ie = b.y;\n" -" scannedKeys[1] += sumPlusRank;\n" -" newOffset[1] = unpack4Key( scannedKeys[1], ie );\n" -" }\n" -" { u32 ie = b.z;\n" -" scannedKeys[2] += sumPlusRank;\n" -" newOffset[2] = unpack4Key( scannedKeys[2], ie );\n" -" }\n" -" { u32 ie = b.w;\n" -" scannedKeys[3] += sumPlusRank;\n" -" newOffset[3] = unpack4Key( scannedKeys[3], ie );\n" -" }\n" -" }\n" -" }\n" -"\n" -"\n" -" GROUP_LDS_BARRIER;\n" -"\n" -" {\n" -" ldsSortData[newOffset[0]] = sortData[0];\n" -" ldsSortData[newOffset[1]] = sortData[1];\n" -" ldsSortData[newOffset[2]] = sortData[2];\n" -" ldsSortData[newOffset[3]] = sortData[3];\n" -"\n" -" GROUP_LDS_BARRIER;\n" -"\n" -" u32 dstAddr = 4*lIdx;\n" -" sortData[0] = ldsSortData[dstAddr+0];\n" -" sortData[1] = ldsSortData[dstAddr+1];\n" -" sortData[2] = ldsSortData[dstAddr+2];\n" -" sortData[3] = ldsSortData[dstAddr+3];\n" -"\n" -" GROUP_LDS_BARRIER;\n" -" }\n" -" }\n" -"}\n" -"\n" -"\n" -"groupshared u32 localHistogramToCarry[NUM_BUCKET];\n" -"groupshared u32 localHistogram[NUM_BUCKET*2];\n" -"#define SET_HISTOGRAM(setIdx, key) ldsSortData[(setIdx)*NUM_BUCKET+key]\n" -"\n" -"\n" -"[numthreads(WG_SIZE, 1, 1)]\n" -"void SortAndScatterKernel( DEFAULT_ARGS )\n" -"{\n" -" u32 gIdx = GET_GLOBAL_IDX;\n" -" u32 lIdx = GET_LOCAL_IDX;\n" -" u32 wgIdx = GET_GROUP_IDX;\n" -" u32 wgSize = GET_GROUP_SIZE;\n" -"\n" -" const int n = m_n;\n" -" const int nWGs = m_nWGs;\n" -" const int startBit = m_startBit;\n" -" const int nBlocksPerWG = m_nBlocksPerWG;\n" -"\n" -" if( lIdx < (NUM_BUCKET) )\n" -" {\n" -" localHistogramToCarry[lIdx] = rHistogram[lIdx*nWGs + wgIdx];\n" -" }\n" -"\n" -" GROUP_LDS_BARRIER;\n" -"\n" -" const int blockSize = ELEMENTS_PER_WORK_ITEM*WG_SIZE;\n" -"\n" -" int nBlocks = n/blockSize - nBlocksPerWG*wgIdx;\n" -"\n" -" int addr = blockSize*nBlocksPerWG*wgIdx + ELEMENTS_PER_WORK_ITEM*lIdx;\n" -"\n" -" for(int iblock=0; iblock>startBit) & 0xf;\n" -"\n" -" { // create histogram\n" -" u32 setIdx = lIdx/16;\n" -" if( lIdx < NUM_BUCKET )\n" -" {\n" -" localHistogram[lIdx] = 0;\n" -" }\n" -" ldsSortData[lIdx] = 0;\n" -" GROUP_LDS_BARRIER;\n" -"\n" -" for(int i=0; i>startBit) & 0xf;\n" -"\n" -" { // create histogram\n" -" if( lIdx < NUM_BUCKET )\n" -" {\n" -" localHistogram[lIdx] = 0;\n" -" localHistogram[NUM_BUCKET+lIdx] = 0;\n" -" }\n" -"// GROUP_LDS_BARRIER;\n" -"\n" -" AtomInc( localHistogram[NUM_BUCKET+keys[0]] );\n" -" AtomInc( localHistogram[NUM_BUCKET+keys[1]] );\n" -" AtomInc( localHistogram[NUM_BUCKET+keys[2]] );\n" -" AtomInc( localHistogram[NUM_BUCKET+keys[3]] );\n" -" \n" -"// GROUP_LDS_BARRIER;\n" -" \n" -" uint hIdx = NUM_BUCKET+lIdx;\n" -" if( lIdx < NUM_BUCKET )\n" -" {\n" -" myHistogram = localHistogram[hIdx];\n" -" }\n" -"// GROUP_LDS_BARRIER;\n" -"\n" -"#if defined(USE_2LEVEL_REDUCE)\n" -" if( lIdx < NUM_BUCKET )\n" -" {\n" -" localHistogram[hIdx] = localHistogram[hIdx-1];\n" -" GROUP_MEM_FENCE;\n" -"\n" -" u32 u0, u1, u2;\n" -" u0 = localHistogram[hIdx-3];\n" -" u1 = localHistogram[hIdx-2];\n" -" u2 = localHistogram[hIdx-1];\n" -" AtomAdd( localHistogram[hIdx], u0 + u1 + u2 );\n" -" GROUP_MEM_FENCE;\n" -" u0 = localHistogram[hIdx-12];\n" -" u1 = localHistogram[hIdx-8];\n" -" u2 = localHistogram[hIdx-4];\n" -" AtomAdd( localHistogram[hIdx], u0 + u1 + u2 );\n" -" GROUP_MEM_FENCE;\n" -" }\n" -"#else\n" -" if( lIdx < NUM_BUCKET )\n" -" {\n" -" localHistogram[hIdx] = localHistogram[hIdx-1];\n" -" GROUP_MEM_FENCE;\n" -" localHistogram[hIdx] += localHistogram[hIdx-1];\n" -" GROUP_MEM_FENCE;\n" -" localHistogram[hIdx] += localHistogram[hIdx-2];\n" -" GROUP_MEM_FENCE;\n" -" localHistogram[hIdx] += localHistogram[hIdx-4];\n" -" GROUP_MEM_FENCE;\n" -" localHistogram[hIdx] += localHistogram[hIdx-8];\n" -" GROUP_MEM_FENCE;\n" -" }\n" -"#endif\n" -"\n" -"// GROUP_LDS_BARRIER;\n" -" }\n" -"\n" -" {\n" -" for(int ie=0; ie>(startBit+ibit)) & 0x3, \n" -" (sortData[1]>>(startBit+ibit)) & 0x3, \n" -" (sortData[2]>>(startBit+ibit)) & 0x3, \n" -" (sortData[3]>>(startBit+ibit)) & 0x3);\n" -"\n" -" u32 key4;\n" -" u32 sKeyPacked[4] = { 0, 0, 0, 0 };\n" -" {\n" -" sKeyPacked[0] |= 1<<(8*b.x);\n" -" sKeyPacked[1] |= 1<<(8*b.y);\n" -" sKeyPacked[2] |= 1<<(8*b.z);\n" -" sKeyPacked[3] |= 1<<(8*b.w);\n" -"\n" -" key4 = sKeyPacked[0] + sKeyPacked[1] + sKeyPacked[2] + sKeyPacked[3];\n" -" }\n" -"\n" -" u32 rankPacked;\n" -" u32 sumPacked;\n" -" {\n" -" rankPacked = localPrefixSum( key4, lIdx, sumPacked, WG_SIZE );\n" -" }\n" -"\n" -" GROUP_LDS_BARRIER;\n" -"\n" -" u32 newOffset[4] = { 0,0,0,0 };\n" -" {\n" -" u32 sumScanned = bit8Scan( sumPacked );\n" -"\n" -" u32 scannedKeys[4];\n" -" scannedKeys[0] = 1<<(8*b.x);\n" -" scannedKeys[1] = 1<<(8*b.y);\n" -" scannedKeys[2] = 1<<(8*b.z);\n" -" scannedKeys[3] = 1<<(8*b.w);\n" -" { // 4 scans at once\n" -" u32 sum4 = 0;\n" -" for(int ie=0; ie<4; ie++)\n" -" {\n" -" u32 tmp = scannedKeys[ie];\n" -" scannedKeys[ie] = sum4;\n" -" sum4 += tmp;\n" -" }\n" -" }\n" -"\n" -" {\n" -" u32 sumPlusRank = sumScanned + rankPacked;\n" -" { u32 ie = b.x;\n" -" scannedKeys[0] += sumPlusRank;\n" -" newOffset[0] = unpack4Key( scannedKeys[0], ie );\n" -" }\n" -" { u32 ie = b.y;\n" -" scannedKeys[1] += sumPlusRank;\n" -" newOffset[1] = unpack4Key( scannedKeys[1], ie );\n" -" }\n" -" { u32 ie = b.z;\n" -" scannedKeys[2] += sumPlusRank;\n" -" newOffset[2] = unpack4Key( scannedKeys[2], ie );\n" -" }\n" -" { u32 ie = b.w;\n" -" scannedKeys[3] += sumPlusRank;\n" -" newOffset[3] = unpack4Key( scannedKeys[3], ie );\n" -" }\n" -" }\n" -" }\n" -"\n" -"\n" -" GROUP_LDS_BARRIER;\n" -"\n" -" {\n" -" ldsSortData[newOffset[0]] = sortData[0];\n" -" ldsSortData[newOffset[1]] = sortData[1];\n" -" ldsSortData[newOffset[2]] = sortData[2];\n" -" ldsSortData[newOffset[3]] = sortData[3];\n" -"\n" -" ldsSortVal[newOffset[0]] = sortVal[0];\n" -" ldsSortVal[newOffset[1]] = sortVal[1];\n" -" ldsSortVal[newOffset[2]] = sortVal[2];\n" -" ldsSortVal[newOffset[3]] = sortVal[3];\n" -"\n" -" GROUP_LDS_BARRIER;\n" -"\n" -" u32 dstAddr = 4*lIdx;\n" -" sortData[0] = ldsSortData[dstAddr+0];\n" -" sortData[1] = ldsSortData[dstAddr+1];\n" -" sortData[2] = ldsSortData[dstAddr+2];\n" -" sortData[3] = ldsSortData[dstAddr+3];\n" -"\n" -" sortVal[0] = ldsSortVal[dstAddr+0];\n" -" sortVal[1] = ldsSortVal[dstAddr+1];\n" -" sortVal[2] = ldsSortVal[dstAddr+2];\n" -" sortVal[3] = ldsSortVal[dstAddr+3];\n" -"\n" -" GROUP_LDS_BARRIER;\n" -" }\n" -" }\n" -"}\n" -"\n" -"\n" -"\n" -"[numthreads(WG_SIZE, 1, 1)]\n" -"void SortAndScatterKeyValueKernel( DEFAULT_ARGS )\n" -"{\n" -" u32 gIdx = GET_GLOBAL_IDX;\n" -" u32 lIdx = GET_LOCAL_IDX;\n" -" u32 wgIdx = GET_GROUP_IDX;\n" -" u32 wgSize = GET_GROUP_SIZE;\n" -"\n" -" const int n = m_n;\n" -" const int nWGs = m_nWGs;\n" -" const int startBit = m_startBit;\n" -" const int nBlocksPerWG = m_nBlocksPerWG;\n" -"\n" -" if( lIdx < (NUM_BUCKET) )\n" -" {\n" -" localHistogramToCarry[lIdx] = rHistogram2[lIdx*nWGs + wgIdx];\n" -" }\n" -"\n" -" GROUP_LDS_BARRIER;\n" -"\n" -" const int blockSize = ELEMENTS_PER_WORK_ITEM*WG_SIZE;\n" -"\n" -" int nBlocks = n/blockSize - nBlocksPerWG*wgIdx;\n" -"\n" -" int addr = blockSize*nBlocksPerWG*wgIdx + ELEMENTS_PER_WORK_ITEM*lIdx;\n" -"\n" -" for(int iblock=0; iblock>startBit) & 0xf;\n" -"\n" -" { // create histogram\n" -" u32 setIdx = lIdx/16;\n" -" if( lIdx < NUM_BUCKET )\n" -" {\n" -" localHistogram[lIdx] = 0;\n" -" }\n" -" ldsSortData[lIdx] = 0;\n" -" GROUP_LDS_BARRIER;\n" -"\n" -" for(int i=0; i rHistogram : register(t0); - -RWStructuredBuffer dataToSort : register( u0 ); -RWStructuredBuffer dataToSortOut : register( u1 ); - - - -#define WG_SIZE 128 -#define ELEMENTS_PER_WORK_ITEM 4 -#define BITS_PER_PASS 4 -#define NUM_BUCKET (1<> targetKey; - key.y = (data.y & mask) >> targetKey; - key.z = (data.z & mask) >> targetKey; - key.w = (data.w & mask) >> targetKey; - return key; -} - -uint packKeys(uint lower, uint upper) -{ - return lower|(upper<<16); -} - -uint4 packKeys(uint4 lower, uint4 upper) -{ - return uint4( lower.x|(upper.x<<16), lower.y|(upper.y<<16), lower.z|(upper.z<<16), lower.w|(upper.w<<16) ); -} - -uint extractLower( uint data ) -{ - return data&0xffff; -} - -uint extractUpper( uint data ) -{ - return (data>>16)&0xffff; -} - -uint4 extractLower( uint4 data ) -{ - return uint4( data.x&0xffff, data.y&0xffff, data.z&0xffff, data.w&0xffff ); -} - -uint4 extractUpper( uint4 data ) -{ - return uint4( (data.x>>16)&0xffff, (data.y>>16)&0xffff, (data.z>>16)&0xffff, (data.w>>16)&0xffff ); -} - -[numthreads(WG_SIZE, 1, 1)] -void SortAndScatterKernel( DEFAULT_ARGS ) -{ - u32 lIdx = GET_LOCAL_IDX; - u32 wgIdx = GET_GROUP_IDX; - - if( lIdx < (NUM_BUCKET) ) - { - localHistogramToCarry[lIdx] = rHistogram[lIdx*m_nWorkGroupsToExecute + wgIdx]; - } - - GROUP_LDS_BARRIER; - - for(uint igroup=wgIdx*m_nBlocksPerGroup; igroup>m_startBit) & 0xf, (myData[1].key>>m_startBit) & 0xf, (myData[2].key>>m_startBit) & 0xf, (myData[3].key>>m_startBit) & 0xf); - for(uint targetKey=0; targetKey<(NUM_BUCKET); targetKey+=4) - { - uint4 key[4]; - uint keySet[2]; - { // pack 4 - uint4 scannedKey[4]; - key[0] = scannedKey[0] = extractKeys( b, targetKey+0 ); - key[1] = scannedKey[1] = extractKeys( b, targetKey+1 ); - key[2] = scannedKey[2] = extractKeys( b, targetKey+2 ); - key[3] = scannedKey[3] = extractKeys( b, targetKey+3 ); - { - uint s[4]; - s[0] = prefixScanVectorEx( scannedKey[0] ); - s[1] = prefixScanVectorEx( scannedKey[1] ); - s[2] = prefixScanVectorEx( scannedKey[2] ); - s[3] = prefixScanVectorEx( scannedKey[3] ); - keySet[0] = packKeys( s[0], s[1] ); - keySet[1] = packKeys( s[2], s[3] ); - } - } - - uint dstAddressBase[4]; - { - - uint totalSumPacked[2]; - uint dstAddressPacked[2]; - - localPrefixScan128Dual( keySet[0], keySet[1], lIdx, dstAddressPacked[0], dstAddressPacked[1], totalSumPacked[0], totalSumPacked[1] ); - - dstAddressBase[0] = extractLower( dstAddressPacked[0] ); - dstAddressBase[1] = extractUpper( dstAddressPacked[0] ); - dstAddressBase[2] = extractLower( dstAddressPacked[1] ); - dstAddressBase[3] = extractUpper( dstAddressPacked[1] ); - - uint4 histogram; - histogram.x = extractLower(totalSumPacked[0]); - histogram.y = extractUpper(totalSumPacked[0]); - histogram.z = extractLower(totalSumPacked[1]); - histogram.w = extractUpper(totalSumPacked[1]); - - if( lIdx == targetKey + 0 ) myHistogram = histogram.x; - else if( lIdx == targetKey + 1 ) myHistogram = histogram.y; - else if( lIdx == targetKey + 2 ) myHistogram = histogram.z; - else if( lIdx == targetKey + 3 ) myHistogram = histogram.w; - - uint histogramSum = prefixScanVectorEx( histogram ); - - if( lIdx == targetKey + 0 ) localPrefixSum[targetKey+0] = localOffset+histogram.x; - else if( lIdx == targetKey + 1 ) localPrefixSum[targetKey+1] = localOffset+histogram.y; - else if( lIdx == targetKey + 2 ) localPrefixSum[targetKey+2] = localOffset+histogram.z; - else if( lIdx == targetKey + 3 ) localPrefixSum[targetKey+3] = localOffset+histogram.w; - - localOffset += histogramSum; - } - - GROUP_LDS_BARRIER; - - - for(int ie=0; ie<4; ie++) - { - uint4 scannedKey = key[ie]; - prefixScanVectorEx( scannedKey ); - - uint offset = localPrefixSum[targetKey + ie] + dstAddressBase[ie]; - uint4 dstAddress = uint4( offset, offset, offset, offset ) + scannedKey; - - newOffset[0] += dstAddress.x*key[ie].x; - newOffset[1] += dstAddress.y*key[ie].y; - newOffset[2] += dstAddress.z*key[ie].z; - newOffset[3] += dstAddress.w*key[ie].w; - } - } - - { // local scatter - SET_LOCAL_SORT_DATA(newOffset[0], myData[0]); - SET_LOCAL_SORT_DATA(newOffset[1], myData[1]); - SET_LOCAL_SORT_DATA(newOffset[2], myData[2]); - SET_LOCAL_SORT_DATA(newOffset[3], myData[3]); - } - - GROUP_LDS_BARRIER; - - { // write data - for(int i=0; i> m_startBit) & 0xf; - int groupOffset = localHistogramToCarry[binIdx]; - int myIdx = dataIdx - localPrefixSum[binIdx]; - - dataToSortOut[ groupOffset + myIdx ] = localData; - } - } - - GROUP_LDS_BARRIER; - if( lIdx < NUM_BUCKET ) - { - localHistogramToCarry[lIdx] += myHistogram; - } - GROUP_LDS_BARRIER; - } -} - - -[numthreads(WG_SIZE, 1, 1)] -void SortAndScatterKernel1( DEFAULT_ARGS ) -{ - u32 lIdx = GET_LOCAL_IDX; - u32 wgIdx = GET_GROUP_IDX; - - if( lIdx < (NUM_BUCKET) ) - { - localHistogramToCarry[lIdx] = rHistogram[lIdx*m_nWorkGroupsToExecute + wgIdx.x]; - } - - GROUP_LDS_BARRIER; - - for(uint igroup=wgIdx.x*m_nBlocksPerGroup; igroup>ib) & 0x1, ~(myData[1].key>>ib) & 0x1, ~(myData[2].key>>ib) & 0x1, ~(myData[3].key>>ib) & 0x1); - uint total; - uint4 rankOfP = localPrefixSum128V( keys, lIdx, total ); - uint4 rankOfN = uint4(startAddrBlock, startAddrBlock+1, startAddrBlock+2, startAddrBlock+3) - rankOfP + uint4( total, total, total, total ); - - uint4 myAddr = (keys==uint4(1,1,1,1))? rankOfP: rankOfN; - - GROUP_LDS_BARRIER; - - SET_LOCAL_SORT_DATA( myAddr.x, myData[0] ); - SET_LOCAL_SORT_DATA( myAddr.y, myData[1] ); - SET_LOCAL_SORT_DATA( myAddr.z, myData[2] ); - SET_LOCAL_SORT_DATA( myAddr.w, myData[3] ); - - GROUP_LDS_BARRIER; - - GET_LOCAL_SORT_DATA( startAddrBlock+0, myData[0] ); - GET_LOCAL_SORT_DATA( startAddrBlock+1, myData[1] ); - GET_LOCAL_SORT_DATA( startAddrBlock+2, myData[2] ); - GET_LOCAL_SORT_DATA( startAddrBlock+3, myData[3] ); - } - - {// create histogram -> prefix sum - if( lIdx < NUM_BUCKET ) - { - localHistogram[lIdx] = 0; - localHistogram[NUM_BUCKET+lIdx] = 0; - } - GROUP_LDS_BARRIER; - uint4 keys = uint4((myData[0].key>>m_startBit) & 0xf, (myData[1].key>>m_startBit) & 0xf, (myData[2].key>>m_startBit) & 0xf, (myData[3].key>>m_startBit) & 0xf); - - InterlockedAdd( localHistogram[NUM_BUCKET+keys.x], 1 ); - InterlockedAdd( localHistogram[NUM_BUCKET+keys.y], 1 ); - InterlockedAdd( localHistogram[NUM_BUCKET+keys.z], 1 ); - InterlockedAdd( localHistogram[NUM_BUCKET+keys.w], 1 ); - - GROUP_LDS_BARRIER; - - uint hIdx = NUM_BUCKET+lIdx; - if( lIdx < NUM_BUCKET ) - { - myHistogram = localHistogram[hIdx]; - } - GROUP_LDS_BARRIER; - - if( lIdx < NUM_BUCKET ) - { - localHistogram[hIdx] = localHistogram[hIdx-1]; - - localHistogram[hIdx] += localHistogram[hIdx-1]; - localHistogram[hIdx] += localHistogram[hIdx-2]; - localHistogram[hIdx] += localHistogram[hIdx-4]; - localHistogram[hIdx] += localHistogram[hIdx-8]; - } - - GROUP_LDS_BARRIER; - } -/* - {// write back - int numLocalElements = WG_SIZE*ELEMENTS_PER_WORK_ITEM; - startAddrBlock = lIdx*4; - uint startAddress = igroup*numLocalElements + startAddrBlock; - - for(int ie=0; ie>m_startBit)&0xf; - int groupOffset = localHistogramToCarry[binIdx]; - int myIdx = dataIdx - localHistogram[NUM_BUCKET+binIdx]; - dataToSortOut[ groupOffset + myIdx ] = myData[ie]; - } - } - - GROUP_LDS_BARRIER; - if( lIdx < NUM_BUCKET ) - { - localHistogramToCarry[lIdx] += myHistogram; - } - GROUP_LDS_BARRIER; - - } -} - -/* -[numthreads(WG_SIZE, 1, 1)] -void SortAndScatterKernel1( uint3 gIdx : SV_GroupID, uint3 lIdx : SV_GroupThreadID ) -{ - if( lIdx.x < (NUM_BUCKET) ) - { - localHistogramToCarry[lIdx.x] = rHistogram[lIdx.x*m_nWorkGroupsToExecute + gIdx.x]; - } - - GROUP_LDS_BARRIER; - - for(uint igroup=gIdx.x*m_nBlocksPerGroup; igroup>ib) & 0x1, ~(myData[1].key>>ib) & 0x1, ~(myData[2].key>>ib) & 0x1, ~(myData[3].key>>ib) & 0x1); - uint total; - uint4 rankOfP = localPrefixSum128V( keys, lIdx.x, total ); - uint4 rankOfN = uint4(startAddrBlock, startAddrBlock+1, startAddrBlock+2, startAddrBlock+3) - rankOfP + uint4( total, total, total, total ); - - uint4 myAddr = (keys==uint4(1,1,1,1))? rankOfP: rankOfN; - - GROUP_LDS_BARRIER; - - SET_LOCAL_SORT_DATA( myAddr.x, myData[0] ); - SET_LOCAL_SORT_DATA( myAddr.y, myData[1] ); - SET_LOCAL_SORT_DATA( myAddr.z, myData[2] ); - SET_LOCAL_SORT_DATA( myAddr.w, myData[3] ); - - GROUP_LDS_BARRIER; - - GET_LOCAL_SORT_DATA( startAddrBlock+0, myData[0] ); - GET_LOCAL_SORT_DATA( startAddrBlock+1, myData[1] ); - GET_LOCAL_SORT_DATA( startAddrBlock+2, myData[2] ); - GET_LOCAL_SORT_DATA( startAddrBlock+3, myData[3] ); - } - - {// create histogram -> prefix sum - if( lIdx.x < NUM_BUCKET ) - { - localHistogram[lIdx.x] = 0; - localHistogram[NUM_BUCKET+lIdx.x] = 0; - } - GROUP_LDS_BARRIER; - uint4 keys = uint4((myData[0].key>>m_startBit) & 0xf, (myData[1].key>>m_startBit) & 0xf, (myData[2].key>>m_startBit) & 0xf, (myData[3].key>>m_startBit) & 0xf); - - InterlockedAdd( localHistogram[NUM_BUCKET+keys.x], 1 ); - InterlockedAdd( localHistogram[NUM_BUCKET+keys.y], 1 ); - InterlockedAdd( localHistogram[NUM_BUCKET+keys.z], 1 ); - InterlockedAdd( localHistogram[NUM_BUCKET+keys.w], 1 ); - - GROUP_LDS_BARRIER; - - uint hIdx = NUM_BUCKET+lIdx.x; - if( lIdx.x < NUM_BUCKET ) - { - myHistogram = localHistogram[hIdx]; - } - GROUP_LDS_BARRIER; - - - if( lIdx.x < NUM_BUCKET ) - { - localHistogram[hIdx] = localHistogram[hIdx-1]; - - localHistogram[hIdx] += localHistogram[hIdx-1]; - localHistogram[hIdx] += localHistogram[hIdx-2]; - localHistogram[hIdx] += localHistogram[hIdx-4]; - localHistogram[hIdx] += localHistogram[hIdx-8]; - } - - GROUP_LDS_BARRIER; - } - {// write back - for(int ie=0; ie>m_startBit)&0xf; - int groupOffset = localHistogramToCarry[binIdx]; - int myIdx = dataIdx - localHistogram[NUM_BUCKET+binIdx]; - - dataToSortOut[ groupOffset + myIdx ] = myData[ie]; - } - } - - GROUP_LDS_BARRIER; - if( lIdx.x < NUM_BUCKET ) - { - localHistogramToCarry[lIdx.x] += myHistogram; - } - GROUP_LDS_BARRIER; - - } -} -*/ - -StructuredBuffer dataToSort1 : register( t0 ); -RWStructuredBuffer wHistogram1 : register(u0); - -#define MY_HISTOGRAM(idx) localHistogramMat[(idx)*WG_SIZE+lIdx.x] - -[numthreads(WG_SIZE, 1, 1)] -void StreamCountKernel( DEFAULT_ARGS ) -{ - u32 lIdx = GET_LOCAL_IDX; - u32 wgIdx = GET_GROUP_IDX; - - int myHistogram[NUM_BUCKET]; - - for(int i=0; i> m_startBit) & 0xf; - localKeys[1] = (localData1.key >> m_startBit) & 0xf; - localKeys[2] = (localData2.key >> m_startBit) & 0xf; - localKeys[3] = (localData3.key >> m_startBit) & 0xf; - } - - MY_HISTOGRAM( localKeys[0] )++; - MY_HISTOGRAM( localKeys[1] )++; - MY_HISTOGRAM( localKeys[2] )++; - MY_HISTOGRAM( localKeys[3] )++; - } - - GROUP_LDS_BARRIER; - - { // reduce to 1 - if( lIdx < 64 )//WG_SIZE/2 ) - { - for(int i=0; i> m_startBit) & 0xf; - localKeys[1] = (localData1.key >> m_startBit) & 0xf; - localKeys[2] = (localData2.key >> m_startBit) & 0xf; - localKeys[3] = (localData3.key >> m_startBit) & 0xf; - } - - myHistogram[ localKeys[0] ]++; - myHistogram[ localKeys[1] ]++; - myHistogram[ localKeys[2] ]++; - myHistogram[ localKeys[3] ]++; - } - - { // move to shared - for(int i=0; i 80*16 ) -[numthreads(WG_SIZE, 1, 1)] -void PrefixScanKernel( DEFAULT_ARGS ) -{ - u32 lIdx = GET_LOCAL_IDX; - u32 wgIdx = GET_GROUP_IDX; - - uint data[12] = {0,0,0,0,0,0,0,0,0,0,0,0}; - for(int i=0; i<12; i++) - { - if( int(12*lIdx+i) < NUM_BUCKET*m_nWorkGroupsToExecute ) - data[i] = wHistogram1[12*lIdx+i]; - } - - uint4 myData = uint4(0,0,0,0); - myData.x = data[0] + data[1]; - myData.y = data[2] + data[3]; - myData.z = data[4] + data[5]; - myData.w = data[6] + data[7]; - - - uint totalSum; - uint4 scanned = localPrefixSum128V( myData, lIdx, totalSum ); - - data[11] = scanned.w + data[9] + data[10]; - data[10] = scanned.w + data[9]; - data[9] = scanned.w; - data[8] = scanned.z + data[6] + data[7]; - data[7] = scanned.z + data[6]; - data[6] = scanned.z; - data[5] = scanned.y + data[3] + data[4]; - data[4] = scanned.y + data[3]; - data[3] = scanned.y; - data[2] = scanned.x + data[0] + data[1]; - data[1] = scanned.x + data[0]; - data[0] = scanned.x; - - for(int i=0; i<12; i++) - { - wHistogram1[12*lIdx+i] = data[i]; - } -} -/* -[numthreads(WG_SIZE, 1, 1)] -void PrefixScanKernel( DEFAULT_ARGS ) -{ - u32 lIdx = GET_LOCAL_IDX; - u32 wgIdx = GET_GROUP_IDX; - - uint data[8] = {0,0,0,0,0,0,0,0}; - for(int i=0; i<8; i++) - { - if( int(8*lIdx+i) < NUM_BUCKET*m_nWorkGroupsToExecute ) - data[i] = wHistogram1[8*lIdx+i]; - } - - uint4 myData = uint4(0,0,0,0); - myData.x = data[0] + data[1]; - myData.y = data[2] + data[3]; - myData.z = data[4] + data[5]; - myData.w = data[6] + data[7]; - - - uint totalSum; - uint4 scanned = localPrefixSum128V( myData, lIdx, totalSum ); - - data[7] = scanned.w + data[6]; - data[6] = scanned.w;// + data[5]; - data[5] = scanned.z + data[4]; - data[4] = scanned.z;// + data[3]; - data[3] = scanned.y + data[2]; - data[2] = scanned.y;// + data[1]; - data[1] = scanned.x + data[0]; - data[0] = scanned.x; - - for(int i=0; i<8; i++) - { - wHistogram1[8*lIdx+i] = data[i]; - } -} -*/ - - -[numthreads(WG_SIZE, 1, 1)] -void CopyKernel( DEFAULT_ARGS ) -{ - u32 lIdx = GET_LOCAL_IDX; - u32 wgIdx = GET_GROUP_IDX; - - for(uint igroup=wgIdx.x*m_nBlocksPerGroup; igroup rHistogram : register(t0);\n" -"\n" -"RWStructuredBuffer dataToSort : register( u0 );\n" -"RWStructuredBuffer dataToSortOut : register( u1 );\n" -"\n" -"\n" -"\n" -"#define WG_SIZE 128\n" -"#define ELEMENTS_PER_WORK_ITEM 4\n" -"#define BITS_PER_PASS 4\n" -"#define NUM_BUCKET (1<> targetKey;\n" -" key.y = (data.y & mask) >> targetKey;\n" -" key.z = (data.z & mask) >> targetKey;\n" -" key.w = (data.w & mask) >> targetKey;\n" -" return key;\n" -"}\n" -"\n" -"uint packKeys(uint lower, uint upper)\n" -"{\n" -" return lower|(upper<<16);\n" -"}\n" -"\n" -"uint4 packKeys(uint4 lower, uint4 upper)\n" -"{\n" -" return uint4( lower.x|(upper.x<<16), lower.y|(upper.y<<16), lower.z|(upper.z<<16), lower.w|(upper.w<<16) );\n" -"}\n" -"\n" -"uint extractLower( uint data )\n" -"{\n" -" return data&0xffff;\n" -"}\n" -"\n" -"uint extractUpper( uint data )\n" -"{\n" -" return (data>>16)&0xffff;\n" -"}\n" -"\n" -"uint4 extractLower( uint4 data )\n" -"{\n" -" return uint4( data.x&0xffff, data.y&0xffff, data.z&0xffff, data.w&0xffff );\n" -"}\n" -"\n" -"uint4 extractUpper( uint4 data )\n" -"{\n" -" return uint4( (data.x>>16)&0xffff, (data.y>>16)&0xffff, (data.z>>16)&0xffff, (data.w>>16)&0xffff );\n" -"}\n" -"\n" -"[numthreads(WG_SIZE, 1, 1)]\n" -"void SortAndScatterKernel( DEFAULT_ARGS ) \n" -"{\n" -" u32 lIdx = GET_LOCAL_IDX;\n" -" u32 wgIdx = GET_GROUP_IDX;\n" -"\n" -" if( lIdx < (NUM_BUCKET) )\n" -" {\n" -" localHistogramToCarry[lIdx] = rHistogram[lIdx*m_nWorkGroupsToExecute + wgIdx];\n" -" }\n" -"\n" -" GROUP_LDS_BARRIER;\n" -"\n" -" for(uint igroup=wgIdx*m_nBlocksPerGroup; igroup>m_startBit) & 0xf, (myData[1].key>>m_startBit) & 0xf, (myData[2].key>>m_startBit) & 0xf, (myData[3].key>>m_startBit) & 0xf);\n" -" for(uint targetKey=0; targetKey<(NUM_BUCKET); targetKey+=4)\n" -" {\n" -" uint4 key[4];\n" -" uint keySet[2];\n" -" { // pack 4\n" -" uint4 scannedKey[4];\n" -" key[0] = scannedKey[0] = extractKeys( b, targetKey+0 );\n" -" key[1] = scannedKey[1] = extractKeys( b, targetKey+1 );\n" -" key[2] = scannedKey[2] = extractKeys( b, targetKey+2 );\n" -" key[3] = scannedKey[3] = extractKeys( b, targetKey+3 );\n" -" {\n" -" uint s[4];\n" -" s[0] = prefixScanVectorEx( scannedKey[0] );\n" -" s[1] = prefixScanVectorEx( scannedKey[1] );\n" -" s[2] = prefixScanVectorEx( scannedKey[2] );\n" -" s[3] = prefixScanVectorEx( scannedKey[3] );\n" -" keySet[0] = packKeys( s[0], s[1] );\n" -" keySet[1] = packKeys( s[2], s[3] );\n" -" }\n" -" }\n" -"\n" -" uint dstAddressBase[4];\n" -" {\n" -"\n" -" uint totalSumPacked[2];\n" -" uint dstAddressPacked[2];\n" -"\n" -" localPrefixScan128Dual( keySet[0], keySet[1], lIdx, dstAddressPacked[0], dstAddressPacked[1], totalSumPacked[0], totalSumPacked[1] );\n" -"\n" -" dstAddressBase[0] = extractLower( dstAddressPacked[0] );\n" -" dstAddressBase[1] = extractUpper( dstAddressPacked[0] );\n" -" dstAddressBase[2] = extractLower( dstAddressPacked[1] );\n" -" dstAddressBase[3] = extractUpper( dstAddressPacked[1] );\n" -"\n" -" uint4 histogram;\n" -" histogram.x = extractLower(totalSumPacked[0]);\n" -" histogram.y = extractUpper(totalSumPacked[0]);\n" -" histogram.z = extractLower(totalSumPacked[1]);\n" -" histogram.w = extractUpper(totalSumPacked[1]);\n" -"\n" -" if( lIdx == targetKey + 0 ) myHistogram = histogram.x;\n" -" else if( lIdx == targetKey + 1 ) myHistogram = histogram.y;\n" -" else if( lIdx == targetKey + 2 ) myHistogram = histogram.z;\n" -" else if( lIdx == targetKey + 3 ) myHistogram = histogram.w;\n" -" \n" -" uint histogramSum = prefixScanVectorEx( histogram );\n" -"\n" -" if( lIdx == targetKey + 0 ) localPrefixSum[targetKey+0] = localOffset+histogram.x;\n" -" else if( lIdx == targetKey + 1 ) localPrefixSum[targetKey+1] = localOffset+histogram.y;\n" -" else if( lIdx == targetKey + 2 ) localPrefixSum[targetKey+2] = localOffset+histogram.z;\n" -" else if( lIdx == targetKey + 3 ) localPrefixSum[targetKey+3] = localOffset+histogram.w;\n" -"\n" -" localOffset += histogramSum;\n" -" }\n" -" \n" -" GROUP_LDS_BARRIER;\n" -"\n" -"\n" -" for(int ie=0; ie<4; ie++)\n" -" {\n" -" uint4 scannedKey = key[ie];\n" -" prefixScanVectorEx( scannedKey );\n" -"\n" -" uint offset = localPrefixSum[targetKey + ie] + dstAddressBase[ie];\n" -" uint4 dstAddress = uint4( offset, offset, offset, offset ) + scannedKey;\n" -"\n" -" newOffset[0] += dstAddress.x*key[ie].x;\n" -" newOffset[1] += dstAddress.y*key[ie].y;\n" -" newOffset[2] += dstAddress.z*key[ie].z;\n" -" newOffset[3] += dstAddress.w*key[ie].w;\n" -" }\n" -" }\n" -"\n" -" { // local scatter\n" -" SET_LOCAL_SORT_DATA(newOffset[0], myData[0]);\n" -" SET_LOCAL_SORT_DATA(newOffset[1], myData[1]);\n" -" SET_LOCAL_SORT_DATA(newOffset[2], myData[2]);\n" -" SET_LOCAL_SORT_DATA(newOffset[3], myData[3]);\n" -" }\n" -"\n" -" GROUP_LDS_BARRIER;\n" -"\n" -" { // write data\n" -" for(int i=0; i> m_startBit) & 0xf;\n" -" int groupOffset = localHistogramToCarry[binIdx];\n" -" int myIdx = dataIdx - localPrefixSum[binIdx];\n" -"\n" -" dataToSortOut[ groupOffset + myIdx ] = localData;\n" -" }\n" -" }\n" -"\n" -" GROUP_LDS_BARRIER;\n" -" if( lIdx < NUM_BUCKET )\n" -" {\n" -" localHistogramToCarry[lIdx] += myHistogram;\n" -" }\n" -" GROUP_LDS_BARRIER;\n" -" }\n" -"}\n" -"\n" -"\n" -"[numthreads(WG_SIZE, 1, 1)]\n" -"void SortAndScatterKernel1( DEFAULT_ARGS )\n" -"{\n" -" u32 lIdx = GET_LOCAL_IDX;\n" -" u32 wgIdx = GET_GROUP_IDX;\n" -"\n" -" if( lIdx < (NUM_BUCKET) )\n" -" {\n" -" localHistogramToCarry[lIdx] = rHistogram[lIdx*m_nWorkGroupsToExecute + wgIdx.x];\n" -" }\n" -"\n" -" GROUP_LDS_BARRIER;\n" -"\n" -" for(uint igroup=wgIdx.x*m_nBlocksPerGroup; igroup>ib) & 0x1, ~(myData[1].key>>ib) & 0x1, ~(myData[2].key>>ib) & 0x1, ~(myData[3].key>>ib) & 0x1);\n" -" uint total;\n" -" uint4 rankOfP = localPrefixSum128V( keys, lIdx, total );\n" -" uint4 rankOfN = uint4(startAddrBlock, startAddrBlock+1, startAddrBlock+2, startAddrBlock+3) - rankOfP + uint4( total, total, total, total );\n" -"\n" -" uint4 myAddr = (keys==uint4(1,1,1,1))? rankOfP: rankOfN;\n" -" \n" -" GROUP_LDS_BARRIER;\n" -"\n" -" SET_LOCAL_SORT_DATA( myAddr.x, myData[0] );\n" -" SET_LOCAL_SORT_DATA( myAddr.y, myData[1] );\n" -" SET_LOCAL_SORT_DATA( myAddr.z, myData[2] );\n" -" SET_LOCAL_SORT_DATA( myAddr.w, myData[3] );\n" -"\n" -" GROUP_LDS_BARRIER;\n" -" \n" -" GET_LOCAL_SORT_DATA( startAddrBlock+0, myData[0] );\n" -" GET_LOCAL_SORT_DATA( startAddrBlock+1, myData[1] );\n" -" GET_LOCAL_SORT_DATA( startAddrBlock+2, myData[2] );\n" -" GET_LOCAL_SORT_DATA( startAddrBlock+3, myData[3] );\n" -" }\n" -"\n" -" {// create histogram -> prefix sum\n" -" if( lIdx < NUM_BUCKET )\n" -" {\n" -" localHistogram[lIdx] = 0;\n" -" localHistogram[NUM_BUCKET+lIdx] = 0;\n" -" }\n" -" GROUP_LDS_BARRIER;\n" -" uint4 keys = uint4((myData[0].key>>m_startBit) & 0xf, (myData[1].key>>m_startBit) & 0xf, (myData[2].key>>m_startBit) & 0xf, (myData[3].key>>m_startBit) & 0xf);\n" -" \n" -" InterlockedAdd( localHistogram[NUM_BUCKET+keys.x], 1 );\n" -" InterlockedAdd( localHistogram[NUM_BUCKET+keys.y], 1 );\n" -" InterlockedAdd( localHistogram[NUM_BUCKET+keys.z], 1 );\n" -" InterlockedAdd( localHistogram[NUM_BUCKET+keys.w], 1 );\n" -" \n" -" GROUP_LDS_BARRIER;\n" -" \n" -" uint hIdx = NUM_BUCKET+lIdx;\n" -" if( lIdx < NUM_BUCKET )\n" -" {\n" -" myHistogram = localHistogram[hIdx];\n" -" }\n" -" GROUP_LDS_BARRIER;\n" -" \n" -" if( lIdx < NUM_BUCKET )\n" -" {\n" -" localHistogram[hIdx] = localHistogram[hIdx-1];\n" -"\n" -" localHistogram[hIdx] += localHistogram[hIdx-1];\n" -" localHistogram[hIdx] += localHistogram[hIdx-2];\n" -" localHistogram[hIdx] += localHistogram[hIdx-4];\n" -" localHistogram[hIdx] += localHistogram[hIdx-8];\n" -" }\n" -"\n" -" GROUP_LDS_BARRIER;\n" -" }\n" -"/*\n" -" {// write back\n" -" int numLocalElements = WG_SIZE*ELEMENTS_PER_WORK_ITEM;\n" -" startAddrBlock = lIdx*4;\n" -" uint startAddress = igroup*numLocalElements + startAddrBlock;\n" -"\n" -" for(int ie=0; ie>m_startBit)&0xf;\n" -" int groupOffset = localHistogramToCarry[binIdx];\n" -" int myIdx = dataIdx - localHistogram[NUM_BUCKET+binIdx];\n" -" dataToSortOut[ groupOffset + myIdx ] = myData[ie];\n" -" }\n" -" }\n" -" \n" -" GROUP_LDS_BARRIER;\n" -" if( lIdx < NUM_BUCKET )\n" -" {\n" -" localHistogramToCarry[lIdx] += myHistogram;\n" -" }\n" -" GROUP_LDS_BARRIER;\n" -" \n" -" }\n" -"}\n" -"\n" -"/*\n" -"[numthreads(WG_SIZE, 1, 1)]\n" -"void SortAndScatterKernel1( uint3 gIdx : SV_GroupID, uint3 lIdx : SV_GroupThreadID )\n" -"{\n" -" if( lIdx.x < (NUM_BUCKET) )\n" -" {\n" -" localHistogramToCarry[lIdx.x] = rHistogram[lIdx.x*m_nWorkGroupsToExecute + gIdx.x];\n" -" }\n" -"\n" -" GROUP_LDS_BARRIER;\n" -"\n" -" for(uint igroup=gIdx.x*m_nBlocksPerGroup; igroup>ib) & 0x1, ~(myData[1].key>>ib) & 0x1, ~(myData[2].key>>ib) & 0x1, ~(myData[3].key>>ib) & 0x1);\n" -" uint total;\n" -" uint4 rankOfP = localPrefixSum128V( keys, lIdx.x, total );\n" -" uint4 rankOfN = uint4(startAddrBlock, startAddrBlock+1, startAddrBlock+2, startAddrBlock+3) - rankOfP + uint4( total, total, total, total );\n" -"\n" -" uint4 myAddr = (keys==uint4(1,1,1,1))? rankOfP: rankOfN;\n" -" \n" -" GROUP_LDS_BARRIER;\n" -"\n" -" SET_LOCAL_SORT_DATA( myAddr.x, myData[0] );\n" -" SET_LOCAL_SORT_DATA( myAddr.y, myData[1] );\n" -" SET_LOCAL_SORT_DATA( myAddr.z, myData[2] );\n" -" SET_LOCAL_SORT_DATA( myAddr.w, myData[3] );\n" -"\n" -" GROUP_LDS_BARRIER;\n" -" \n" -" GET_LOCAL_SORT_DATA( startAddrBlock+0, myData[0] );\n" -" GET_LOCAL_SORT_DATA( startAddrBlock+1, myData[1] );\n" -" GET_LOCAL_SORT_DATA( startAddrBlock+2, myData[2] );\n" -" GET_LOCAL_SORT_DATA( startAddrBlock+3, myData[3] );\n" -" }\n" -" \n" -" {// create histogram -> prefix sum\n" -" if( lIdx.x < NUM_BUCKET )\n" -" {\n" -" localHistogram[lIdx.x] = 0;\n" -" localHistogram[NUM_BUCKET+lIdx.x] = 0;\n" -" }\n" -" GROUP_LDS_BARRIER;\n" -" uint4 keys = uint4((myData[0].key>>m_startBit) & 0xf, (myData[1].key>>m_startBit) & 0xf, (myData[2].key>>m_startBit) & 0xf, (myData[3].key>>m_startBit) & 0xf);\n" -" \n" -" InterlockedAdd( localHistogram[NUM_BUCKET+keys.x], 1 );\n" -" InterlockedAdd( localHistogram[NUM_BUCKET+keys.y], 1 );\n" -" InterlockedAdd( localHistogram[NUM_BUCKET+keys.z], 1 );\n" -" InterlockedAdd( localHistogram[NUM_BUCKET+keys.w], 1 );\n" -" \n" -" GROUP_LDS_BARRIER;\n" -" \n" -" uint hIdx = NUM_BUCKET+lIdx.x;\n" -" if( lIdx.x < NUM_BUCKET )\n" -" {\n" -" myHistogram = localHistogram[hIdx];\n" -" }\n" -" GROUP_LDS_BARRIER;\n" -" \n" -"\n" -" if( lIdx.x < NUM_BUCKET )\n" -" {\n" -" localHistogram[hIdx] = localHistogram[hIdx-1];\n" -"\n" -" localHistogram[hIdx] += localHistogram[hIdx-1];\n" -" localHistogram[hIdx] += localHistogram[hIdx-2];\n" -" localHistogram[hIdx] += localHistogram[hIdx-4];\n" -" localHistogram[hIdx] += localHistogram[hIdx-8];\n" -" }\n" -"\n" -" GROUP_LDS_BARRIER;\n" -" }\n" -" {// write back\n" -" for(int ie=0; ie>m_startBit)&0xf;\n" -" int groupOffset = localHistogramToCarry[binIdx];\n" -" int myIdx = dataIdx - localHistogram[NUM_BUCKET+binIdx];\n" -" \n" -" dataToSortOut[ groupOffset + myIdx ] = myData[ie];\n" -" }\n" -" }\n" -" \n" -" GROUP_LDS_BARRIER;\n" -" if( lIdx.x < NUM_BUCKET )\n" -" {\n" -" localHistogramToCarry[lIdx.x] += myHistogram;\n" -" }\n" -" GROUP_LDS_BARRIER;\n" -" \n" -" }\n" -"}\n" -"*/\n" -"\n" -"StructuredBuffer dataToSort1 : register( t0 );\n" -"RWStructuredBuffer wHistogram1 : register(u0);\n" -"\n" -"#define MY_HISTOGRAM(idx) localHistogramMat[(idx)*WG_SIZE+lIdx.x]\n" -"\n" -"[numthreads(WG_SIZE, 1, 1)]\n" -"void StreamCountKernel( DEFAULT_ARGS ) \n" -"{\n" -" u32 lIdx = GET_LOCAL_IDX;\n" -" u32 wgIdx = GET_GROUP_IDX;\n" -"\n" -" int myHistogram[NUM_BUCKET];\n" -"\n" -" for(int i=0; i> m_startBit) & 0xf;\n" -" localKeys[1] = (localData1.key >> m_startBit) & 0xf;\n" -" localKeys[2] = (localData2.key >> m_startBit) & 0xf;\n" -" localKeys[3] = (localData3.key >> m_startBit) & 0xf;\n" -" }\n" -"\n" -" MY_HISTOGRAM( localKeys[0] )++;\n" -" MY_HISTOGRAM( localKeys[1] )++;\n" -" MY_HISTOGRAM( localKeys[2] )++;\n" -" MY_HISTOGRAM( localKeys[3] )++;\n" -" }\n" -"\n" -" GROUP_LDS_BARRIER;\n" -"\n" -" { // reduce to 1\n" -" if( lIdx < 64 )//WG_SIZE/2 )\n" -" {\n" -" for(int i=0; i> m_startBit) & 0xf;\n" -" localKeys[1] = (localData1.key >> m_startBit) & 0xf;\n" -" localKeys[2] = (localData2.key >> m_startBit) & 0xf;\n" -" localKeys[3] = (localData3.key >> m_startBit) & 0xf;\n" -" }\n" -"\n" -" myHistogram[ localKeys[0] ]++;\n" -" myHistogram[ localKeys[1] ]++;\n" -" myHistogram[ localKeys[2] ]++;\n" -" myHistogram[ localKeys[3] ]++;\n" -" }\n" -"\n" -" { // move to shared\n" -" for(int i=0; i 80*16 )\n" -"[numthreads(WG_SIZE, 1, 1)]\n" -"void PrefixScanKernel( DEFAULT_ARGS )\n" -"{\n" -" u32 lIdx = GET_LOCAL_IDX;\n" -" u32 wgIdx = GET_GROUP_IDX;\n" -"\n" -" uint data[12] = {0,0,0,0,0,0,0,0,0,0,0,0};\n" -" for(int i=0; i<12; i++)\n" -" {\n" -" if( int(12*lIdx+i) < NUM_BUCKET*m_nWorkGroupsToExecute )\n" -" data[i] = wHistogram1[12*lIdx+i];\n" -" }\n" -"\n" -" uint4 myData = uint4(0,0,0,0);\n" -" myData.x = data[0] + data[1];\n" -" myData.y = data[2] + data[3];\n" -" myData.z = data[4] + data[5];\n" -" myData.w = data[6] + data[7];\n" -"\n" -"\n" -" uint totalSum;\n" -" uint4 scanned = localPrefixSum128V( myData, lIdx, totalSum );\n" -"\n" -" data[11] = scanned.w + data[9] + data[10];\n" -" data[10] = scanned.w + data[9];\n" -" data[9] = scanned.w;\n" -" data[8] = scanned.z + data[6] + data[7];\n" -" data[7] = scanned.z + data[6];\n" -" data[6] = scanned.z;\n" -" data[5] = scanned.y + data[3] + data[4];\n" -" data[4] = scanned.y + data[3];\n" -" data[3] = scanned.y;\n" -" data[2] = scanned.x + data[0] + data[1];\n" -" data[1] = scanned.x + data[0];\n" -" data[0] = scanned.x;\n" -"\n" -" for(int i=0; i<12; i++)\n" -" {\n" -" wHistogram1[12*lIdx+i] = data[i];\n" -" }\n" -"}\n" -"/*\n" -"[numthreads(WG_SIZE, 1, 1)]\n" -"void PrefixScanKernel( DEFAULT_ARGS )\n" -"{\n" -" u32 lIdx = GET_LOCAL_IDX;\n" -" u32 wgIdx = GET_GROUP_IDX;\n" -"\n" -" uint data[8] = {0,0,0,0,0,0,0,0};\n" -" for(int i=0; i<8; i++)\n" -" {\n" -" if( int(8*lIdx+i) < NUM_BUCKET*m_nWorkGroupsToExecute )\n" -" data[i] = wHistogram1[8*lIdx+i];\n" -" }\n" -"\n" -" uint4 myData = uint4(0,0,0,0);\n" -" myData.x = data[0] + data[1];\n" -" myData.y = data[2] + data[3];\n" -" myData.z = data[4] + data[5];\n" -" myData.w = data[6] + data[7];\n" -"\n" -"\n" -" uint totalSum;\n" -" uint4 scanned = localPrefixSum128V( myData, lIdx, totalSum );\n" -"\n" -" data[7] = scanned.w + data[6];\n" -" data[6] = scanned.w;// + data[5];\n" -" data[5] = scanned.z + data[4];\n" -" data[4] = scanned.z;// + data[3];\n" -" data[3] = scanned.y + data[2];\n" -" data[2] = scanned.y;// + data[1];\n" -" data[1] = scanned.x + data[0];\n" -" data[0] = scanned.x;\n" -"\n" -" for(int i=0; i<8; i++)\n" -" {\n" -" wHistogram1[8*lIdx+i] = data[i];\n" -" }\n" -"}\n" -"*/\n" -"\n" -"\n" -"[numthreads(WG_SIZE, 1, 1)]\n" -"void CopyKernel( DEFAULT_ARGS )\n" -"{\n" -" u32 lIdx = GET_LOCAL_IDX;\n" -" u32 wgIdx = GET_GROUP_IDX;\n" -"\n" -" for(uint igroup=wgIdx.x*m_nBlocksPerGroup; igroup -class RadixSort : public RadixSortBase -{ - public: - struct Data - { - HostBuffer* m_workBuffer; - }; - - enum - { - BITS_PER_PASS = 8, - NUM_TABLES = (1<m_type == TYPE_HOST ); - - Data* data = new Data; - data->m_workBuffer = new HostBuffer( deviceData, maxSize ); - return data; - } - - static - void deallocate(Data* data) - { - delete data->m_workBuffer; - delete data; - } - - static - void execute(Data* data, Buffer& inout, int n, int sortBits = 32) - { - ADLASSERT( inout.getType() == TYPE_HOST ); - - int tables[NUM_TABLES]; - int counter[NUM_TABLES]; - - SortData* src = inout.m_ptr; - SortData* dst = data->m_workBuffer->m_ptr; - - int count=0; - for(int startBit=0; startBit> startBit) & (NUM_TABLES-1); - tables[tableIdx]++; - } - - // prefix scan - int sum = 0; - for(int i=0; i> startBit) & (NUM_TABLES-1); - - dst[tables[tableIdx] + counter[tableIdx]] = src[i]; - counter[tableIdx] ++; - } - - swap2( src, dst ); - count++; - } - - { - if (count&1) - //if( src != inout.m_ptr ) - { - memcpy( dst, src, sizeof(SortData)*n ); - } - } - } -}; diff --git a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Sort/RadixSortSimpleCL.h b/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Sort/RadixSortSimpleCL.h deleted file mode 100644 index 8325529ff..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Sort/RadixSortSimpleCL.h +++ /dev/null @@ -1,134 +0,0 @@ -static const char* radixSortSimpleKernelsCL = \ - "#pragma OPENCL EXTENSION cl_amd_printf : enable\n" - "#pragma OPENCL EXTENSION cl_khr_local_int32_base_atomics : enable\n" - "\n" - "typedef unsigned int u32;\n" - "#define GET_GROUP_IDX get_group_id(0)\n" - "#define GET_LOCAL_IDX get_local_id(0)\n" - "#define GET_GLOBAL_IDX get_global_id(0)\n" - "#define GET_GROUP_SIZE get_local_size(0)\n" - "#define GROUP_LDS_BARRIER barrier(CLK_LOCAL_MEM_FENCE)\n" - "#define AtomInc(x) atom_inc(&(x))\n" - "#define AtomInc1(x, out) out = atom_inc(&(x))\n" - "\n" - "\n" - "#define WG_SIZE 128\n" - "#define NUM_PER_WI 4\n" - "\n" - "\n" - "typedef struct\n" - "{\n" - " u32 m_key;\n" - " u32 m_value;\n" - "}SortData;\n" - "\n" - "\n" - "typedef struct\n" - "{\n" - " u32 m_startBit;\n" - " u32 m_numGroups;\n" - " u32 m_padding[2];\n" - "} ConstBuffer;\n" - "\n" - "\n" - "__kernel\n" - "__attribute__((reqd_work_group_size(WG_SIZE,1,1)))\n" - "void LocalCountKernel(__global SortData* sortData,\n" - " __global u32* ldsHistogramOut,\n" - " ConstBuffer cb)\n" - "{\n" - " __local u32 ldsHistogram[16][256];\n" - "\n" - " int lIdx = GET_LOCAL_IDX;\n" - " int gIdx = GET_GLOBAL_IDX;\n" - "\n" - " for(int i=0; i<16; i++)\n" - " {\n" - " ldsHistogram[i][lIdx] = 0.f;\n" - " ldsHistogram[i][lIdx+128] = 0.f;\n" - " }\n" - "\n" - " GROUP_LDS_BARRIER;\n" - "\n" - " SortData datas[NUM_PER_WI];\n" - " datas[0] = sortData[gIdx*NUM_PER_WI+0];\n" - " datas[1] = sortData[gIdx*NUM_PER_WI+1];\n" - " datas[2] = sortData[gIdx*NUM_PER_WI+2];\n" - " datas[3] = sortData[gIdx*NUM_PER_WI+3];\n" - "\n" - " datas[0].m_key = (datas[0].m_key >> cb.m_startBit) & 0xff;\n" - " datas[1].m_key = (datas[1].m_key >> cb.m_startBit) & 0xff;\n" - " datas[2].m_key = (datas[2].m_key >> cb.m_startBit) & 0xff;\n" - " datas[3].m_key = (datas[3].m_key >> cb.m_startBit) & 0xff;\n" - "\n" - " int tableIdx = lIdx%16;\n" - "\n" - " AtomInc(ldsHistogram[tableIdx][datas[0].m_key]);\n" - " AtomInc(ldsHistogram[tableIdx][datas[1].m_key]);\n" - " AtomInc(ldsHistogram[tableIdx][datas[2].m_key]);\n" - " AtomInc(ldsHistogram[tableIdx][datas[3].m_key]);\n" - "\n" - " GROUP_LDS_BARRIER;\n" - "\n" - " u32 sum0, sum1;\n" - " sum0 = sum1 = 0;\n" - " for(int i=0; i<16; i++)\n" - " {\n" - " sum0 += ldsHistogram[i][lIdx];\n" - " sum1 += ldsHistogram[i][lIdx+128];\n" - " }\n" - "\n" - " ldsHistogramOut[lIdx*cb.m_numGroups+GET_GROUP_IDX] = sum0;\n" - " ldsHistogramOut[(lIdx+128)*cb.m_numGroups+GET_GROUP_IDX] = sum1;\n" - "}\n" - "\n" - "__kernel\n" - "__attribute__((reqd_work_group_size(WG_SIZE,1,1)))\n" - "void ScatterKernel(__global SortData* sortData,\n" - " __global SortData* sortDataOut,\n" - " __global u32* scannedHistogram,\n" - " ConstBuffer cb)\n" - "{\n" - " __local u32 ldsCurrentLocation[256];\n" - "\n" - " int lIdx = GET_LOCAL_IDX;\n" - " int gIdx = GET_GLOBAL_IDX;\n" - "\n" - " {\n" - " ldsCurrentLocation[lIdx] = scannedHistogram[lIdx*cb.m_numGroups+GET_GROUP_IDX];\n" - " ldsCurrentLocation[lIdx+128] = scannedHistogram[(lIdx+128)*cb.m_numGroups+GET_GROUP_IDX];\n" - " }\n" - "\n" - " GROUP_LDS_BARRIER;\n" - "\n" - " SortData datas[NUM_PER_WI];\n" - " int keys[NUM_PER_WI];\n" - " datas[0] = sortData[gIdx*NUM_PER_WI+0];\n" - " datas[1] = sortData[gIdx*NUM_PER_WI+1];\n" - " datas[2] = sortData[gIdx*NUM_PER_WI+2];\n" - " datas[3] = sortData[gIdx*NUM_PER_WI+3];\n" - "\n" - " keys[0] = (datas[0].m_key >> cb.m_startBit) & 0xff;\n" - " keys[1] = (datas[1].m_key >> cb.m_startBit) & 0xff;\n" - " keys[2] = (datas[2].m_key >> cb.m_startBit) & 0xff;\n" - " keys[3] = (datas[3].m_key >> cb.m_startBit) & 0xff;\n" - "\n" - " int dst[NUM_PER_WI];\n" - " for(int i=0; i sortData : register( t0 );\n" - "RWStructuredBuffer ldsHistogramOut : register( u0 );\n" - "\n" - "groupshared u32 ldsHistogram[16][256];\n" - "\n" - "[numthreads(WG_SIZE, 1, 1)]\n" - "void LocalCountKernel( DEFAULT_ARGS )\n" - "{\n" - " int lIdx = GET_LOCAL_IDX;\n" - " int gIdx = GET_GLOBAL_IDX;\n" - "\n" - " for(int i=0; i<16; i++)\n" - " {\n" - " ldsHistogram[i][lIdx] = 0.f;\n" - " ldsHistogram[i][lIdx+128] = 0.f;\n" - " }\n" - "\n" - " GROUP_LDS_BARRIER;\n" - "\n" - " SortData datas[NUM_PER_WI];\n" - " datas[0] = sortData[gIdx*NUM_PER_WI+0];\n" - " datas[1] = sortData[gIdx*NUM_PER_WI+1];\n" - " datas[2] = sortData[gIdx*NUM_PER_WI+2];\n" - " datas[3] = sortData[gIdx*NUM_PER_WI+3];\n" - "\n" - " datas[0].m_key = (datas[0].m_key >> m_startBit) & 0xff;\n" - " datas[1].m_key = (datas[1].m_key >> m_startBit) & 0xff;\n" - " datas[2].m_key = (datas[2].m_key >> m_startBit) & 0xff;\n" - " datas[3].m_key = (datas[3].m_key >> m_startBit) & 0xff;\n" - "\n" - " int tableIdx = lIdx%16;\n" - "\n" - " AtomInc(ldsHistogram[tableIdx][datas[0].m_key]);\n" - " AtomInc(ldsHistogram[tableIdx][datas[1].m_key]);\n" - " AtomInc(ldsHistogram[tableIdx][datas[2].m_key]);\n" - " AtomInc(ldsHistogram[tableIdx][datas[3].m_key]);\n" - "\n" - " GROUP_LDS_BARRIER;\n" - "\n" - " u32 sum0, sum1;\n" - " sum0 = sum1 = 0;\n" - " for(int i=0; i<16; i++)\n" - " {\n" - " sum0 += ldsHistogram[i][lIdx];\n" - " sum1 += ldsHistogram[i][lIdx+128];\n" - " }\n" - "\n" - " ldsHistogramOut[lIdx*m_numGroups+GET_GROUP_IDX] = sum0;\n" - " ldsHistogramOut[(lIdx+128)*m_numGroups+GET_GROUP_IDX] = sum1;\n" - "}\n" - "\n" - "\n" - "RWStructuredBuffer sortDataOut : register( u0 );\n" - "RWStructuredBuffer scannedHistogram : register( u1 );\n" - "\n" - "groupshared u32 ldsCurrentLocation[256];\n" - "\n" - "[numthreads(WG_SIZE, 1, 1)]\n" - "void ScatterKernel( DEFAULT_ARGS )\n" - "{\n" - " int lIdx = GET_LOCAL_IDX;\n" - " int gIdx = GET_GLOBAL_IDX;\n" - "\n" - " {\n" - " ldsCurrentLocation[lIdx] = scannedHistogram[lIdx*m_numGroups+GET_GROUP_IDX];\n" - " ldsCurrentLocation[lIdx+128] = scannedHistogram[(lIdx+128)*m_numGroups+GET_GROUP_IDX];\n" - " }\n" - "\n" - " GROUP_LDS_BARRIER;\n" - "\n" - " SortData datas[NUM_PER_WI];\n" - " int keys[NUM_PER_WI];\n" - " datas[0] = sortData[gIdx*NUM_PER_WI+0];\n" - " datas[1] = sortData[gIdx*NUM_PER_WI+1];\n" - " datas[2] = sortData[gIdx*NUM_PER_WI+2];\n" - " datas[3] = sortData[gIdx*NUM_PER_WI+3];\n" - "\n" - " keys[0] = (datas[0].m_key >> m_startBit) & 0xff;\n" - " keys[1] = (datas[1].m_key >> m_startBit) & 0xff;\n" - " keys[2] = (datas[2].m_key >> m_startBit) & 0xff;\n" - " keys[3] = (datas[3].m_key >> m_startBit) & 0xff;\n" - "\n" - " int dst[NUM_PER_WI];\n" - " for(int i=0; i> cb.m_startBit) & 0xff; - datas[1].m_key = (datas[1].m_key >> cb.m_startBit) & 0xff; - datas[2].m_key = (datas[2].m_key >> cb.m_startBit) & 0xff; - datas[3].m_key = (datas[3].m_key >> cb.m_startBit) & 0xff; - - int tableIdx = lIdx%16; - - AtomInc(ldsHistogram[tableIdx][datas[0].m_key]); - AtomInc(ldsHistogram[tableIdx][datas[1].m_key]); - AtomInc(ldsHistogram[tableIdx][datas[2].m_key]); - AtomInc(ldsHistogram[tableIdx][datas[3].m_key]); - - GROUP_LDS_BARRIER; - - u32 sum0, sum1; - sum0 = sum1 = 0; - for(int i=0; i<16; i++) - { - sum0 += ldsHistogram[i][lIdx]; - sum1 += ldsHistogram[i][lIdx+128]; - } - - ldsHistogramOut[lIdx*cb.m_numGroups+GET_GROUP_IDX] = sum0; - ldsHistogramOut[(lIdx+128)*cb.m_numGroups+GET_GROUP_IDX] = sum1; -} - -__kernel -__attribute__((reqd_work_group_size(WG_SIZE,1,1))) -void ScatterKernel(__global SortData* sortData, - __global SortData* sortDataOut, - __global u32* scannedHistogram, - ConstBuffer cb) -{ - __local u32 ldsCurrentLocation[256]; - - int lIdx = GET_LOCAL_IDX; - int gIdx = GET_GLOBAL_IDX; - - { - ldsCurrentLocation[lIdx] = scannedHistogram[lIdx*cb.m_numGroups+GET_GROUP_IDX]; - ldsCurrentLocation[lIdx+128] = scannedHistogram[(lIdx+128)*cb.m_numGroups+GET_GROUP_IDX]; - } - - GROUP_LDS_BARRIER; - - SortData datas[NUM_PER_WI]; - int keys[NUM_PER_WI]; - datas[0] = sortData[gIdx*NUM_PER_WI+0]; - datas[1] = sortData[gIdx*NUM_PER_WI+1]; - datas[2] = sortData[gIdx*NUM_PER_WI+2]; - datas[3] = sortData[gIdx*NUM_PER_WI+3]; - - keys[0] = (datas[0].m_key >> cb.m_startBit) & 0xff; - keys[1] = (datas[1].m_key >> cb.m_startBit) & 0xff; - keys[2] = (datas[2].m_key >> cb.m_startBit) & 0xff; - keys[3] = (datas[3].m_key >> cb.m_startBit) & 0xff; - - int dst[NUM_PER_WI]; - for(int i=0; i sortData : register( t0 ); -RWStructuredBuffer ldsHistogramOut : register( u0 ); - -groupshared u32 ldsHistogram[16][256]; - -[numthreads(WG_SIZE, 1, 1)] -void LocalCountKernel( DEFAULT_ARGS ) -{ - int lIdx = GET_LOCAL_IDX; - int gIdx = GET_GLOBAL_IDX; - - for(int i=0; i<16; i++) - { - ldsHistogram[i][lIdx] = 0.f; - ldsHistogram[i][lIdx+128] = 0.f; - } - - GROUP_LDS_BARRIER; - - SortData datas[NUM_PER_WI]; - datas[0] = sortData[gIdx*NUM_PER_WI+0]; - datas[1] = sortData[gIdx*NUM_PER_WI+1]; - datas[2] = sortData[gIdx*NUM_PER_WI+2]; - datas[3] = sortData[gIdx*NUM_PER_WI+3]; - - datas[0].m_key = (datas[0].m_key >> m_startBit) & 0xff; - datas[1].m_key = (datas[1].m_key >> m_startBit) & 0xff; - datas[2].m_key = (datas[2].m_key >> m_startBit) & 0xff; - datas[3].m_key = (datas[3].m_key >> m_startBit) & 0xff; - - int tableIdx = lIdx%16; - - AtomInc(ldsHistogram[tableIdx][datas[0].m_key]); - AtomInc(ldsHistogram[tableIdx][datas[1].m_key]); - AtomInc(ldsHistogram[tableIdx][datas[2].m_key]); - AtomInc(ldsHistogram[tableIdx][datas[3].m_key]); - - GROUP_LDS_BARRIER; - - u32 sum0, sum1; - sum0 = sum1 = 0; - for(int i=0; i<16; i++) - { - sum0 += ldsHistogram[i][lIdx]; - sum1 += ldsHistogram[i][lIdx+128]; - } - - ldsHistogramOut[lIdx*m_numGroups+GET_GROUP_IDX] = sum0; - ldsHistogramOut[(lIdx+128)*m_numGroups+GET_GROUP_IDX] = sum1; -} - - -RWStructuredBuffer sortDataOut : register( u0 ); -RWStructuredBuffer scannedHistogram : register( u1 ); - -groupshared u32 ldsCurrentLocation[256]; - -[numthreads(WG_SIZE, 1, 1)] -void ScatterKernel( DEFAULT_ARGS ) -{ - int lIdx = GET_LOCAL_IDX; - int gIdx = GET_GLOBAL_IDX; - - { - ldsCurrentLocation[lIdx] = scannedHistogram[lIdx*m_numGroups+GET_GROUP_IDX]; - ldsCurrentLocation[lIdx+128] = scannedHistogram[(lIdx+128)*m_numGroups+GET_GROUP_IDX]; - } - - GROUP_LDS_BARRIER; - - SortData datas[NUM_PER_WI]; - int keys[NUM_PER_WI]; - datas[0] = sortData[gIdx*NUM_PER_WI+0]; - datas[1] = sortData[gIdx*NUM_PER_WI+1]; - datas[2] = sortData[gIdx*NUM_PER_WI+2]; - datas[3] = sortData[gIdx*NUM_PER_WI+3]; - - keys[0] = (datas[0].m_key >> m_startBit) & 0xff; - keys[1] = (datas[1].m_key >> m_startBit) & 0xff; - keys[2] = (datas[2].m_key >> m_startBit) & 0xff; - keys[3] = (datas[3].m_key >> m_startBit) & 0xff; - - int dst[NUM_PER_WI]; - for(int i=0; i> cb.m_startBit) & 0xff;\n" -" datas[1].m_key = (datas[1].m_key >> cb.m_startBit) & 0xff;\n" -" datas[2].m_key = (datas[2].m_key >> cb.m_startBit) & 0xff;\n" -" datas[3].m_key = (datas[3].m_key >> cb.m_startBit) & 0xff;\n" -"\n" -" int tableIdx = lIdx%16;\n" -" \n" -" AtomInc(ldsHistogram[tableIdx][datas[0].m_key]);\n" -" AtomInc(ldsHistogram[tableIdx][datas[1].m_key]);\n" -" AtomInc(ldsHistogram[tableIdx][datas[2].m_key]);\n" -" AtomInc(ldsHistogram[tableIdx][datas[3].m_key]);\n" -"\n" -" GROUP_LDS_BARRIER;\n" -" \n" -" u32 sum0, sum1;\n" -" sum0 = sum1 = 0;\n" -" for(int i=0; i<16; i++)\n" -" {\n" -" sum0 += ldsHistogram[i][lIdx];\n" -" sum1 += ldsHistogram[i][lIdx+128];\n" -" }\n" -"\n" -" ldsHistogramOut[lIdx*cb.m_numGroups+GET_GROUP_IDX] = sum0;\n" -" ldsHistogramOut[(lIdx+128)*cb.m_numGroups+GET_GROUP_IDX] = sum1;\n" -"}\n" -"\n" -"__kernel\n" -"__attribute__((reqd_work_group_size(WG_SIZE,1,1)))\n" -"void ScatterKernel(__global SortData* sortData,\n" -" __global SortData* sortDataOut,\n" -" __global u32* scannedHistogram, \n" -" ConstBuffer cb)\n" -"{\n" -" __local u32 ldsCurrentLocation[256];\n" -"\n" -" int lIdx = GET_LOCAL_IDX;\n" -" int gIdx = GET_GLOBAL_IDX;\n" -" \n" -" {\n" -" ldsCurrentLocation[lIdx] = scannedHistogram[lIdx*cb.m_numGroups+GET_GROUP_IDX];\n" -" ldsCurrentLocation[lIdx+128] = scannedHistogram[(lIdx+128)*cb.m_numGroups+GET_GROUP_IDX];\n" -" }\n" -"\n" -" GROUP_LDS_BARRIER;\n" -" \n" -" SortData datas[NUM_PER_WI];\n" -" int keys[NUM_PER_WI];\n" -" datas[0] = sortData[gIdx*NUM_PER_WI+0];\n" -" datas[1] = sortData[gIdx*NUM_PER_WI+1];\n" -" datas[2] = sortData[gIdx*NUM_PER_WI+2];\n" -" datas[3] = sortData[gIdx*NUM_PER_WI+3];\n" -"\n" -" keys[0] = (datas[0].m_key >> cb.m_startBit) & 0xff;\n" -" keys[1] = (datas[1].m_key >> cb.m_startBit) & 0xff;\n" -" keys[2] = (datas[2].m_key >> cb.m_startBit) & 0xff;\n" -" keys[3] = (datas[3].m_key >> cb.m_startBit) & 0xff;\n" -"\n" -" int dst[NUM_PER_WI];\n" -" for(int i=0; i sortData : register( t0 );\n" -"RWStructuredBuffer ldsHistogramOut : register( u0 );\n" -"\n" -"groupshared u32 ldsHistogram[16][256];\n" -"\n" -"[numthreads(WG_SIZE, 1, 1)]\n" -"void LocalCountKernel( DEFAULT_ARGS )\n" -"{\n" -" int lIdx = GET_LOCAL_IDX;\n" -" int gIdx = GET_GLOBAL_IDX;\n" -" \n" -" for(int i=0; i<16; i++)\n" -" {\n" -" ldsHistogram[i][lIdx] = 0.f;\n" -" ldsHistogram[i][lIdx+128] = 0.f;\n" -" }\n" -" \n" -" GROUP_LDS_BARRIER;\n" -" \n" -" SortData datas[NUM_PER_WI];\n" -" datas[0] = sortData[gIdx*NUM_PER_WI+0];\n" -" datas[1] = sortData[gIdx*NUM_PER_WI+1];\n" -" datas[2] = sortData[gIdx*NUM_PER_WI+2];\n" -" datas[3] = sortData[gIdx*NUM_PER_WI+3];\n" -"\n" -" datas[0].m_key = (datas[0].m_key >> m_startBit) & 0xff;\n" -" datas[1].m_key = (datas[1].m_key >> m_startBit) & 0xff;\n" -" datas[2].m_key = (datas[2].m_key >> m_startBit) & 0xff;\n" -" datas[3].m_key = (datas[3].m_key >> m_startBit) & 0xff;\n" -"\n" -" int tableIdx = lIdx%16;\n" -" \n" -" AtomInc(ldsHistogram[tableIdx][datas[0].m_key]);\n" -" AtomInc(ldsHistogram[tableIdx][datas[1].m_key]);\n" -" AtomInc(ldsHistogram[tableIdx][datas[2].m_key]);\n" -" AtomInc(ldsHistogram[tableIdx][datas[3].m_key]);\n" -"\n" -" GROUP_LDS_BARRIER;\n" -" \n" -" u32 sum0, sum1;\n" -" sum0 = sum1 = 0;\n" -" for(int i=0; i<16; i++)\n" -" {\n" -" sum0 += ldsHistogram[i][lIdx];\n" -" sum1 += ldsHistogram[i][lIdx+128];\n" -" }\n" -"\n" -" ldsHistogramOut[lIdx*m_numGroups+GET_GROUP_IDX] = sum0;\n" -" ldsHistogramOut[(lIdx+128)*m_numGroups+GET_GROUP_IDX] = sum1;\n" -"}\n" -"\n" -"\n" -"RWStructuredBuffer sortDataOut : register( u0 );\n" -"RWStructuredBuffer scannedHistogram : register( u1 );\n" -"\n" -"groupshared u32 ldsCurrentLocation[256];\n" -"\n" -"[numthreads(WG_SIZE, 1, 1)]\n" -"void ScatterKernel( DEFAULT_ARGS )\n" -"{\n" -" int lIdx = GET_LOCAL_IDX;\n" -" int gIdx = GET_GLOBAL_IDX;\n" -" \n" -" {\n" -" ldsCurrentLocation[lIdx] = scannedHistogram[lIdx*m_numGroups+GET_GROUP_IDX];\n" -" ldsCurrentLocation[lIdx+128] = scannedHistogram[(lIdx+128)*m_numGroups+GET_GROUP_IDX];\n" -" }\n" -"\n" -" GROUP_LDS_BARRIER;\n" -" \n" -" SortData datas[NUM_PER_WI];\n" -" int keys[NUM_PER_WI];\n" -" datas[0] = sortData[gIdx*NUM_PER_WI+0];\n" -" datas[1] = sortData[gIdx*NUM_PER_WI+1];\n" -" datas[2] = sortData[gIdx*NUM_PER_WI+2];\n" -" datas[3] = sortData[gIdx*NUM_PER_WI+3];\n" -"\n" -" keys[0] = (datas[0].m_key >> m_startBit) & 0xff;\n" -" keys[1] = (datas[1].m_key >> m_startBit) & 0xff;\n" -" keys[2] = (datas[2].m_key >> m_startBit) & 0xff;\n" -" keys[3] = (datas[3].m_key >> m_startBit) & 0xff;\n" -"\n" -" int dst[NUM_PER_WI];\n" -" for(int i=0; i -#include - -template -class RadixSortStandard : public RadixSortBase -{ - public: - typedef Launcher::BufferInfo BufferInfo; - - enum - { - WG_SIZE = 128, - NUM_PER_WI = 4, - - BITS_PER_PASS = 4, - }; - - struct Data : public RadixSort::Data - { - Kernel* m_localSortKernel; - Kernel* m_scatterKernel; - Kernel* m_copyKernel; - - Buffer* m_workBuffer0; - Buffer* m_workBuffer1; - Buffer* m_workBuffer2; - Buffer* m_workBuffer3; - Buffer* m_constBuffer[32/BITS_PER_PASS]; - }; - - - static - Data* allocate(const Device* deviceData, int maxSize, Option option = SORT_NORMAL); - - static - void deallocate(void* data); - - static - void execute(void* data, Buffer& inout, int n, int sortBits); -}; - -template -typename RadixSortStandard::Data* RadixSortStandard::allocate(const Device* deviceData, int maxSize, Option option) -{ - ADLASSERT( type == deviceData->m_type ); - - u32 maxNumGroups = (maxSize+WG_SIZE*NUM_PER_WI-1)/(WG_SIZE*NUM_PER_WI); - - const char* src[] = -#if defined(ADL_LOAD_KERNEL_FROM_STRING) - {radixSortStandardKernelsCL,radixSortStandardKernelsDX11}; -// ADLASSERT(0); -#else - {0,0}; -#endif - - Data* data = new Data; - data->m_option = option; - data->m_deviceData = deviceData; - - data->m_localSortKernel = deviceData->getKernel( PATH, KERNEL0, 0, src[type] ); - data->m_scatterKernel = deviceData->getKernel( PATH, KERNEL1, 0, src[type] ); - data->m_copyKernel = deviceData->getKernel( PATH, KERNEL2, 0, src[type] ); - - // is this correct? - data->m_scanData = PrefixScan::allocate( deviceData, maxNumGroups*(1<m_workBuffer0 = new Buffer( deviceData, maxNumGroups*(1<m_workBuffer1 = new Buffer( deviceData, maxNumGroups*(1<m_workBuffer2 = new Buffer( deviceData, maxNumGroups*(1<m_workBuffer3 = new Buffer( deviceData, maxSize ); - for(int i=0; i<32/BITS_PER_PASS; i++) - data->m_constBuffer[i] = new Buffer( deviceData, 1, BufferBase::BUFFER_CONST ); - data->m_maxSize = maxSize; - - return data; -} - -template -void RadixSortStandard::deallocate(void* rawData) -{ - Data* data = (Data*)rawData; - - delete data->m_workBuffer0; - delete data->m_workBuffer1; - delete data->m_workBuffer2; - delete data->m_workBuffer3; - for(int i=0; i<32/BITS_PER_PASS; i++) - delete data->m_constBuffer[i]; - - PrefixScan::deallocate( data->m_scanData ); - - delete data; -} - -template -void RadixSortStandard::execute(void* rawData, Buffer& inout, int n, int sortBits) -{ - Data* data = (Data*)rawData; - - ADLASSERT( n%512 == 0 ); - ADLASSERT( n <= data->m_maxSize ); - ADLASSERT( NUM_PER_WI == 4 ); - - Buffer* src = BufferUtils::map( data->m_deviceData, &inout ); - Buffer* dst = data->m_workBuffer3; - - const Device* deviceData = data->m_deviceData; - - int numGroups = (n+WG_SIZE*NUM_PER_WI-1)/(WG_SIZE*NUM_PER_WI); - - int4 constBuffer; - - int iPass = 0; - for(int startBit=0; startBitm_workBuffer0 ), BufferInfo( data->m_workBuffer1 ) }; - - Launcher launcher( deviceData, data->m_localSortKernel ); - launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(Launcher::BufferInfo) ); - launcher.setConst( *data->m_constBuffer[iPass], constBuffer ); - launcher.launch1D( WG_SIZE*numGroups, WG_SIZE ); - } - - PrefixScan::execute( data->m_scanData, *data->m_workBuffer0, *data->m_workBuffer2, numGroups*(1<m_workBuffer2, true ), BufferInfo( data->m_workBuffer1, true ), - BufferInfo( dst ) }; - - Launcher launcher( deviceData, data->m_scatterKernel ); - launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(Launcher::BufferInfo) ); - launcher.setConst( *data->m_constBuffer[iPass], constBuffer ); - launcher.launch1D( WG_SIZE*numGroups, WG_SIZE ); - } - - if(0) - { - BufferInfo bInfo[] = { BufferInfo( dst, true ), BufferInfo( src ) }; - - Launcher launcher( deviceData, data->m_copyKernel ); - launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(Launcher::BufferInfo) ); - launcher.launch1D( n, WG_SIZE ); - } - swap2( src, dst ); - } - - if( src != &inout ) - { - BufferInfo bInfo[] = { BufferInfo( src, true ), BufferInfo( dst ) }; - - Launcher launcher( deviceData, data->m_copyKernel ); - launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(Launcher::BufferInfo) ); - launcher.launch1D( n, WG_SIZE ); - } - - BufferUtils::unmap( src, &inout ); -} - -#undef PATH -#undef KERNEL0 -#undef KERNEL1 -#undef KERNEL2 diff --git a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Sort/RadixSortStandardKernels.cl b/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Sort/RadixSortStandardKernels.cl deleted file mode 100644 index c79348d60..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Sort/RadixSortStandardKernels.cl +++ /dev/null @@ -1,345 +0,0 @@ -/* -Bullet Continuous Collision Detection and Physics Library -Copyright (c) 2011 Advanced Micro Devices, Inc. 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. -*/ -//Author Takahiro Harada - - -#pragma OPENCL EXTENSION cl_amd_printf : enable -#pragma OPENCL EXTENSION cl_khr_local_int32_base_atomics : enable - -typedef unsigned int u32; -#define GET_GROUP_IDX get_group_id(0) -#define GET_LOCAL_IDX get_local_id(0) -#define GET_GLOBAL_IDX get_global_id(0) -#define GET_GROUP_SIZE get_local_size(0) -#define GROUP_LDS_BARRIER barrier(CLK_LOCAL_MEM_FENCE) -#define GROUP_MEM_FENCE mem_fence(CLK_LOCAL_MEM_FENCE) -#define AtomInc(x) atom_inc(&(x)) -#define AtomInc1(x, out) out = atom_inc(&(x)) - -#define make_uint4 (uint4) -#define make_uint2 (uint2) - -#define SELECT_UINT4( b, a, condition ) select( b,a,condition ) - -#define WG_SIZE 128 -#define NUM_PER_WI 4 - - -typedef struct -{ - u32 m_key; - u32 m_value; -}SortData; - - -typedef struct -{ - u32 m_startBit; - u32 m_numGroups; - u32 m_padding[2]; -} ConstBuffer; - -#define BITS_PER_PASS 4 - - - -uint4 prefixScanVector( uint4 data ) -{ - data.y += data.x; - data.w += data.z; - data.z += data.y; - data.w += data.y; - return data; -} - -uint prefixScanVectorEx( uint4* data ) -{ - uint4 backup = data[0]; - data[0].y += data[0].x; - data[0].w += data[0].z; - data[0].z += data[0].y; - data[0].w += data[0].y; - uint sum = data[0].w; - *data -= backup; - return sum; -} - -uint4 localPrefixSum128V( uint4 pData, uint lIdx, uint* totalSum, __local u32 sorterSharedMemory[] ) -{ - { // Set data - sorterSharedMemory[lIdx] = 0; - sorterSharedMemory[lIdx+WG_SIZE] = prefixScanVectorEx( &pData ); - } - - GROUP_LDS_BARRIER; - - { // Prefix sum - int idx = 2*lIdx + (WG_SIZE+1); - if( lIdx < 64 ) - { - sorterSharedMemory[idx] += sorterSharedMemory[idx-1]; - GROUP_MEM_FENCE; - sorterSharedMemory[idx] += sorterSharedMemory[idx-2]; - GROUP_MEM_FENCE; - sorterSharedMemory[idx] += sorterSharedMemory[idx-4]; - GROUP_MEM_FENCE; - sorterSharedMemory[idx] += sorterSharedMemory[idx-8]; - GROUP_MEM_FENCE; - sorterSharedMemory[idx] += sorterSharedMemory[idx-16]; - GROUP_MEM_FENCE; - sorterSharedMemory[idx] += sorterSharedMemory[idx-32]; - GROUP_MEM_FENCE; - sorterSharedMemory[idx] += sorterSharedMemory[idx-64]; - GROUP_MEM_FENCE; - - sorterSharedMemory[idx-1] += sorterSharedMemory[idx-2]; - GROUP_MEM_FENCE; - } - } - - GROUP_LDS_BARRIER; - - *totalSum = sorterSharedMemory[WG_SIZE*2-1]; - uint addValue = sorterSharedMemory[lIdx+127]; - return pData + make_uint4(addValue, addValue, addValue, addValue); -} - - -void generateHistogram(u32 lIdx, u32 wgIdx, - uint4 sortedData, - __local u32 *histogram) -{ - if( lIdx < (1<>cb.m_startBit, sortData[1].m_key>>cb.m_startBit, - sortData[2].m_key>>cb.m_startBit, sortData[3].m_key>>cb.m_startBit ); - - generateHistogram( lIdx, wgIdx, localKeys, ldsSortData ); - - GROUP_LDS_BARRIER; - - int nBins = (1<>cb.m_startBit)&cmpValue, (sortData[1].m_key>>cb.m_startBit)&cmpValue, - (sortData[2].m_key>>cb.m_startBit)&cmpValue, (sortData[3].m_key>>cb.m_startBit)&cmpValue );; - - // data is already sorted. So simply subtract local prefix sum - uint4 dstAddr; - dstAddr.x = ldsGlobalHistogram[radix.x] + (localAddr.x - ldsLocalHistogram[radix.x]); - dstAddr.y = ldsGlobalHistogram[radix.y] + (localAddr.y - ldsLocalHistogram[radix.y]); - dstAddr.z = ldsGlobalHistogram[radix.z] + (localAddr.z - ldsLocalHistogram[radix.z]); - dstAddr.w = ldsGlobalHistogram[radix.w] + (localAddr.w - ldsLocalHistogram[radix.w]); - - dst[dstAddr.x] = sortData[0]; - dst[dstAddr.y] = sortData[1]; - dst[dstAddr.z] = sortData[2]; - dst[dstAddr.w] = sortData[3]; -} - -__kernel -__attribute__((reqd_work_group_size(WG_SIZE,1,1))) -void CopyKernel(__global SortData *src, __global SortData *dst) -{ - dst[ GET_GLOBAL_IDX ] = src[ GET_GLOBAL_IDX ]; -} diff --git a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Sort/RadixSortStandardKernels.hlsl b/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Sort/RadixSortStandardKernels.hlsl deleted file mode 100644 index 55a6a1ca7..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Sort/RadixSortStandardKernels.hlsl +++ /dev/null @@ -1,322 +0,0 @@ -/* - 2011 Takahiro Harada -*/ - -typedef uint u32; - -#define GET_GROUP_IDX groupIdx.x -#define GET_LOCAL_IDX localIdx.x -#define GET_GLOBAL_IDX globalIdx.x -#define GROUP_LDS_BARRIER GroupMemoryBarrierWithGroupSync() -#define GROUP_MEM_FENCE -#define DEFAULT_ARGS uint3 globalIdx : SV_DispatchThreadID, uint3 localIdx : SV_GroupThreadID, uint3 groupIdx : SV_GroupID -#define AtomInc(x) InterlockedAdd(x, 1) -#define AtomInc1(x, out) InterlockedAdd(x, 1, out) - -#define make_uint4 uint4 -#define make_uint2 uint2 - -uint4 SELECT_UINT4(uint4 b,uint4 a,uint4 condition ){ return make_uint4( ((condition).x)?a.x:b.x, ((condition).y)?a.y:b.y, ((condition).z)?a.z:b.z, ((condition).w)?a.w:b.w ); } - -// takahiro end -#define WG_SIZE 128 -#define NUM_PER_WI 4 - -#define GET_GROUP_SIZE WG_SIZE - -typedef struct -{ - u32 m_key; - u32 m_value; -}SortData; - -cbuffer SortCB : register( b0 ) -{ - u32 m_startBit; - u32 m_numGroups; - u32 m_padding[2]; -}; - -#define BITS_PER_PASS 4 - - -uint4 prefixScanVector( uint4 data ) -{ - data.y += data.x; - data.w += data.z; - data.z += data.y; - data.w += data.y; - return data; -} - -uint prefixScanVectorEx( inout uint4 data ) -{ - uint4 backup = data; - data.y += data.x; - data.w += data.z; - data.z += data.y; - data.w += data.y; - uint sum = data.w; - data -= backup; - return sum; -} - - - -RWStructuredBuffer sortDataIn : register( u0 ); -RWStructuredBuffer ldsHistogramOut0 : register( u1 ); -RWStructuredBuffer ldsHistogramOut1 : register( u2 ); - -groupshared u32 ldsSortData[ WG_SIZE*NUM_PER_WI + 16 ]; - - -uint4 localPrefixSum128V( uint4 pData, uint lIdx, inout uint totalSum ) -{ - { // Set data - ldsSortData[lIdx] = 0; - ldsSortData[lIdx+WG_SIZE] = prefixScanVectorEx( pData ); - } - - GROUP_LDS_BARRIER; - - { // Prefix sum - int idx = 2*lIdx + (WG_SIZE+1); - if( lIdx < 64 ) - { - ldsSortData[idx] += ldsSortData[idx-1]; - GROUP_MEM_FENCE; - ldsSortData[idx] += ldsSortData[idx-2]; - GROUP_MEM_FENCE; - ldsSortData[idx] += ldsSortData[idx-4]; - GROUP_MEM_FENCE; - ldsSortData[idx] += ldsSortData[idx-8]; - GROUP_MEM_FENCE; - ldsSortData[idx] += ldsSortData[idx-16]; - GROUP_MEM_FENCE; - ldsSortData[idx] += ldsSortData[idx-32]; - GROUP_MEM_FENCE; - ldsSortData[idx] += ldsSortData[idx-64]; - GROUP_MEM_FENCE; - - ldsSortData[idx-1] += ldsSortData[idx-2]; - GROUP_MEM_FENCE; - } - } - - GROUP_LDS_BARRIER; - - totalSum = ldsSortData[WG_SIZE*2-1]; - uint addValue = ldsSortData[lIdx+127]; - return pData + make_uint4(addValue, addValue, addValue, addValue); -} - -void generateHistogram(u32 lIdx, u32 wgIdx, - uint4 sortedData) -{ - if( lIdx < (1<>m_startBit, sortData[1].m_key>>m_startBit, - sortData[2].m_key>>m_startBit, sortData[3].m_key>>m_startBit ); - - generateHistogram( lIdx, wgIdx, localKeys ); - - GROUP_LDS_BARRIER; - - int nBins = (1< src : register( t0 ); -StructuredBuffer histogramGlobalRadixMajor : register( t1 ); -StructuredBuffer histogramLocalGroupMajor : register( t2 ); - -RWStructuredBuffer dst : register( u0 ); - -groupshared u32 ldsLocalHistogram[ 2*(1<>m_startBit)&cmpValue, (sortData[1].m_key>>m_startBit)&cmpValue, - (sortData[2].m_key>>m_startBit)&cmpValue, (sortData[3].m_key>>m_startBit)&cmpValue );; - - // data is already sorted. So simply subtract local prefix sum - uint4 dstAddr; - dstAddr.x = ldsGlobalHistogram[radix.x] + (localAddr.x - ldsLocalHistogram[radix.x]); - dstAddr.y = ldsGlobalHistogram[radix.y] + (localAddr.y - ldsLocalHistogram[radix.y]); - dstAddr.z = ldsGlobalHistogram[radix.z] + (localAddr.z - ldsLocalHistogram[radix.z]); - dstAddr.w = ldsGlobalHistogram[radix.w] + (localAddr.w - ldsLocalHistogram[radix.w]); - - dst[dstAddr.x] = sortData[0]; - dst[dstAddr.y] = sortData[1]; - dst[dstAddr.z] = sortData[2]; - dst[dstAddr.w] = sortData[3]; -} - -[numthreads(WG_SIZE, 1, 1)] -void CopyKernel( DEFAULT_ARGS ) -{ - dst[ GET_GLOBAL_IDX ] = src[ GET_GLOBAL_IDX ]; -} diff --git a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Sort/RadixSortStandardKernelsCL.h b/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Sort/RadixSortStandardKernelsCL.h deleted file mode 100644 index e793c7e94..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Sort/RadixSortStandardKernelsCL.h +++ /dev/null @@ -1,347 +0,0 @@ -static const char* radixSortStandardKernelsCL= \ -"/*\n" -"Bullet Continuous Collision Detection and Physics Library\n" -"Copyright (c) 2011 Advanced Micro Devices, Inc. http://bulletphysics.org\n" -"\n" -"This software is provided 'as-is', without any express or implied warranty.\n" -"In no event will the authors be held liable for any damages arising from the use of this software.\n" -"Permission is granted to anyone to use this software for any purpose, \n" -"including commercial applications, and to alter it and redistribute it freely, \n" -"subject to the following restrictions:\n" -"\n" -"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.\n" -"2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.\n" -"3. This notice may not be removed or altered from any source distribution.\n" -"*/\n" -"//Author Takahiro Harada\n" -"\n" -"\n" -"#pragma OPENCL EXTENSION cl_amd_printf : enable\n" -"#pragma OPENCL EXTENSION cl_khr_local_int32_base_atomics : enable\n" -"\n" -"typedef unsigned int u32;\n" -"#define GET_GROUP_IDX get_group_id(0)\n" -"#define GET_LOCAL_IDX get_local_id(0)\n" -"#define GET_GLOBAL_IDX get_global_id(0)\n" -"#define GET_GROUP_SIZE get_local_size(0)\n" -"#define GROUP_LDS_BARRIER barrier(CLK_LOCAL_MEM_FENCE)\n" -"#define GROUP_MEM_FENCE mem_fence(CLK_LOCAL_MEM_FENCE)\n" -"#define AtomInc(x) atom_inc(&(x))\n" -"#define AtomInc1(x, out) out = atom_inc(&(x))\n" -"\n" -"#define make_uint4 (uint4)\n" -"#define make_uint2 (uint2)\n" -"\n" -"#define SELECT_UINT4( b, a, condition ) select( b,a,condition )\n" -"\n" -"#define WG_SIZE 128\n" -"#define NUM_PER_WI 4\n" -"\n" -"\n" -"typedef struct\n" -"{\n" -" u32 m_key; \n" -" u32 m_value;\n" -"}SortData;\n" -"\n" -"\n" -"typedef struct\n" -"{\n" -" u32 m_startBit;\n" -" u32 m_numGroups;\n" -" u32 m_padding[2];\n" -"} ConstBuffer;\n" -"\n" -"#define BITS_PER_PASS 4\n" -"\n" -"\n" -"\n" -"uint4 prefixScanVector( uint4 data )\n" -"{\n" -" data.y += data.x;\n" -" data.w += data.z;\n" -" data.z += data.y;\n" -" data.w += data.y;\n" -" return data;\n" -"}\n" -"\n" -"uint prefixScanVectorEx( uint4* data )\n" -"{\n" -" uint4 backup = data[0];\n" -" data[0].y += data[0].x;\n" -" data[0].w += data[0].z;\n" -" data[0].z += data[0].y;\n" -" data[0].w += data[0].y;\n" -" uint sum = data[0].w;\n" -" *data -= backup;\n" -" return sum;\n" -"}\n" -"\n" -"uint4 localPrefixSum128V( uint4 pData, uint lIdx, uint* totalSum, __local u32 sorterSharedMemory[] )\n" -"{\n" -" { // Set data\n" -" sorterSharedMemory[lIdx] = 0;\n" -" sorterSharedMemory[lIdx+WG_SIZE] = prefixScanVectorEx( &pData );\n" -" }\n" -"\n" -" GROUP_LDS_BARRIER;\n" -"\n" -" { // Prefix sum\n" -" int idx = 2*lIdx + (WG_SIZE+1);\n" -" if( lIdx < 64 )\n" -" {\n" -" sorterSharedMemory[idx] += sorterSharedMemory[idx-1];\n" -" GROUP_MEM_FENCE;\n" -" sorterSharedMemory[idx] += sorterSharedMemory[idx-2]; \n" -" GROUP_MEM_FENCE;\n" -" sorterSharedMemory[idx] += sorterSharedMemory[idx-4];\n" -" GROUP_MEM_FENCE;\n" -" sorterSharedMemory[idx] += sorterSharedMemory[idx-8];\n" -" GROUP_MEM_FENCE;\n" -" sorterSharedMemory[idx] += sorterSharedMemory[idx-16];\n" -" GROUP_MEM_FENCE;\n" -" sorterSharedMemory[idx] += sorterSharedMemory[idx-32]; \n" -" GROUP_MEM_FENCE;\n" -" sorterSharedMemory[idx] += sorterSharedMemory[idx-64];\n" -" GROUP_MEM_FENCE;\n" -"\n" -" sorterSharedMemory[idx-1] += sorterSharedMemory[idx-2];\n" -" GROUP_MEM_FENCE;\n" -" }\n" -" }\n" -"\n" -" GROUP_LDS_BARRIER;\n" -"\n" -" *totalSum = sorterSharedMemory[WG_SIZE*2-1];\n" -" uint addValue = sorterSharedMemory[lIdx+127];\n" -" return pData + make_uint4(addValue, addValue, addValue, addValue);\n" -"}\n" -"\n" -"\n" -"void generateHistogram(u32 lIdx, u32 wgIdx, \n" -" uint4 sortedData,\n" -" __local u32 *histogram)\n" -"{\n" -" if( lIdx < (1<>cb.m_startBit, sortData[1].m_key>>cb.m_startBit, \n" -" sortData[2].m_key>>cb.m_startBit, sortData[3].m_key>>cb.m_startBit );\n" -"\n" -" generateHistogram( lIdx, wgIdx, localKeys, ldsSortData );\n" -"\n" -" GROUP_LDS_BARRIER;\n" -"\n" -" int nBins = (1<>cb.m_startBit)&cmpValue, (sortData[1].m_key>>cb.m_startBit)&cmpValue, \n" -" (sortData[2].m_key>>cb.m_startBit)&cmpValue, (sortData[3].m_key>>cb.m_startBit)&cmpValue );;\n" -"\n" -" // data is already sorted. So simply subtract local prefix sum\n" -" uint4 dstAddr;\n" -" dstAddr.x = ldsGlobalHistogram[radix.x] + (localAddr.x - ldsLocalHistogram[radix.x]);\n" -" dstAddr.y = ldsGlobalHistogram[radix.y] + (localAddr.y - ldsLocalHistogram[radix.y]);\n" -" dstAddr.z = ldsGlobalHistogram[radix.z] + (localAddr.z - ldsLocalHistogram[radix.z]);\n" -" dstAddr.w = ldsGlobalHistogram[radix.w] + (localAddr.w - ldsLocalHistogram[radix.w]);\n" -"\n" -" dst[dstAddr.x] = sortData[0];\n" -" dst[dstAddr.y] = sortData[1];\n" -" dst[dstAddr.z] = sortData[2];\n" -" dst[dstAddr.w] = sortData[3];\n" -"}\n" -"\n" -"__kernel\n" -"__attribute__((reqd_work_group_size(WG_SIZE,1,1)))\n" -"void CopyKernel(__global SortData *src, __global SortData *dst)\n" -"{\n" -" dst[ GET_GLOBAL_IDX ] = src[ GET_GLOBAL_IDX ];\n" -"}\n" -; diff --git a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Sort/RadixSortStandardKernelsDX11.h b/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Sort/RadixSortStandardKernelsDX11.h deleted file mode 100644 index 1a919ed18..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Sort/RadixSortStandardKernelsDX11.h +++ /dev/null @@ -1,324 +0,0 @@ -static const char* radixSortStandardKernelsDX11= \ -"/*\n" -" 2011 Takahiro Harada\n" -"*/\n" -"\n" -"typedef uint u32;\n" -"\n" -"#define GET_GROUP_IDX groupIdx.x\n" -"#define GET_LOCAL_IDX localIdx.x\n" -"#define GET_GLOBAL_IDX globalIdx.x\n" -"#define GROUP_LDS_BARRIER GroupMemoryBarrierWithGroupSync()\n" -"#define GROUP_MEM_FENCE\n" -"#define DEFAULT_ARGS uint3 globalIdx : SV_DispatchThreadID, uint3 localIdx : SV_GroupThreadID, uint3 groupIdx : SV_GroupID\n" -"#define AtomInc(x) InterlockedAdd(x, 1)\n" -"#define AtomInc1(x, out) InterlockedAdd(x, 1, out)\n" -"\n" -"#define make_uint4 uint4\n" -"#define make_uint2 uint2\n" -"\n" -"uint4 SELECT_UINT4(uint4 b,uint4 a,uint4 condition ){ return make_uint4( ((condition).x)?a.x:b.x, ((condition).y)?a.y:b.y, ((condition).z)?a.z:b.z, ((condition).w)?a.w:b.w ); }\n" -"\n" -"// takahiro end\n" -"#define WG_SIZE 128\n" -"#define NUM_PER_WI 4\n" -"\n" -"#define GET_GROUP_SIZE WG_SIZE\n" -"\n" -"typedef struct\n" -"{\n" -" u32 m_key; \n" -" u32 m_value;\n" -"}SortData;\n" -"\n" -"cbuffer SortCB : register( b0 )\n" -"{\n" -" u32 m_startBit;\n" -" u32 m_numGroups;\n" -" u32 m_padding[2];\n" -"};\n" -"\n" -"#define BITS_PER_PASS 4\n" -"\n" -"\n" -"uint4 prefixScanVector( uint4 data )\n" -"{\n" -" data.y += data.x;\n" -" data.w += data.z;\n" -" data.z += data.y;\n" -" data.w += data.y;\n" -" return data;\n" -"}\n" -"\n" -"uint prefixScanVectorEx( inout uint4 data )\n" -"{\n" -" uint4 backup = data;\n" -" data.y += data.x;\n" -" data.w += data.z;\n" -" data.z += data.y;\n" -" data.w += data.y;\n" -" uint sum = data.w;\n" -" data -= backup;\n" -" return sum;\n" -"}\n" -"\n" -"\n" -"\n" -"RWStructuredBuffer sortDataIn : register( u0 );\n" -"RWStructuredBuffer ldsHistogramOut0 : register( u1 );\n" -"RWStructuredBuffer ldsHistogramOut1 : register( u2 );\n" -"\n" -"groupshared u32 ldsSortData[ WG_SIZE*NUM_PER_WI + 16 ];\n" -"\n" -"\n" -"uint4 localPrefixSum128V( uint4 pData, uint lIdx, inout uint totalSum )\n" -"{\n" -" { // Set data\n" -" ldsSortData[lIdx] = 0;\n" -" ldsSortData[lIdx+WG_SIZE] = prefixScanVectorEx( pData );\n" -" }\n" -"\n" -" GROUP_LDS_BARRIER;\n" -"\n" -" { // Prefix sum\n" -" int idx = 2*lIdx + (WG_SIZE+1);\n" -" if( lIdx < 64 )\n" -" {\n" -" ldsSortData[idx] += ldsSortData[idx-1];\n" -" GROUP_MEM_FENCE;\n" -" ldsSortData[idx] += ldsSortData[idx-2]; \n" -" GROUP_MEM_FENCE;\n" -" ldsSortData[idx] += ldsSortData[idx-4];\n" -" GROUP_MEM_FENCE;\n" -" ldsSortData[idx] += ldsSortData[idx-8];\n" -" GROUP_MEM_FENCE;\n" -" ldsSortData[idx] += ldsSortData[idx-16];\n" -" GROUP_MEM_FENCE;\n" -" ldsSortData[idx] += ldsSortData[idx-32]; \n" -" GROUP_MEM_FENCE;\n" -" ldsSortData[idx] += ldsSortData[idx-64];\n" -" GROUP_MEM_FENCE;\n" -"\n" -" ldsSortData[idx-1] += ldsSortData[idx-2];\n" -" GROUP_MEM_FENCE;\n" -" }\n" -" }\n" -"\n" -" GROUP_LDS_BARRIER;\n" -"\n" -" totalSum = ldsSortData[WG_SIZE*2-1];\n" -" uint addValue = ldsSortData[lIdx+127];\n" -" return pData + make_uint4(addValue, addValue, addValue, addValue);\n" -"}\n" -"\n" -"void generateHistogram(u32 lIdx, u32 wgIdx, \n" -" uint4 sortedData)\n" -"{\n" -" if( lIdx < (1<>m_startBit, sortData[1].m_key>>m_startBit, \n" -" sortData[2].m_key>>m_startBit, sortData[3].m_key>>m_startBit );\n" -"\n" -" generateHistogram( lIdx, wgIdx, localKeys );\n" -"\n" -" GROUP_LDS_BARRIER;\n" -"\n" -" int nBins = (1< src : register( t0 );\n" -"StructuredBuffer histogramGlobalRadixMajor : register( t1 );\n" -"StructuredBuffer histogramLocalGroupMajor : register( t2 );\n" -"\n" -"RWStructuredBuffer dst : register( u0 );\n" -"\n" -"groupshared u32 ldsLocalHistogram[ 2*(1<>m_startBit)&cmpValue, (sortData[1].m_key>>m_startBit)&cmpValue, \n" -" (sortData[2].m_key>>m_startBit)&cmpValue, (sortData[3].m_key>>m_startBit)&cmpValue );;\n" -"\n" -" // data is already sorted. So simply subtract local prefix sum\n" -" uint4 dstAddr;\n" -" dstAddr.x = ldsGlobalHistogram[radix.x] + (localAddr.x - ldsLocalHistogram[radix.x]);\n" -" dstAddr.y = ldsGlobalHistogram[radix.y] + (localAddr.y - ldsLocalHistogram[radix.y]);\n" -" dstAddr.z = ldsGlobalHistogram[radix.z] + (localAddr.z - ldsLocalHistogram[radix.z]);\n" -" dstAddr.w = ldsGlobalHistogram[radix.w] + (localAddr.w - ldsLocalHistogram[radix.w]);\n" -"\n" -" dst[dstAddr.x] = sortData[0];\n" -" dst[dstAddr.y] = sortData[1];\n" -" dst[dstAddr.z] = sortData[2];\n" -" dst[dstAddr.w] = sortData[3];\n" -"}\n" -"\n" -"[numthreads(WG_SIZE, 1, 1)]\n" -"void CopyKernel( DEFAULT_ARGS )\n" -"{\n" -" dst[ GET_GLOBAL_IDX ] = src[ GET_GLOBAL_IDX ];\n" -"}\n" -; diff --git a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Sort/SortData.h b/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Sort/SortData.h deleted file mode 100644 index 3d88ebdfd..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Sort/SortData.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - 2011 Takahiro Harada -*/ - -#pragma once - -#include - -namespace adl -{ - -struct SortData -{ - SortData(){} - SortData( u32 key, u32 value ) : m_key(key), m_value(value) {} - - union - { - u32 m_key; - struct { u16 m_key16[2]; }; - }; - u32 m_value; - - friend bool operator <(const SortData& a, const SortData& b) - { - return a.m_key < b.m_key; - } -}; - - -}; diff --git a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Sort/radixsortadvanced.inl b/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Sort/radixsortadvanced.inl deleted file mode 100644 index 210b5dd6b..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Sort/radixsortadvanced.inl +++ /dev/null @@ -1,146 +0,0 @@ -/* - 2011 Takahiro Harada -*/ - -#define PATH "..\\..\\AdlPrimitives\\Sort\\RadixSortAdvancedKernels" -#define KERNEL0 "StreamCountKernel" -#define KERNEL1 "SortAndScatterKernel1" -#define KERNEL2 "PrefixScanKernel" - -template -class RadixSortAdvanced : public RadixSortBase -{ - public: - typedef Launcher::BufferInfo BufferInfo; - - enum - { - WG_SIZE = 128, - NUM_PER_WI = 4, - MAX_NUM_WORKGROUPS = 60, - }; - - struct Data : public RadixSort::Data - { - Kernel* m_localCountKernel; - Kernel* m_scatterKernel; - Kernel* m_scanKernel; - - Buffer* m_workBuffer0; - Buffer* m_workBuffer1; - Buffer* m_constBuffer[32/4]; - }; - - - static - Data* allocate(const Device* deviceData, int maxSize, Option option = SORT_NORMAL); - - static - void deallocate(void* data); - - static - void execute(void* data, Buffer& inout, int n, int sortBits); -}; - -template -typename RadixSortAdvanced::Data* RadixSortAdvanced::allocate(const Device* deviceData, int maxSize, Option option) -{ - ADLASSERT( type == deviceData->m_type ); - - const char* src[] = { 0, 0, 0 }; - - Data* data = new Data; - data->m_option = option; - data->m_deviceData = deviceData; - - data->m_localCountKernel = deviceData->getKernel( PATH, KERNEL0, 0, src[type] ); - data->m_scatterKernel = deviceData->getKernel( PATH, KERNEL1, 0, src[type] ); - data->m_scanKernel = deviceData->getKernel( PATH, KERNEL2, 0, src[type] ); - - data->m_workBuffer0 = new Buffer( deviceData, MAX_NUM_WORKGROUPS*16 ); - data->m_workBuffer1 = new Buffer( deviceData, maxSize ); - for(int i=0; i<32/4; i++) - data->m_constBuffer[i] = new Buffer( deviceData, 1, BufferBase::BUFFER_CONST ); - data->m_maxSize = maxSize; - - return data; -} - -template -void RadixSortAdvanced::deallocate(void* rawData) -{ - Data* data = (Data*)rawData; - - delete data->m_workBuffer0; - delete data->m_workBuffer1; - for(int i=0; i<32/4; i++) - delete data->m_constBuffer[i]; - - delete data; -} - -template -void RadixSortAdvanced::execute(void* rawData, Buffer& inout, int n, int sortBits) -{ - Data* data = (Data*)rawData; - - ADLASSERT( sortBits == 32 ); - - ADLASSERT( NUM_PER_WI == 4 ); - ADLASSERT( n%(WG_SIZE*NUM_PER_WI) == 0 ); - ADLASSERT( MAX_NUM_WORKGROUPS < 128*8/16 ); - - Buffer* src = &inout; - Buffer* dst = data->m_workBuffer1; - - const Device* deviceData = data->m_deviceData; - - int nBlocks = n/(NUM_PER_WI*WG_SIZE); - const int nWorkGroupsToExecute = min2((int)MAX_NUM_WORKGROUPS, nBlocks); - int nBlocksPerGroup = (nBlocks+nWorkGroupsToExecute-1)/nWorkGroupsToExecute; - ADLASSERT( nWorkGroupsToExecute <= MAX_NUM_WORKGROUPS ); - - int4 constBuffer = make_int4(0, nBlocks, nWorkGroupsToExecute, nBlocksPerGroup); - - int iPass = 0; - int startBit = 0; - for(int startBit=0; startBit<32; startBit+=4, iPass++) - { - constBuffer.x = startBit; - - { - BufferInfo bInfo[] = { BufferInfo( src, true ), BufferInfo( data->m_workBuffer0 ) }; - - Launcher launcher( deviceData, data->m_localCountKernel ); - launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(Launcher::BufferInfo) ); - launcher.setConst( *data->m_constBuffer[iPass], constBuffer ); - launcher.launch1D( WG_SIZE* nWorkGroupsToExecute, WG_SIZE ); - } - - - { - BufferInfo bInfo[] = { BufferInfo( data->m_workBuffer0 ) }; - - Launcher launcher( deviceData, data->m_scanKernel ); - launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(Launcher::BufferInfo) ); - launcher.setConst( *data->m_constBuffer[iPass], constBuffer ); - launcher.launch1D( WG_SIZE, WG_SIZE ); - } - - { - BufferInfo bInfo[] = { BufferInfo( data->m_workBuffer0, true ), BufferInfo( src ), BufferInfo( dst ) }; - - Launcher launcher( deviceData, data->m_scatterKernel ); - launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(Launcher::BufferInfo) ); - launcher.setConst( *data->m_constBuffer[iPass], constBuffer ); - launcher.launch1D( WG_SIZE*nWorkGroupsToExecute, WG_SIZE ); - } - - swap2( src, dst ); - } -} - -#undef PATH -#undef KERNEL0 -#undef KERNEL1 -#undef KERNEL2 diff --git a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Sort/radixsortsimple.inl b/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Sort/radixsortsimple.inl deleted file mode 100644 index 3fcab75fa..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/Sort/radixsortsimple.inl +++ /dev/null @@ -1,149 +0,0 @@ -/* - 2011 Takahiro Harada -*/ - -#define PATH "..\\..\\opencl\\primitives\\AdlPrimitives\\Sort\\RadixSortSimpleKernels" -#define KERNEL0 "LocalCountKernel" -#define KERNEL1 "ScatterKernel" - -#include -#include - -template -class RadixSortSimple : public RadixSortBase -{ - public: - typedef Launcher::BufferInfo BufferInfo; - - enum - { - WG_SIZE = 128, - NUM_PER_WI = 4, - }; - - struct Data : public RadixSort::Data - { - Kernel* m_localCountKernel; - Kernel* m_scatterKernel; - - Buffer* m_workBuffer0; - Buffer* m_workBuffer1; - Buffer* m_workBuffer2; - Buffer* m_constBuffer[4]; - }; - - - static - Data* allocate(const Device* deviceData, int maxSize, Option option = SORT_NORMAL); - - static - void deallocate(void* data); - - static - void execute(void* data, Buffer& inout, int n, int sortBits); -}; - -template -typename RadixSortSimple::Data* RadixSortSimple::allocate(const Device* deviceData, int maxSize, Option option) -{ - ADLASSERT( type == deviceData->m_type ); - - const char* src[] = -#if defined(ADL_LOAD_KERNEL_FROM_STRING) - {radixSortSimpleKernelsCL, radixSortSimpleKernelsDX11}; -#else - { 0, 0 }; -#endif - u32 maxNumGroups = (maxSize+WG_SIZE*NUM_PER_WI-1)/(WG_SIZE*NUM_PER_WI); - - Data* data = new Data; - data->m_option = option; - data->m_deviceData = deviceData; - - data->m_localCountKernel = deviceData->getKernel( PATH, KERNEL0, 0, src[type] ); - data->m_scatterKernel = deviceData->getKernel( PATH, KERNEL1, 0, src[type] ); - - data->m_scanData = PrefixScan::allocate( deviceData, maxSize ); - - data->m_workBuffer0 = new Buffer( deviceData, maxNumGroups*256 ); - data->m_workBuffer1 = new Buffer( deviceData, maxNumGroups*256 ); - data->m_workBuffer2 = new Buffer( deviceData, maxSize ); - data->m_constBuffer[0] = new Buffer( deviceData, 1, BufferBase::BUFFER_CONST ); - data->m_constBuffer[1] = new Buffer( deviceData, 1, BufferBase::BUFFER_CONST ); - data->m_constBuffer[2] = new Buffer( deviceData, 1, BufferBase::BUFFER_CONST ); - data->m_constBuffer[3] = new Buffer( deviceData, 1, BufferBase::BUFFER_CONST ); - data->m_maxSize = maxSize; - - return data; -} - -template -void RadixSortSimple::deallocate(void* rawData) -{ - Data* data = (Data*)rawData; - - delete data->m_workBuffer0; - delete data->m_workBuffer1; - delete data->m_workBuffer2; - delete data->m_constBuffer[0]; - delete data->m_constBuffer[1]; - delete data->m_constBuffer[2]; - delete data->m_constBuffer[3]; - - PrefixScan::deallocate( data->m_scanData ); - - delete data; -} - -template -void RadixSortSimple::execute(void* rawData, Buffer& inout, int n, int sortBits) -{ - Data* data = (Data*)rawData; - - ADLASSERT( sortBits == 32 ); - ADLASSERT( n%512 == 0 ); - ADLASSERT( n <= data->m_maxSize ); - - Buffer* src = &inout; - Buffer* dst = data->m_workBuffer2; - - const Device* deviceData = data->m_deviceData; - - int numGroups = (n+WG_SIZE*NUM_PER_WI-1)/(WG_SIZE*NUM_PER_WI); - - int4 constBuffer; - - int iPass = 0; - for(int startBit=0; startBit<32; startBit+=8, iPass++) - { - constBuffer.x = startBit; - constBuffer.y = numGroups; - constBuffer.z = WG_SIZE; - - { - BufferInfo bInfo[] = { BufferInfo( src, true ), BufferInfo( data->m_workBuffer0 ) }; - - Launcher launcher( deviceData, data->m_localCountKernel ); - launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(Launcher::BufferInfo) ); - launcher.setConst( *data->m_constBuffer[iPass], constBuffer ); - launcher.launch1D( WG_SIZE*numGroups, WG_SIZE ); - } - - PrefixScan::execute( data->m_scanData, *data->m_workBuffer0, *data->m_workBuffer1, numGroups*256 ); - - { - BufferInfo bInfo[] = { BufferInfo( src, true ), BufferInfo( dst ), BufferInfo( data->m_workBuffer1 ) }; - - Launcher launcher( deviceData, data->m_scatterKernel ); - launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(Launcher::BufferInfo) ); - launcher.setConst( *data->m_constBuffer[iPass], constBuffer ); - launcher.launch1D( WG_SIZE*numGroups, WG_SIZE ); - } - - swap2( src, dst ); - } -} - -#undef PATH -#undef KERNEL0 -#undef KERNEL1 diff --git a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/stringify.py b/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/stringify.py deleted file mode 100644 index e79e281e4..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/stringify.py +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/env python -import sys -import os -import shutil - -arg = sys.argv[1] -fh = open(arg) - -print 'static const char* '+sys.argv[2]+'= \\' -for line in fh.readlines(): - a = line.strip('\n') - print '"'+a+'\\n"' -print ';' diff --git a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/stringifykernels.bat b/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/stringifykernels.bat deleted file mode 100644 index 3a2aa63f1..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlPrimitives/stringifykernels.bat +++ /dev/null @@ -1,22 +0,0 @@ -stringify.py Fill/FillKernels.cl fillKernelsCL >Fill/FillKernelsCL.h -stringify.py Fill/FillKernels.hlsl fillKernelsDX11 >Fill/FillKernelsDX11.h -stringify.py Scan/PrefixScanKernels.cl prefixScanKernelsCL >Scan/PrefixScanKernelsCL.h -stringify.py Scan/PrefixScanKernels.hlsl prefixScanKernelsDX11 >Scan/PrefixScanKernelsDX11.h -stringify.py Search/BoundSearchKernels.cl boundSearchKernelsCL >Search/BoundSearchKernelsCL.h -stringify.py Search/BoundSearchKernels.hlsl boundSearchKernelsDX11 >Search/BoundSearchKernelsDX11.h -stringify.py Sort/RadixSortSimpleKernels.cl radixSortSimpleKernelsCL >Sort/RadixSortSimpleKernelsCL.h -stringify.py Sort/RadixSortSimpleKernels.hlsl radixSortSimpleKernelsDX11 >Sort/RadixSortSimpleKernelsDX11.h -stringify.py Sort/RadixSortStandardKernels.cl radixSortStandardKernelsCL >Sort/RadixSortStandardKernelsCL.h - -stringify.py Sort/RadixSort32Kernels.cl radixSort32KernelsCL >Sort/RadixSort32KernelsCL.h -stringify.py Sort/RadixSort32Kernels.hlsl radixSort32KernelsDX11 >Sort/RadixSort32KernelsDX11.h - -stringify.py Copy/CopyKernels.cl copyKernelsCL >Copy/CopyKernelsCL.h -stringify.py Copy/CopyKernels.hlsl copyKernelsDX11 >Copy/CopyKernelsDX11.h - -stringify.py Sort/RadixSortStandardKernels.hlsl radixSortStandardKernelsDX11 >Sort/RadixSortStandardKernelsDX11.h -stringify.py Sort/RadixSortAdvancedKernels.hlsl radixSortAdvancedKernelsDX11 >Sort/RadixSortAdvancedKernelsDX11.h - - - - diff --git a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlTest/AMD/premake4.lua b/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlTest/AMD/premake4.lua deleted file mode 100644 index d47cec9fa..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlTest/AMD/premake4.lua +++ /dev/null @@ -1,31 +0,0 @@ - - hasCL = findOpenCL_AMD() - hasDX11 = findDirectX11() - - if (hasCL) then - - project "OpenCL_DX11_primitives_test_AMD" - - initOpenCL_AMD() - - if (hasDX11) then - initDirectX11() - end - - language "C++" - - kind "ConsoleApp" - targetdir "../../../../bin" - includedirs {"..","../.."} - - links { - "OpenCL" - } - - files { - "../main.cpp", - "../RadixSortBenchmark.h", - "../UnitTests.h" - } - - end \ No newline at end of file diff --git a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlTest/Intel/premake4.lua b/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlTest/Intel/premake4.lua deleted file mode 100644 index 157405f90..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlTest/Intel/premake4.lua +++ /dev/null @@ -1,31 +0,0 @@ - - hasCL = findOpenCL_Intel() - hasDX11 = findDirectX11() - - if (hasCL) then - - project "OpenCL_DX11_primitives_test_Intel" - - initOpenCL_Intel() - - if (hasDX11) then - initDirectX11() - end - - language "C++" - - kind "ConsoleApp" - targetdir "../../../../bin" - includedirs {"..","../.."} - - links { - "OpenCL" - } - - files { - "../main.cpp", - "../RadixSortBenchmark.h", - "../UnitTests.h" - } - - end \ No newline at end of file diff --git a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlTest/LaunchOverheadBenchmark.h b/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlTest/LaunchOverheadBenchmark.h deleted file mode 100644 index 4b1ae7d0f..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlTest/LaunchOverheadBenchmark.h +++ /dev/null @@ -1,103 +0,0 @@ -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Takahiro Harada - - -#include - - - -template -__inline -void copyTest( Device* device ) -{ - int size = 65*1024; - - Buffer buf0( device, size ); - Buffer buf1( device, size ); - - Stopwatch sw( device ); - - Copy::Data* data = Copy::allocate( device ); - - for(int i=0; i<10; i++) - Copy::execute( data, buf1, buf0, size, CopyBase::PER_WI_1 ); - DeviceUtils::waitForCompletion( device ); - - { - const int nTests = 12; - - float t[nTests]; - - for(int ii=0; ii::execute( data, buf1, buf0, size, CopyBase::PER_WI_1 ); - } - DeviceUtils::waitForCompletion( device ); - sw.stop(); - - t[ii] = sw.getMs()/(float)iter; - } - - for(int ii=0; ii::deallocate( data ); -} - -void launchOverheadBenchmark() -{ - printf("LaunchOverheadBenchmark\n"); - - - Device* ddcl; -#if defined(ADL_ENABLE_DX11) - Device* dddx; -#endif - { - DeviceUtils::Config cfg; - ddcl = DeviceUtils::allocate( TYPE_CL, cfg ); -#if defined(ADL_ENABLE_DX11) - dddx = DeviceUtils::allocate( TYPE_DX11, cfg ); -#endif - } - - { - printf("CL\n"); - copyTest( ddcl ); - } -#ifdef ADL_ENABLE_DX11 - { - printf("DX11\n"); - copyTest( dddx ); - } -#endif - - -} - - -//1, 2, 4, 8, 16, 32, 64, 128, 256, - diff --git a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlTest/NVIDIA/premake4.lua b/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlTest/NVIDIA/premake4.lua deleted file mode 100644 index e4d5cea98..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlTest/NVIDIA/premake4.lua +++ /dev/null @@ -1,31 +0,0 @@ - - hasCL = findOpenCL_NVIDIA() - hasDX11 = findDirectX11() - - if (hasCL) then - - project "OpenCL_DX11_primitives_test_NVIDIA" - - initOpenCL_NVIDIA() - - if (hasDX11) then - initDirectX11() - end - - language "C++" - - kind "ConsoleApp" - targetdir "../../../../bin" - includedirs {"..","../.."} - - links { - "OpenCL" - } - - files { - "../main.cpp", - "../RadixSortBenchmark.h", - "../UnitTests.h" - } - - end \ No newline at end of file diff --git a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlTest/RadixSortBenchmark.h b/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlTest/RadixSortBenchmark.h deleted file mode 100644 index 35404dd06..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlTest/RadixSortBenchmark.h +++ /dev/null @@ -1,121 +0,0 @@ - -template -void run( Device* device, int minSize = 512, int maxSize = 64*1024 )//, int increment = 512 ) -{ - ADLASSERT( TYPE == device->m_type ); - - Stopwatch sw( device ); - -// RadixSort::Data* data0 = RadixSort::allocate( device, maxSize, RadixSortBase::SORT_SIMPLE ); - RadixSort::Data* data0 = RadixSort::allocate( device, maxSize, RadixSortBase::SORT_STANDARD ); - RadixSort::Data* data1 = RadixSort::allocate( device, maxSize, RadixSortBase::SORT_STANDARD ); - RadixSort::Data* data2 = RadixSort::allocate( device, maxSize, RadixSortBase::SORT_ADVANCED ); - - Buffer buf0( device, maxSize ); - Buffer buf1( device, maxSize ); - Buffer buf2( device, maxSize ); - - SortData* input = new SortData[ maxSize ]; - -// for(int iter = minSize; iter<=maxSize; iter+=increment) - for(int iter = minSize; iter<=maxSize; iter*=2) - { - int size = NEXTMULTIPLEOF( iter, 512 ); - - for(int i=0; i::execute( data0, buf0, size ); - - sw.split(); - - RadixSort::execute( data1, buf1, size ); - - sw.split(); - - RadixSort::execute( data2, buf2, size ); - - sw.stop(); - - - float t[3]; - sw.getMs( t, 3 ); -// printf(" %d %3.2f %3.2f %3.2f\n", size, t[0], t[1], t[2]); - printf(" %d %3.2f %3.2f\n", size, t[1], t[2]); - } - - RadixSort::deallocate( data0 ); - RadixSort::deallocate( data1 ); - RadixSort::deallocate( data2 ); - - delete [] input; -} - -template -void run32( Device* device, int size ) -{ - //Cayman: 4194.30Keys: 373.05MKeys/s - //Cypress: 4194.30Keys: 315.13MKeys/s - ADLASSERT( TYPE == device->m_type ); - - Stopwatch sw( device ); - - RadixSort32::Data* data = RadixSort32::allocate( device, size ); - Copy::Data* copyData = Copy::allocate( device ); - - Buffer inputMaster( device, size ); - Buffer input( device, size ); - Buffer output( device, size ); - { - u32* host = new u32[size]; - for(int i=0; i::execute( copyData, (Buffer&)input, (Buffer&)inputMaster, size ); -// RadixSort32::execute( data, input, size ); - RadixSort32::execute( data, input, output, size ); - } - sw.stop(); - - { - float tInS = sw.getMs()/1000.f/(float)nIter; - float mKeysPerS = size/1000.f/1000.f/tInS; - printf("%3.2fMKeys: %3.2fMKeys/s\n", size/1000.f, mKeysPerS); - } - - RadixSort32::deallocate( data ); - Copy::deallocate( copyData ); -} - -template -void radixSortBenchmark() -{ - - Device* device; - { - DeviceUtils::Config cfg; - device = DeviceUtils::allocate( TYPE, cfg ); - } - - run32( device, 256*1024*8*2 ); -// run32( device, 256*20*6 ); - -// run( device, 512, 1024*128*4 ); - - DeviceUtils::deallocate( device ); - -} diff --git a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlTest/UnitTests.h b/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlTest/UnitTests.h deleted file mode 100644 index a1ab2e417..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlTest/UnitTests.h +++ /dev/null @@ -1,801 +0,0 @@ -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Takahiro Harada - - -#include -#include -#include -#include -#include -#include - -#include - -using namespace adl; - -#define NUM_TESTS 10 - -int g_nPassed = 0; -int g_nFailed = 0; -bool g_testFailed = 0; - -//#define TEST_INIT bool g_testFailed = 0; -#define TEST_INIT g_testFailed = 0; -#define TEST_ASSERT(x) if( !(x) ){g_testFailed = 1;} -//#define TEST_ASSERT(x) if( !(x) ){g_testFailed = 1;ADLASSERT(x);} -#define TEST_REPORT(testName) printf("[%s] %s\n",(g_testFailed)?"X":"O", testName); if(g_testFailed) g_nFailed++; else g_nPassed++; - -void memCpyTest( Device* deviceData ) -{ - TEST_INIT; - int maxSize = 64*1024; - Buffer buff( deviceData, maxSize ); - - u32* hostBuff = new u32[maxSize]; - - for(int iter=0; iterquery(deviceData, ".\\Kernel", "VectorAddKernel" ); - - { - int size = 1024; - Buffer buf0( deviceData, size ); - Buffer buf1( deviceData, size ); - Buffer cBuf( deviceData, 1, BufferBase::BUFFER_CONST ); - int* hostBuf0 = new int[size]; - int* hostBuf1 = new int[size]; - for(int i=0; i*)&buf0 ), Launcher::BufferInfo( (Buffer*)&buf1, true ) }; - - Launcher launcher( deviceData, kernel ); - launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(Launcher::BufferInfo) ); - launcher.setConst( (Buffer&)cBuf, constBuffer ); - launcher.launch1D( size ); - - buf0.read( hostBuf0, size ); - buf1.read( hostBuf1, size ); - DeviceUtils::waitForCompletion( deviceData ); - } - - for(int i=0; i -void scanTest( Device* deviceGPU, Device* deviceHost ) -{ - TEST_INIT; - - ADLASSERT( type == deviceGPU->m_type ); - - int maxSize = 1024*256; - - HostBuffer buf0( deviceHost, maxSize ); - HostBuffer buf1( deviceHost, maxSize ); - Buffer buf2( deviceGPU, maxSize ); - Buffer buf3( deviceGPU, maxSize ); - - PrefixScan::Data* data0 = PrefixScan::allocate( deviceGPU, maxSize ); - PrefixScan::Data* data1 = PrefixScan::allocate( deviceHost, maxSize ); - - int dx = maxSize/NUM_TESTS; - for(int iter=0; iter::execute( data1, buf0, buf1, size, &sumHost ); - PrefixScan::execute( data0, buf2, buf3, size, &sumGPU ); - - buf3.read( buf0.m_ptr, size ); - DeviceUtils::waitForCompletion( deviceGPU ); - TEST_ASSERT( sumHost == sumGPU ); - for(int i=0; i::deallocate( data1 ); - PrefixScan::deallocate( data0 ); - - TEST_REPORT( "scanTest" ); -} - -template -bool radixSortTest( Device* deviceGPU, Device* deviceHost ) -{ - TEST_INIT; - ADLASSERT( type == deviceGPU->m_type ); - - int maxSize = 1024*256; - - HostBuffer buf0( deviceHost, maxSize ); - HostBuffer buf1( deviceHost, maxSize ); - Buffer buf2( deviceGPU, maxSize ); - - RadixSort::Data* dataH = RadixSort::allocate( deviceHost, maxSize, RadixSortBase::SORT_SIMPLE ); - RadixSort::Data* dataC = RadixSort::allocate( deviceGPU, maxSize, SORT_TYPE ); - - int dx = maxSize/NUM_TESTS; - for(int iter=0; iter::execute( dataH, buf0, size ); - RadixSort::execute( dataC, buf2, size ); - - buf2.read( buf1.m_ptr, size ); - DeviceUtils::waitForCompletion( deviceGPU ); - for(int i=0; i::deallocate( dataH ); - RadixSort::deallocate( dataC ); - - return g_testFailed; -} - -template -void radixSortSimpleTest( Device* deviceGPU, Device* deviceHost ) -{ - TEST_INIT; - g_testFailed = radixSortTest(deviceGPU, deviceHost); - TEST_REPORT( "radixSortSimpleTest" ); -} - -template -void radixSortStandardTest( Device* deviceGPU, Device* deviceHost ) -{ - TEST_INIT; - g_testFailed = radixSortTest(deviceGPU, deviceHost); - TEST_REPORT( "radixSortStandardTest" ); -} - -template -void radixSortAdvancedTest( Device* deviceGPU, Device* deviceHost ) -{ - TEST_INIT; - g_testFailed = radixSortTest(deviceGPU, deviceHost); - TEST_REPORT( "radixSortAdvancedTest" ); -} - -template -void boundSearchTest( Device* deviceGPU, Device* deviceHost ) -{ - TEST_INIT; - - ADLASSERT( type == deviceGPU->m_type ); - - int maxSize = 1024*256; - int bucketSize = 256; - - HostBuffer buf0( deviceHost, maxSize ); - HostBuffer lowerH( deviceHost, maxSize ); - HostBuffer upperH( deviceHost, maxSize ); - - Buffer buf( deviceGPU, maxSize ); - Buffer lower( deviceGPU, maxSize ); - Buffer upper( deviceGPU, maxSize ); - - BoundSearch::Data* dataH = BoundSearch::allocate( deviceGPU ); - RadixSort::Data* dataHSort = RadixSort::allocate( deviceHost, maxSize, RadixSortBase::SORT_SIMPLE ); - - int dx = maxSize/NUM_TESTS; - for(int iter=0; iter::execute( dataHSort, buf0, size ); - buf.write( buf0.m_ptr, size ); - { - u32* host = new u32[size]; - for(int i=0; i::execute( dataH, buf, size, lower, bucketSize, BoundSearchBase::BOUND_LOWER ); - BoundSearch::execute( dataH, buf, size, upper, bucketSize, BoundSearchBase::BOUND_UPPER ); - - lower.read( lowerH.m_ptr, bucketSize ); - upper.read( upperH.m_ptr, bucketSize ); - DeviceUtils::waitForCompletion( deviceGPU ); -/* - for(u32 i=1; i<(u32)bucketSize; i++) - { - for(u32 j=lowerH[i-1]; j::deallocate( dataH ); - RadixSort::deallocate( dataHSort ); - - TEST_REPORT( "boundSearchTest" ); -} - -template -void fillIntTest( Device* deviceGPU, Device* deviceHost ) -{ - TEST_INIT; - - ADLASSERT( type == deviceGPU->m_type ); - - int maxSize = 1024*256; - - HostBuffer buf0( deviceHost, maxSize ); - HostBuffer buf1( deviceHost, maxSize ); - Buffer buf2( deviceGPU, maxSize ); - - Fill::Data* data0 = Fill::allocate( deviceHost ); - Fill::Data* data1 = Fill::allocate( deviceGPU ); - - int dx = maxSize/NUM_TESTS; - for(int iter=0; iter::execute( data0, buf0, 12, size ); - Fill::execute( data1, buf2, 12, size ); - - buf2.read( buf1.m_ptr, size ); - DeviceUtils::waitForCompletion( deviceGPU ); - for(int i=0; i::deallocate( data0 ); - Fill::deallocate( data1 ); - - TEST_REPORT( "fillIntTest" ); -} - -template -void fillInt2Test( Device* deviceGPU, Device* deviceHost ) -{ - TEST_INIT; - - ADLASSERT( type == deviceGPU->m_type ); - - int maxSize = 1024*256; - - HostBuffer buf0( deviceHost, maxSize ); - HostBuffer buf1( deviceHost, maxSize ); - Buffer buf2( deviceGPU, maxSize ); - - Fill::Data* data0 = Fill::allocate( deviceHost ); - Fill::Data* data1 = Fill::allocate( deviceGPU ); - - int dx = maxSize/NUM_TESTS; - for(int iter=0; iter::execute( data0, buf0, make_int2( 12, 12 ), size ); - Fill::execute( data1, buf2, make_int2( 12, 12 ), size ); - - buf2.read( buf1.m_ptr, size ); - DeviceUtils::waitForCompletion( deviceGPU ); - for(int i=0; i::deallocate( data0 ); - Fill::deallocate( data1 ); - - TEST_REPORT( "fillInt2Test" ); -} - -template -void fillInt4Test( Device* deviceGPU, Device* deviceHost ) -{ - TEST_INIT; - - ADLASSERT( type == deviceGPU->m_type ); - - int maxSize = 1024*256; - - HostBuffer buf0( deviceHost, maxSize ); - HostBuffer buf1( deviceHost, maxSize ); - Buffer buf2( deviceGPU, maxSize ); - - Fill::Data* data0 = Fill::allocate( deviceHost ); - Fill::Data* data1 = Fill::allocate( deviceGPU ); - - int dx = maxSize/NUM_TESTS; - for(int iter=0; iter::execute( data0, buf0, make_int4( 12 ), size ); - Fill::execute( data1, buf2, make_int4( 12 ), size ); - - buf2.read( buf1.m_ptr, size ); - DeviceUtils::waitForCompletion( deviceGPU ); - for(int i=0; i::deallocate( data0 ); - Fill::deallocate( data1 ); - - TEST_REPORT( "fillInt4Test" ); -} - - -template -bool CopyF4Test( Device* deviceGPU, Device* deviceHost ) -{ - TEST_INIT; - ADLASSERT( type == deviceGPU->m_type ); - - int maxSize = 1024*256; - - HostBuffer buf0( deviceHost, maxSize ); - HostBuffer buf1( deviceHost, maxSize ); - Buffer buf2( deviceGPU, maxSize ); - Buffer buf3( deviceGPU, maxSize ); - HostBuffer devResult( deviceHost, maxSize ); - - Copy::Data* data0 = Copy::allocate( deviceHost ); - Copy::Data* data1 = Copy::allocate( deviceGPU ); - - int dx = maxSize/NUM_TESTS; - for(int iter=0; iter::execute( data0, buf1, buf0, size, OPTION ); - Copy::execute( data1, buf3, buf2, size, OPTION ); - - buf3.read( devResult.m_ptr, size ); - DeviceUtils::waitForCompletion( deviceGPU ); - for(int i=0; i::deallocate( data0 ); - Copy::deallocate( data1 ); - - return g_testFailed; -} - -template -void Copy1F4Test( Device* deviceGPU, Device* deviceHost ) -{ - TEST_INIT; - g_testFailed = CopyF4Test( deviceGPU, deviceHost ); - TEST_REPORT( "Copy1F4Test" ); -} - -template -void Copy2F4Test( Device* deviceGPU, Device* deviceHost ) -{ - TEST_INIT; - g_testFailed = CopyF4Test( deviceGPU, deviceHost ); - TEST_REPORT( "Copy2F4Test" ); -} - -template -void Copy4F4Test( Device* deviceGPU, Device* deviceHost ) -{ - TEST_INIT; - g_testFailed = CopyF4Test( deviceGPU, deviceHost ); - TEST_REPORT( "Copy4F4Test" ); -} - - -template -void CopyF1Test( Device* deviceGPU, Device* deviceHost ) -{ - TEST_INIT; - ADLASSERT( type == deviceGPU->m_type ); - - int maxSize = 1024*256; - - HostBuffer buf0( deviceHost, maxSize ); - HostBuffer buf1( deviceHost, maxSize ); - Buffer buf2( deviceGPU, maxSize ); - Buffer buf3( deviceGPU, maxSize ); - HostBuffer devResult( deviceHost, maxSize ); - - Copy::Data* data0 = Copy::allocate( deviceHost ); - Copy::Data* data1 = Copy::allocate( deviceGPU ); - - int dx = maxSize/NUM_TESTS; - for(int iter=0; iter::execute( data0, buf1, buf0, size ); - Copy::execute( data1, buf3, buf2, size ); - - buf3.read( devResult.m_ptr, size ); - DeviceUtils::waitForCompletion( deviceGPU ); - for(int i=0; i::deallocate( data0 ); - Copy::deallocate( data1 ); - - TEST_REPORT( "CopyF1Test" ); -} - -template -void CopyF2Test( Device* deviceGPU, Device* deviceHost ) -{ - TEST_INIT; - ADLASSERT( type == deviceGPU->m_type ); - - int maxSize = 1024*256; - - HostBuffer buf0( deviceHost, maxSize ); - HostBuffer buf1( deviceHost, maxSize ); - Buffer buf2( deviceGPU, maxSize ); - Buffer buf3( deviceGPU, maxSize ); - HostBuffer devResult( deviceHost, maxSize ); - - Copy::Data* data0 = Copy::allocate( deviceHost ); - Copy::Data* data1 = Copy::allocate( deviceGPU ); - - int dx = maxSize/NUM_TESTS; - for(int iter=0; iter::execute( data0, buf1, buf0, size ); - Copy::execute( data1, buf3, buf2, size ); - - buf3.read( devResult.m_ptr, size ); - DeviceUtils::waitForCompletion( deviceGPU ); - for(int i=0; i::deallocate( data0 ); - Copy::deallocate( data1 ); - - TEST_REPORT( "CopyF2Test" ); -} - -template -void radixSort32Test( Device* deviceGPU, Device* deviceHost ) -{ - TEST_INIT; - ADLASSERT( type == deviceGPU->m_type ); - - int maxSize = 1024*256; - - HostBuffer buf0( deviceHost, maxSize ); - HostBuffer buf1( deviceHost, maxSize ); - Buffer buf2( deviceGPU, maxSize ); - - RadixSort32::Data* dataH = RadixSort32::allocate( deviceHost, maxSize ); - RadixSort32::Data* dataC = RadixSort32::allocate( deviceGPU, maxSize ); - - int dx = maxSize/NUM_TESTS; - for(int iter=0; iter::execute( dataH, buf0, size, 32 ); - RadixSort32::execute( dataC, buf2, size, 32 ); - - buf2.read( buf1.m_ptr, size ); - DeviceUtils::waitForCompletion( deviceGPU ); -// for(int i=0; i::deallocate( dataH ); - RadixSort32::deallocate( dataC ); - - TEST_REPORT( "RadixSort32Test" ); -} - -template -void radixSortKeyValue32Test( Device* deviceGPU, Device* deviceHost ) -{ - TEST_INIT; - ADLASSERT( type == deviceGPU->m_type ); - - int maxSize = 1024*256; - - // Host buffers - HostBuffer buf0( deviceHost, maxSize ); // Buffer for keys in host and will be sorted by host. - HostBuffer buf1( deviceHost, maxSize ); // Buffer for keys in host and will be saved by device after sorting in device. - HostBuffer buf2( deviceHost, maxSize ); // Buffer for values in host. This buffer is paired with buf0. - HostBuffer buf3( deviceHost, maxSize ); // Buffer for values in host and will be saved by device after sorting. It is paired with buf1. - - // Device buffers - Buffer buf4( deviceGPU, maxSize ); // Buffer for input keys for device. - Buffer buf5( deviceGPU, maxSize ); // Buffer for output keys from device and will be sorted by device. This key data will be saved to buf1 to be compared with a result(buf0) from host. - Buffer buf6( deviceGPU, maxSize ); // Buffer for input values in device. - Buffer buf7( deviceGPU, maxSize ); // Buffer for output values in device. - - RadixSort32::Data* dataH = RadixSort32::allocate( deviceHost, maxSize ); - RadixSort32::Data* dataC = RadixSort32::allocate( deviceGPU, maxSize ); - - int dx = maxSize/NUM_TESTS; - - for(int iter=0; iter::execute( dataH, buf0, buf2, size, 32 ); - RadixSort32::execute( dataC, buf4, buf5, buf6, buf7, size, 32 ); - buf5.read( buf1.m_ptr, size ); - buf7.read( buf3.m_ptr, size ); - - DeviceUtils::waitForCompletion( deviceGPU ); - - for(int i=0; i::deallocate( dataH ); - RadixSort32::deallocate( dataC ); - - TEST_REPORT( "RadixSortKeyValue32Test" ); -} - -#if defined(ADL_ENABLE_DX11) - #define RUN_GPU( func ) func(ddcl); func(dddx); - #define RUN_GPU_TEMPLATE( func ) func( ddcl, ddhost ); func( dddx, ddhost ); - #define RUN_CL_TEMPLATE( func ) func( ddcl, ddhost ); -#else - #define RUN_GPU( func ) func(ddcl); - #define RUN_GPU_TEMPLATE( func ) func( ddcl, ddhost ); -#endif -#define RUN_ALL( func ) RUN_GPU( func ); func(ddhost); - -void runAllTest() -{ - g_nPassed = 0; - g_nFailed = 0; - - - Device* ddcl; - Device* ddhost; -#if defined(ADL_ENABLE_DX11) - Device* dddx; -#endif - - { - DeviceUtils::Config cfg; - - // Choose AMD or NVidia -#ifdef CL_PLATFORM_AMD - cfg.m_vendor = adl::DeviceUtils::Config::VD_AMD; -#endif - -#ifdef CL_PLATFORM_INTEL - cfg.m_vendor = adl::DeviceUtils::Config::VD_INTEL; - cfg.m_type = DeviceUtils::Config::DEVICE_CPU; -#endif - - -#ifdef CL_PLATFORM_NVIDIA - cfg.m_vendor = adl::DeviceUtils::Config::VD_NV; -#endif - - - ddcl = DeviceUtils::allocate( TYPE_CL, cfg ); - ddhost = DeviceUtils::allocate( TYPE_HOST, cfg ); -// cfg.m_type = DeviceUtils::Config::DEVICE_GPU; -#if defined(ADL_ENABLE_DX11) - dddx = DeviceUtils::allocate( TYPE_DX11, cfg ); -#endif - } - - { - char name[128]; - ddcl->getDeviceName( name ); - printf("CL: %s\n", name); -#ifdef ADL_ENABLE_DX11 - dddx->getDeviceName( name ); - printf("DX11: %s\n", name); -#endif - } - - RUN_GPU_TEMPLATE( radixSort32Test ); - RUN_GPU_TEMPLATE( radixSortKeyValue32Test ); - - if (1) - { - RUN_GPU_TEMPLATE( CopyF1Test ); - RUN_GPU_TEMPLATE( CopyF2Test ); - - boundSearchTest( ddhost, ddhost ); -// fillTest( ddhost, ddhost ); -// fillTest( ddcl, ddhost ); - - - - - RUN_GPU_TEMPLATE( boundSearchTest ); - - RUN_GPU_TEMPLATE( fillIntTest ); - RUN_GPU_TEMPLATE( fillInt2Test ); - RUN_GPU_TEMPLATE( fillInt4Test ); - - RUN_ALL( stopwatchTest ); - RUN_ALL( memCpyTest ); -// RUN_GPU( kernelTest ); - RUN_GPU_TEMPLATE( scanTest ); - RUN_GPU_TEMPLATE( radixSortSimpleTest ); - - RUN_GPU_TEMPLATE( radixSortStandardTest ); - - RUN_GPU_TEMPLATE( radixSort32Test ); - -// RUN_GPU_TEMPLATE( boundSearchTest ); - RUN_GPU_TEMPLATE( Copy1F4Test ); - RUN_GPU_TEMPLATE( Copy2F4Test ); - RUN_GPU_TEMPLATE( Copy4F4Test ); - } - - DeviceUtils::deallocate( ddcl ); - DeviceUtils::deallocate( ddhost ); -#if defined(ADL_ENABLE_DX11) - DeviceUtils::deallocate( dddx ); -#endif - - printf("=========\n%d Passed\n%d Failed\n", g_nPassed, g_nFailed); - - -} \ No newline at end of file diff --git a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlTest/main.cpp b/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlTest/main.cpp deleted file mode 100644 index 2f9eaa16b..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlTest/main.cpp +++ /dev/null @@ -1,118 +0,0 @@ -/* -Copyright (c) 2012 Advanced Micro Devices, Inc. - -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. -*/ -//Originally written by Takahiro Harada - - -#include - -#include -#include - -#include "UnitTests.h" -#include "RadixSortBenchmark.h" -#include "LaunchOverheadBenchmark.h" - - -#undef NUM_TESTS - - -struct ConstBuffer -{ - float4 m_a; - float4 m_b; - float4 m_c; -}; - -int main() -{ - if(0) - { // radix sort test - Device* deviceHost; - Device* deviceGPU; - { - DeviceUtils::Config cfg; - - // Choose AMD or NVidia -#ifdef CL_PLATFORM_AMD - cfg.m_vendor = DeviceUtils::Config::VD_AMD; -#endif - -#ifdef CL_PLATFORM_INTEL - cfg.m_vendor = DeviceUtils::Config::VD_INTEL; -#endif - -#ifdef CL_PLATFORM_NVIDIA - cfg.m_vendor = adl::DeviceUtils::Config::VD_NV; -#endif - deviceGPU = DeviceUtils::allocate( TYPE_DX11, cfg ); - deviceHost = DeviceUtils::allocate( TYPE_HOST, cfg ); - } - - { - int maxSize = 512*20; - int size = maxSize; - - HostBuffer buf0( deviceHost, maxSize ); - HostBuffer buf1( deviceHost, maxSize ); - Buffer buf2( deviceGPU, maxSize ); - - RadixSort::Data* dataH = RadixSort::allocate( deviceHost, maxSize, RadixSortBase::SORT_STANDARD ); - RadixSort::Data* dataC = RadixSort::allocate( deviceGPU, maxSize, RadixSortBase::SORT_ADVANCED ); - - { - size = NEXTMULTIPLEOF( size, 512 ); - - for(int i=0; i::execute( dataH, buf0, size ); - RadixSort::execute( dataC, buf2, size ); - - buf2.read( buf1.m_ptr, size ); - DeviceUtils::waitForCompletion( deviceGPU ); - for(int i=0; i::deallocate( dataH ); - RadixSort::deallocate( dataC ); - } - - DeviceUtils::deallocate( deviceHost ); - DeviceUtils::deallocate( deviceGPU ); - } - - if(0) - { - launchOverheadBenchmark(); - } - - if(0) - { - radixSortBenchmark(); - } - - if(0) - { - radixSortBenchmark(); - } - - if(1) - { - runAllTest(); - } - printf("End, press \n"); - getchar(); -} - diff --git a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlTest/premake4.lua b/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlTest/premake4.lua deleted file mode 100644 index 2c16f4ba4..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/primitives/AdlTest/premake4.lua +++ /dev/null @@ -1,4 +0,0 @@ - -include "AMD" -include "NVIDIA" -include "Intel" \ No newline at end of file diff --git a/Extras/RigidBodyGpuPipeline/opencl/primitives/benchmark/AMD/premake4.lua b/Extras/RigidBodyGpuPipeline/opencl/primitives/benchmark/AMD/premake4.lua deleted file mode 100644 index 370403738..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/primitives/benchmark/AMD/premake4.lua +++ /dev/null @@ -1,29 +0,0 @@ - - hasCL = findOpenCL_AMD() - hasDX11 = findDirectX11() - - if (hasCL) then - - project "OpenCL_DX11_radixsort_benchmark_AMD" - - initOpenCL_AMD() - - if (hasDX11) then - initDirectX11() - end - - language "C++" - - kind "ConsoleApp" - targetdir "../../../../bin" - includedirs {"..","../.."} - - links { - "OpenCL" - } - - files { - "../test_large_problem_sorting.cpp" - } - - end \ No newline at end of file diff --git a/Extras/RigidBodyGpuPipeline/opencl/primitives/benchmark/NVIDIA/premake4.lua b/Extras/RigidBodyGpuPipeline/opencl/primitives/benchmark/NVIDIA/premake4.lua deleted file mode 100644 index b959d13fc..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/primitives/benchmark/NVIDIA/premake4.lua +++ /dev/null @@ -1,29 +0,0 @@ - - hasCL = findOpenCL_NVIDIA() - hasDX11 = findDirectX11() - - if (hasCL) then - - project "OpenCL_DX11_radixsort_benchmark_NVIDIA" - - initOpenCL_NVIDIA() - - if (hasDX11) then - initDirectX11() - end - - language "C++" - - kind "ConsoleApp" - targetdir "../../../../bin" - includedirs {"..","../.."} - - links { - "OpenCL" - } - - files { - "../test_large_problem_sorting.cpp" - } - - end \ No newline at end of file diff --git a/Extras/RigidBodyGpuPipeline/opencl/primitives/benchmark/premake4.lua b/Extras/RigidBodyGpuPipeline/opencl/primitives/benchmark/premake4.lua deleted file mode 100644 index e3cf35221..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/primitives/benchmark/premake4.lua +++ /dev/null @@ -1,2 +0,0 @@ -include "AMD" -include "NVIDIA" diff --git a/Extras/RigidBodyGpuPipeline/opencl/primitives/benchmark/test_large_problem_sorting.cpp b/Extras/RigidBodyGpuPipeline/opencl/primitives/benchmark/test_large_problem_sorting.cpp deleted file mode 100644 index b1673012d..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/primitives/benchmark/test_large_problem_sorting.cpp +++ /dev/null @@ -1,705 +0,0 @@ -/****************************************************************************** - * Copyright 2010 Duane Merrill - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * - * - * - * AUTHORS' REQUEST: - * - * If you use|reference|benchmark this code, please cite our Technical - * Report (http://www.cs.virginia.edu/~dgm4d/papers/RadixSortTR.pdf): - * - * @TechReport{ Merrill:Sorting:2010, - * author = "Duane Merrill and Andrew Grimshaw", - * title = "Revisiting Sorting for GPGPU Stream Architectures", - * year = "2010", - * institution = "University of Virginia, Department of Computer Science", - * address = "Charlottesville, VA, USA", - * number = "CS2010-03" - * } - * - * For more information, see our Google Code project site: - * http://code.google.com/p/back40computing/ - * - * Thanks! - ******************************************************************************/ - -/****************************************************************************** - * Simple test driver program for *large-problem* radix sorting. - * - * Useful for demonstrating how to integrate radix sorting into - * your application - ******************************************************************************/ - -/****************************************************************************** - * Converted from CUDA to OpenCL/DirectCompute by Erwin Coumans - ******************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include - -#define BUFFERSIZE_WORKAROUND - -//#include -#include -/********************** -* -*/ - -#include "Adl/Adl.h" -#include "AdlPrimitives/Sort/RadixSort32.h" -#include "AdlPrimitives/Sort/SortData.h" - -using namespace adl; - - -/*********************** -* -*/ - -bool g_verbose; - - -/****************************************************************************** - * Routines - ******************************************************************************/ - - -/** - * Keys-only sorting. Uses the GPU to sort the specified vector of elements for the given - * number of iterations, displaying runtime information. - * - * @param[in] num_elements - * Size in elements of the vector to sort - * @param[in] h_keys - * Vector of keys to sort - * @param[in] iterations - * Number of times to invoke the GPU sorting primitive - * @param[in] cfg - * Config - */ -template -void TimedSort( - unsigned int num_elements, - K *h_keys, - unsigned int iterations, const DeviceUtils::Config& cfg) -{ - std::string sType = "No type selected"; - - if (type == TYPE_CL) - sType = "OpenCL"; - else if (type == TYPE_DX11) - sType = "DX11"; - - printf("Keys-only, %s, %d iterations, %d elements\n", sType.c_str(), iterations, num_elements); - - int max_elements = num_elements; - -#ifdef BUFFERSIZE_WORKAROUND - if (max_elements < 1024*256) - max_elements = 1024*256; -#endif - - // Allocate device storage - Device* deviceData = NULL; - - if ( type == TYPE_CL ) - deviceData = new DeviceCL(); -#ifdef ADL_ENABLE_DX11 - else if ( type == TYPE_DX11 ) - deviceData = new DeviceDX11(); -#endif //ADL_ENABLE_DX11 - - deviceData->initialize(cfg); - - RadixSort32::Data* planData = RadixSort32::allocate( deviceData, max_elements); - - { - Buffer keysInOut(deviceData,max_elements); - - // Create sorting enactor - keysInOut.write(h_keys,num_elements); - DeviceUtils::waitForCompletion( deviceData); - - RadixSort32::execute( planData,keysInOut,num_elements, 32); - DeviceUtils::waitForCompletion( deviceData); - - // Perform the timed number of sorting iterations - double elapsed = 0; - float duration = 0; - StopwatchHost watch; - watch.init(deviceData); - - watch.start(); - - for (int i = 0; i < iterations; i++) - { - - // Move a fresh copy of the problem into device storage - keysInOut.write(h_keys,num_elements); - DeviceUtils::waitForCompletion( deviceData); - - // Start GPU timing record - watch.start(); - - // Call the sorting API routine - RadixSort32::execute( planData,keysInOut,num_elements, 32); - DeviceUtils::waitForCompletion( deviceData); - - watch.stop(); - duration = watch.getMs(); - - // End GPU timing record - elapsed += (double) duration; - } - - // Display timing information - double avg_runtime = elapsed / iterations; - // double throughput = ((double) num_elements) / avg_runtime / 1000.0 / 1000.0; - // printf(", %f GPU ms, %f x10^9 elts/sec\n", avg_runtime, throughput); - double throughput = ((double) num_elements) / avg_runtime / 1000.0 ; - printf(", %f GPU ms, %f x10^6 elts/sec\n", avg_runtime, throughput); - - // Copy out data - keysInOut.read(h_keys,num_elements); - - DeviceUtils::waitForCompletion( deviceData); - - } - // Free allocated memory - RadixSort32::deallocate( planData); - delete deviceData; - // Clean up events -} - -/** - * Key-value sorting. Uses the GPU to sort the specified vector of elements for the given - * number of iterations, displaying runtime information. - * - * @param[in] num_elements - * Size in elements of the vector to sort - * @param[in] h_keys - * Vector of keys to sort - * @param[in,out] h_values - * Vector of values to sort - * @param[in] iterations - * Number of times to invoke the GPU sorting primitive - * @param[in] cfg - * Config - */ -template -void TimedSort( - unsigned int num_elements, - K *h_keys, - V *h_values, - unsigned int iterations, const DeviceUtils::Config& cfg) -{ - std::string sType = "No type selected"; - - if (type == TYPE_CL) - sType = "OpenCL"; - else if (type == TYPE_DX11) - sType = "DX11"; - - printf("Key-values, %s, %d iterations, %d elements\n", sType.c_str(), iterations, num_elements); - - int max_elements = num_elements; - -#ifdef BUFFERSIZE_WORKAROUND - if (max_elements < 1024*256) - max_elements = 1024*256; -#endif - - // Allocate device storage - Device* deviceData = NULL; - - if ( type == TYPE_CL ) - deviceData = new DeviceCL(); -#ifdef ADL_ENABLE_DX11 - else if ( type == TYPE_DX11 ) - deviceData = new DeviceDX11(); -#endif //ADL_ENABLE_DX11 - - deviceData->initialize(cfg); - RadixSort32::Data* planData = RadixSort32::allocate( deviceData, max_elements); - { - Buffer keysIn(deviceData,max_elements); - Buffer valuesIn(deviceData,max_elements); - - Buffer keysOut(deviceData,max_elements); - Buffer valuesOut(deviceData,max_elements); - - //printf("Key-values, %d iterations, %d elements", iterations, num_elements); - - // Create sorting enactor - keysIn.write(h_keys,num_elements); - DeviceUtils::waitForCompletion( deviceData); - valuesIn.write(h_values,num_elements); - DeviceUtils::waitForCompletion( deviceData); - - - // Perform a single sorting iteration to allocate memory, prime code caches, etc. - //RadixSort::execute( planData, buffer, num_elements ); - - //RadixSort32::execute( planData, keysIn,keysOut, valuesIn,valuesOut, num_elements, 32); - RadixSort32::execute( planData, keysIn,keysOut, valuesIn,valuesOut, num_elements, 32); - DeviceUtils::waitForCompletion( deviceData); - - // Perform the timed number of sorting iterations - double elapsed = 0; - float duration = 0; - StopwatchHost watch; - watch.init(deviceData); - - watch.start(); - - for (int i = 0; i < iterations; i++) - { - - // Move a fresh copy of the problem into device storage - keysIn.write(h_keys,num_elements); - valuesIn.write(h_values,num_elements); - - DeviceUtils::waitForCompletion( deviceData); - - // Start GPU timing record - watch.start(); - - // Call the sorting API routine - - RadixSort32::execute( planData, keysIn,keysOut, valuesIn,valuesOut, num_elements, 32); - - DeviceUtils::waitForCompletion( deviceData); - - watch.stop(); - duration = watch.getMs(); - - // End GPU timing record - elapsed += (double) duration; - } - - // Display timing information - double avg_runtime = elapsed / iterations; - // double throughput = ((double) num_elements) / avg_runtime / 1000.0 / 1000.0; - // printf(", %f GPU ms, %f x10^9 elts/sec\n", avg_runtime, throughput); - double throughput = ((double) num_elements) / avg_runtime / 1000.0 ; - printf(", %f GPU ms, %f x10^6 elts/sec\n", avg_runtime, throughput); - - //memset(h_keys,1,num_elements); - //memset(h_values,1,num_elements); - // Copy out data - keysOut.read(h_keys,num_elements); - valuesOut.read(h_values,num_elements); - - DeviceUtils::waitForCompletion( deviceData); - } - - // Free allocated memory - RadixSort32::deallocate( planData); - delete deviceData; - // Clean up events - -} - - - -/** - * Generates random 32-bit keys. - * - * We always take the second-order byte from rand() because the higher-order - * bits returned by rand() are commonly considered more uniformly distributed - * than the lower-order bits. - * - * We can decrease the entropy level of keys by adopting the technique - * of Thearling and Smith in which keys are computed from the bitwise AND of - * multiple random samples: - * - * entropy_reduction | Effectively-unique bits per key - * ----------------------------------------------------- - * -1 | 0 - * 0 | 32 - * 1 | 25.95 - * 2 | 17.41 - * 3 | 10.78 - * 4 | 6.42 - * ... | ... - * - */ -template -void RandomBits(K &key, int entropy_reduction = 0, int lower_key_bits = sizeof(K) * 8) -{ - const unsigned int NUM_UCHARS = (sizeof(K) + sizeof(unsigned char) - 1) / sizeof(unsigned char); - unsigned char key_bits[NUM_UCHARS]; - - do { - - for (int j = 0; j < NUM_UCHARS; j++) { - unsigned char quarterword = 0xff; - for (int i = 0; i <= entropy_reduction; i++) { - quarterword &= (rand() >> 7); - } - key_bits[j] = quarterword; - } - - if (lower_key_bits < sizeof(K) * 8) { - unsigned long long base = 0; - memcpy(&base, key_bits, sizeof(K)); - base &= (1 << lower_key_bits) - 1; - memcpy(key_bits, &base, sizeof(K)); - } - - memcpy(&key, key_bits, sizeof(K)); - - } while (key != key); // avoids NaNs when generating random floating point numbers -} - - -/****************************************************************************** - * Templated routines for printing keys/values to the console - ******************************************************************************/ - -template -void PrintValue(T val) { - printf("%d", val); -} - -template<> -void PrintValue(float val) { - printf("%f", val); -} - -template<> -void PrintValue(double val) { - printf("%f", val); -} - -template<> -void PrintValue(unsigned char val) { - printf("%u", val); -} - -template<> -void PrintValue(unsigned short val) { - printf("%u", val); -} - -template<> -void PrintValue(unsigned int val) { - printf("%u", val); -} - -template<> -void PrintValue(long val) { - printf("%ld", val); -} - -template<> -void PrintValue(unsigned long val) { - printf("%lu", val); -} - -template<> -void PrintValue(long long val) { - printf("%lld", val); -} - -template<> -void PrintValue(unsigned long long val) { - printf("%llu", val); -} - - - -/** - * Compares the equivalence of two arrays - */ -template -int CompareResults(T* computed, T* reference, SizeT len, bool verbose = true) -{ - printf("\n"); - for (SizeT i = 0; i < len; i++) { - - if (computed[i] != reference[i]) { - printf("INCORRECT: [%lu]: ", (unsigned long) i); - PrintValue(computed[i]); - printf(" != "); - PrintValue(reference[i]); - - if (verbose) { - printf("\nresult[..."); - for (size_t j = (i >= 5) ? i - 5 : 0; (j < i + 5) && (j < len); j++) { - PrintValue(computed[j]); - printf(", "); - } - printf("...]"); - printf("\nreference[..."); - for (size_t j = (i >= 5) ? i - 5 : 0; (j < i + 5) && (j < len); j++) { - PrintValue(reference[j]); - printf(", "); - } - printf("...]"); - } - - return 1; - } - } - - printf("CORRECT\n"); - return 0; -} - -/** - * Creates an example sorting problem whose keys is a vector of the specified - * number of K elements, values of V elements, and then dispatches the problem - * to the GPU for the given number of iterations, displaying runtime information. - * - * @param[in] iterations - * Number of times to invoke the GPU sorting primitive - * @param[in] num_elements - * Size in elements of the vector to sort - * @param[in] cfg - * Config - */ -template -void TestSort( - unsigned int iterations, - int num_elements, - bool keys_only, const DeviceUtils::Config& cfg) -{ - // Allocate the sorting problem on the host and fill the keys with random bytes - - K *h_keys = NULL; - K *h_reference_keys = NULL; - V *h_values = NULL; - h_keys = (K*) malloc(num_elements * sizeof(K)); - h_reference_keys = (K*) malloc(num_elements * sizeof(K)); - if (!keys_only) h_values = (V*) malloc(num_elements * sizeof(V)); - - - // Use random bits - for (unsigned int i = 0; i < num_elements; ++i) { - RandomBits(h_keys[i], 0); - //h_keys[i] = 0xffffffffu-i; - if (!keys_only) - h_values[i] = h_keys[i];//0xffffffffu-i; - - h_reference_keys[i] = h_keys[i]; - } - - // Run the timing test - if (keys_only) { - TimedSort(num_elements, h_keys, iterations, cfg); - } else { - TimedSort(num_elements, h_keys, h_values, iterations, cfg); - } - -// cudaThreadSynchronize(); - - // Display sorted key data - if (g_verbose) { - printf("\n\nKeys:\n"); - for (int i = 0; i < num_elements; i++) { - PrintValue(h_keys[i]); - printf(", "); - } - printf("\n\n"); - } - - // Verify solution - std::sort(h_reference_keys, h_reference_keys + num_elements); - CompareResults(h_keys, h_reference_keys, num_elements, true); - printf("\n"); - fflush(stdout); - - // Free our allocated host memory - if (h_keys != NULL) free(h_keys); - if (h_values != NULL) free(h_values); -} - - - -/** - * Displays the commandline usage for this tool - */ -void Usage() -{ - printf("\ntest_large_problem_sorting [--device=] [--v] [--i=] [--n=] [--keys-only]\n"); - printf("\n"); - printf("\t--v\tDisplays sorted results to the console.\n"); - printf("\n"); - printf("\t--i\tPerforms the sorting operation times\n"); - printf("\t\t\ton the device. Re-copies original input each time. Default = 1\n"); - printf("\n"); - printf("\t--n\tThe number of elements to comprise the sample problem\n"); - printf("\t\t\tDefault = 512\n"); - printf("\n"); - printf("\t--keys-only\tSpecifies that keys are not accommodated by value pairings\n"); - printf("\n"); -} - - -/****************************************************************************** - * Command-line parsing - ******************************************************************************/ -#include -#include -#include - -class CommandLineArgs -{ -protected: - - std::map pairs; - -public: - - // Constructor - CommandLineArgs(int argc, char **argv) - { - using namespace std; - - for (int i = 1; i < argc; i++) - { - string arg = argv[i]; - - if ((arg[0] != '-') || (arg[1] != '-')) { - continue; - } - - string::size_type pos; - string key, val; - if ((pos = arg.find( '=')) == string::npos) { - key = string(arg, 2, arg.length() - 2); - val = ""; - } else { - key = string(arg, 2, pos - 2); - val = string(arg, pos + 1, arg.length() - 1); - } - pairs[key] = val; - } - } - - bool CheckCmdLineFlag(const char* arg_name) - { - using namespace std; - map::iterator itr; - if ((itr = pairs.find(arg_name)) != pairs.end()) { - return true; - } - return false; - } - - template - void GetCmdLineArgument(const char *arg_name, T &val); - - int ParsedArgc() - { - return pairs.size(); - } -}; - -template -void CommandLineArgs::GetCmdLineArgument(const char *arg_name, T &val) -{ - using namespace std; - map::iterator itr; - if ((itr = pairs.find(arg_name)) != pairs.end()) { - istringstream strstream(itr->second); - strstream >> val; - } -} - -template <> -void CommandLineArgs::GetCmdLineArgument(const char* arg_name, char* &val) -{ - using namespace std; - map::iterator itr; - if ((itr = pairs.find(arg_name)) != pairs.end()) { - - string s = itr->second; - val = (char*) malloc(sizeof(char) * (s.length() + 1)); - strcpy(val, s.c_str()); - - } else { - val = NULL; - } -} - - - - - -/****************************************************************************** - * Main - ******************************************************************************/ - -int main( int argc, char** argv) -{ - - //srand(time(NULL)); - srand(0); // presently deterministic - - unsigned int num_elements = 1024*1024*12;//16*1024;//8*524288;//2048;//512;//524288; - unsigned int iterations = 10; - bool keys_only; - - // - // Check command line arguments - // - - CommandLineArgs args(argc,argv); - - if (args.CheckCmdLineFlag("help")) - { - Usage(); - return 0; - } - - args.GetCmdLineArgument("i", iterations); - args.GetCmdLineArgument("n", num_elements); - keys_only = args.CheckCmdLineFlag("keys-only"); - g_verbose = args.CheckCmdLineFlag("v"); - - DeviceUtils::Config cfg; - - // Choose AMD or NVidia -#ifdef CL_PLATFORM_AMD - cfg.m_vendor = DeviceUtils::Config::VD_AMD; -#endif - -#ifdef CL_PLATFORM_NVIDIA - cfg.m_vendor = DeviceUtils::Config::VD_NV; -#endif - - TestSort( - iterations, - num_elements, - keys_only, cfg); - -#ifdef ADL_ENABLE_DX11 - TestSort( - iterations, - num_elements, - keys_only, cfg); -#endif //ADL_ENABLE_DX11 -} - - - diff --git a/Extras/RigidBodyGpuPipeline/opencl/vector_add/AMD/premake4.lua b/Extras/RigidBodyGpuPipeline/opencl/vector_add/AMD/premake4.lua deleted file mode 100644 index 4b5e39b9b..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/vector_add/AMD/premake4.lua +++ /dev/null @@ -1,21 +0,0 @@ - - hasCL = findOpenCL_AMD() - - if (hasCL) then - - project "OpenCL_VectorAdd_AMD" - - initOpenCL_AMD() - - language "C++" - - kind "ConsoleApp" - targetdir "../../../bin" - - files { - "../main.cpp", - "../../basic_initialize/btOpenCLUtils.cpp", - "../../basic_initialize/btOpenCLUtils.h" - } - - end \ No newline at end of file diff --git a/Extras/RigidBodyGpuPipeline/opencl/vector_add/Intel/premake4.lua b/Extras/RigidBodyGpuPipeline/opencl/vector_add/Intel/premake4.lua deleted file mode 100644 index 0f1be986b..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/vector_add/Intel/premake4.lua +++ /dev/null @@ -1,23 +0,0 @@ - - hasCL = findOpenCL_Intel() - - if (hasCL) then - - project "OpenCL_intialize_Intel" - - initOpenCL_Intel() - - language "C++" - - kind "ConsoleApp" - targetdir "../../../bin" - --- includedirs {"..","../../../../include/gpu_research"} - - files { - "../main.cpp", - "../btOpenCLUtils.cpp", - "../btOpenCLUtils.h" - } - - end \ No newline at end of file diff --git a/Extras/RigidBodyGpuPipeline/opencl/vector_add/NVIDIA/premake4.lua b/Extras/RigidBodyGpuPipeline/opencl/vector_add/NVIDIA/premake4.lua deleted file mode 100644 index e7c1d156f..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/vector_add/NVIDIA/premake4.lua +++ /dev/null @@ -1,23 +0,0 @@ - - hasCL = findOpenCL_NVIDIA() - - if (hasCL) then - - project "OpenCL_intialize_NVIDIA" - - initOpenCL_NVIDIA() - - language "C++" - - kind "ConsoleApp" - targetdir "../../../bin" - --- includedirs {"..","../../../../include/gpu_research"} - - files { - "../main.cpp", - "../btOpenCLUtils.cpp", - "../btOpenCLUtils.h" - } - - end \ No newline at end of file diff --git a/Extras/RigidBodyGpuPipeline/opencl/vector_add/VectorAddKernels.cl b/Extras/RigidBodyGpuPipeline/opencl/vector_add/VectorAddKernels.cl deleted file mode 100644 index 2ff17826a..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/vector_add/VectorAddKernels.cl +++ /dev/null @@ -1,16 +0,0 @@ - - -__kernel void VectorAdd(__global const float8* a, __global const float8* b, __global float8* c, int numElements) -{ - // get oct-float index into global data array - int iGID = get_global_id(0); - if (iGID>=numElements) - return; - - float8 aGID = a[iGID]; - float8 bGID = b[iGID]; - - float8 result = aGID + bGID; - // write back out to GMEM - c[iGID] = result; -} diff --git a/Extras/RigidBodyGpuPipeline/opencl/vector_add/VectorAddKernels.h b/Extras/RigidBodyGpuPipeline/opencl/vector_add/VectorAddKernels.h deleted file mode 100644 index fb7e2fc21..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/vector_add/VectorAddKernels.h +++ /dev/null @@ -1,18 +0,0 @@ -static const char* vectorAddCL= \ -"\n" -"\n" -"__kernel void VectorAdd(__global const float8* a, __global const float8* b, __global float8* c, int numElements)\n" -"{\n" -" // get oct-float index into global data array\n" -" int iGID = get_global_id(0);\n" -" if (iGID>=numElements)\n" -" return;\n" -"\n" -" float8 aGID = a[iGID];\n" -" float8 bGID = b[iGID];\n" -"\n" -" float8 result = aGID + bGID;\n" -" // write back out to GMEM\n" -" c[iGID] = result;\n" -"}\n" -; diff --git a/Extras/RigidBodyGpuPipeline/opencl/vector_add/main.cpp b/Extras/RigidBodyGpuPipeline/opencl/vector_add/main.cpp deleted file mode 100644 index 54afa4ee8..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/vector_add/main.cpp +++ /dev/null @@ -1,367 +0,0 @@ - -///VectorAdd sample, from the NVidia JumpStart Guide -///http://developer.download.nvidia.com/OpenCL/NVIDIA_OpenCL_JumpStart_Guide.pdf - -///Instead of #include we include -///Apart from this include file, all other code should compile and work on OpenCL compliant implementation - - -//#define LOAD_FROM_FILE - -#ifdef __APPLE__ - #include -#else - #include -#endif //__APPLE__ - -#include -#include -#include -#include - -#define GRID3DOCL_CHECKERROR(a, b) if((a)!=(b)) { printf("3D GRID OCL Error : %d\n", (a)); btAssert((a) == (b)); } -size_t wgSize; - -#include "VectorAddKernels.h" - - - -char* loadProgSource(const char* cFilename, const char* cPreamble, size_t* szFinalLength) -{ - // locals - FILE* pFileStream = NULL; - size_t szSourceLength; - - // open the OpenCL source code file - pFileStream = fopen(cFilename, "rb"); - if(pFileStream == 0) - { - return NULL; - } - - size_t szPreambleLength = strlen(cPreamble); - - // get the length of the source code - fseek(pFileStream, 0, SEEK_END); - szSourceLength = ftell(pFileStream); - fseek(pFileStream, 0, SEEK_SET); - - // allocate a buffer for the source code string and read it in - char* cSourceString = (char *)malloc(szSourceLength + szPreambleLength + 1); - memcpy(cSourceString, cPreamble, szPreambleLength); - fread((cSourceString) + szPreambleLength, szSourceLength, 1, pFileStream); - - // close the file and return the total length of the combined (preamble + source) string - fclose(pFileStream); - if(szFinalLength != 0) - { - *szFinalLength = szSourceLength + szPreambleLength; - } - cSourceString[szSourceLength + szPreambleLength] = '\0'; - - return cSourceString; -} - -size_t workitem_size[3]; - -void printDevInfo(cl_device_id device) -{ - char device_string[1024]; - - clGetDeviceInfo(device, CL_DEVICE_NAME, sizeof(device_string), &device_string, NULL); - printf( " Device %s:\n", device_string); - - // CL_DEVICE_INFO - cl_device_type type; - clGetDeviceInfo(device, CL_DEVICE_TYPE, sizeof(type), &type, NULL); - if( type & CL_DEVICE_TYPE_CPU ) - printf(" CL_DEVICE_TYPE:\t\t%s\n", "CL_DEVICE_TYPE_CPU"); - if( type & CL_DEVICE_TYPE_GPU ) - printf( " CL_DEVICE_TYPE:\t\t%s\n", "CL_DEVICE_TYPE_GPU"); - if( type & CL_DEVICE_TYPE_ACCELERATOR ) - printf( " CL_DEVICE_TYPE:\t\t%s\n", "CL_DEVICE_TYPE_ACCELERATOR"); - if( type & CL_DEVICE_TYPE_DEFAULT ) - printf( " CL_DEVICE_TYPE:\t\t%s\n", "CL_DEVICE_TYPE_DEFAULT"); - - // CL_DEVICE_MAX_COMPUTE_UNITS - cl_uint compute_units; - clGetDeviceInfo(device, CL_DEVICE_MAX_COMPUTE_UNITS, sizeof(compute_units), &compute_units, NULL); - printf( " CL_DEVICE_MAX_COMPUTE_UNITS:\t%d\n", compute_units); - - // CL_DEVICE_MAX_WORK_GROUP_SIZE - - clGetDeviceInfo(device, CL_DEVICE_MAX_WORK_ITEM_SIZES, sizeof(workitem_size), &workitem_size, NULL); - printf( " CL_DEVICE_MAX_WORK_ITEM_SIZES:\t%zu / %zu / %zu \n", workitem_size[0], workitem_size[1], workitem_size[2]); - -} - - - - -// Main function -// ********************************************************************* -int main(int argc, char **argv) -{ - void *srcA, *srcB, *dst; // Host buffers for OpenCL test - cl_context cxGPUContext; // OpenCL context - cl_command_queue cqCommandQue; // OpenCL command que - cl_device_id* cdDevices; // OpenCL device list - cl_program cpProgram; // OpenCL program - cl_kernel ckKernel; // OpenCL kernel - cl_mem cmMemObjs[3]; // OpenCL memory buffer objects: 3 for device - size_t szGlobalWorkSize[1]; // 1D var for Total # of work items - size_t szLocalWorkSize[1]; // 1D var for # of work items in the work group - size_t szParmDataBytes; // Byte size of context information - cl_int ciErr1, ciErr2; // Error code var - - - int iTestN = 100000 * 8; // Size of Vectors to process - - int actualGlobalSize = iTestN / 8; - - - // set Global and Local work size dimensions - szGlobalWorkSize[0] = iTestN >> 3; // do 8 computations per work item - szLocalWorkSize[0]= iTestN>>3; - - - // Allocate and initialize host arrays - srcA = (void *)malloc (sizeof(cl_float) * iTestN); - srcB = (void *)malloc (sizeof(cl_float) * iTestN); - dst = (void *)malloc (sizeof(cl_float) * iTestN); - - int i; - - // Initialize arrays with some values - for (i=0;i processing outside of the buffer - //make sure to check kernel - } - - size_t globalThreads[] = {num_t * workgroupSize}; - size_t localThreads[] = {workgroupSize}; - - - localWorkSize[0] = workgroupSize; - globalWorkSize[0] = num_t * workgroupSize; - localWorkSize[1] = 1; - globalWorkSize[1] = 1; - - // Copy input data from host to GPU and launch kernel - ciErr1 |= clEnqueueNDRangeKernel(cqCommandQue, ckKernel, 1, NULL, globalThreads, localThreads, 0, NULL, NULL); - - } - - if (ciErrNum != CL_SUCCESS) - { - printf("cannot clEnqueueNDRangeKernel\n"); - exit(0); - } - - clFinish(cqCommandQue); - // Read back results and check accumulated errors - ciErr1 |= clEnqueueReadBuffer(cqCommandQue, cmMemObjs[2], CL_TRUE, 0, sizeof(cl_float8) * szGlobalWorkSize[0], dst, 0, NULL, NULL); - - // Release kernel, program, and memory objects - // NOTE: Most properly this should be done at any of the exit points above, but it is omitted elsewhere for clarity. - free(cdDevices); - clReleaseKernel(ckKernel); - clReleaseProgram(cpProgram); - clReleaseCommandQueue(cqCommandQue); - clReleaseContext(cxGPUContext); - - - // print the results - int iErrorCount = 0; - for (i = 0; i < iTestN; i++) - { - if (((float*)dst)[i] != ((float*)srcA)[i]+((float*)srcB)[i]) - iErrorCount++; - } - - if (iErrorCount) - { - printf("MiniCL validation FAILED\n"); - } else - { - printf("MiniCL validation SUCCESSFULL\n"); - } - // Free host memory, close log and return success - for (i = 0; i < 3; i++) - { - clReleaseMemObject(cmMemObjs[i]); - } - - free(srcA); - free(srcB); - free (dst); - printf("Press ENTER to quit\n"); - getchar(); -} - - diff --git a/Extras/RigidBodyGpuPipeline/opencl/vector_add/premake4.lua b/Extras/RigidBodyGpuPipeline/opencl/vector_add/premake4.lua deleted file mode 100644 index 56a16eed5..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/vector_add/premake4.lua +++ /dev/null @@ -1,4 +0,0 @@ - - include "AMD" --- include "Intel" --- include "NVIDIA" diff --git a/Extras/RigidBodyGpuPipeline/opencl/vector_add/stringify.py b/Extras/RigidBodyGpuPipeline/opencl/vector_add/stringify.py deleted file mode 100644 index e79e281e4..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/vector_add/stringify.py +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/env python -import sys -import os -import shutil - -arg = sys.argv[1] -fh = open(arg) - -print 'static const char* '+sys.argv[2]+'= \\' -for line in fh.readlines(): - a = line.strip('\n') - print '"'+a+'\\n"' -print ';' diff --git a/Extras/RigidBodyGpuPipeline/opencl/vector_add/stringifyVectorAddKernel.bat b/Extras/RigidBodyGpuPipeline/opencl/vector_add/stringifyVectorAddKernel.bat deleted file mode 100644 index 9b3913db1..000000000 --- a/Extras/RigidBodyGpuPipeline/opencl/vector_add/stringifyVectorAddKernel.bat +++ /dev/null @@ -1,8 +0,0 @@ -stringify.py VectorAddKernels.cl vectorAddCL >VectorAddKernels.h - - - - -@echo Warning: -@echo You might still need to find/replace for \\n (due to macros) and replace #include statements by their content -pause diff --git a/Extras/RigidBodyGpuPipeline/readme.txt b/Extras/RigidBodyGpuPipeline/readme.txt deleted file mode 100644 index 914da0eb7..000000000 --- a/Extras/RigidBodyGpuPipeline/readme.txt +++ /dev/null @@ -1,8 +0,0 @@ -This GPU rigid body pipeline is only tested under Windows with the latest GPUs and GPU/OpenCL drivers. -AMD Radeon 5970, preferably Tahiti 7970 with Catalyst 12.x or NVIDIA 470 with latest drivers (at least 290.53) - -Click on the build/vs2010.bat file to generation Visual Studio project files. -It requires either the AMD APP SDK 2.6 or later, or NVIDIA CUDA SDK. - -Check out the videos at http://youtube.com/erwincoumans or the slides at http://github.com/erwincoumans/experiments/downloads -