summaryrefslogtreecommitdiff
path: root/thirdparty
diff options
context:
space:
mode:
Diffstat (limited to 'thirdparty')
-rw-r--r--thirdparty/README.md34
-rw-r--r--thirdparty/b2d_convexdecomp/b2Glue.h3
-rw-r--r--thirdparty/bullet/Bullet3Common/b3AlignedObjectArray.h8
-rw-r--r--thirdparty/bullet/Bullet3Common/b3FileUtils.h2
-rw-r--r--thirdparty/bullet/Bullet3Dynamics/ConstraintSolver/b3Generic6DofConstraint.cpp4
-rw-r--r--thirdparty/bullet/Bullet3Dynamics/ConstraintSolver/b3Generic6DofConstraint.h2
-rw-r--r--thirdparty/bullet/Bullet3OpenCL/Initialize/b3OpenCLUtils.cpp2
-rw-r--r--thirdparty/bullet/BulletCollision/BroadphaseCollision/btAxisSweep3Internal.h8
-rw-r--r--thirdparty/bullet/BulletCollision/BroadphaseCollision/btBroadphaseProxy.h1
-rw-r--r--thirdparty/bullet/BulletCollision/BroadphaseCollision/btDbvtBroadphase.cpp11
-rw-r--r--thirdparty/bullet/BulletCollision/BroadphaseCollision/btDbvtBroadphase.h3
-rw-r--r--thirdparty/bullet/BulletCollision/BroadphaseCollision/btDispatcher.h4
-rw-r--r--thirdparty/bullet/BulletCollision/BroadphaseCollision/btOverlappingPairCache.cpp91
-rw-r--r--thirdparty/bullet/BulletCollision/BroadphaseCollision/btOverlappingPairCache.h12
-rw-r--r--thirdparty/bullet/BulletCollision/BroadphaseCollision/btSimpleBroadphase.cpp5
-rw-r--r--thirdparty/bullet/BulletCollision/CollisionDispatch/SphereTriangleDetector.cpp6
-rw-r--r--thirdparty/bullet/BulletCollision/CollisionDispatch/btBox2dBox2dCollisionAlgorithm.cpp8
-rw-r--r--thirdparty/bullet/BulletCollision/CollisionDispatch/btCollisionDispatcher.cpp11
-rw-r--r--thirdparty/bullet/BulletCollision/CollisionDispatch/btCollisionObject.cpp19
-rw-r--r--thirdparty/bullet/BulletCollision/CollisionDispatch/btCollisionObject.h13
-rw-r--r--thirdparty/bullet/BulletCollision/CollisionDispatch/btCollisionWorld.cpp26
-rw-r--r--thirdparty/bullet/BulletCollision/CollisionDispatch/btCollisionWorld.h3
-rw-r--r--thirdparty/bullet/BulletCollision/CollisionDispatch/btCompoundCollisionAlgorithm.cpp14
-rw-r--r--thirdparty/bullet/BulletCollision/CollisionDispatch/btCompoundCompoundCollisionAlgorithm.cpp21
-rw-r--r--thirdparty/bullet/BulletCollision/CollisionDispatch/btConvexConcaveCollisionAlgorithm.cpp105
-rw-r--r--thirdparty/bullet/BulletCollision/CollisionDispatch/btConvexConvexAlgorithm.cpp150
-rw-r--r--thirdparty/bullet/BulletCollision/CollisionDispatch/btHashedSimplePairCache.cpp7
-rw-r--r--thirdparty/bullet/BulletCollision/CollisionDispatch/btHashedSimplePairCache.h6
-rw-r--r--thirdparty/bullet/BulletCollision/CollisionDispatch/btInternalEdgeUtility.cpp19
-rw-r--r--thirdparty/bullet/BulletCollision/CollisionDispatch/btSimulationIslandManager.cpp42
-rw-r--r--thirdparty/bullet/BulletCollision/CollisionShapes/btCapsuleShape.h1
-rw-r--r--thirdparty/bullet/BulletCollision/CollisionShapes/btCompoundShape.cpp2
-rw-r--r--thirdparty/bullet/BulletCollision/CollisionShapes/btCompoundShape.h2
-rw-r--r--thirdparty/bullet/BulletCollision/CollisionShapes/btConvexPolyhedron.cpp12
-rw-r--r--thirdparty/bullet/BulletCollision/CollisionShapes/btConvexPolyhedron.h1
-rw-r--r--thirdparty/bullet/BulletCollision/CollisionShapes/btConvexShape.cpp8
-rw-r--r--thirdparty/bullet/BulletCollision/CollisionShapes/btMiniSDF.cpp532
-rw-r--r--thirdparty/bullet/BulletCollision/CollisionShapes/btMiniSDF.h134
-rw-r--r--thirdparty/bullet/BulletCollision/CollisionShapes/btPolyhedralConvexShape.cpp79
-rw-r--r--thirdparty/bullet/BulletCollision/CollisionShapes/btPolyhedralConvexShape.h3
-rw-r--r--thirdparty/bullet/BulletCollision/CollisionShapes/btSdfCollisionShape.cpp99
-rw-r--r--thirdparty/bullet/BulletCollision/CollisionShapes/btSdfCollisionShape.h30
-rw-r--r--thirdparty/bullet/BulletCollision/CollisionShapes/btShapeHull.cpp277
-rw-r--r--thirdparty/bullet/BulletCollision/CollisionShapes/btShapeHull.h4
-rw-r--r--thirdparty/bullet/BulletCollision/CollisionShapes/btStaticPlaneShape.cpp2
-rw-r--r--thirdparty/bullet/BulletCollision/CollisionShapes/btTriangleIndexVertexArray.h2
-rw-r--r--thirdparty/bullet/BulletCollision/NarrowPhaseCollision/btContinuousConvexCollision.cpp25
-rw-r--r--thirdparty/bullet/BulletCollision/NarrowPhaseCollision/btContinuousConvexCollision.h2
-rw-r--r--thirdparty/bullet/BulletCollision/NarrowPhaseCollision/btGjkEpaPenetrationDepthSolver.cpp68
-rw-r--r--thirdparty/bullet/BulletCollision/NarrowPhaseCollision/btGjkPairDetector.cpp1130
-rw-r--r--thirdparty/bullet/BulletCollision/NarrowPhaseCollision/btPersistentManifold.cpp151
-rw-r--r--thirdparty/bullet/BulletCollision/NarrowPhaseCollision/btPersistentManifold.h116
-rw-r--r--thirdparty/bullet/BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.cpp9
-rw-r--r--thirdparty/bullet/BulletDynamics/ConstraintSolver/btBatchedConstraints.cpp1128
-rw-r--r--thirdparty/bullet/BulletDynamics/ConstraintSolver/btBatchedConstraints.h66
-rw-r--r--thirdparty/bullet/BulletDynamics/ConstraintSolver/btConstraintSolver.h3
-rw-r--r--thirdparty/bullet/BulletDynamics/ConstraintSolver/btContactSolverInfo.h3
-rw-r--r--thirdparty/bullet/BulletDynamics/ConstraintSolver/btGeneric6DofConstraint.cpp4
-rw-r--r--thirdparty/bullet/BulletDynamics/ConstraintSolver/btGeneric6DofConstraint.h2
-rw-r--r--thirdparty/bullet/BulletDynamics/ConstraintSolver/btGeneric6DofSpring2Constraint.cpp27
-rw-r--r--thirdparty/bullet/BulletDynamics/ConstraintSolver/btGeneric6DofSpring2Constraint.h2
-rw-r--r--thirdparty/bullet/BulletDynamics/ConstraintSolver/btGeneric6DofSpringConstraint.cpp4
-rw-r--r--thirdparty/bullet/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.cpp757
-rw-r--r--thirdparty/bullet/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.h52
-rw-r--r--thirdparty/bullet/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolverMt.cpp1621
-rw-r--r--thirdparty/bullet/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolverMt.h154
-rwxr-xr-x[-rw-r--r--]thirdparty/bullet/BulletDynamics/ConstraintSolver/btSliderConstraint.cpp0
-rwxr-xr-x[-rw-r--r--]thirdparty/bullet/BulletDynamics/ConstraintSolver/btSliderConstraint.h0
-rw-r--r--thirdparty/bullet/BulletDynamics/Dynamics/btDiscreteDynamicsWorld.cpp14
-rw-r--r--thirdparty/bullet/BulletDynamics/Dynamics/btDiscreteDynamicsWorldMt.cpp99
-rw-r--r--thirdparty/bullet/BulletDynamics/Dynamics/btDiscreteDynamicsWorldMt.h6
-rw-r--r--thirdparty/bullet/BulletDynamics/Dynamics/btSimulationIslandManagerMt.cpp143
-rw-r--r--thirdparty/bullet/BulletDynamics/Dynamics/btSimulationIslandManagerMt.h36
-rw-r--r--thirdparty/bullet/BulletDynamics/Featherstone/btMultiBody.cpp121
-rw-r--r--thirdparty/bullet/BulletDynamics/Featherstone/btMultiBody.h54
-rw-r--r--thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyConstraint.cpp10
-rw-r--r--thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyConstraint.h8
-rw-r--r--thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyConstraintSolver.cpp383
-rw-r--r--thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyConstraintSolver.h4
-rw-r--r--thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyDynamicsWorld.cpp70
-rw-r--r--thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyDynamicsWorld.h2
-rw-r--r--thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyFixedConstraint.cpp28
-rw-r--r--thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyGearConstraint.cpp33
-rw-r--r--thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyJointLimitConstraint.cpp34
-rw-r--r--thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyJointMotor.cpp32
-rw-r--r--thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyLink.h2
-rw-r--r--thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyLinkCollider.h52
-rw-r--r--thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyMLCPConstraintSolver.cpp966
-rw-r--r--thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyMLCPConstraintSolver.h187
-rw-r--r--thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyPoint2Point.cpp28
-rw-r--r--thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodySliderConstraint.cpp29
-rw-r--r--thirdparty/bullet/BulletDynamics/Vehicle/btRaycastVehicle.cpp30
-rw-r--r--thirdparty/bullet/BulletInverseDynamics/IDErrorMessages.hpp8
-rw-r--r--thirdparty/bullet/BulletInverseDynamics/IDMath.cpp42
-rw-r--r--thirdparty/bullet/BulletInverseDynamics/MultiBodyTree.cpp60
-rw-r--r--thirdparty/bullet/BulletInverseDynamics/details/IDLinearMathInterface.hpp12
-rw-r--r--thirdparty/bullet/BulletInverseDynamics/details/IDMatVec.hpp10
-rw-r--r--thirdparty/bullet/BulletInverseDynamics/details/MultiBodyTreeImpl.cpp30
-rw-r--r--thirdparty/bullet/BulletInverseDynamics/details/MultiBodyTreeInitCache.cpp12
-rw-r--r--thirdparty/bullet/BulletSoftBody/btSoftMultiBodyDynamicsWorld.cpp6
-rw-r--r--thirdparty/bullet/LinearMath/TaskScheduler/btTaskScheduler.cpp802
-rw-r--r--thirdparty/bullet/LinearMath/TaskScheduler/btThreadSupportInterface.h70
-rw-r--r--thirdparty/bullet/LinearMath/TaskScheduler/btThreadSupportPosix.cpp365
-rw-r--r--thirdparty/bullet/LinearMath/TaskScheduler/btThreadSupportWin32.cpp472
-rw-r--r--thirdparty/bullet/LinearMath/btAlignedAllocator.cpp4
-rw-r--r--thirdparty/bullet/LinearMath/btHashMap.h34
-rw-r--r--thirdparty/bullet/LinearMath/btIDebugDraw.h6
-rw-r--r--thirdparty/bullet/LinearMath/btMatrix3x3.h104
-rw-r--r--thirdparty/bullet/LinearMath/btQuaternion.h40
-rw-r--r--thirdparty/bullet/LinearMath/btQuickprof.cpp74
-rw-r--r--thirdparty/bullet/LinearMath/btQuickprof.h3
-rw-r--r--thirdparty/bullet/LinearMath/btScalar.h2
-rw-r--r--thirdparty/bullet/LinearMath/btSerializer.cpp1132
-rw-r--r--thirdparty/bullet/LinearMath/btSerializer.h8
-rw-r--r--thirdparty/bullet/LinearMath/btSerializer64.cpp1132
-rw-r--r--thirdparty/bullet/LinearMath/btThreads.cpp121
-rw-r--r--thirdparty/bullet/LinearMath/btThreads.h27
-rw-r--r--thirdparty/bullet/LinearMath/btVector3.h22
-rw-r--r--thirdparty/bullet/clew/clew.c2
-rw-r--r--thirdparty/cvtt/ConvectionKernels.cpp7586
-rw-r--r--thirdparty/cvtt/ConvectionKernels.h145
-rw-r--r--thirdparty/cvtt/ConvectionKernels_BC7_SingleColor.h1940
-rw-r--r--thirdparty/cvtt/LICENSE.txt45
-rw-r--r--thirdparty/enet/godot.cpp63
-rw-r--r--thirdparty/fonts/NotoSansDevanagariUI_Regular.ttfbin0 -> 199888 bytes
-rw-r--r--thirdparty/glad/glad.c1539
-rw-r--r--thirdparty/glad/glad/glad.h87
-rw-r--r--thirdparty/libogg/ogg/config_types.h2
-rw-r--r--thirdparty/libvpx/vpx_config.h7
-rw-r--r--thirdparty/libwebp/src/dec/alphai_dec.h2
-rw-r--r--thirdparty/libwebp/src/dec/buffer_dec.c3
-rw-r--r--thirdparty/libwebp/src/dec/common_dec.h2
-rw-r--r--thirdparty/libwebp/src/dec/frame_dec.c9
-rw-r--r--thirdparty/libwebp/src/dec/idec_dec.c25
-rw-r--r--thirdparty/libwebp/src/dec/vp8_dec.h2
-rw-r--r--thirdparty/libwebp/src/dec/vp8i_dec.h4
-rw-r--r--thirdparty/libwebp/src/dec/vp8l_dec.c103
-rw-r--r--thirdparty/libwebp/src/dec/vp8li_dec.h2
-rw-r--r--thirdparty/libwebp/src/dec/webpi_dec.h2
-rw-r--r--thirdparty/libwebp/src/demux/demux.c2
-rw-r--r--thirdparty/libwebp/src/dsp/dsp.h6
-rw-r--r--thirdparty/libwebp/src/dsp/enc.c6
-rw-r--r--thirdparty/libwebp/src/dsp/enc_avx2.c21
-rw-r--r--thirdparty/libwebp/src/dsp/lossless.c2
-rw-r--r--thirdparty/libwebp/src/dsp/lossless.h14
-rw-r--r--thirdparty/libwebp/src/dsp/lossless_enc.c86
-rw-r--r--thirdparty/libwebp/src/dsp/lossless_enc_mips32.c79
-rw-r--r--thirdparty/libwebp/src/dsp/lossless_enc_sse2.c44
-rw-r--r--thirdparty/libwebp/src/dsp/msa_macro.h2
-rw-r--r--thirdparty/libwebp/src/dsp/rescaler.c4
-rw-r--r--thirdparty/libwebp/src/dsp/rescaler_mips32.c4
-rw-r--r--thirdparty/libwebp/src/dsp/rescaler_mips_dsp_r2.c10
-rw-r--r--thirdparty/libwebp/src/dsp/rescaler_msa.c7
-rw-r--r--thirdparty/libwebp/src/dsp/rescaler_neon.c18
-rw-r--r--thirdparty/libwebp/src/dsp/rescaler_sse2.c35
-rw-r--r--thirdparty/libwebp/src/dsp/yuv.h2
-rw-r--r--thirdparty/libwebp/src/enc/analysis_enc.c2
-rw-r--r--thirdparty/libwebp/src/enc/backward_references_cost_enc.c2
-rw-r--r--thirdparty/libwebp/src/enc/backward_references_enc.c1
-rw-r--r--thirdparty/libwebp/src/enc/cost_enc.h2
-rw-r--r--thirdparty/libwebp/src/enc/delta_palettization_enc.c455
-rw-r--r--thirdparty/libwebp/src/enc/delta_palettization_enc.h25
-rw-r--r--thirdparty/libwebp/src/enc/histogram_enc.c196
-rw-r--r--thirdparty/libwebp/src/enc/histogram_enc.h10
-rw-r--r--thirdparty/libwebp/src/enc/iterator_enc.c2
-rw-r--r--thirdparty/libwebp/src/enc/picture_tools_enc.c41
-rw-r--r--thirdparty/libwebp/src/enc/vp8i_enc.h6
-rw-r--r--thirdparty/libwebp/src/enc/vp8l_enc.c17
-rw-r--r--thirdparty/libwebp/src/enc/vp8li_enc.h2
-rw-r--r--thirdparty/libwebp/src/mux/animi.h2
-rw-r--r--thirdparty/libwebp/src/mux/muxedit.c18
-rw-r--r--thirdparty/libwebp/src/mux/muxi.h18
-rw-r--r--thirdparty/libwebp/src/mux/muxinternal.c53
-rw-r--r--thirdparty/libwebp/src/mux/muxread.c61
-rw-r--r--thirdparty/libwebp/src/utils/bit_reader_inl_utils.h2
-rw-r--r--thirdparty/libwebp/src/utils/bit_reader_utils.h2
-rw-r--r--thirdparty/libwebp/src/utils/bit_writer_utils.h2
-rw-r--r--thirdparty/libwebp/src/utils/filters_utils.h2
-rw-r--r--thirdparty/libwebp/src/utils/quant_levels_dec_utils.c8
-rw-r--r--thirdparty/libwebp/src/utils/quant_levels_dec_utils.h2
-rw-r--r--thirdparty/libwebp/src/utils/quant_levels_utils.h2
-rw-r--r--thirdparty/libwebp/src/utils/random_utils.h2
-rw-r--r--thirdparty/libwebp/src/utils/rescaler_utils.h2
-rw-r--r--thirdparty/libwebp/src/utils/thread_utils.h2
-rw-r--r--thirdparty/libwebp/src/utils/utils.h2
-rw-r--r--thirdparty/libwebp/src/webp/decode.h2
-rw-r--r--thirdparty/libwebp/src/webp/demux.h2
-rw-r--r--thirdparty/libwebp/src/webp/encode.h2
-rw-r--r--thirdparty/libwebp/src/webp/format_constants.h2
-rw-r--r--thirdparty/libwebp/src/webp/mux.h2
-rw-r--r--thirdparty/libwebp/src/webp/mux_types.h2
-rw-r--r--thirdparty/libwebp/src/webp/types.h2
-rw-r--r--thirdparty/libwebsockets/core/context.c25
-rw-r--r--thirdparty/libwebsockets/core/libwebsockets.c55
-rw-r--r--thirdparty/libwebsockets/core/output.c12
-rw-r--r--thirdparty/libwebsockets/core/private.h33
-rw-r--r--thirdparty/libwebsockets/libwebsockets.h44
-rw-r--r--thirdparty/libwebsockets/lws_config.h2
-rw-r--r--thirdparty/libwebsockets/lws_config_private.h2
-rw-r--r--thirdparty/libwebsockets/misc/lejp.c25
-rw-r--r--thirdparty/libwebsockets/plat/lws-plat-unix.c10
-rw-r--r--thirdparty/libwebsockets/plat/lws-plat-win.c54
-rw-r--r--thirdparty/libwebsockets/roles/h1/ops-h1.c14
-rw-r--r--thirdparty/libwebsockets/roles/http/client/client-handshake.c10
-rw-r--r--thirdparty/libwebsockets/roles/http/client/client.c38
-rw-r--r--thirdparty/libwebsockets/roles/http/header.c76
-rw-r--r--thirdparty/libwebsockets/roles/http/private.h1
-rw-r--r--thirdparty/libwebsockets/roles/http/server/lejp-conf.c64
-rw-r--r--thirdparty/libwebsockets/roles/http/server/parsers.c26
-rw-r--r--thirdparty/libwebsockets/roles/http/server/server.c50
-rw-r--r--thirdparty/libwebsockets/roles/ws/client-parser-ws.c11
-rw-r--r--thirdparty/libwebsockets/roles/ws/ops-ws.c26
-rw-r--r--thirdparty/libwebsockets/tls/mbedtls/mbedtls-server.c2
-rw-r--r--thirdparty/libwebsockets/tls/mbedtls/ssl.c2
-rw-r--r--thirdparty/libwebsockets/tls/mbedtls/wrapper/include/internal/ssl_types.h4
-rw-r--r--thirdparty/libwebsockets/uwp_fixes.diff47
-rw-r--r--thirdparty/libwebsockets/win32helpers/getopt.c306
-rw-r--r--thirdparty/libwebsockets/win32helpers/getopt_long.c480
-rw-r--r--thirdparty/libwebsockets/win32helpers/gettimeofday.c70
-rw-r--r--thirdparty/miniupnpc/minissdpc.c121
-rw-r--r--thirdparty/miniupnpc/miniupnpcstrings.h2
-rw-r--r--thirdparty/misc/aes256.h2
-rw-r--r--thirdparty/misc/easing_equations.cpp308
-rw-r--r--thirdparty/misc/hq2x.cpp2
-rw-r--r--thirdparty/misc/hq2x.h2
-rw-r--r--thirdparty/misc/md5.h2
-rw-r--r--thirdparty/misc/open-simplex-noise-LICENSE25
-rw-r--r--thirdparty/misc/open-simplex-noise-no-allocate.patch133
-rw-r--r--thirdparty/misc/open-simplex-noise.c2254
-rw-r--r--thirdparty/misc/open-simplex-noise.h58
-rw-r--r--thirdparty/misc/pcg.h2
-rw-r--r--thirdparty/misc/stb_vorbis.h2
-rw-r--r--thirdparty/misc/triangulator.h8
-rw-r--r--thirdparty/misc/yuv2rgb.h2
-rw-r--r--thirdparty/pvrtccompressor/BitScale.h2
-rw-r--r--thirdparty/squish/Add-Decompress-Bc5-to-Squish.patch143
-rw-r--r--thirdparty/squish/colourblock.cpp89
-rw-r--r--thirdparty/squish/config.h20
-rw-r--r--thirdparty/squish/godot-changes.patch102
-rw-r--r--thirdparty/thekla_atlas/nvcore/nvcore.h5
-rw-r--r--thirdparty/thekla_atlas/nvmath/nvmath.h8
-rw-r--r--thirdparty/thekla_atlas/poshlib/posh.h5
-rw-r--r--thirdparty/tinyexr/tinyexr.h1481
-rw-r--r--thirdparty/xatlas/xatlas.cpp7384
-rw-r--r--thirdparty/xatlas/xatlas.h160
-rw-r--r--thirdparty/zstd/1314.diff13
-rw-r--r--thirdparty/zstd/SCsub29
-rw-r--r--thirdparty/zstd/common/cpu.h2
248 files changed, 35231 insertions, 5612 deletions
diff --git a/thirdparty/README.md b/thirdparty/README.md
index 11745bc532..e63e1fc109 100644
--- a/thirdparty/README.md
+++ b/thirdparty/README.md
@@ -19,7 +19,7 @@ comments.
## bullet
- Upstream: https://github.com/bulletphysics/bullet3
-- Version: git (d05ad4b, 2017)
+- Version: git (12409f1118a7c7a266f9071350c70789dfe73bb9, Commits on Sep 6, 2018 )
- License: zlib
Files extracted from upstream source:
@@ -40,6 +40,17 @@ File extracted from a recent Fedora install:
as it's generated on the user's system.)
+## cvtt
+
+- Upstream: https://github.com/elasota/cvtt
+- Version: 1.0.0-beta4
+- License: MIT
+
+Files extracted from upstream source:
+
+- all .cpp, .h, and .txt files in ConvectionKernels/
+
+
## enet
- Upstream: http://enet.bespin.org
@@ -117,7 +128,7 @@ Files extracted from upstream source:
## glad
- Upstream: https://github.com/Dav1dde/glad
-- Version: 0.1.25
+- Version: 0.1.28
- License: MIT
The files we package are automatically generated.
@@ -222,7 +233,7 @@ Godot-made change marked with `// -- GODOT --` comments.
## libwebp
- Upstream: https://chromium.googlesource.com/webm/libwebp/
-- Version: 1.0.0
+- Version: 1.0.1
- License: BSD-3-Clause
Files extracted from upstream source:
@@ -253,8 +264,8 @@ File extracted from upstream source:
- From `roles/ws` exclude `ext` folder.
- From `tls` exclude `openssl` folder.
- Also copy `win32helpers/` from `win32port/` inside `thirdparty/libwebsockets`
-- A small fix has been added in `libwebsockets/libwebsockets.h` to `#include <sys/socket.h>` for the BSD family.
- This change has been PRed upstream, and should be merged before the next update. Remember to check and remove this line.
+- A fix has been added to allow building for 32-bits UWP, replacing `GetFileSize[Ex]` and `CreateFileW` with supported functions.
+ There is a diff for this change in `thirdparty/libwebsockets/uwp_fixes.diff`
Important: `lws_config.h` and `lws_config_private.h` contains custom
Godot build configurations, check them out when updating.
@@ -343,6 +354,11 @@ Collection of single-file libraries used in Godot components.
* Upstream: https://github.com/ivanfratric/polypartition (`src/polypartition.cpp`)
* Version: TBD, class was renamed
* License: MIT
+- `open-simplex-noise.{c,h}`
+ * Upstream: https://github.com/smcameron/open-simplex-noise-in-c
+ * Version: git (0d555e7, 2015)
+ * License: Unlicense
+
### modules
@@ -357,6 +373,10 @@ Collection of single-file libraries used in Godot components.
### scene
+- `easing_equations.cpp`
+ * Upstream: http://robertpenner.com/easing/ via https://github.com/jesusgollonet/ofpennereasing (modified to fit Godot types)
+ * Version: git (af72c14, 2008) + Godot types and style changes
+ * License: BSD-3-Clause
- `mikktspace.{c,h}`
* Upstream: https://wiki.blender.org/index.php/Dev:Shading/Tangent_Space_Normal_Maps
* Version: 1.0
@@ -483,7 +503,7 @@ changes are marked with `// -- GODOT --` comments.
## tinyexr
- Upstream: https://github.com/syoyo/tinyexr
-- Version: git (e385dad, 2018)
+- Version: git (5ae30aa, 2018)
- License: BSD-3-Clause
Files extracted from upstream source:
@@ -512,3 +532,5 @@ Files extracted from upstream source:
- lib/{common/,compress/,decompress/,zstd.h}
- LICENSE
+
+- Applied the patch in `thirdparty/zstd/1314.diff` (PR 1314 upstream, already merged). Needed to build on UWP ARM. Can be removed when a new version is released with the patch.
diff --git a/thirdparty/b2d_convexdecomp/b2Glue.h b/thirdparty/b2d_convexdecomp/b2Glue.h
index 425486356e..175f75be75 100644
--- a/thirdparty/b2d_convexdecomp/b2Glue.h
+++ b/thirdparty/b2d_convexdecomp/b2Glue.h
@@ -19,7 +19,8 @@
#ifndef B2GLUE_H
#define B2GLUE_H
-#include "math_2d.h"
+#include "core/math/vector2.h"
+
#include <limits.h>
namespace b2ConvexDecomp {
diff --git a/thirdparty/bullet/Bullet3Common/b3AlignedObjectArray.h b/thirdparty/bullet/Bullet3Common/b3AlignedObjectArray.h
index 947362d08e..ef71016565 100644
--- a/thirdparty/bullet/Bullet3Common/b3AlignedObjectArray.h
+++ b/thirdparty/bullet/Bullet3Common/b3AlignedObjectArray.h
@@ -528,6 +528,14 @@ protected:
otherArray.copy(0, otherSize, m_data);
}
+ void removeAtIndex(int index)
+ {
+ if (index<size())
+ {
+ swap( index,size()-1);
+ pop_back();
+ }
+ }
};
#endif //B3_OBJECT_ARRAY__
diff --git a/thirdparty/bullet/Bullet3Common/b3FileUtils.h b/thirdparty/bullet/Bullet3Common/b3FileUtils.h
index 1a331029ea..b5e8225cf0 100644
--- a/thirdparty/bullet/Bullet3Common/b3FileUtils.h
+++ b/thirdparty/bullet/Bullet3Common/b3FileUtils.h
@@ -36,7 +36,7 @@ struct b3FileUtils
for (int i=0;!f && i<numPrefixes;i++)
{
-#ifdef _WIN32
+#ifdef _MSC_VER
sprintf_s(relativeFileName,maxRelativeFileNameMaxLen,"%s%s",prefix[i],orgFileName);
#else
sprintf(relativeFileName,"%s%s",prefix[i],orgFileName);
diff --git a/thirdparty/bullet/Bullet3Dynamics/ConstraintSolver/b3Generic6DofConstraint.cpp b/thirdparty/bullet/Bullet3Dynamics/ConstraintSolver/b3Generic6DofConstraint.cpp
index 168a773d56..3ae2922e58 100644
--- a/thirdparty/bullet/Bullet3Dynamics/ConstraintSolver/b3Generic6DofConstraint.cpp
+++ b/thirdparty/bullet/Bullet3Dynamics/ConstraintSolver/b3Generic6DofConstraint.cpp
@@ -599,8 +599,8 @@ int b3Generic6DofConstraint::get_limit_motor_info2(
tag_vel,
info->fps * limot->m_stopERP);
info->m_constraintError[srow] += mot_fact * limot->m_targetVelocity;
- info->m_lowerLimit[srow] = -limot->m_maxMotorForce;
- info->m_upperLimit[srow] = limot->m_maxMotorForce;
+ info->m_lowerLimit[srow] = -limot->m_maxMotorForce / info->fps;
+ info->m_upperLimit[srow] = limot->m_maxMotorForce / info->fps;
}
}
if(limit)
diff --git a/thirdparty/bullet/Bullet3Dynamics/ConstraintSolver/b3Generic6DofConstraint.h b/thirdparty/bullet/Bullet3Dynamics/ConstraintSolver/b3Generic6DofConstraint.h
index 084d36055c..169b1b94ad 100644
--- a/thirdparty/bullet/Bullet3Dynamics/ConstraintSolver/b3Generic6DofConstraint.h
+++ b/thirdparty/bullet/Bullet3Dynamics/ConstraintSolver/b3Generic6DofConstraint.h
@@ -69,7 +69,7 @@ public:
{
m_accumulatedImpulse = 0.f;
m_targetVelocity = 0;
- m_maxMotorForce = 0.1f;
+ m_maxMotorForce = 6.0f;
m_maxLimitForce = 300.0f;
m_loLimit = 1.0f;
m_hiLimit = -1.0f;
diff --git a/thirdparty/bullet/Bullet3OpenCL/Initialize/b3OpenCLUtils.cpp b/thirdparty/bullet/Bullet3OpenCL/Initialize/b3OpenCLUtils.cpp
index dd194fc7ba..896191c89c 100644
--- a/thirdparty/bullet/Bullet3OpenCL/Initialize/b3OpenCLUtils.cpp
+++ b/thirdparty/bullet/Bullet3OpenCL/Initialize/b3OpenCLUtils.cpp
@@ -619,7 +619,7 @@ cl_program b3OpenCLUtils_compileCLProgramFromString(cl_context clContext, cl_dev
strippedName = strip2(clFileNameForCaching,"\\");
strippedName = strip2(strippedName,"/");
-#ifdef _MSVC_VER
+#ifdef _MSC_VER
sprintf_s(binaryFileName,B3_MAX_STRING_LENGTH,"%s/%s.%s.%s.bin",sCachedBinaryPath,strippedName, deviceName,driverVersion );
#else
sprintf(binaryFileName,"%s/%s.%s.%s.bin",sCachedBinaryPath,strippedName, deviceName,driverVersion );
diff --git a/thirdparty/bullet/BulletCollision/BroadphaseCollision/btAxisSweep3Internal.h b/thirdparty/bullet/BulletCollision/BroadphaseCollision/btAxisSweep3Internal.h
index 2c4d41bc04..323aa96dca 100644
--- a/thirdparty/bullet/BulletCollision/BroadphaseCollision/btAxisSweep3Internal.h
+++ b/thirdparty/bullet/BulletCollision/BroadphaseCollision/btAxisSweep3Internal.h
@@ -628,7 +628,6 @@ void btAxisSweep3Internal<BP_FP_INT_TYPE>::resetPool(btDispatcher* /*dispatcher*
}
-extern int gOverlappingPairs;
//#include <stdio.h>
template <typename BP_FP_INT_TYPE>
@@ -695,10 +694,9 @@ void btAxisSweep3Internal<BP_FP_INT_TYPE>::calculateOverlappingPairs(btDispatche
pair.m_pProxy0 = 0;
pair.m_pProxy1 = 0;
m_invalidPair++;
- gOverlappingPairs--;
- }
-
- }
+ }
+
+ }
///if you don't like to skip the invalid pairs in the array, execute following code:
#define CLEAN_INVALID_PAIRS 1
diff --git a/thirdparty/bullet/BulletCollision/BroadphaseCollision/btBroadphaseProxy.h b/thirdparty/bullet/BulletCollision/BroadphaseCollision/btBroadphaseProxy.h
index adaf083a21..f6e1202a69 100644
--- a/thirdparty/bullet/BulletCollision/BroadphaseCollision/btBroadphaseProxy.h
+++ b/thirdparty/bullet/BulletCollision/BroadphaseCollision/btBroadphaseProxy.h
@@ -66,6 +66,7 @@ CONCAVE_SHAPES_START_HERE,
EMPTY_SHAPE_PROXYTYPE,
STATIC_PLANE_PROXYTYPE,
CUSTOM_CONCAVE_SHAPE_TYPE,
+ SDF_SHAPE_PROXYTYPE=CUSTOM_CONCAVE_SHAPE_TYPE,
CONCAVE_SHAPES_END_HERE,
COMPOUND_SHAPE_PROXYTYPE,
diff --git a/thirdparty/bullet/BulletCollision/BroadphaseCollision/btDbvtBroadphase.cpp b/thirdparty/bullet/BulletCollision/BroadphaseCollision/btDbvtBroadphase.cpp
index 4d12b1c9c7..14cd1a31ea 100644
--- a/thirdparty/bullet/BulletCollision/BroadphaseCollision/btDbvtBroadphase.cpp
+++ b/thirdparty/bullet/BulletCollision/BroadphaseCollision/btDbvtBroadphase.cpp
@@ -17,7 +17,7 @@ subject to the following restrictions:
#include "btDbvtBroadphase.h"
#include "LinearMath/btThreads.h"
-
+btScalar gDbvtMargin = btScalar(0.05);
//
// Profiling
//
@@ -332,12 +332,9 @@ void btDbvtBroadphase::setAabb( btBroadphaseProxy* absproxy,
if(delta[0]<0) velocity[0]=-velocity[0];
if(delta[1]<0) velocity[1]=-velocity[1];
if(delta[2]<0) velocity[2]=-velocity[2];
- if (
-#ifdef DBVT_BP_MARGIN
- m_sets[0].update(proxy->leaf,aabb,velocity,DBVT_BP_MARGIN)
-#else
- m_sets[0].update(proxy->leaf,aabb,velocity)
-#endif
+ if (
+ m_sets[0].update(proxy->leaf, aabb, velocity, gDbvtMargin)
+
)
{
++m_updates_done;
diff --git a/thirdparty/bullet/BulletCollision/BroadphaseCollision/btDbvtBroadphase.h b/thirdparty/bullet/BulletCollision/BroadphaseCollision/btDbvtBroadphase.h
index 8feb95d51f..90b333d846 100644
--- a/thirdparty/bullet/BulletCollision/BroadphaseCollision/btDbvtBroadphase.h
+++ b/thirdparty/bullet/BulletCollision/BroadphaseCollision/btDbvtBroadphase.h
@@ -29,7 +29,8 @@ subject to the following restrictions:
#define DBVT_BP_PREVENTFALSEUPDATE 0
#define DBVT_BP_ACCURATESLEEPING 0
#define DBVT_BP_ENABLE_BENCHMARK 0
-#define DBVT_BP_MARGIN (btScalar)0.05
+//#define DBVT_BP_MARGIN (btScalar)0.05
+extern btScalar gDbvtMargin;
#if DBVT_BP_PROFILE
#define DBVT_BP_PROFILING_RATE 256
diff --git a/thirdparty/bullet/BulletCollision/BroadphaseCollision/btDispatcher.h b/thirdparty/bullet/BulletCollision/BroadphaseCollision/btDispatcher.h
index 7b0f9489af..a0e4c18927 100644
--- a/thirdparty/bullet/BulletCollision/BroadphaseCollision/btDispatcher.h
+++ b/thirdparty/bullet/BulletCollision/BroadphaseCollision/btDispatcher.h
@@ -46,7 +46,8 @@ struct btDispatcherInfo
m_useEpa(true),
m_allowedCcdPenetration(btScalar(0.04)),
m_useConvexConservativeDistanceUtil(false),
- m_convexConservativeDistanceThreshold(0.0f)
+ m_convexConservativeDistanceThreshold(0.0f),
+ m_deterministicOverlappingPairs(false)
{
}
@@ -62,6 +63,7 @@ struct btDispatcherInfo
btScalar m_allowedCcdPenetration;
bool m_useConvexConservativeDistanceUtil;
btScalar m_convexConservativeDistanceThreshold;
+ bool m_deterministicOverlappingPairs;
};
enum ebtDispatcherQueryType
diff --git a/thirdparty/bullet/BulletCollision/BroadphaseCollision/btOverlappingPairCache.cpp b/thirdparty/bullet/BulletCollision/BroadphaseCollision/btOverlappingPairCache.cpp
index 55ebf06f1e..9e3337c5f6 100644
--- a/thirdparty/bullet/BulletCollision/BroadphaseCollision/btOverlappingPairCache.cpp
+++ b/thirdparty/bullet/BulletCollision/BroadphaseCollision/btOverlappingPairCache.cpp
@@ -23,11 +23,6 @@ subject to the following restrictions:
#include <stdio.h>
-int gOverlappingPairs = 0;
-
-int gRemovePairs =0;
-int gAddedPairs =0;
-int gFindPairs =0;
@@ -134,13 +129,12 @@ void btHashedOverlappingPairCache::removeOverlappingPairsContainingProxy(btBroad
btBroadphasePair* btHashedOverlappingPairCache::findPair(btBroadphaseProxy* proxy0, btBroadphaseProxy* proxy1)
{
- gFindPairs++;
- if(proxy0->m_uniqueId>proxy1->m_uniqueId)
+ if(proxy0->m_uniqueId>proxy1->m_uniqueId)
btSwap(proxy0,proxy1);
int proxyId1 = proxy0->getUid();
int proxyId2 = proxy1->getUid();
- /*if (proxyId1 > proxyId2)
+ /*if (proxyId1 > proxyId2)
btSwap(proxyId1, proxyId2);*/
int hash = static_cast<int>(getHash(static_cast<unsigned int>(proxyId1), static_cast<unsigned int>(proxyId2)) & (m_overlappingPairArray.capacity()-1));
@@ -271,13 +265,12 @@ btBroadphasePair* btHashedOverlappingPairCache::internalAddPair(btBroadphaseProx
void* btHashedOverlappingPairCache::removeOverlappingPair(btBroadphaseProxy* proxy0, btBroadphaseProxy* proxy1,btDispatcher* dispatcher)
{
- gRemovePairs++;
- if(proxy0->m_uniqueId>proxy1->m_uniqueId)
+ if(proxy0->m_uniqueId>proxy1->m_uniqueId)
btSwap(proxy0,proxy1);
int proxyId1 = proxy0->getUid();
int proxyId2 = proxy1->getUid();
- /*if (proxyId1 > proxyId2)
+ /*if (proxyId1 > proxyId2)
btSwap(proxyId1, proxyId2);*/
int hash = static_cast<int>(getHash(static_cast<unsigned int>(proxyId1),static_cast<unsigned int>(proxyId2)) & (m_overlappingPairArray.capacity()-1));
@@ -386,8 +379,6 @@ void btHashedOverlappingPairCache::processAllOverlappingPairs(btOverlapCallback*
if (callback->processOverlap(*pair))
{
removeOverlappingPair(pair->m_pProxy0,pair->m_pProxy1,dispatcher);
-
- gOverlappingPairs--;
} else
{
i++;
@@ -395,6 +386,70 @@ void btHashedOverlappingPairCache::processAllOverlappingPairs(btOverlapCallback*
}
}
+struct MyPairIndex
+{
+ int m_orgIndex;
+ int m_uidA0;
+ int m_uidA1;
+};
+
+class MyPairIndeSortPredicate
+{
+public:
+
+ bool operator() ( const MyPairIndex& a, const MyPairIndex& b ) const
+ {
+ const int uidA0 = a.m_uidA0;
+ const int uidB0 = b.m_uidA0;
+ const int uidA1 = a.m_uidA1;
+ const int uidB1 = b.m_uidA1;
+ return uidA0 > uidB0 || (uidA0 == uidB0 && uidA1 > uidB1);
+ }
+};
+
+void btHashedOverlappingPairCache::processAllOverlappingPairs(btOverlapCallback* callback,btDispatcher* dispatcher, const struct btDispatcherInfo& dispatchInfo)
+{
+ if (dispatchInfo.m_deterministicOverlappingPairs)
+ {
+ btBroadphasePairArray& pa = getOverlappingPairArray();
+ btAlignedObjectArray<MyPairIndex> indices;
+ {
+ BT_PROFILE("sortOverlappingPairs");
+ indices.resize(pa.size());
+ for (int i=0;i<indices.size();i++)
+ {
+ const btBroadphasePair& p = pa[i];
+ const int uidA0 = p.m_pProxy0 ? p.m_pProxy0->m_uniqueId : -1;
+ const int uidA1 = p.m_pProxy1 ? p.m_pProxy1->m_uniqueId : -1;
+
+ indices[i].m_uidA0 = uidA0;
+ indices[i].m_uidA1 = uidA1;
+ indices[i].m_orgIndex = i;
+ }
+ indices.quickSort(MyPairIndeSortPredicate());
+ }
+ {
+ BT_PROFILE("btHashedOverlappingPairCache::processAllOverlappingPairs");
+ int i;
+ for (i=0;i<indices.size();)
+ {
+ btBroadphasePair* pair = &pa[indices[i].m_orgIndex];
+ if (callback->processOverlap(*pair))
+ {
+ removeOverlappingPair(pair->m_pProxy0,pair->m_pProxy1,dispatcher);
+ } else
+ {
+ i++;
+ }
+ }
+ }
+ } else
+ {
+ processAllOverlappingPairs(callback, dispatcher);
+ }
+}
+
+
void btHashedOverlappingPairCache::sortOverlappingPairs(btDispatcher* dispatcher)
{
///need to keep hashmap in sync with pair address, so rebuild all
@@ -435,7 +490,6 @@ void* btSortedOverlappingPairCache::removeOverlappingPair(btBroadphaseProxy* pro
int findIndex = m_overlappingPairArray.findLinearSearch(findPair);
if (findIndex < m_overlappingPairArray.size())
{
- gOverlappingPairs--;
btBroadphasePair& pair = m_overlappingPairArray[findIndex];
void* userData = pair.m_internalInfo1;
cleanOverlappingPair(pair,dispatcher);
@@ -468,11 +522,8 @@ btBroadphasePair* btSortedOverlappingPairCache::addOverlappingPair(btBroadphaseP
void* mem = &m_overlappingPairArray.expandNonInitializing();
btBroadphasePair* pair = new (mem) btBroadphasePair(*proxy0,*proxy1);
-
- gOverlappingPairs++;
- gAddedPairs++;
-
- if (m_ghostPairCallback)
+
+ if (m_ghostPairCallback)
m_ghostPairCallback->addOverlappingPair(proxy0, proxy1);
return pair;
@@ -526,7 +577,6 @@ void btSortedOverlappingPairCache::processAllOverlappingPairs(btOverlapCallback*
pair->m_pProxy1 = 0;
m_overlappingPairArray.swap(i,m_overlappingPairArray.size()-1);
m_overlappingPairArray.pop_back();
- gOverlappingPairs--;
} else
{
i++;
@@ -559,7 +609,6 @@ void btSortedOverlappingPairCache::cleanOverlappingPair(btBroadphasePair& pair,b
pair.m_algorithm->~btCollisionAlgorithm();
dispatcher->freeCollisionAlgorithm(pair.m_algorithm);
pair.m_algorithm=0;
- gRemovePairs--;
}
}
}
diff --git a/thirdparty/bullet/BulletCollision/BroadphaseCollision/btOverlappingPairCache.h b/thirdparty/bullet/BulletCollision/BroadphaseCollision/btOverlappingPairCache.h
index f7be7d45b3..7a38d34f05 100644
--- a/thirdparty/bullet/BulletCollision/BroadphaseCollision/btOverlappingPairCache.h
+++ b/thirdparty/bullet/BulletCollision/BroadphaseCollision/btOverlappingPairCache.h
@@ -49,10 +49,6 @@ struct btOverlapFilterCallback
-extern int gRemovePairs;
-extern int gAddedPairs;
-extern int gFindPairs;
-
const int BT_NULL_PAIR=0xffffffff;
///The btOverlappingPairCache provides an interface for overlapping pair management (add, remove, storage), used by the btBroadphaseInterface broadphases.
@@ -78,6 +74,10 @@ public:
virtual void processAllOverlappingPairs(btOverlapCallback*,btDispatcher* dispatcher) = 0;
+ virtual void processAllOverlappingPairs(btOverlapCallback* callback,btDispatcher* dispatcher, const struct btDispatcherInfo& dispatchInfo)
+ {
+ processAllOverlappingPairs(callback, dispatcher);
+ }
virtual btBroadphasePair* findPair(btBroadphaseProxy* proxy0, btBroadphaseProxy* proxy1) = 0;
virtual bool hasDeferredRemoval() = 0;
@@ -129,8 +129,6 @@ public:
// no new pair is created and the old one is returned.
virtual btBroadphasePair* addOverlappingPair(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1)
{
- gAddedPairs++;
-
if (!needsBroadphaseCollision(proxy0,proxy1))
return 0;
@@ -144,6 +142,8 @@ public:
virtual void processAllOverlappingPairs(btOverlapCallback*,btDispatcher* dispatcher);
+ virtual void processAllOverlappingPairs(btOverlapCallback* callback,btDispatcher* dispatcher, const struct btDispatcherInfo& dispatchInfo);
+
virtual btBroadphasePair* getOverlappingPairArrayPtr()
{
return &m_overlappingPairArray[0];
diff --git a/thirdparty/bullet/BulletCollision/BroadphaseCollision/btSimpleBroadphase.cpp b/thirdparty/bullet/BulletCollision/BroadphaseCollision/btSimpleBroadphase.cpp
index f1d5f5476e..5f89f960e8 100644
--- a/thirdparty/bullet/BulletCollision/BroadphaseCollision/btSimpleBroadphase.cpp
+++ b/thirdparty/bullet/BulletCollision/BroadphaseCollision/btSimpleBroadphase.cpp
@@ -24,8 +24,6 @@ subject to the following restrictions:
#include <new>
-extern int gOverlappingPairs;
-
void btSimpleBroadphase::validate()
{
for (int i=0;i<m_numHandles;i++)
@@ -315,8 +313,7 @@ void btSimpleBroadphase::calculateOverlappingPairs(btDispatcher* dispatcher)
pair.m_pProxy0 = 0;
pair.m_pProxy1 = 0;
m_invalidPair++;
- gOverlappingPairs--;
- }
+ }
}
diff --git a/thirdparty/bullet/BulletCollision/CollisionDispatch/SphereTriangleDetector.cpp b/thirdparty/bullet/BulletCollision/CollisionDispatch/SphereTriangleDetector.cpp
index c81af95672..e5bac8438e 100644
--- a/thirdparty/bullet/BulletCollision/CollisionDispatch/SphereTriangleDetector.cpp
+++ b/thirdparty/bullet/BulletCollision/CollisionDispatch/SphereTriangleDetector.cpp
@@ -132,6 +132,7 @@ bool SphereTriangleDetector::collide(const btVector3& sphereCenter,btVector3 &po
else {
// Could be inside one of the contact capsules
btScalar contactCapsuleRadiusSqr = radiusWithThreshold*radiusWithThreshold;
+ btScalar minDistSqr = contactCapsuleRadiusSqr;
btVector3 nearestOnEdge;
for (int i = 0; i < m_triangle->getNumEdges(); i++) {
@@ -141,8 +142,9 @@ bool SphereTriangleDetector::collide(const btVector3& sphereCenter,btVector3 &po
m_triangle->getEdge(i, pa, pb);
btScalar distanceSqr = SegmentSqrDistance(pa, pb, sphereCenter, nearestOnEdge);
- if (distanceSqr < contactCapsuleRadiusSqr) {
- // Yep, we're inside a capsule
+ if (distanceSqr < minDistSqr) {
+ // Yep, we're inside a capsule, and record the capsule with smallest distance
+ minDistSqr = distanceSqr;
hasContact = true;
contactPoint = nearestOnEdge;
}
diff --git a/thirdparty/bullet/BulletCollision/CollisionDispatch/btBox2dBox2dCollisionAlgorithm.cpp b/thirdparty/bullet/BulletCollision/CollisionDispatch/btBox2dBox2dCollisionAlgorithm.cpp
index 2c36277821..cabbb0bf6a 100644
--- a/thirdparty/bullet/BulletCollision/CollisionDispatch/btBox2dBox2dCollisionAlgorithm.cpp
+++ b/thirdparty/bullet/BulletCollision/CollisionDispatch/btBox2dBox2dCollisionAlgorithm.cpp
@@ -151,8 +151,8 @@ static btScalar EdgeSeparation(const btBox2dShape* poly1, const btTransform& xf1
int index = 0;
btScalar minDot = BT_LARGE_FLOAT;
- if( count2 > 0 )
- index = (int) normal1.minDot( vertices2, count2, minDot);
+ if( count2 > 0 )
+ index = (int) normal1.minDot( vertices2, count2, minDot);
btVector3 v1 = b2Mul(xf1, vertices1[edge1]);
btVector3 v2 = b2Mul(xf2, vertices2[index]);
@@ -175,8 +175,8 @@ static btScalar FindMaxSeparation(int* edgeIndex,
// Find edge normal on poly1 that has the largest projection onto d.
int edge = 0;
btScalar maxDot;
- if( count1 > 0 )
- edge = (int) dLocal1.maxDot( normals1, count1, maxDot);
+ if( count1 > 0 )
+ edge = (int) dLocal1.maxDot( normals1, count1, maxDot);
// Get the separation for the edge normal.
btScalar s = EdgeSeparation(poly1, xf1, edge, poly2, xf2);
diff --git a/thirdparty/bullet/BulletCollision/CollisionDispatch/btCollisionDispatcher.cpp b/thirdparty/bullet/BulletCollision/CollisionDispatch/btCollisionDispatcher.cpp
index 5739a1ef01..f8794dec47 100644
--- a/thirdparty/bullet/BulletCollision/CollisionDispatch/btCollisionDispatcher.cpp
+++ b/thirdparty/bullet/BulletCollision/CollisionDispatch/btCollisionDispatcher.cpp
@@ -27,8 +27,6 @@ subject to the following restrictions:
#include "BulletCollision/CollisionDispatch/btCollisionConfiguration.h"
#include "BulletCollision/CollisionDispatch/btCollisionObjectWrapper.h"
-int gNumManifold = 0;
-
#ifdef BT_DEBUG
#include <stdio.h>
#endif
@@ -77,8 +75,6 @@ btCollisionDispatcher::~btCollisionDispatcher()
btPersistentManifold* btCollisionDispatcher::getNewManifold(const btCollisionObject* body0,const btCollisionObject* body1)
{
- gNumManifold++;
-
//btAssert(gNumManifold < 65535);
@@ -121,7 +117,6 @@ void btCollisionDispatcher::clearManifold(btPersistentManifold* manifold)
void btCollisionDispatcher::releaseManifold(btPersistentManifold* manifold)
{
- gNumManifold--;
//printf("releaseManifold: gNumManifold %d\n",gNumManifold);
clearManifold(manifold);
@@ -246,13 +241,17 @@ public:
+
void btCollisionDispatcher::dispatchAllCollisionPairs(btOverlappingPairCache* pairCache,const btDispatcherInfo& dispatchInfo,btDispatcher* dispatcher)
{
//m_blockedForChanges = true;
btCollisionPairCallback collisionCallback(dispatchInfo,this);
- pairCache->processAllOverlappingPairs(&collisionCallback,dispatcher);
+ {
+ BT_PROFILE("processAllOverlappingPairs");
+ pairCache->processAllOverlappingPairs(&collisionCallback,dispatcher, dispatchInfo);
+ }
//m_blockedForChanges = false;
diff --git a/thirdparty/bullet/BulletCollision/CollisionDispatch/btCollisionObject.cpp b/thirdparty/bullet/BulletCollision/CollisionDispatch/btCollisionObject.cpp
index b595c56bc5..05f96a14bc 100644
--- a/thirdparty/bullet/BulletCollision/CollisionDispatch/btCollisionObject.cpp
+++ b/thirdparty/bullet/BulletCollision/CollisionDispatch/btCollisionObject.cpp
@@ -16,6 +16,7 @@ subject to the following restrictions:
#include "btCollisionObject.h"
#include "LinearMath/btSerializer.h"
+#include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h"
btCollisionObject::btCollisionObject()
: m_interpolationLinearVelocity(0.f, 0.f, 0.f),
@@ -38,7 +39,7 @@ btCollisionObject::btCollisionObject()
m_rollingFriction(0.0f),
m_spinningFriction(0.f),
m_contactDamping(.1),
- m_contactStiffness(1e4),
+ m_contactStiffness(BT_LARGE_FLOAT),
m_internalType(CO_COLLISION_OBJECT),
m_userObjectPointer(0),
m_userIndex2(-1),
@@ -114,10 +115,18 @@ const char* btCollisionObject::serialize(void* dataBuffer, btSerializer* seriali
dataOut->m_ccdSweptSphereRadius = m_ccdSweptSphereRadius;
dataOut->m_ccdMotionThreshold = m_ccdMotionThreshold;
dataOut->m_checkCollideWith = m_checkCollideWith;
-
- // Fill padding with zeros to appease msan.
- memset(dataOut->m_padding, 0, sizeof(dataOut->m_padding));
-
+ if (m_broadphaseHandle)
+ {
+ dataOut->m_collisionFilterGroup = m_broadphaseHandle->m_collisionFilterGroup;
+ dataOut->m_collisionFilterMask = m_broadphaseHandle->m_collisionFilterMask;
+ dataOut->m_uniqueId = m_broadphaseHandle->m_uniqueId;
+ }
+ else
+ {
+ dataOut->m_collisionFilterGroup = 0;
+ dataOut->m_collisionFilterMask = 0;
+ dataOut->m_uniqueId = -1;
+ }
return btCollisionObjectDataName;
}
diff --git a/thirdparty/bullet/BulletCollision/CollisionDispatch/btCollisionObject.h b/thirdparty/bullet/BulletCollision/CollisionDispatch/btCollisionObject.h
index fec831bffc..135f8a033c 100644
--- a/thirdparty/bullet/BulletCollision/CollisionDispatch/btCollisionObject.h
+++ b/thirdparty/bullet/BulletCollision/CollisionDispatch/btCollisionObject.h
@@ -621,7 +621,6 @@ struct btCollisionObjectDoubleData
double m_hitFraction;
double m_ccdSweptSphereRadius;
double m_ccdMotionThreshold;
-
int m_hasAnisotropicFriction;
int m_collisionFlags;
int m_islandTag1;
@@ -629,8 +628,9 @@ struct btCollisionObjectDoubleData
int m_activationState1;
int m_internalType;
int m_checkCollideWith;
-
- char m_padding[4];
+ int m_collisionFilterGroup;
+ int m_collisionFilterMask;
+ int m_uniqueId;//m_uniqueId is introduced for paircache. could get rid of this, by calculating the address offset etc.
};
///do not change those serialization structures, it requires an updated sBulletDNAstr/sBulletDNAstr64
@@ -650,13 +650,12 @@ struct btCollisionObjectFloatData
float m_deactivationTime;
float m_friction;
float m_rollingFriction;
- float m_contactDamping;
+ float m_contactDamping;
float m_contactStiffness;
float m_restitution;
float m_hitFraction;
float m_ccdSweptSphereRadius;
float m_ccdMotionThreshold;
-
int m_hasAnisotropicFriction;
int m_collisionFlags;
int m_islandTag1;
@@ -664,7 +663,9 @@ struct btCollisionObjectFloatData
int m_activationState1;
int m_internalType;
int m_checkCollideWith;
- char m_padding[4];
+ int m_collisionFilterGroup;
+ int m_collisionFilterMask;
+ int m_uniqueId;
};
diff --git a/thirdparty/bullet/BulletCollision/CollisionDispatch/btCollisionWorld.cpp b/thirdparty/bullet/BulletCollision/CollisionDispatch/btCollisionWorld.cpp
index c3e912fdca..3de8d6995e 100644
--- a/thirdparty/bullet/BulletCollision/CollisionDispatch/btCollisionWorld.cpp
+++ b/thirdparty/bullet/BulletCollision/CollisionDispatch/btCollisionWorld.cpp
@@ -1646,7 +1646,7 @@ void btCollisionWorld::serializeCollisionObjects(btSerializer* serializer)
for (i=0;i<m_collisionObjects.size();i++)
{
btCollisionObject* colObj = m_collisionObjects[i];
- if ((colObj->getInternalType() == btCollisionObject::CO_COLLISION_OBJECT) || (colObj->getInternalType() == btCollisionObject::CO_FEATHERSTONE_LINK))
+ if (colObj->getInternalType() == btCollisionObject::CO_COLLISION_OBJECT)
{
colObj->serializeSingleObject(serializer);
}
@@ -1654,12 +1654,36 @@ void btCollisionWorld::serializeCollisionObjects(btSerializer* serializer)
}
+
+void btCollisionWorld::serializeContactManifolds(btSerializer* serializer)
+{
+ if (serializer->getSerializationFlags() & BT_SERIALIZE_CONTACT_MANIFOLDS)
+ {
+ int numManifolds = getDispatcher()->getNumManifolds();
+ for (int i = 0; i < numManifolds; i++)
+ {
+ const btPersistentManifold* manifold = getDispatcher()->getInternalManifoldPointer()[i];
+ //don't serialize empty manifolds, they just take space
+ //(may have to do it anyway if it destroys determinism)
+ if (manifold->getNumContacts() == 0)
+ continue;
+
+ btChunk* chunk = serializer->allocate(manifold->calculateSerializeBufferSize(), 1);
+ const char* structType = manifold->serialize(manifold, chunk->m_oldPtr, serializer);
+ serializer->finalizeChunk(chunk, structType, BT_CONTACTMANIFOLD_CODE, (void*)manifold);
+ }
+ }
+}
+
+
void btCollisionWorld::serialize(btSerializer* serializer)
{
serializer->startSerialization();
serializeCollisionObjects(serializer);
+
+ serializeContactManifolds(serializer);
serializer->finishSerialization();
}
diff --git a/thirdparty/bullet/BulletCollision/CollisionDispatch/btCollisionWorld.h b/thirdparty/bullet/BulletCollision/CollisionDispatch/btCollisionWorld.h
index eede2b28ca..886476e8ad 100644
--- a/thirdparty/bullet/BulletCollision/CollisionDispatch/btCollisionWorld.h
+++ b/thirdparty/bullet/BulletCollision/CollisionDispatch/btCollisionWorld.h
@@ -107,6 +107,9 @@ protected:
void serializeCollisionObjects(btSerializer* serializer);
+ void serializeContactManifolds(btSerializer* serializer);
+
+
public:
//this constructor doesn't own the dispatcher and paircache/broadphase
diff --git a/thirdparty/bullet/BulletCollision/CollisionDispatch/btCompoundCollisionAlgorithm.cpp b/thirdparty/bullet/BulletCollision/CollisionDispatch/btCompoundCollisionAlgorithm.cpp
index 7f4dea1c6d..91b7809c17 100644
--- a/thirdparty/bullet/BulletCollision/CollisionDispatch/btCompoundCollisionAlgorithm.cpp
+++ b/thirdparty/bullet/BulletCollision/CollisionDispatch/btCompoundCollisionAlgorithm.cpp
@@ -156,10 +156,12 @@ public:
btCollisionObjectWrapper compoundWrap(this->m_compoundColObjWrap,childShape,m_compoundColObjWrap->getCollisionObject(),newChildWorldTrans,-1,index);
btCollisionAlgorithm* algo = 0;
+ bool allocatedAlgorithm = false;
if (m_resultOut->m_closestPointDistanceThreshold > 0)
{
algo = m_dispatcher->findAlgorithm(&compoundWrap, m_otherObjWrap, 0, BT_CLOSEST_POINT_ALGORITHMS);
+ allocatedAlgorithm = true;
}
else
{
@@ -204,7 +206,11 @@ public:
{
m_resultOut->setBody1Wrap(tmpWrap);
}
-
+ if(allocatedAlgorithm)
+ {
+ algo->~btCollisionAlgorithm();
+ m_dispatcher->freeCollisionAlgorithm(algo);
+ }
}
}
void Process(const btDbvtNode* leaf)
@@ -253,9 +259,9 @@ void btCompoundCollisionAlgorithm::processCollision (const btCollisionObjectWrap
m_compoundShapeRevision = compoundShape->getUpdateRevision();
}
- if (m_childCollisionAlgorithms.size()==0)
- return;
-
+ if (m_childCollisionAlgorithms.size()==0)
+ return;
+
const btDbvt* tree = compoundShape->getDynamicAabbTree();
//use a dynamic aabb tree to cull potential child-overlaps
btCompoundLeafCallback callback(colObjWrap,otherObjWrap,m_dispatcher,dispatchInfo,resultOut,&m_childCollisionAlgorithms[0],m_sharedManifold);
diff --git a/thirdparty/bullet/BulletCollision/CollisionDispatch/btCompoundCompoundCollisionAlgorithm.cpp b/thirdparty/bullet/BulletCollision/CollisionDispatch/btCompoundCompoundCollisionAlgorithm.cpp
index d4a1aa78e4..20b542f670 100644
--- a/thirdparty/bullet/BulletCollision/CollisionDispatch/btCompoundCompoundCollisionAlgorithm.cpp
+++ b/thirdparty/bullet/BulletCollision/CollisionDispatch/btCompoundCompoundCollisionAlgorithm.cpp
@@ -181,11 +181,12 @@ struct btCompoundCompoundLeafCallback : btDbvt::ICollide
btSimplePair* pair = m_childCollisionAlgorithmCache->findPair(childIndex0,childIndex1);
-
+ bool removePair = false;
btCollisionAlgorithm* colAlgo = 0;
if (m_resultOut->m_closestPointDistanceThreshold > 0)
{
colAlgo = m_dispatcher->findAlgorithm(&compoundWrap0, &compoundWrap1, 0, BT_CLOSEST_POINT_ALGORITHMS);
+ removePair = true;
}
else
{
@@ -223,7 +224,11 @@ struct btCompoundCompoundLeafCallback : btDbvt::ICollide
m_resultOut->setBody0Wrap(tmpWrap0);
m_resultOut->setBody1Wrap(tmpWrap1);
-
+ if (removePair)
+ {
+ colAlgo->~btCollisionAlgorithm();
+ m_dispatcher->freeCollisionAlgorithm(colAlgo);
+ }
}
}
@@ -396,32 +401,24 @@ void btCompoundCompoundCollisionAlgorithm::processCollision (const btCollisionOb
btCollisionAlgorithm* algo = (btCollisionAlgorithm*)pairs[i].m_userPointer;
{
- btTransform orgTrans0;
const btCollisionShape* childShape0 = 0;
btTransform newChildWorldTrans0;
- btTransform orgInterpolationTrans0;
childShape0 = compoundShape0->getChildShape(pairs[i].m_indexA);
- orgTrans0 = col0ObjWrap->getWorldTransform();
- orgInterpolationTrans0 = col0ObjWrap->getWorldTransform();
const btTransform& childTrans0 = compoundShape0->getChildTransform(pairs[i].m_indexA);
- newChildWorldTrans0 = orgTrans0*childTrans0 ;
+ newChildWorldTrans0 = col0ObjWrap->getWorldTransform()*childTrans0 ;
childShape0->getAabb(newChildWorldTrans0,aabbMin0,aabbMax0);
}
btVector3 thresholdVec(resultOut->m_closestPointDistanceThreshold, resultOut->m_closestPointDistanceThreshold, resultOut->m_closestPointDistanceThreshold);
aabbMin0 -= thresholdVec;
aabbMax0 += thresholdVec;
{
- btTransform orgInterpolationTrans1;
const btCollisionShape* childShape1 = 0;
- btTransform orgTrans1;
btTransform newChildWorldTrans1;
childShape1 = compoundShape1->getChildShape(pairs[i].m_indexB);
- orgTrans1 = col1ObjWrap->getWorldTransform();
- orgInterpolationTrans1 = col1ObjWrap->getWorldTransform();
const btTransform& childTrans1 = compoundShape1->getChildTransform(pairs[i].m_indexB);
- newChildWorldTrans1 = orgTrans1*childTrans1 ;
+ newChildWorldTrans1 = col1ObjWrap->getWorldTransform()*childTrans1 ;
childShape1->getAabb(newChildWorldTrans1,aabbMin1,aabbMax1);
}
diff --git a/thirdparty/bullet/BulletCollision/CollisionDispatch/btConvexConcaveCollisionAlgorithm.cpp b/thirdparty/bullet/BulletCollision/CollisionDispatch/btConvexConcaveCollisionAlgorithm.cpp
index 39ff7934d9..d8cbe96142 100644
--- a/thirdparty/bullet/BulletCollision/CollisionDispatch/btConvexConcaveCollisionAlgorithm.cpp
+++ b/thirdparty/bullet/BulletCollision/CollisionDispatch/btConvexConcaveCollisionAlgorithm.cpp
@@ -27,6 +27,7 @@ subject to the following restrictions:
#include "LinearMath/btIDebugDraw.h"
#include "BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.h"
#include "BulletCollision/CollisionDispatch/btCollisionObjectWrapper.h"
+#include "BulletCollision/CollisionShapes/btSdfCollisionShape.h"
btConvexConcaveCollisionAlgorithm::btConvexConcaveCollisionAlgorithm( const btCollisionAlgorithmConstructionInfo& ci, const btCollisionObjectWrapper* body0Wrap,const btCollisionObjectWrapper* body1Wrap,bool isSwapped)
: btActivatingCollisionAlgorithm(ci,body0Wrap,body1Wrap),
@@ -152,7 +153,7 @@ partId, int triangleIndex)
{
m_resultOut->setBody1Wrap(tmpWrap);
}
-
+
colAlgo->~btCollisionAlgorithm();
@@ -163,7 +164,7 @@ partId, int triangleIndex)
-void btConvexTriangleCallback::setTimeStepAndCounters(btScalar collisionMarginTriangle,const btDispatcherInfo& dispatchInfo,const btCollisionObjectWrapper* convexBodyWrap, const btCollisionObjectWrapper* triBodyWrap, btManifoldResult* resultOut)
+void btConvexTriangleCallback::setTimeStepAndCounters(btScalar collisionMarginTriangle, const btDispatcherInfo& dispatchInfo, const btCollisionObjectWrapper* convexBodyWrap, const btCollisionObjectWrapper* triBodyWrap, btManifoldResult* resultOut)
{
m_convexBodyWrap = convexBodyWrap;
m_triBodyWrap = triBodyWrap;
@@ -177,14 +178,14 @@ void btConvexTriangleCallback::setTimeStepAndCounters(btScalar collisionMarginTr
convexInTriangleSpace = m_triBodyWrap->getWorldTransform().inverse() * m_convexBodyWrap->getWorldTransform();
const btCollisionShape* convexShape = static_cast<const btCollisionShape*>(m_convexBodyWrap->getCollisionShape());
//CollisionShape* triangleShape = static_cast<btCollisionShape*>(triBody->m_collisionShape);
- convexShape->getAabb(convexInTriangleSpace,m_aabbMin,m_aabbMax);
- btScalar extraMargin = collisionMarginTriangle+ resultOut->m_closestPointDistanceThreshold;
-
- btVector3 extra(extraMargin,extraMargin,extraMargin);
+ convexShape->getAabb(convexInTriangleSpace, m_aabbMin, m_aabbMax);
+ btScalar extraMargin = collisionMarginTriangle + resultOut->m_closestPointDistanceThreshold;
+
+ btVector3 extra(extraMargin, extraMargin, extraMargin);
m_aabbMax += extra;
m_aabbMin -= extra;
-
+
}
void btConvexConcaveCollisionAlgorithm::clearCache()
@@ -193,35 +194,99 @@ void btConvexConcaveCollisionAlgorithm::clearCache()
}
-void btConvexConcaveCollisionAlgorithm::processCollision (const btCollisionObjectWrapper* body0Wrap,const btCollisionObjectWrapper* body1Wrap,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut)
+void btConvexConcaveCollisionAlgorithm::processCollision (const btCollisionObjectWrapper* body0Wrap, const btCollisionObjectWrapper* body1Wrap, const btDispatcherInfo& dispatchInfo, btManifoldResult* resultOut)
{
BT_PROFILE("btConvexConcaveCollisionAlgorithm::processCollision");
-
+
const btCollisionObjectWrapper* convexBodyWrap = m_isSwapped ? body1Wrap : body0Wrap;
const btCollisionObjectWrapper* triBodyWrap = m_isSwapped ? body0Wrap : body1Wrap;
if (triBodyWrap->getCollisionShape()->isConcave())
{
+ if (triBodyWrap->getCollisionShape()->getShapeType() == SDF_SHAPE_PROXYTYPE)
+ {
+ btSdfCollisionShape* sdfShape = (btSdfCollisionShape*)triBodyWrap->getCollisionShape();
+ if (convexBodyWrap->getCollisionShape()->isConvex())
+ {
+ btConvexShape* convex = (btConvexShape*)convexBodyWrap->getCollisionShape();
+ btAlignedObjectArray<btVector3> queryVertices;
+
+ if (convex->isPolyhedral())
+ {
+ btPolyhedralConvexShape* poly = (btPolyhedralConvexShape*)convex;
+ for (int v = 0; v < poly->getNumVertices(); v++)
+ {
+ btVector3 vtx;
+ poly->getVertex(v, vtx);
+ queryVertices.push_back(vtx);
+ }
+ }
+ btScalar maxDist = SIMD_EPSILON;
+
+ if (convex->getShapeType() == SPHERE_SHAPE_PROXYTYPE)
+ {
+ queryVertices.push_back(btVector3(0, 0, 0));
+ btSphereShape* sphere = (btSphereShape*)convex;
+ maxDist = sphere->getRadius() + SIMD_EPSILON;
+
+ }
+ if (queryVertices.size())
+ {
+ resultOut->setPersistentManifold(m_btConvexTriangleCallback.m_manifoldPtr);
+ //m_btConvexTriangleCallback.m_manifoldPtr->clearManifold();
+
+ btPolyhedralConvexShape* poly = (btPolyhedralConvexShape*)convex;
+ for (int v = 0; v < queryVertices.size(); v++)
+ {
+ const btVector3& vtx = queryVertices[v];
+ btVector3 vtxWorldSpace = convexBodyWrap->getWorldTransform()*vtx;
+ btVector3 vtxInSdf = triBodyWrap->getWorldTransform().invXform(vtxWorldSpace);
+
+ btVector3 normalLocal;
+ btScalar dist;
+ if (sdfShape->queryPoint(vtxInSdf, dist, normalLocal))
+ {
+ if (dist <= maxDist)
+ {
+ normalLocal.safeNormalize();
+ btVector3 normal = triBodyWrap->getWorldTransform().getBasis()*normalLocal;
+
+ if (convex->getShapeType() == SPHERE_SHAPE_PROXYTYPE)
+ {
+ btSphereShape* sphere = (btSphereShape*)convex;
+ dist -= sphere->getRadius();
+ vtxWorldSpace -= sphere->getRadius()*normal;
+
+ }
+ resultOut->addContactPoint(normal,vtxWorldSpace-normal*dist, dist);
+ }
+ }
+ }
+ resultOut->refreshContactPoints();
+ }
-
- const btConcaveShape* concaveShape = static_cast<const btConcaveShape*>( triBodyWrap->getCollisionShape());
-
- if (convexBodyWrap->getCollisionShape()->isConvex())
+ }
+ } else
{
- btScalar collisionMarginTriangle = concaveShape->getMargin();
+ const btConcaveShape* concaveShape = static_cast<const btConcaveShape*>( triBodyWrap->getCollisionShape());
+
+ if (convexBodyWrap->getCollisionShape()->isConvex())
+ {
+ btScalar collisionMarginTriangle = concaveShape->getMargin();
- resultOut->setPersistentManifold(m_btConvexTriangleCallback.m_manifoldPtr);
- m_btConvexTriangleCallback.setTimeStepAndCounters(collisionMarginTriangle,dispatchInfo,convexBodyWrap,triBodyWrap,resultOut);
+ resultOut->setPersistentManifold(m_btConvexTriangleCallback.m_manifoldPtr);
+ m_btConvexTriangleCallback.setTimeStepAndCounters(collisionMarginTriangle,dispatchInfo,convexBodyWrap,triBodyWrap,resultOut);
- m_btConvexTriangleCallback.m_manifoldPtr->setBodies(convexBodyWrap->getCollisionObject(),triBodyWrap->getCollisionObject());
+ m_btConvexTriangleCallback.m_manifoldPtr->setBodies(convexBodyWrap->getCollisionObject(),triBodyWrap->getCollisionObject());
- concaveShape->processAllTriangles( &m_btConvexTriangleCallback,m_btConvexTriangleCallback.getAabbMin(),m_btConvexTriangleCallback.getAabbMax());
+ concaveShape->processAllTriangles( &m_btConvexTriangleCallback,m_btConvexTriangleCallback.getAabbMin(),m_btConvexTriangleCallback.getAabbMax());
- resultOut->refreshContactPoints();
+ resultOut->refreshContactPoints();
- m_btConvexTriangleCallback.clearWrapperData();
+ m_btConvexTriangleCallback.clearWrapperData();
+ }
}
}
diff --git a/thirdparty/bullet/BulletCollision/CollisionDispatch/btConvexConvexAlgorithm.cpp b/thirdparty/bullet/BulletCollision/CollisionDispatch/btConvexConvexAlgorithm.cpp
index b54bd48932..3e8bc6e426 100644
--- a/thirdparty/bullet/BulletCollision/CollisionDispatch/btConvexConvexAlgorithm.cpp
+++ b/thirdparty/bullet/BulletCollision/CollisionDispatch/btConvexConvexAlgorithm.cpp
@@ -28,6 +28,7 @@ subject to the following restrictions:
#include "BulletCollision/CollisionShapes/btConvexShape.h"
#include "BulletCollision/CollisionShapes/btCapsuleShape.h"
#include "BulletCollision/CollisionShapes/btTriangleShape.h"
+#include "BulletCollision/CollisionShapes/btConvexPolyhedron.h"
@@ -259,7 +260,7 @@ struct btPerturbedContactResult : public btManifoldResult
btVector3 endPtOrg = pointInWorld + normalOnBInWorld*orgDepth;
endPt = (m_unPerturbedTransform*m_transformA.inverse())(endPtOrg);
newDepth = (endPt - pointInWorld).dot(normalOnBInWorld);
- startPt = endPt+normalOnBInWorld*newDepth;
+ startPt = endPt - normalOnBInWorld*newDepth;
} else
{
endPt = pointInWorld + normalOnBInWorld*orgDepth;
@@ -442,10 +443,26 @@ void btConvexConvexAlgorithm ::processCollision (const btCollisionObjectWrapper*
struct btDummyResult : public btDiscreteCollisionDetectorInterface::Result
{
+ btVector3 m_normalOnBInWorld;
+ btVector3 m_pointInWorld;
+ btScalar m_depth;
+ bool m_hasContact;
+
+
+ btDummyResult()
+ : m_hasContact(false)
+ {
+ }
+
+
virtual void setShapeIdentifiersA(int partId0,int index0){}
virtual void setShapeIdentifiersB(int partId1,int index1){}
virtual void addContactPoint(const btVector3& normalOnBInWorld,const btVector3& pointInWorld,btScalar depth)
{
+ m_hasContact = true;
+ m_normalOnBInWorld = normalOnBInWorld;
+ m_pointInWorld = pointInWorld;
+ m_depth = depth;
}
};
@@ -560,15 +577,18 @@ void btConvexConvexAlgorithm ::processCollision (const btCollisionObjectWrapper*
} else
{
+
+
//we can also deal with convex versus triangle (without connectivity data)
- if (polyhedronA->getConvexPolyhedron() && polyhedronB->getShapeType()==TRIANGLE_SHAPE_PROXYTYPE)
+ if (dispatchInfo.m_enableSatConvex && polyhedronA->getConvexPolyhedron() && polyhedronB->getShapeType()==TRIANGLE_SHAPE_PROXYTYPE)
{
- btVertexArray vertices;
+
+ btVertexArray worldSpaceVertices;
btTriangleShape* tri = (btTriangleShape*)polyhedronB;
- vertices.push_back( body1Wrap->getWorldTransform()*tri->m_vertices1[0]);
- vertices.push_back( body1Wrap->getWorldTransform()*tri->m_vertices1[1]);
- vertices.push_back( body1Wrap->getWorldTransform()*tri->m_vertices1[2]);
+ worldSpaceVertices.push_back( body1Wrap->getWorldTransform()*tri->m_vertices1[0]);
+ worldSpaceVertices.push_back( body1Wrap->getWorldTransform()*tri->m_vertices1[1]);
+ worldSpaceVertices.push_back( body1Wrap->getWorldTransform()*tri->m_vertices1[2]);
//tri->initializePolyhedralFeatures();
@@ -579,17 +599,99 @@ void btConvexConvexAlgorithm ::processCollision (const btCollisionObjectWrapper*
btScalar maxDist = threshold;
bool foundSepAxis = false;
- if (0)
+ bool useSatSepNormal = true;
+
+ if (useSatSepNormal)
{
- polyhedronB->initializePolyhedralFeatures();
+#if 0
+ if (0)
+ {
+ //initializePolyhedralFeatures performs a convex hull computation, not needed for a single triangle
+ polyhedronB->initializePolyhedralFeatures();
+ } else
+#endif
+ {
+
+ btVector3 uniqueEdges[3] = {tri->m_vertices1[1]-tri->m_vertices1[0],
+ tri->m_vertices1[2]-tri->m_vertices1[1],
+ tri->m_vertices1[0]-tri->m_vertices1[2]};
+
+ uniqueEdges[0].normalize();
+ uniqueEdges[1].normalize();
+ uniqueEdges[2].normalize();
+
+ btConvexPolyhedron polyhedron;
+ polyhedron.m_vertices.push_back(tri->m_vertices1[2]);
+ polyhedron.m_vertices.push_back(tri->m_vertices1[0]);
+ polyhedron.m_vertices.push_back(tri->m_vertices1[1]);
+
+
+ {
+ btFace combinedFaceA;
+ combinedFaceA.m_indices.push_back(0);
+ combinedFaceA.m_indices.push_back(1);
+ combinedFaceA.m_indices.push_back(2);
+ btVector3 faceNormal = uniqueEdges[0].cross(uniqueEdges[1]);
+ faceNormal.normalize();
+ btScalar planeEq=1e30f;
+ for (int v=0;v<combinedFaceA.m_indices.size();v++)
+ {
+ btScalar eq = tri->m_vertices1[combinedFaceA.m_indices[v]].dot(faceNormal);
+ if (planeEq>eq)
+ {
+ planeEq=eq;
+ }
+ }
+ combinedFaceA.m_plane[0] = faceNormal[0];
+ combinedFaceA.m_plane[1] = faceNormal[1];
+ combinedFaceA.m_plane[2] = faceNormal[2];
+ combinedFaceA.m_plane[3] = -planeEq;
+ polyhedron.m_faces.push_back(combinedFaceA);
+ }
+ {
+ btFace combinedFaceB;
+ combinedFaceB.m_indices.push_back(0);
+ combinedFaceB.m_indices.push_back(2);
+ combinedFaceB.m_indices.push_back(1);
+ btVector3 faceNormal = -uniqueEdges[0].cross(uniqueEdges[1]);
+ faceNormal.normalize();
+ btScalar planeEq=1e30f;
+ for (int v=0;v<combinedFaceB.m_indices.size();v++)
+ {
+ btScalar eq = tri->m_vertices1[combinedFaceB.m_indices[v]].dot(faceNormal);
+ if (planeEq>eq)
+ {
+ planeEq=eq;
+ }
+ }
+
+ combinedFaceB.m_plane[0] = faceNormal[0];
+ combinedFaceB.m_plane[1] = faceNormal[1];
+ combinedFaceB.m_plane[2] = faceNormal[2];
+ combinedFaceB.m_plane[3] = -planeEq;
+ polyhedron.m_faces.push_back(combinedFaceB);
+ }
+
+
+ polyhedron.m_uniqueEdges.push_back(uniqueEdges[0]);
+ polyhedron.m_uniqueEdges.push_back(uniqueEdges[1]);
+ polyhedron.m_uniqueEdges.push_back(uniqueEdges[2]);
+ polyhedron.initialize2();
+
+ polyhedronB->setPolyhedralFeatures(polyhedron);
+ }
+
+
+
foundSepAxis = btPolyhedralContactClipping::findSeparatingAxis(
- *polyhedronA->getConvexPolyhedron(), *polyhedronB->getConvexPolyhedron(),
- body0Wrap->getWorldTransform(),
- body1Wrap->getWorldTransform(),
- sepNormalWorldSpace,*resultOut);
+ *polyhedronA->getConvexPolyhedron(), *polyhedronB->getConvexPolyhedron(),
+ body0Wrap->getWorldTransform(),
+ body1Wrap->getWorldTransform(),
+ sepNormalWorldSpace,*resultOut);
// printf("sepNormalWorldSpace=%f,%f,%f\n",sepNormalWorldSpace.getX(),sepNormalWorldSpace.getY(),sepNormalWorldSpace.getZ());
- } else
+ }
+ else
{
#ifdef ZERO_MARGIN
gjkPairDetector.setIgnoreMargin(true);
@@ -598,6 +700,24 @@ void btConvexConvexAlgorithm ::processCollision (const btCollisionObjectWrapper*
gjkPairDetector.getClosestPoints(input,dummy,dispatchInfo.m_debugDraw);
#endif//ZERO_MARGIN
+ if (dummy.m_hasContact && dummy.m_depth<0)
+ {
+
+ if (foundSepAxis)
+ {
+ if (dummy.m_normalOnBInWorld.dot(sepNormalWorldSpace)<0.99)
+ {
+ printf("?\n");
+ }
+ } else
+ {
+ printf("!\n");
+ }
+ sepNormalWorldSpace.setValue(0,0,1);// = dummy.m_normalOnBInWorld;
+ //minDist = dummy.m_depth;
+ foundSepAxis = true;
+ }
+#if 0
btScalar l2 = gjkPairDetector.getCachedSeparatingAxis().length2();
if (l2>SIMD_EPSILON)
{
@@ -607,6 +727,7 @@ void btConvexConvexAlgorithm ::processCollision (const btCollisionObjectWrapper*
minDist = gjkPairDetector.getCachedSeparatingDistance()-min0->getMargin()-min1->getMargin();
foundSepAxis = true;
}
+#endif
}
@@ -614,7 +735,7 @@ void btConvexConvexAlgorithm ::processCollision (const btCollisionObjectWrapper*
{
worldVertsB2.resize(0);
btPolyhedralContactClipping::clipFaceAgainstHull(sepNormalWorldSpace, *polyhedronA->getConvexPolyhedron(),
- body0Wrap->getWorldTransform(), vertices, worldVertsB2,minDist-threshold, maxDist, *resultOut);
+ body0Wrap->getWorldTransform(), worldSpaceVertices, worldVertsB2,minDist-threshold, maxDist, *resultOut);
}
@@ -625,6 +746,7 @@ void btConvexConvexAlgorithm ::processCollision (const btCollisionObjectWrapper*
return;
}
+
}
diff --git a/thirdparty/bullet/BulletCollision/CollisionDispatch/btHashedSimplePairCache.cpp b/thirdparty/bullet/BulletCollision/CollisionDispatch/btHashedSimplePairCache.cpp
index 8c8a7c3c1e..8271981b29 100644
--- a/thirdparty/bullet/BulletCollision/CollisionDispatch/btHashedSimplePairCache.cpp
+++ b/thirdparty/bullet/BulletCollision/CollisionDispatch/btHashedSimplePairCache.cpp
@@ -20,11 +20,12 @@ subject to the following restrictions:
#include <stdio.h>
+#ifdef BT_DEBUG_COLLISION_PAIRS
int gOverlappingSimplePairs = 0;
int gRemoveSimplePairs =0;
int gAddedSimplePairs =0;
int gFindSimplePairs =0;
-
+#endif //BT_DEBUG_COLLISION_PAIRS
@@ -61,7 +62,9 @@ void btHashedSimplePairCache::removeAllPairs()
btSimplePair* btHashedSimplePairCache::findPair(int indexA, int indexB)
{
+#ifdef BT_DEBUG_COLLISION_PAIRS
gFindSimplePairs++;
+#endif
/*if (indexA > indexB)
@@ -172,7 +175,9 @@ btSimplePair* btHashedSimplePairCache::internalAddPair(int indexA, int indexB)
void* btHashedSimplePairCache::removeOverlappingPair(int indexA, int indexB)
{
+#ifdef BT_DEBUG_COLLISION_PAIRS
gRemoveSimplePairs++;
+#endif
/*if (indexA > indexB)
diff --git a/thirdparty/bullet/BulletCollision/CollisionDispatch/btHashedSimplePairCache.h b/thirdparty/bullet/BulletCollision/CollisionDispatch/btHashedSimplePairCache.h
index 2aaf6201f3..318981cda1 100644
--- a/thirdparty/bullet/BulletCollision/CollisionDispatch/btHashedSimplePairCache.h
+++ b/thirdparty/bullet/BulletCollision/CollisionDispatch/btHashedSimplePairCache.h
@@ -43,12 +43,12 @@ struct btSimplePair
typedef btAlignedObjectArray<btSimplePair> btSimplePairArray;
-
+#ifdef BT_DEBUG_COLLISION_PAIRS
extern int gOverlappingSimplePairs;
extern int gRemoveSimplePairs;
extern int gAddedSimplePairs;
extern int gFindSimplePairs;
-
+#endif //BT_DEBUG_COLLISION_PAIRS
@@ -75,7 +75,9 @@ public:
// no new pair is created and the old one is returned.
virtual btSimplePair* addOverlappingPair(int indexA,int indexB)
{
+#ifdef BT_DEBUG_COLLISION_PAIRS
gAddedSimplePairs++;
+#endif
return internalAddPair(indexA,indexB);
}
diff --git a/thirdparty/bullet/BulletCollision/CollisionDispatch/btInternalEdgeUtility.cpp b/thirdparty/bullet/BulletCollision/CollisionDispatch/btInternalEdgeUtility.cpp
index 6cba442ca5..898320ee1a 100644
--- a/thirdparty/bullet/BulletCollision/CollisionDispatch/btInternalEdgeUtility.cpp
+++ b/thirdparty/bullet/BulletCollision/CollisionDispatch/btInternalEdgeUtility.cpp
@@ -455,11 +455,20 @@ void btAdjustInternalEdgeContacts(btManifoldPoint& cp, const btCollisionObjectWr
btBvhTriangleMeshShape* trimesh = 0;
if( colObj0Wrap->getCollisionObject()->getCollisionShape()->getShapeType() == SCALED_TRIANGLE_MESH_SHAPE_PROXYTYPE )
- trimesh = ((btScaledBvhTriangleMeshShape*)colObj0Wrap->getCollisionObject()->getCollisionShape())->getChildShape();
- else
- trimesh = (btBvhTriangleMeshShape*)colObj0Wrap->getCollisionObject()->getCollisionShape();
-
- btTriangleInfoMap* triangleInfoMapPtr = (btTriangleInfoMap*) trimesh->getTriangleInfoMap();
+ {
+ trimesh = ((btScaledBvhTriangleMeshShape*)colObj0Wrap->getCollisionObject()->getCollisionShape())->getChildShape();
+ }
+ else
+ {
+ if (colObj0Wrap->getCollisionObject()->getCollisionShape()->getShapeType()==TRIANGLE_MESH_SHAPE_PROXYTYPE)
+ {
+ trimesh = (btBvhTriangleMeshShape*)colObj0Wrap->getCollisionObject()->getCollisionShape();
+ }
+ }
+ if (trimesh==0)
+ return;
+
+ btTriangleInfoMap* triangleInfoMapPtr = (btTriangleInfoMap*) trimesh->getTriangleInfoMap();
if (!triangleInfoMapPtr)
return;
diff --git a/thirdparty/bullet/BulletCollision/CollisionDispatch/btSimulationIslandManager.cpp b/thirdparty/bullet/BulletCollision/CollisionDispatch/btSimulationIslandManager.cpp
index 1344782257..91c76a8dac 100644
--- a/thirdparty/bullet/BulletCollision/CollisionDispatch/btSimulationIslandManager.cpp
+++ b/thirdparty/bullet/BulletCollision/CollisionDispatch/btSimulationIslandManager.cpp
@@ -199,6 +199,22 @@ class btPersistentManifoldSortPredicate
}
};
+class btPersistentManifoldSortPredicateDeterministic
+{
+public:
+
+ SIMD_FORCE_INLINE bool operator() (const btPersistentManifold* lhs, const btPersistentManifold* rhs) const
+ {
+ return (
+ (getIslandId(lhs) < getIslandId(rhs))
+ || ((getIslandId(lhs) == getIslandId(rhs)) && lhs->getBody0()->getBroadphaseHandle()->m_uniqueId < rhs->getBody0()->getBroadphaseHandle()->m_uniqueId)
+ ||((getIslandId(lhs) == getIslandId(rhs)) && (lhs->getBody0()->getBroadphaseHandle()->m_uniqueId == rhs->getBody0()->getBroadphaseHandle()->m_uniqueId) &&
+ (lhs->getBody1()->getBroadphaseHandle()->m_uniqueId < rhs->getBody1()->getBroadphaseHandle()->m_uniqueId))
+ );
+
+ }
+};
+
void btSimulationIslandManager::buildIslands(btDispatcher* dispatcher,btCollisionWorld* collisionWorld)
{
@@ -245,13 +261,11 @@ void btSimulationIslandManager::buildIslands(btDispatcher* dispatcher,btCollisio
btAssert((colObj0->getIslandTag() == islandId) || (colObj0->getIslandTag() == -1));
if (colObj0->getIslandTag() == islandId)
{
- if (colObj0->getActivationState()== ACTIVE_TAG)
- {
- allSleeping = false;
- }
- if (colObj0->getActivationState()== DISABLE_DEACTIVATION)
+ if (colObj0->getActivationState()== ACTIVE_TAG ||
+ colObj0->getActivationState()== DISABLE_DEACTIVATION)
{
allSleeping = false;
+ break;
}
}
}
@@ -318,7 +332,12 @@ void btSimulationIslandManager::buildIslands(btDispatcher* dispatcher,btCollisio
for (i=0;i<maxNumManifolds ;i++)
{
btPersistentManifold* manifold = dispatcher->getManifoldByIndexInternal(i);
-
+ if (collisionWorld->getDispatchInfo().m_deterministicOverlappingPairs)
+ {
+ if (manifold->getNumContacts() == 0)
+ continue;
+ }
+
const btCollisionObject* colObj0 = static_cast<const btCollisionObject*>(manifold->getBody0());
const btCollisionObject* colObj1 = static_cast<const btCollisionObject*>(manifold->getBody1());
@@ -379,7 +398,16 @@ void btSimulationIslandManager::buildAndProcessIslands(btDispatcher* dispatcher,
//tried a radix sort, but quicksort/heapsort seems still faster
//@todo rewrite island management
- m_islandmanifold.quickSort(btPersistentManifoldSortPredicate());
+ //btPersistentManifoldSortPredicateDeterministic sorts contact manifolds based on islandid,
+ //but also based on object0 unique id and object1 unique id
+ if (collisionWorld->getDispatchInfo().m_deterministicOverlappingPairs)
+ {
+ m_islandmanifold.quickSort(btPersistentManifoldSortPredicateDeterministic());
+ } else
+ {
+ m_islandmanifold.quickSort(btPersistentManifoldSortPredicate());
+ }
+
//m_islandmanifold.heapSort(btPersistentManifoldSortPredicate());
//now process all active islands (sets of manifolds for now)
diff --git a/thirdparty/bullet/BulletCollision/CollisionShapes/btCapsuleShape.h b/thirdparty/bullet/BulletCollision/CollisionShapes/btCapsuleShape.h
index 7d64b46abf..5a3362834a 100644
--- a/thirdparty/bullet/BulletCollision/CollisionShapes/btCapsuleShape.h
+++ b/thirdparty/bullet/BulletCollision/CollisionShapes/btCapsuleShape.h
@@ -49,6 +49,7 @@ public:
virtual void setMargin(btScalar collisionMargin)
{
//don't override the margin for capsules, their entire radius == margin
+ (void)collisionMargin;
}
virtual void getAabb (const btTransform& t, btVector3& aabbMin, btVector3& aabbMax) const
diff --git a/thirdparty/bullet/BulletCollision/CollisionShapes/btCompoundShape.cpp b/thirdparty/bullet/BulletCollision/CollisionShapes/btCompoundShape.cpp
index e8c8c336cd..85572da307 100644
--- a/thirdparty/bullet/BulletCollision/CollisionShapes/btCompoundShape.cpp
+++ b/thirdparty/bullet/BulletCollision/CollisionShapes/btCompoundShape.cpp
@@ -213,7 +213,7 @@ void btCompoundShape::calculateLocalInertia(btScalar mass,btVector3& inertia) co
-void btCompoundShape::calculatePrincipalAxisTransform(btScalar* masses, btTransform& principal, btVector3& inertia) const
+void btCompoundShape::calculatePrincipalAxisTransform(const btScalar* masses, btTransform& principal, btVector3& inertia) const
{
int n = m_children.size();
diff --git a/thirdparty/bullet/BulletCollision/CollisionShapes/btCompoundShape.h b/thirdparty/bullet/BulletCollision/CollisionShapes/btCompoundShape.h
index 4eef8dba30..2cbcd1bfca 100644
--- a/thirdparty/bullet/BulletCollision/CollisionShapes/btCompoundShape.h
+++ b/thirdparty/bullet/BulletCollision/CollisionShapes/btCompoundShape.h
@@ -160,7 +160,7 @@ public:
///"principal" has to be applied inversely to all children transforms in order for the local coordinate system of the compound
///shape to be centered at the center of mass and to coincide with the principal axes. This also necessitates a correction of the world transform
///of the collision object by the principal transform.
- void calculatePrincipalAxisTransform(btScalar* masses, btTransform& principal, btVector3& inertia) const;
+ void calculatePrincipalAxisTransform(const btScalar* masses, btTransform& principal, btVector3& inertia) const;
int getUpdateRevision() const
{
diff --git a/thirdparty/bullet/BulletCollision/CollisionShapes/btConvexPolyhedron.cpp b/thirdparty/bullet/BulletCollision/CollisionShapes/btConvexPolyhedron.cpp
index 4f45319a83..0fea00df5c 100644
--- a/thirdparty/bullet/BulletCollision/CollisionShapes/btConvexPolyhedron.cpp
+++ b/thirdparty/bullet/BulletCollision/CollisionShapes/btConvexPolyhedron.cpp
@@ -104,9 +104,9 @@ void btConvexPolyhedron::initialize()
btHashMap<btInternalVertexPair,btInternalEdge> edges;
- btScalar TotalArea = 0.0f;
- m_localCenter.setValue(0, 0, 0);
+
+
for(int i=0;i<m_faces.size();i++)
{
int numVertices = m_faces[i].m_indices.size();
@@ -172,6 +172,13 @@ void btConvexPolyhedron::initialize()
}
#endif//USE_CONNECTED_FACES
+ initialize2();
+}
+
+void btConvexPolyhedron::initialize2()
+{
+ m_localCenter.setValue(0, 0, 0);
+ btScalar TotalArea = 0.0f;
for(int i=0;i<m_faces.size();i++)
{
int numVertices = m_faces[i].m_indices.size();
@@ -274,7 +281,6 @@ void btConvexPolyhedron::initialize()
}
#endif
}
-
void btConvexPolyhedron::project(const btTransform& trans, const btVector3& dir, btScalar& minProj, btScalar& maxProj, btVector3& witnesPtMin,btVector3& witnesPtMax) const
{
minProj = FLT_MAX;
diff --git a/thirdparty/bullet/BulletCollision/CollisionShapes/btConvexPolyhedron.h b/thirdparty/bullet/BulletCollision/CollisionShapes/btConvexPolyhedron.h
index d3cd066ac8..c5aa20f453 100644
--- a/thirdparty/bullet/BulletCollision/CollisionShapes/btConvexPolyhedron.h
+++ b/thirdparty/bullet/BulletCollision/CollisionShapes/btConvexPolyhedron.h
@@ -54,6 +54,7 @@ ATTRIBUTE_ALIGNED16(class) btConvexPolyhedron
btVector3 mE;
void initialize();
+ void initialize2();
bool testContainment() const;
void project(const btTransform& trans, const btVector3& dir, btScalar& minProj, btScalar& maxProj, btVector3& witnesPtMin,btVector3& witnesPtMax) const;
diff --git a/thirdparty/bullet/BulletCollision/CollisionShapes/btConvexShape.cpp b/thirdparty/bullet/BulletCollision/CollisionShapes/btConvexShape.cpp
index 8d7fb054d6..2f84858598 100644
--- a/thirdparty/bullet/BulletCollision/CollisionShapes/btConvexShape.cpp
+++ b/thirdparty/bullet/BulletCollision/CollisionShapes/btConvexShape.cpp
@@ -118,9 +118,13 @@ static btVector3 convexHullSupport (const btVector3& localDirOrg, const btVector
return supVec;
#else
- btScalar maxDot;
- long ptIndex = vec.maxDot( points, numPoints, maxDot);
+ btScalar maxDot;
+ long ptIndex = vec.maxDot( points, numPoints, maxDot);
btAssert(ptIndex >= 0);
+ if (ptIndex<0)
+ {
+ ptIndex = 0;
+ }
btVector3 supVec = points[ptIndex] * localScaling;
return supVec;
#endif //__SPU__
diff --git a/thirdparty/bullet/BulletCollision/CollisionShapes/btMiniSDF.cpp b/thirdparty/bullet/BulletCollision/CollisionShapes/btMiniSDF.cpp
new file mode 100644
index 0000000000..afe45e1d2d
--- /dev/null
+++ b/thirdparty/bullet/BulletCollision/CollisionShapes/btMiniSDF.cpp
@@ -0,0 +1,532 @@
+#include "btMiniSDF.h"
+
+//
+//Based on code from DiscreGrid, https://github.com/InteractiveComputerGraphics/Discregrid
+//example:
+//GenerateSDF.exe -r "32 32 32" -d "-1.6 -1.6 -.6 1.6 1.6 .6" concave_box.obj
+//The MIT License (MIT)
+//
+//Copyright (c) 2017 Dan Koschier
+//
+
+#include <limits.h>
+#include <string.h> //memcpy
+
+struct btSdfDataStream
+{
+ const char* m_data;
+ int m_size;
+
+ int m_currentOffset;
+
+ btSdfDataStream(const char* data, int size)
+ :m_data(data),
+ m_size(size),
+ m_currentOffset(0)
+ {
+
+ }
+
+ template<class T> bool read(T& val)
+ {
+ int bytes = sizeof(T);
+ if (m_currentOffset+bytes<=m_size)
+ {
+ char* dest = (char*)&val;
+ memcpy(dest,&m_data[m_currentOffset],bytes);
+ m_currentOffset+=bytes;
+ return true;
+ }
+ btAssert(0);
+ return false;
+ }
+};
+
+
+bool btMiniSDF::load(const char* data, int size)
+{
+ int fileSize = -1;
+
+ btSdfDataStream ds(data,size);
+ {
+ double buf[6];
+ ds.read(buf);
+ m_domain.m_min[0] = buf[0];
+ m_domain.m_min[1] = buf[1];
+ m_domain.m_min[2] = buf[2];
+ m_domain.m_min[3] = 0;
+ m_domain.m_max[0] = buf[3];
+ m_domain.m_max[1] = buf[4];
+ m_domain.m_max[2] = buf[5];
+ m_domain.m_max[3] = 0;
+ }
+ {
+ unsigned int buf2[3];
+ ds.read(buf2);
+ m_resolution[0] = buf2[0];
+ m_resolution[1] = buf2[1];
+ m_resolution[2] = buf2[2];
+ }
+ {
+ double buf[3];
+ ds.read(buf);
+ m_cell_size[0] = buf[0];
+ m_cell_size[1] = buf[1];
+ m_cell_size[2] = buf[2];
+ }
+ {
+ double buf[3];
+ ds.read(buf);
+ m_inv_cell_size[0] = buf[0];
+ m_inv_cell_size[1] = buf[1];
+ m_inv_cell_size[2] = buf[2];
+ }
+ {
+ unsigned long long int cells;
+ ds.read(cells);
+ m_n_cells = cells;
+ }
+ {
+ unsigned long long int fields;
+ ds.read(fields);
+ m_n_fields = fields;
+ }
+
+
+ unsigned long long int nodes0;
+ std::size_t n_nodes0;
+ ds.read(nodes0);
+ n_nodes0 = nodes0;
+ if (n_nodes0 > 1024 * 1024 * 1024)
+ {
+ return m_isValid;
+ }
+ m_nodes.resize(n_nodes0);
+ for (unsigned int i=0;i<n_nodes0;i++)
+ {
+ unsigned long long int n_nodes1;
+ ds.read(n_nodes1);
+ btAlignedObjectArray<double>& nodes = m_nodes[i];
+ nodes.resize(n_nodes1);
+ for ( int j=0;j<nodes.size();j++)
+ {
+ double& node = nodes[j];
+ ds.read(node);
+ }
+ }
+
+ unsigned long long int n_cells0;
+ ds.read(n_cells0);
+ m_cells.resize(n_cells0);
+ for (int i=0;i<n_cells0;i++)
+ {
+ unsigned long long int n_cells1;
+ btAlignedObjectArray<btCell32 >& cells = m_cells[i];
+ ds.read(n_cells1);
+ cells.resize(n_cells1);
+ for (int j=0;j<n_cells1;j++)
+ {
+ btCell32& cell = cells[j];
+ ds.read(cell);
+ }
+ }
+
+ {
+ unsigned long long int n_cell_maps0;
+ ds.read(n_cell_maps0);
+
+ m_cell_map.resize(n_cell_maps0);
+ for (int i=0;i<n_cell_maps0;i++)
+ {
+ unsigned long long int n_cell_maps1;
+ btAlignedObjectArray<unsigned int>& cell_maps = m_cell_map[i];
+ ds.read(n_cell_maps1);
+ cell_maps.resize(n_cell_maps1);
+ for (int j=0;j<n_cell_maps1;j++)
+ {
+ unsigned int& cell_map = cell_maps[j];
+ ds.read(cell_map);
+ }
+ }
+ }
+
+ m_isValid = (ds.m_currentOffset == ds.m_size);
+ return m_isValid;
+}
+
+
+unsigned int btMiniSDF::multiToSingleIndex(btMultiIndex const & ijk) const
+{
+ return m_resolution[1] * m_resolution[0] * ijk.ijk[2] + m_resolution[0] * ijk.ijk[1] + ijk.ijk[0];
+}
+
+btAlignedBox3d
+btMiniSDF::subdomain(btMultiIndex const& ijk) const
+{
+ btAssert(m_isValid);
+ btVector3 tmp;
+ tmp.m_floats[0] = m_cell_size[0]*(double)ijk.ijk[0];
+ tmp.m_floats[1] = m_cell_size[1]*(double)ijk.ijk[1];
+ tmp.m_floats[2] = m_cell_size[2]*(double)ijk.ijk[2];
+
+
+ btVector3 origin = m_domain.min() + tmp;
+
+ btAlignedBox3d box = btAlignedBox3d (origin, origin + m_cell_size);
+ return box;
+}
+
+btMultiIndex
+btMiniSDF::singleToMultiIndex(unsigned int l) const
+{
+ btAssert(m_isValid);
+ unsigned int n01 = m_resolution[0] * m_resolution[1];
+ unsigned int k = l / n01;
+ unsigned int temp = l % n01;
+ unsigned int j = temp / m_resolution[0];
+ unsigned int i = temp % m_resolution[0];
+ btMultiIndex mi;
+ mi.ijk[0] = i;
+ mi.ijk[1] = j;
+ mi.ijk[2] = k;
+ return mi;
+}
+
+btAlignedBox3d
+btMiniSDF::subdomain(unsigned int l) const
+{
+ btAssert(m_isValid);
+ return subdomain(singleToMultiIndex(l));
+}
+
+
+btShapeMatrix
+btMiniSDF::shape_function_(btVector3 const& xi, btShapeGradients* gradient) const
+{
+ btAssert(m_isValid);
+ btShapeMatrix res;
+
+ btScalar x = xi[0];
+ btScalar y = xi[1];
+ btScalar z = xi[2];
+
+ btScalar x2 = x*x;
+ btScalar y2 = y*y;
+ btScalar z2 = z*z;
+
+ btScalar _1mx = 1.0 - x;
+ btScalar _1my = 1.0 - y;
+ btScalar _1mz = 1.0 - z;
+
+ btScalar _1px = 1.0 + x;
+ btScalar _1py = 1.0 + y;
+ btScalar _1pz = 1.0 + z;
+
+ btScalar _1m3x = 1.0 - 3.0 * x;
+ btScalar _1m3y = 1.0 - 3.0 * y;
+ btScalar _1m3z = 1.0 - 3.0 * z;
+
+ btScalar _1p3x = 1.0 + 3.0 * x;
+ btScalar _1p3y = 1.0 + 3.0 * y;
+ btScalar _1p3z = 1.0 + 3.0 * z;
+
+ btScalar _1mxt1my = _1mx * _1my;
+ btScalar _1mxt1py = _1mx * _1py;
+ btScalar _1pxt1my = _1px * _1my;
+ btScalar _1pxt1py = _1px * _1py;
+
+ btScalar _1mxt1mz = _1mx * _1mz;
+ btScalar _1mxt1pz = _1mx * _1pz;
+ btScalar _1pxt1mz = _1px * _1mz;
+ btScalar _1pxt1pz = _1px * _1pz;
+
+ btScalar _1myt1mz = _1my * _1mz;
+ btScalar _1myt1pz = _1my * _1pz;
+ btScalar _1pyt1mz = _1py * _1mz;
+ btScalar _1pyt1pz = _1py * _1pz;
+
+ btScalar _1mx2 = 1.0 - x2;
+ btScalar _1my2 = 1.0 - y2;
+ btScalar _1mz2 = 1.0 - z2;
+
+
+ // Corner nodes.
+ btScalar fac = 1.0 / 64.0 * (9.0 * (x2 + y2 + z2) - 19.0);
+ res[0] = fac * _1mxt1my * _1mz;
+ res[1] = fac * _1pxt1my * _1mz;
+ res[2] = fac * _1mxt1py * _1mz;
+ res[3] = fac * _1pxt1py * _1mz;
+ res[4] = fac * _1mxt1my * _1pz;
+ res[5] = fac * _1pxt1my * _1pz;
+ res[6] = fac * _1mxt1py * _1pz;
+ res[7] = fac * _1pxt1py * _1pz;
+
+ // Edge nodes.
+
+ fac = 9.0 / 64.0 * _1mx2;
+ btScalar fact1m3x = fac * _1m3x;
+ btScalar fact1p3x = fac * _1p3x;
+ res[ 8] = fact1m3x * _1myt1mz;
+ res[ 9] = fact1p3x * _1myt1mz;
+ res[10] = fact1m3x * _1myt1pz;
+ res[11] = fact1p3x * _1myt1pz;
+ res[12] = fact1m3x * _1pyt1mz;
+ res[13] = fact1p3x * _1pyt1mz;
+ res[14] = fact1m3x * _1pyt1pz;
+ res[15] = fact1p3x * _1pyt1pz;
+
+ fac = 9.0 / 64.0 * _1my2;
+ btScalar fact1m3y = fac * _1m3y;
+ btScalar fact1p3y = fac * _1p3y;
+ res[16] = fact1m3y * _1mxt1mz;
+ res[17] = fact1p3y * _1mxt1mz;
+ res[18] = fact1m3y * _1pxt1mz;
+ res[19] = fact1p3y * _1pxt1mz;
+ res[20] = fact1m3y * _1mxt1pz;
+ res[21] = fact1p3y * _1mxt1pz;
+ res[22] = fact1m3y * _1pxt1pz;
+ res[23] = fact1p3y * _1pxt1pz;
+
+ fac = 9.0 / 64.0 * _1mz2;
+ btScalar fact1m3z = fac * _1m3z;
+ btScalar fact1p3z = fac * _1p3z;
+ res[24] = fact1m3z * _1mxt1my;
+ res[25] = fact1p3z * _1mxt1my;
+ res[26] = fact1m3z * _1mxt1py;
+ res[27] = fact1p3z * _1mxt1py;
+ res[28] = fact1m3z * _1pxt1my;
+ res[29] = fact1p3z * _1pxt1my;
+ res[30] = fact1m3z * _1pxt1py;
+ res[31] = fact1p3z * _1pxt1py;
+
+ if (gradient)
+ {
+ btShapeGradients& dN = *gradient;
+
+ btScalar _9t3x2py2pz2m19 = 9.0 * (3.0 * x2 + y2 + z2) - 19.0;
+ btScalar _9tx2p3y2pz2m19 = 9.0 * (x2 + 3.0 * y2 + z2) - 19.0;
+ btScalar _9tx2py2p3z2m19 = 9.0 * (x2 + y2 + 3.0 * z2) - 19.0;
+ btScalar _18x = 18.0 * x;
+ btScalar _18y = 18.0 * y;
+ btScalar _18z = 18.0 * z;
+
+ btScalar _3m9x2 = 3.0 - 9.0 * x2;
+ btScalar _3m9y2 = 3.0 - 9.0 * y2;
+ btScalar _3m9z2 = 3.0 - 9.0 * z2;
+
+ btScalar _2x = 2.0 * x;
+ btScalar _2y = 2.0 * y;
+ btScalar _2z = 2.0 * z;
+
+ btScalar _18xm9t3x2py2pz2m19 = _18x - _9t3x2py2pz2m19;
+ btScalar _18xp9t3x2py2pz2m19 = _18x + _9t3x2py2pz2m19;
+ btScalar _18ym9tx2p3y2pz2m19 = _18y - _9tx2p3y2pz2m19;
+ btScalar _18yp9tx2p3y2pz2m19 = _18y + _9tx2p3y2pz2m19;
+ btScalar _18zm9tx2py2p3z2m19 = _18z - _9tx2py2p3z2m19;
+ btScalar _18zp9tx2py2p3z2m19 = _18z + _9tx2py2p3z2m19;
+
+ dN(0,0) =_18xm9t3x2py2pz2m19 * _1myt1mz;
+ dN(0,1) =_1mxt1mz * _18ym9tx2p3y2pz2m19;
+ dN(0,2) =_1mxt1my * _18zm9tx2py2p3z2m19;
+ dN(1,0) =_18xp9t3x2py2pz2m19 * _1myt1mz;
+ dN(1,1) =_1pxt1mz * _18ym9tx2p3y2pz2m19;
+ dN(1,2) =_1pxt1my * _18zm9tx2py2p3z2m19;
+ dN(2,0) =_18xm9t3x2py2pz2m19 * _1pyt1mz;
+ dN(2,1) =_1mxt1mz * _18yp9tx2p3y2pz2m19;
+ dN(2,2) =_1mxt1py * _18zm9tx2py2p3z2m19;
+ dN(3,0) =_18xp9t3x2py2pz2m19 * _1pyt1mz;
+ dN(3,1) =_1pxt1mz * _18yp9tx2p3y2pz2m19;
+ dN(3,2) =_1pxt1py * _18zm9tx2py2p3z2m19;
+ dN(4,0) =_18xm9t3x2py2pz2m19 * _1myt1pz;
+ dN(4,1) =_1mxt1pz * _18ym9tx2p3y2pz2m19;
+ dN(4,2) =_1mxt1my * _18zp9tx2py2p3z2m19;
+ dN(5,0) =_18xp9t3x2py2pz2m19 * _1myt1pz;
+ dN(5,1) =_1pxt1pz * _18ym9tx2p3y2pz2m19;
+ dN(5,2) =_1pxt1my * _18zp9tx2py2p3z2m19;
+ dN(6,0) =_18xm9t3x2py2pz2m19 * _1pyt1pz;
+ dN(6,1) =_1mxt1pz * _18yp9tx2p3y2pz2m19;
+ dN(6,2) =_1mxt1py * _18zp9tx2py2p3z2m19;
+ dN(7,0) =_18xp9t3x2py2pz2m19 * _1pyt1pz;
+ dN(7,1) =_1pxt1pz * _18yp9tx2p3y2pz2m19;
+ dN(7,2) =_1pxt1py * _18zp9tx2py2p3z2m19;
+
+ dN.topRowsDivide(8, 64.0);
+
+ btScalar _m3m9x2m2x = -_3m9x2 - _2x;
+ btScalar _p3m9x2m2x = _3m9x2 - _2x;
+ btScalar _1mx2t1m3x = _1mx2 * _1m3x;
+ btScalar _1mx2t1p3x = _1mx2 * _1p3x;
+ dN( 8,0) = _m3m9x2m2x * _1myt1mz,
+ dN( 8,1) = -_1mx2t1m3x * _1mz,
+ dN( 8,2) = -_1mx2t1m3x * _1my;
+ dN( 9,0) = _p3m9x2m2x * _1myt1mz,
+ dN( 9,1) = -_1mx2t1p3x * _1mz,
+ dN( 9,2) = -_1mx2t1p3x * _1my;
+ dN(10,0) = _m3m9x2m2x * _1myt1pz,
+ dN(10,1) = -_1mx2t1m3x * _1pz,
+ dN(10,2) = _1mx2t1m3x * _1my;
+ dN(11,0) = _p3m9x2m2x * _1myt1pz,
+ dN(11,1) = -_1mx2t1p3x * _1pz,
+ dN(11,2) = _1mx2t1p3x * _1my;
+ dN(12,0) = _m3m9x2m2x * _1pyt1mz,
+ dN(12,1) = _1mx2t1m3x * _1mz,
+ dN(12,2) = -_1mx2t1m3x * _1py;
+ dN(13,0) = _p3m9x2m2x * _1pyt1mz,
+ dN(13,1) = _1mx2t1p3x * _1mz,
+ dN(13,2) = -_1mx2t1p3x * _1py;
+ dN(14,0) = _m3m9x2m2x * _1pyt1pz,
+ dN(14,1) = _1mx2t1m3x * _1pz,
+ dN(14,2) = _1mx2t1m3x * _1py;
+ dN(15,0) = _p3m9x2m2x * _1pyt1pz,
+ dN(15,1) = _1mx2t1p3x * _1pz,
+ dN(15,2) = _1mx2t1p3x * _1py;
+
+ btScalar _m3m9y2m2y = -_3m9y2 - _2y;
+ btScalar _p3m9y2m2y = _3m9y2 - _2y;
+ btScalar _1my2t1m3y = _1my2 * _1m3y;
+ btScalar _1my2t1p3y = _1my2 * _1p3y;
+ dN(16,0) = -_1my2t1m3y * _1mz,
+ dN(16,1) = _m3m9y2m2y * _1mxt1mz,
+ dN(16,2) = -_1my2t1m3y * _1mx;
+ dN(17,0) = -_1my2t1p3y * _1mz,
+ dN(17,1) = _p3m9y2m2y * _1mxt1mz,
+ dN(17,2) = -_1my2t1p3y * _1mx;
+ dN(18,0) = _1my2t1m3y * _1mz,
+ dN(18,1) = _m3m9y2m2y * _1pxt1mz,
+ dN(18,2) = -_1my2t1m3y * _1px;
+ dN(19,0) = _1my2t1p3y * _1mz,
+ dN(19,1) = _p3m9y2m2y * _1pxt1mz,
+ dN(19,2) = -_1my2t1p3y * _1px;
+ dN(20,0) = -_1my2t1m3y * _1pz,
+ dN(20,1) = _m3m9y2m2y * _1mxt1pz,
+ dN(20,2) = _1my2t1m3y * _1mx;
+ dN(21,0) = -_1my2t1p3y * _1pz,
+ dN(21,1) = _p3m9y2m2y * _1mxt1pz,
+ dN(21,2) = _1my2t1p3y * _1mx;
+ dN(22,0) = _1my2t1m3y * _1pz,
+ dN(22,1) = _m3m9y2m2y * _1pxt1pz,
+ dN(22,2) = _1my2t1m3y * _1px;
+ dN(23,0) = _1my2t1p3y * _1pz,
+ dN(23,1) = _p3m9y2m2y * _1pxt1pz,
+ dN(23,2) = _1my2t1p3y * _1px;
+
+
+ btScalar _m3m9z2m2z = -_3m9z2 - _2z;
+ btScalar _p3m9z2m2z = _3m9z2 - _2z;
+ btScalar _1mz2t1m3z = _1mz2 * _1m3z;
+ btScalar _1mz2t1p3z = _1mz2 * _1p3z;
+ dN(24,0) = -_1mz2t1m3z * _1my,
+ dN(24,1) = -_1mz2t1m3z * _1mx,
+ dN(24,2) = _m3m9z2m2z * _1mxt1my;
+ dN(25,0) = -_1mz2t1p3z * _1my,
+ dN(25,1) = -_1mz2t1p3z * _1mx,
+ dN(25,2) = _p3m9z2m2z * _1mxt1my;
+ dN(26,0) = -_1mz2t1m3z * _1py,
+ dN(26,1) = _1mz2t1m3z * _1mx,
+ dN(26,2) = _m3m9z2m2z * _1mxt1py;
+ dN(27,0) = -_1mz2t1p3z * _1py,
+ dN(27,1) = _1mz2t1p3z * _1mx,
+ dN(27,2) = _p3m9z2m2z * _1mxt1py;
+ dN(28,0) = _1mz2t1m3z * _1my,
+ dN(28,1) = -_1mz2t1m3z * _1px,
+ dN(28,2) = _m3m9z2m2z * _1pxt1my;
+ dN(29,0) = _1mz2t1p3z * _1my,
+ dN(29,1) = -_1mz2t1p3z * _1px,
+ dN(29,2) = _p3m9z2m2z * _1pxt1my;
+ dN(30,0) = _1mz2t1m3z * _1py,
+ dN(30,1) = _1mz2t1m3z * _1px,
+ dN(30,2) = _m3m9z2m2z * _1pxt1py;
+ dN(31,0) = _1mz2t1p3z * _1py,
+ dN(31,1) = _1mz2t1p3z * _1px,
+ dN(31,2) = _p3m9z2m2z * _1pxt1py;
+
+ dN.bottomRowsMul(32u - 8u, 9.0 / 64.0);
+
+ }
+
+ return res;
+}
+
+
+
+bool btMiniSDF::interpolate(unsigned int field_id, double& dist, btVector3 const& x,
+ btVector3* gradient) const
+{
+ btAssert(m_isValid);
+ if (!m_isValid)
+ return false;
+
+ if (!m_domain.contains(x))
+ return false;
+
+ btVector3 tmpmi = ((x - m_domain.min())*(m_inv_cell_size));//.cast<unsigned int>().eval();
+ unsigned int mi[3] = {(unsigned int )tmpmi[0],(unsigned int )tmpmi[1],(unsigned int )tmpmi[2]};
+ if (mi[0] >= m_resolution[0])
+ mi[0] = m_resolution[0]-1;
+ if (mi[1] >= m_resolution[1])
+ mi[1] = m_resolution[1]-1;
+ if (mi[2] >= m_resolution[2])
+ mi[2] = m_resolution[2]-1;
+ btMultiIndex mui;
+ mui.ijk[0] = mi[0];
+ mui.ijk[1] = mi[1];
+ mui.ijk[2] = mi[2];
+ int i = multiToSingleIndex(mui);
+ unsigned int i_ = m_cell_map[field_id][i];
+ if (i_ == UINT_MAX)
+ return false;
+
+ btAlignedBox3d sd = subdomain(i);
+ i = i_;
+ btVector3 d = sd.m_max-sd.m_min;//.diagonal().eval();
+
+ btVector3 denom = (sd.max() - sd.min());
+ btVector3 c0 = btVector3(2.0,2.0,2.0)/denom;
+ btVector3 c1 = (sd.max() + sd.min())/denom;
+ btVector3 xi = (c0*x - c1);
+
+ btCell32 const& cell = m_cells[field_id][i];
+ if (!gradient)
+ {
+ //auto phi = m_coefficients[field_id][i].dot(shape_function_(xi, 0));
+ double phi = 0.0;
+ btShapeMatrix N = shape_function_(xi, 0);
+ for (unsigned int j = 0u; j < 32u; ++j)
+ {
+ unsigned int v = cell.m_cells[j];
+ double c = m_nodes[field_id][v];
+ if (c == DBL_MAX)
+ {
+ return false;;
+ }
+ phi += c * N[j];
+ }
+
+ dist = phi;
+ return true;
+ }
+
+ btShapeGradients dN;
+ btShapeMatrix N = shape_function_(xi, &dN);
+
+ double phi = 0.0;
+ gradient->setZero();
+ for (unsigned int j = 0u; j < 32u; ++j)
+ {
+ unsigned int v = cell.m_cells[j];
+ double c = m_nodes[field_id][v];
+ if (c == DBL_MAX)
+ {
+ gradient->setZero();
+ return false;
+ }
+ phi += c * N[j];
+ (*gradient)[0] += c * dN(j, 0);
+ (*gradient)[1] += c * dN(j, 1);
+ (*gradient)[2] += c * dN(j, 2);
+ }
+ (*gradient) *= c0;
+ dist = phi;
+ return true;
+}
+
diff --git a/thirdparty/bullet/BulletCollision/CollisionShapes/btMiniSDF.h b/thirdparty/bullet/BulletCollision/CollisionShapes/btMiniSDF.h
new file mode 100644
index 0000000000..3de90e4f8a
--- /dev/null
+++ b/thirdparty/bullet/BulletCollision/CollisionShapes/btMiniSDF.h
@@ -0,0 +1,134 @@
+#ifndef MINISDF_H
+#define MINISDF_H
+
+#include "LinearMath/btVector3.h"
+#include "LinearMath/btAabbUtil2.h"
+#include "LinearMath/btAlignedObjectArray.h"
+
+
+struct btMultiIndex
+{
+ unsigned int ijk[3];
+};
+
+struct btAlignedBox3d
+{
+ btVector3 m_min;
+ btVector3 m_max;
+
+ const btVector3& min() const
+ {
+ return m_min;
+ }
+
+ const btVector3& max() const
+ {
+ return m_max;
+ }
+
+
+ bool contains(const btVector3& x) const
+ {
+ return TestPointAgainstAabb2(m_min, m_max, x);
+ }
+
+ btAlignedBox3d(const btVector3& mn, const btVector3& mx)
+ :m_min(mn),
+ m_max(mx)
+ {
+ }
+
+ btAlignedBox3d()
+ {
+ }
+};
+
+struct btShapeMatrix
+{
+ double m_vec[32];
+
+ inline double& operator[](int i)
+ {
+ return m_vec[i];
+ }
+
+ inline const double& operator[](int i) const
+ {
+ return m_vec[i];
+ }
+
+};
+
+struct btShapeGradients
+{
+ btVector3 m_vec[32];
+
+ void topRowsDivide(int row, double denom)
+ {
+ for (int i=0;i<row;i++)
+ {
+ m_vec[i] /= denom;
+ }
+ }
+
+ void bottomRowsMul(int row, double val)
+ {
+ for (int i=32-row;i<32;i++)
+ {
+ m_vec[i] *= val;
+ }
+ }
+
+ inline btScalar& operator()(int i, int j)
+ {
+ return m_vec[i][j];
+ }
+};
+
+struct btCell32
+{
+ unsigned int m_cells[32];
+};
+
+struct btMiniSDF
+{
+
+ btAlignedBox3d m_domain;
+ unsigned int m_resolution[3];
+ btVector3 m_cell_size;
+ btVector3 m_inv_cell_size;
+ std::size_t m_n_cells;
+ std::size_t m_n_fields;
+ bool m_isValid;
+
+
+ btAlignedObjectArray<btAlignedObjectArray<double> > m_nodes;
+ btAlignedObjectArray<btAlignedObjectArray<btCell32 > > m_cells;
+ btAlignedObjectArray<btAlignedObjectArray<unsigned int> > m_cell_map;
+
+ btMiniSDF()
+ :m_isValid(false)
+ {
+ }
+ bool load(const char* data, int size);
+ bool isValid() const
+ {
+ return m_isValid;
+ }
+ unsigned int multiToSingleIndex(btMultiIndex const & ijk) const;
+
+ btAlignedBox3d subdomain(btMultiIndex const& ijk) const;
+
+ btMultiIndex singleToMultiIndex(unsigned int l) const;
+
+ btAlignedBox3d subdomain(unsigned int l) const;
+
+
+ btShapeMatrix
+ shape_function_(btVector3 const& xi, btShapeGradients* gradient = 0) const;
+
+ bool interpolate(unsigned int field_id, double& dist, btVector3 const& x, btVector3* gradient) const;
+};
+
+
+#endif //MINISDF_H
diff --git a/thirdparty/bullet/BulletCollision/CollisionShapes/btPolyhedralConvexShape.cpp b/thirdparty/bullet/BulletCollision/CollisionShapes/btPolyhedralConvexShape.cpp
index 4854f370f7..d51b6760fc 100644
--- a/thirdparty/bullet/BulletCollision/CollisionShapes/btPolyhedralConvexShape.cpp
+++ b/thirdparty/bullet/BulletCollision/CollisionShapes/btPolyhedralConvexShape.cpp
@@ -39,6 +39,17 @@ btPolyhedralConvexShape::~btPolyhedralConvexShape()
}
}
+void btPolyhedralConvexShape::setPolyhedralFeatures(btConvexPolyhedron& polyhedron)
+{
+ if (m_polyhedron)
+ {
+ *m_polyhedron = polyhedron;
+ } else
+ {
+ void* mem = btAlignedAlloc(sizeof(btConvexPolyhedron),16);
+ m_polyhedron = new (mem) btConvexPolyhedron(polyhedron);
+ }
+}
bool btPolyhedralConvexShape::initializePolyhedralFeatures(int shiftVerticesByMargin)
{
@@ -87,8 +98,72 @@ bool btPolyhedralConvexShape::initializePolyhedralFeatures(int shiftVerticesByMa
conv.compute(&orgVertices[0].getX(), sizeof(btVector3),orgVertices.size(),0.f,0.f);
}
+#ifndef BT_RECONSTRUCT_FACES
+
+ int numVertices = conv.vertices.size();
+ m_polyhedron->m_vertices.resize(numVertices);
+ for (int p=0;p<numVertices;p++)
+ {
+ m_polyhedron->m_vertices[p] = conv.vertices[p];
+ }
+
+ int v0, v1;
+ for (int j = 0; j < conv.faces.size(); j++)
+ {
+ btVector3 edges[3];
+ int numEdges = 0;
+ btFace combinedFace;
+ const btConvexHullComputer::Edge* edge = &conv.edges[conv.faces[j]];
+ v0 = edge->getSourceVertex();
+ int prevVertex=v0;
+ combinedFace.m_indices.push_back(v0);
+ v1 = edge->getTargetVertex();
+ while (v1 != v0)
+ {
+
+ btVector3 wa = conv.vertices[prevVertex];
+ btVector3 wb = conv.vertices[v1];
+ btVector3 newEdge = wb-wa;
+ newEdge.normalize();
+ if (numEdges<2)
+ edges[numEdges++] = newEdge;
+ //face->addIndex(v1);
+ combinedFace.m_indices.push_back(v1);
+ edge = edge->getNextEdgeOfFace();
+ prevVertex = v1;
+ int v01 = edge->getSourceVertex();
+ v1 = edge->getTargetVertex();
+
+ }
+
+ btAssert(combinedFace.m_indices.size() > 2);
+
+ btVector3 faceNormal = edges[0].cross(edges[1]);
+ faceNormal.normalize();
+
+ btScalar planeEq=1e30f;
+
+ for (int v=0;v<combinedFace.m_indices.size();v++)
+ {
+ btScalar eq = m_polyhedron->m_vertices[combinedFace.m_indices[v]].dot(faceNormal);
+ if (planeEq>eq)
+ {
+ planeEq=eq;
+ }
+ }
+ combinedFace.m_plane[0] = faceNormal.getX();
+ combinedFace.m_plane[1] = faceNormal.getY();
+ combinedFace.m_plane[2] = faceNormal.getZ();
+ combinedFace.m_plane[3] = -planeEq;
+
+ m_polyhedron->m_faces.push_back(combinedFace);
+ }
+
+
+#else//BT_RECONSTRUCT_FACES
+
btAlignedObjectArray<btVector3> faceNormals;
int numFaces = conv.faces.size();
faceNormals.resize(numFaces);
@@ -311,7 +386,9 @@ bool btPolyhedralConvexShape::initializePolyhedralFeatures(int shiftVerticesByMa
}
-
+
+#endif //BT_RECONSTRUCT_FACES
+
m_polyhedron->initialize();
return true;
diff --git a/thirdparty/bullet/BulletCollision/CollisionShapes/btPolyhedralConvexShape.h b/thirdparty/bullet/BulletCollision/CollisionShapes/btPolyhedralConvexShape.h
index 7bf8e01c1f..b7ddb6e060 100644
--- a/thirdparty/bullet/BulletCollision/CollisionShapes/btPolyhedralConvexShape.h
+++ b/thirdparty/bullet/BulletCollision/CollisionShapes/btPolyhedralConvexShape.h
@@ -43,6 +43,9 @@ public:
///experimental/work-in-progress
virtual bool initializePolyhedralFeatures(int shiftVerticesByMargin=0);
+ virtual void setPolyhedralFeatures(btConvexPolyhedron& polyhedron);
+
+
const btConvexPolyhedron* getConvexPolyhedron() const
{
return m_polyhedron;
diff --git a/thirdparty/bullet/BulletCollision/CollisionShapes/btSdfCollisionShape.cpp b/thirdparty/bullet/BulletCollision/CollisionShapes/btSdfCollisionShape.cpp
new file mode 100644
index 0000000000..828acda470
--- /dev/null
+++ b/thirdparty/bullet/BulletCollision/CollisionShapes/btSdfCollisionShape.cpp
@@ -0,0 +1,99 @@
+#include "btSdfCollisionShape.h"
+#include "btMiniSDF.h"
+#include "LinearMath/btAabbUtil2.h"
+
+struct btSdfCollisionShapeInternalData
+{
+ btVector3 m_localScaling;
+ btScalar m_margin;
+ btMiniSDF m_sdf;
+
+ btSdfCollisionShapeInternalData()
+ :m_localScaling(1,1,1),
+ m_margin(0)
+ {
+
+ }
+};
+
+bool btSdfCollisionShape::initializeSDF(const char* sdfData, int sizeInBytes)
+{
+ bool valid = m_data->m_sdf.load(sdfData, sizeInBytes);
+ return valid;
+}
+btSdfCollisionShape::btSdfCollisionShape()
+{
+ m_shapeType = SDF_SHAPE_PROXYTYPE;
+ m_data = new btSdfCollisionShapeInternalData();
+
+
+
+ //"E:/develop/bullet3/data/toys/ground_hole64_64_8.cdf");//ground_cube.cdf");
+ /*unsigned int field_id=0;
+ Eigen::Vector3d x (1,10,1);
+ Eigen::Vector3d gradient;
+ double dist = m_data->m_sdf.interpolate(field_id, x, &gradient);
+ printf("dist=%g\n", dist);
+ */
+
+}
+btSdfCollisionShape::~btSdfCollisionShape()
+{
+ delete m_data;
+}
+
+void btSdfCollisionShape::getAabb(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const
+{
+ btAssert(m_data->m_sdf.isValid());
+ btVector3 localAabbMin = m_data->m_sdf.m_domain.m_min;
+ btVector3 localAabbMax = m_data->m_sdf.m_domain.m_max;
+ btScalar margin(0);
+ btTransformAabb(localAabbMin,localAabbMax,margin,t,aabbMin,aabbMax);
+
+}
+
+
+void btSdfCollisionShape::setLocalScaling(const btVector3& scaling)
+{
+ m_data->m_localScaling = scaling;
+}
+const btVector3& btSdfCollisionShape::getLocalScaling() const
+{
+ return m_data->m_localScaling;
+}
+void btSdfCollisionShape::calculateLocalInertia(btScalar mass,btVector3& inertia) const
+{
+ inertia.setValue(0,0,0);
+}
+const char* btSdfCollisionShape::getName()const
+{
+ return "btSdfCollisionShape";
+}
+void btSdfCollisionShape::setMargin(btScalar margin)
+{
+ m_data->m_margin = margin;
+}
+btScalar btSdfCollisionShape::getMargin() const
+{
+ return m_data->m_margin;
+}
+
+void btSdfCollisionShape::processAllTriangles(btTriangleCallback* callback,const btVector3& aabbMin,const btVector3& aabbMax) const
+{
+ //not yet
+}
+
+
+bool btSdfCollisionShape::queryPoint(const btVector3& ptInSDF, btScalar& distOut, btVector3& normal)
+{
+ int field = 0;
+ btVector3 grad;
+ double dist;
+ bool hasResult = m_data->m_sdf.interpolate(field,dist, ptInSDF,&grad);
+ if (hasResult)
+ {
+ normal.setValue(grad[0],grad[1],grad[2]);
+ distOut= dist;
+ }
+ return hasResult;
+}
diff --git a/thirdparty/bullet/BulletCollision/CollisionShapes/btSdfCollisionShape.h b/thirdparty/bullet/BulletCollision/CollisionShapes/btSdfCollisionShape.h
new file mode 100644
index 0000000000..6e32db9cd8
--- /dev/null
+++ b/thirdparty/bullet/BulletCollision/CollisionShapes/btSdfCollisionShape.h
@@ -0,0 +1,30 @@
+#ifndef BT_SDF_COLLISION_SHAPE_H
+#define BT_SDF_COLLISION_SHAPE_H
+
+#include "btConcaveShape.h"
+
+class btSdfCollisionShape : public btConcaveShape
+{
+ struct btSdfCollisionShapeInternalData* m_data;
+
+public:
+
+ btSdfCollisionShape();
+ virtual ~btSdfCollisionShape();
+
+ bool initializeSDF(const char* sdfData, int sizeInBytes);
+
+ virtual void getAabb(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const;
+ virtual void setLocalScaling(const btVector3& scaling);
+ virtual const btVector3& getLocalScaling() const;
+ virtual void calculateLocalInertia(btScalar mass,btVector3& inertia) const;
+ virtual const char* getName()const;
+ virtual void setMargin(btScalar margin);
+ virtual btScalar getMargin() const;
+
+ virtual void processAllTriangles(btTriangleCallback* callback,const btVector3& aabbMin,const btVector3& aabbMax) const;
+
+ bool queryPoint(const btVector3& ptInSDF, btScalar& distOut, btVector3& normal);
+};
+
+#endif //BT_SDF_COLLISION_SHAPE_H
diff --git a/thirdparty/bullet/BulletCollision/CollisionShapes/btShapeHull.cpp b/thirdparty/bullet/BulletCollision/CollisionShapes/btShapeHull.cpp
index 3beaf86580..9f712fe555 100644
--- a/thirdparty/bullet/BulletCollision/CollisionShapes/btShapeHull.cpp
+++ b/thirdparty/bullet/BulletCollision/CollisionShapes/btShapeHull.cpp
@@ -20,6 +20,8 @@ subject to the following restrictions:
#include "LinearMath/btConvexHull.h"
#define NUM_UNITSPHERE_POINTS 42
+#define NUM_UNITSPHERE_POINTS_HIGHRES 256
+
btShapeHull::btShapeHull (const btConvexShape* shape)
{
@@ -36,9 +38,9 @@ btShapeHull::~btShapeHull ()
}
bool
-btShapeHull::buildHull (btScalar /*margin*/)
+btShapeHull::buildHull (btScalar /*margin*/, int highres)
{
- int numSampleDirections = NUM_UNITSPHERE_POINTS;
+ int numSampleDirections = highres? NUM_UNITSPHERE_POINTS_HIGHRES:NUM_UNITSPHERE_POINTS;
{
int numPDA = m_shape->getNumPreferredPenetrationDirections();
if (numPDA)
@@ -47,17 +49,17 @@ btShapeHull::buildHull (btScalar /*margin*/)
{
btVector3 norm;
m_shape->getPreferredPenetrationDirection(i,norm);
- getUnitSpherePoints()[numSampleDirections] = norm;
+ getUnitSpherePoints(highres)[numSampleDirections] = norm;
numSampleDirections++;
}
}
}
- btVector3 supportPoints[NUM_UNITSPHERE_POINTS+MAX_PREFERRED_PENETRATION_DIRECTIONS*2];
+ btVector3 supportPoints[NUM_UNITSPHERE_POINTS_HIGHRES+MAX_PREFERRED_PENETRATION_DIRECTIONS*2];
int i;
for (i = 0; i < numSampleDirections; i++)
{
- supportPoints[i] = m_shape->localGetSupportingVertex(getUnitSpherePoints()[i]);
+ supportPoints[i] = m_shape->localGetSupportingVertex(getUnitSpherePoints(highres)[i]);
}
HullDesc hd;
@@ -118,9 +120,268 @@ btShapeHull::numIndices () const
}
-btVector3* btShapeHull::getUnitSpherePoints()
+btVector3* btShapeHull::getUnitSpherePoints(int highres)
{
- static btVector3 sUnitSpherePoints[NUM_UNITSPHERE_POINTS+MAX_PREFERRED_PENETRATION_DIRECTIONS*2] =
+ static btVector3 sUnitSpherePointsHighres[NUM_UNITSPHERE_POINTS_HIGHRES + MAX_PREFERRED_PENETRATION_DIRECTIONS * 2] =
+ {
+ btVector3(btScalar(0.997604), btScalar(0.067004), btScalar(0.017144)),
+ btVector3(btScalar(0.984139), btScalar(-0.086784), btScalar(-0.154427)),
+ btVector3(btScalar(0.971065), btScalar(0.124164), btScalar(-0.203224)),
+ btVector3(btScalar(0.955844), btScalar(0.291173), btScalar(-0.037704)),
+ btVector3(btScalar(0.957405), btScalar(0.212238), btScalar(0.195157)),
+ btVector3(btScalar(0.971650), btScalar(-0.012709), btScalar(0.235561)),
+ btVector3(btScalar(0.984920), btScalar(-0.161831), btScalar(0.059695)),
+ btVector3(btScalar(0.946673), btScalar(-0.299288), btScalar(-0.117536)),
+ btVector3(btScalar(0.922670), btScalar(-0.219186), btScalar(-0.317019)),
+ btVector3(btScalar(0.928134), btScalar(-0.007265), btScalar(-0.371867)),
+ btVector3(btScalar(0.875642), btScalar(0.198434), btScalar(-0.439988)),
+ btVector3(btScalar(0.908035), btScalar(0.325975), btScalar(-0.262562)),
+ btVector3(btScalar(0.864519), btScalar(0.488706), btScalar(-0.116755)),
+ btVector3(btScalar(0.893009), btScalar(0.428046), btScalar(0.137185)),
+ btVector3(btScalar(0.857494), btScalar(0.362137), btScalar(0.364776)),
+ btVector3(btScalar(0.900815), btScalar(0.132524), btScalar(0.412987)),
+ btVector3(btScalar(0.934964), btScalar(-0.241739), btScalar(0.259179)),
+ btVector3(btScalar(0.894570), btScalar(-0.103504), btScalar(0.434263)),
+ btVector3(btScalar(0.922085), btScalar(-0.376668), btScalar(0.086241)),
+ btVector3(btScalar(0.862177), btScalar(-0.499154), btScalar(-0.085330)),
+ btVector3(btScalar(0.861982), btScalar(-0.420218), btScalar(-0.282861)),
+ btVector3(btScalar(0.818076), btScalar(-0.328256), btScalar(-0.471804)),
+ btVector3(btScalar(0.762657), btScalar(-0.179329), btScalar(-0.621124)),
+ btVector3(btScalar(0.826857), btScalar(0.019760), btScalar(-0.561786)),
+ btVector3(btScalar(0.731434), btScalar(0.206599), btScalar(-0.649817)),
+ btVector3(btScalar(0.769486), btScalar(0.379052), btScalar(-0.513770)),
+ btVector3(btScalar(0.796806), btScalar(0.507176), btScalar(-0.328145)),
+ btVector3(btScalar(0.679722), btScalar(0.684101), btScalar(-0.264123)),
+ btVector3(btScalar(0.786854), btScalar(0.614886), btScalar(0.050912)),
+ btVector3(btScalar(0.769486), btScalar(0.571141), btScalar(0.285139)),
+ btVector3(btScalar(0.707432), btScalar(0.492789), btScalar(0.506288)),
+ btVector3(btScalar(0.774560), btScalar(0.268037), btScalar(0.572652)),
+ btVector3(btScalar(0.796220), btScalar(0.031230), btScalar(0.604077)),
+ btVector3(btScalar(0.837395), btScalar(-0.320285), btScalar(0.442461)),
+ btVector3(btScalar(0.848127), btScalar(-0.450548), btScalar(0.278307)),
+ btVector3(btScalar(0.775536), btScalar(-0.206354), btScalar(0.596465)),
+ btVector3(btScalar(0.816320), btScalar(-0.567007), btScalar(0.109469)),
+ btVector3(btScalar(0.741191), btScalar(-0.668690), btScalar(-0.056832)),
+ btVector3(btScalar(0.755632), btScalar(-0.602975), btScalar(-0.254949)),
+ btVector3(btScalar(0.720311), btScalar(-0.521318), btScalar(-0.457165)),
+ btVector3(btScalar(0.670746), btScalar(-0.386583), btScalar(-0.632835)),
+ btVector3(btScalar(0.587031), btScalar(-0.219769), btScalar(-0.778836)),
+ btVector3(btScalar(0.676015), btScalar(-0.003182), btScalar(-0.736676)),
+ btVector3(btScalar(0.566932), btScalar(0.186963), btScalar(-0.802064)),
+ btVector3(btScalar(0.618254), btScalar(0.398105), btScalar(-0.677533)),
+ btVector3(btScalar(0.653964), btScalar(0.575224), btScalar(-0.490933)),
+ btVector3(btScalar(0.525367), btScalar(0.743205), btScalar(-0.414028)),
+ btVector3(btScalar(0.506439), btScalar(0.836528), btScalar(-0.208885)),
+ btVector3(btScalar(0.651427), btScalar(0.756426), btScalar(-0.056247)),
+ btVector3(btScalar(0.641670), btScalar(0.745149), btScalar(0.180908)),
+ btVector3(btScalar(0.602643), btScalar(0.687211), btScalar(0.405180)),
+ btVector3(btScalar(0.516586), btScalar(0.596999), btScalar(0.613447)),
+ btVector3(btScalar(0.602252), btScalar(0.387801), btScalar(0.697573)),
+ btVector3(btScalar(0.646549), btScalar(0.153911), btScalar(0.746956)),
+ btVector3(btScalar(0.650842), btScalar(-0.087756), btScalar(0.753983)),
+ btVector3(btScalar(0.740411), btScalar(-0.497404), btScalar(0.451830)),
+ btVector3(btScalar(0.726946), btScalar(-0.619890), btScalar(0.295093)),
+ btVector3(btScalar(0.637768), btScalar(-0.313092), btScalar(0.703624)),
+ btVector3(btScalar(0.678942), btScalar(-0.722934), btScalar(0.126645)),
+ btVector3(btScalar(0.489072), btScalar(-0.867195), btScalar(-0.092942)),
+ btVector3(btScalar(0.622742), btScalar(-0.757541), btScalar(-0.194636)),
+ btVector3(btScalar(0.596788), btScalar(-0.693576), btScalar(-0.403098)),
+ btVector3(btScalar(0.550150), btScalar(-0.582172), btScalar(-0.598287)),
+ btVector3(btScalar(0.474436), btScalar(-0.429745), btScalar(-0.768101)),
+ btVector3(btScalar(0.372574), btScalar(-0.246016), btScalar(-0.894583)),
+ btVector3(btScalar(0.480095), btScalar(-0.026513), btScalar(-0.876626)),
+ btVector3(btScalar(0.352474), btScalar(0.177242), btScalar(-0.918787)),
+ btVector3(btScalar(0.441848), btScalar(0.374386), btScalar(-0.814946)),
+ btVector3(btScalar(0.492389), btScalar(0.582223), btScalar(-0.646693)),
+ btVector3(btScalar(0.343498), btScalar(0.866080), btScalar(-0.362693)),
+ btVector3(btScalar(0.362036), btScalar(0.745149), btScalar(-0.559639)),
+ btVector3(btScalar(0.334131), btScalar(0.937044), btScalar(-0.099774)),
+ btVector3(btScalar(0.486925), btScalar(0.871718), btScalar(0.052473)),
+ btVector3(btScalar(0.452776), btScalar(0.845665), btScalar(0.281820)),
+ btVector3(btScalar(0.399503), btScalar(0.771785), btScalar(0.494576)),
+ btVector3(btScalar(0.296469), btScalar(0.673018), btScalar(0.677469)),
+ btVector3(btScalar(0.392088), btScalar(0.479179), btScalar(0.785213)),
+ btVector3(btScalar(0.452190), btScalar(0.252094), btScalar(0.855286)),
+ btVector3(btScalar(0.478339), btScalar(0.013149), btScalar(0.877928)),
+ btVector3(btScalar(0.481656), btScalar(-0.219380), btScalar(0.848259)),
+ btVector3(btScalar(0.615327), btScalar(-0.494293), btScalar(0.613837)),
+ btVector3(btScalar(0.594642), btScalar(-0.650414), btScalar(0.472325)),
+ btVector3(btScalar(0.562249), btScalar(-0.771345), btScalar(0.297631)),
+ btVector3(btScalar(0.467411), btScalar(-0.437133), btScalar(0.768231)),
+ btVector3(btScalar(0.519513), btScalar(-0.847947), btScalar(0.103808)),
+ btVector3(btScalar(0.297640), btScalar(-0.938159), btScalar(-0.176288)),
+ btVector3(btScalar(0.446727), btScalar(-0.838615), btScalar(-0.311359)),
+ btVector3(btScalar(0.331790), btScalar(-0.942437), btScalar(0.040762)),
+ btVector3(btScalar(0.413358), btScalar(-0.748403), btScalar(-0.518259)),
+ btVector3(btScalar(0.347596), btScalar(-0.621640), btScalar(-0.701737)),
+ btVector3(btScalar(0.249831), btScalar(-0.456186), btScalar(-0.853984)),
+ btVector3(btScalar(0.131772), btScalar(-0.262931), btScalar(-0.955678)),
+ btVector3(btScalar(0.247099), btScalar(-0.042261), btScalar(-0.967975)),
+ btVector3(btScalar(0.113624), btScalar(0.165965), btScalar(-0.979491)),
+ btVector3(btScalar(0.217438), btScalar(0.374580), btScalar(-0.901220)),
+ btVector3(btScalar(0.307983), btScalar(0.554615), btScalar(-0.772786)),
+ btVector3(btScalar(0.166702), btScalar(0.953181), btScalar(-0.252021)),
+ btVector3(btScalar(0.172751), btScalar(0.844499), btScalar(-0.506743)),
+ btVector3(btScalar(0.177630), btScalar(0.711125), btScalar(-0.679876)),
+ btVector3(btScalar(0.120064), btScalar(0.992260), btScalar(-0.030482)),
+ btVector3(btScalar(0.289640), btScalar(0.949098), btScalar(0.122546)),
+ btVector3(btScalar(0.239879), btScalar(0.909047), btScalar(0.340377)),
+ btVector3(btScalar(0.181142), btScalar(0.821363), btScalar(0.540641)),
+ btVector3(btScalar(0.066986), btScalar(0.719097), btScalar(0.691327)),
+ btVector3(btScalar(0.156750), btScalar(0.545478), btScalar(0.823079)),
+ btVector3(btScalar(0.236172), btScalar(0.342306), btScalar(0.909353)),
+ btVector3(btScalar(0.277541), btScalar(0.112693), btScalar(0.953856)),
+ btVector3(btScalar(0.295299), btScalar(-0.121974), btScalar(0.947415)),
+ btVector3(btScalar(0.287883), btScalar(-0.349254), btScalar(0.891591)),
+ btVector3(btScalar(0.437165), btScalar(-0.634666), btScalar(0.636869)),
+ btVector3(btScalar(0.407113), btScalar(-0.784954), btScalar(0.466664)),
+ btVector3(btScalar(0.375111), btScalar(-0.888193), btScalar(0.264839)),
+ btVector3(btScalar(0.275394), btScalar(-0.560591), btScalar(0.780723)),
+ btVector3(btScalar(0.122015), btScalar(-0.992209), btScalar(-0.024821)),
+ btVector3(btScalar(0.087866), btScalar(-0.966156), btScalar(-0.241676)),
+ btVector3(btScalar(0.239489), btScalar(-0.885665), btScalar(-0.397437)),
+ btVector3(btScalar(0.167287), btScalar(-0.965184), btScalar(0.200817)),
+ btVector3(btScalar(0.201632), btScalar(-0.776789), btScalar(-0.596335)),
+ btVector3(btScalar(0.122015), btScalar(-0.637971), btScalar(-0.760098)),
+ btVector3(btScalar(0.008054), btScalar(-0.464741), btScalar(-0.885214)),
+ btVector3(btScalar(-0.116054), btScalar(-0.271096), btScalar(-0.955482)),
+ btVector3(btScalar(-0.000727), btScalar(-0.056065), btScalar(-0.998424)),
+ btVector3(btScalar(-0.134007), btScalar(0.152939), btScalar(-0.978905)),
+ btVector3(btScalar(-0.025900), btScalar(0.366026), btScalar(-0.930108)),
+ btVector3(btScalar(0.081231), btScalar(0.557337), btScalar(-0.826072)),
+ btVector3(btScalar(-0.002874), btScalar(0.917213), btScalar(-0.398023)),
+ btVector3(btScalar(-0.050683), btScalar(0.981761), btScalar(-0.182534)),
+ btVector3(btScalar(-0.040536), btScalar(0.710153), btScalar(-0.702713)),
+ btVector3(btScalar(-0.139081), btScalar(0.827973), btScalar(-0.543048)),
+ btVector3(btScalar(-0.101029), btScalar(0.994010), btScalar(0.041152)),
+ btVector3(btScalar(0.069328), btScalar(0.978067), btScalar(0.196133)),
+ btVector3(btScalar(0.023860), btScalar(0.911380), btScalar(0.410645)),
+ btVector3(btScalar(-0.153521), btScalar(0.736789), btScalar(0.658145)),
+ btVector3(btScalar(-0.070002), btScalar(0.591750), btScalar(0.802780)),
+ btVector3(btScalar(0.002590), btScalar(0.312948), btScalar(0.949562)),
+ btVector3(btScalar(0.090988), btScalar(-0.020680), btScalar(0.995627)),
+ btVector3(btScalar(0.088842), btScalar(-0.250099), btScalar(0.964006)),
+ btVector3(btScalar(0.083378), btScalar(-0.470185), btScalar(0.878318)),
+ btVector3(btScalar(0.240074), btScalar(-0.749764), btScalar(0.616374)),
+ btVector3(btScalar(0.210803), btScalar(-0.885860), btScalar(0.412987)),
+ btVector3(btScalar(0.077524), btScalar(-0.660524), btScalar(0.746565)),
+ btVector3(btScalar(-0.096736), btScalar(-0.990070), btScalar(-0.100945)),
+ btVector3(btScalar(-0.052634), btScalar(-0.990264), btScalar(0.127426)),
+ btVector3(btScalar(-0.106102), btScalar(-0.938354), btScalar(-0.328340)),
+ btVector3(btScalar(0.013323), btScalar(-0.863112), btScalar(-0.504596)),
+ btVector3(btScalar(-0.002093), btScalar(-0.936993), btScalar(0.349161)),
+ btVector3(btScalar(-0.106297), btScalar(-0.636610), btScalar(-0.763612)),
+ btVector3(btScalar(-0.229430), btScalar(-0.463769), btScalar(-0.855546)),
+ btVector3(btScalar(-0.245236), btScalar(-0.066175), btScalar(-0.966999)),
+ btVector3(btScalar(-0.351587), btScalar(-0.270513), btScalar(-0.896145)),
+ btVector3(btScalar(-0.370906), btScalar(0.133108), btScalar(-0.918982)),
+ btVector3(btScalar(-0.264360), btScalar(0.346000), btScalar(-0.900049)),
+ btVector3(btScalar(-0.151375), btScalar(0.543728), btScalar(-0.825291)),
+ btVector3(btScalar(-0.218697), btScalar(0.912741), btScalar(-0.344346)),
+ btVector3(btScalar(-0.274507), btScalar(0.953764), btScalar(-0.121635)),
+ btVector3(btScalar(-0.259677), btScalar(0.692266), btScalar(-0.673044)),
+ btVector3(btScalar(-0.350416), btScalar(0.798810), btScalar(-0.488786)),
+ btVector3(btScalar(-0.320170), btScalar(0.941127), btScalar(0.108297)),
+ btVector3(btScalar(-0.147667), btScalar(0.952792), btScalar(0.265034)),
+ btVector3(btScalar(-0.188061), btScalar(0.860636), btScalar(0.472910)),
+ btVector3(btScalar(-0.370906), btScalar(0.739900), btScalar(0.560941)),
+ btVector3(btScalar(-0.297143), btScalar(0.585334), btScalar(0.754178)),
+ btVector3(btScalar(-0.189622), btScalar(0.428241), btScalar(0.883393)),
+ btVector3(btScalar(-0.091272), btScalar(0.098695), btScalar(0.990747)),
+ btVector3(btScalar(-0.256945), btScalar(0.228375), btScalar(0.938827)),
+ btVector3(btScalar(-0.111761), btScalar(-0.133251), btScalar(0.984696)),
+ btVector3(btScalar(-0.118006), btScalar(-0.356253), btScalar(0.926725)),
+ btVector3(btScalar(-0.119372), btScalar(-0.563896), btScalar(0.817029)),
+ btVector3(btScalar(0.041228), btScalar(-0.833949), btScalar(0.550010)),
+ btVector3(btScalar(-0.121909), btScalar(-0.736543), btScalar(0.665172)),
+ btVector3(btScalar(-0.307681), btScalar(-0.931160), btScalar(-0.195026)),
+ btVector3(btScalar(-0.283679), btScalar(-0.957990), btScalar(0.041348)),
+ btVector3(btScalar(-0.227284), btScalar(-0.935243), btScalar(0.270890)),
+ btVector3(btScalar(-0.293436), btScalar(-0.858252), btScalar(-0.420860)),
+ btVector3(btScalar(-0.175767), btScalar(-0.780677), btScalar(-0.599262)),
+ btVector3(btScalar(-0.170108), btScalar(-0.858835), btScalar(0.482865)),
+ btVector3(btScalar(-0.332854), btScalar(-0.635055), btScalar(-0.696857)),
+ btVector3(btScalar(-0.447791), btScalar(-0.445299), btScalar(-0.775128)),
+ btVector3(btScalar(-0.470622), btScalar(-0.074146), btScalar(-0.879164)),
+ btVector3(btScalar(-0.639417), btScalar(-0.340505), btScalar(-0.689049)),
+ btVector3(btScalar(-0.598438), btScalar(0.104722), btScalar(-0.794256)),
+ btVector3(btScalar(-0.488575), btScalar(0.307699), btScalar(-0.816313)),
+ btVector3(btScalar(-0.379882), btScalar(0.513592), btScalar(-0.769077)),
+ btVector3(btScalar(-0.425740), btScalar(0.862775), btScalar(-0.272516)),
+ btVector3(btScalar(-0.480769), btScalar(0.875412), btScalar(-0.048439)),
+ btVector3(btScalar(-0.467890), btScalar(0.648716), btScalar(-0.600043)),
+ btVector3(btScalar(-0.543799), btScalar(0.730956), btScalar(-0.411881)),
+ btVector3(btScalar(-0.516284), btScalar(0.838277), btScalar(0.174076)),
+ btVector3(btScalar(-0.353343), btScalar(0.876384), btScalar(0.326519)),
+ btVector3(btScalar(-0.572875), btScalar(0.614497), btScalar(0.542007)),
+ btVector3(btScalar(-0.503600), btScalar(0.497261), btScalar(0.706161)),
+ btVector3(btScalar(-0.530920), btScalar(0.754870), btScalar(0.384685)),
+ btVector3(btScalar(-0.395884), btScalar(0.366414), btScalar(0.841818)),
+ btVector3(btScalar(-0.300656), btScalar(0.001678), btScalar(0.953661)),
+ btVector3(btScalar(-0.461060), btScalar(0.146912), btScalar(0.875000)),
+ btVector3(btScalar(-0.315486), btScalar(-0.232212), btScalar(0.919893)),
+ btVector3(btScalar(-0.323682), btScalar(-0.449187), btScalar(0.832644)),
+ btVector3(btScalar(-0.318999), btScalar(-0.639527), btScalar(0.699134)),
+ btVector3(btScalar(-0.496771), btScalar(-0.866029), btScalar(-0.055271)),
+ btVector3(btScalar(-0.496771), btScalar(-0.816257), btScalar(-0.294377)),
+ btVector3(btScalar(-0.456377), btScalar(-0.869528), btScalar(0.188130)),
+ btVector3(btScalar(-0.380858), btScalar(-0.827144), btScalar(0.412792)),
+ btVector3(btScalar(-0.449352), btScalar(-0.727405), btScalar(-0.518259)),
+ btVector3(btScalar(-0.570533), btScalar(-0.551064), btScalar(-0.608632)),
+ btVector3(btScalar(-0.656394), btScalar(-0.118280), btScalar(-0.744874)),
+ btVector3(btScalar(-0.756696), btScalar(-0.438105), btScalar(-0.484882)),
+ btVector3(btScalar(-0.801773), btScalar(-0.204798), btScalar(-0.561005)),
+ btVector3(btScalar(-0.785186), btScalar(0.038618), btScalar(-0.617805)),
+ btVector3(btScalar(-0.709082), btScalar(0.262399), btScalar(-0.654306)),
+ btVector3(btScalar(-0.583412), btScalar(0.462265), btScalar(-0.667383)),
+ btVector3(btScalar(-0.616001), btScalar(0.761286), btScalar(-0.201272)),
+ btVector3(btScalar(-0.660687), btScalar(0.750204), btScalar(0.020072)),
+ btVector3(btScalar(-0.744987), btScalar(0.435823), btScalar(-0.504791)),
+ btVector3(btScalar(-0.713765), btScalar(0.605554), btScalar(-0.351373)),
+ btVector3(btScalar(-0.686251), btScalar(0.687600), btScalar(0.236927)),
+ btVector3(btScalar(-0.680201), btScalar(0.429407), btScalar(0.593732)),
+ btVector3(btScalar(-0.733474), btScalar(0.546450), btScalar(0.403814)),
+ btVector3(btScalar(-0.591023), btScalar(0.292923), btScalar(0.751445)),
+ btVector3(btScalar(-0.500283), btScalar(-0.080757), btScalar(0.861922)),
+ btVector3(btScalar(-0.643710), btScalar(0.070115), btScalar(0.761985)),
+ btVector3(btScalar(-0.506332), btScalar(-0.308425), btScalar(0.805122)),
+ btVector3(btScalar(-0.503015), btScalar(-0.509847), btScalar(0.697573)),
+ btVector3(btScalar(-0.482525), btScalar(-0.682105), btScalar(0.549229)),
+ btVector3(btScalar(-0.680396), btScalar(-0.716323), btScalar(-0.153451)),
+ btVector3(btScalar(-0.658346), btScalar(-0.746264), btScalar(0.097562)),
+ btVector3(btScalar(-0.653272), btScalar(-0.646915), btScalar(-0.392948)),
+ btVector3(btScalar(-0.590828), btScalar(-0.732655), btScalar(0.337645)),
+ btVector3(btScalar(-0.819140), btScalar(-0.518013), btScalar(-0.246166)),
+ btVector3(btScalar(-0.900513), btScalar(-0.282178), btScalar(-0.330487)),
+ btVector3(btScalar(-0.914953), btScalar(-0.028652), btScalar(-0.402122)),
+ btVector3(btScalar(-0.859924), btScalar(0.220209), btScalar(-0.459898)),
+ btVector3(btScalar(-0.777185), btScalar(0.613720), btScalar(-0.137836)),
+ btVector3(btScalar(-0.805285), btScalar(0.586889), btScalar(0.082728)),
+ btVector3(btScalar(-0.872413), btScalar(0.406077), btScalar(-0.271735)),
+ btVector3(btScalar(-0.859339), btScalar(0.448072), btScalar(0.246101)),
+ btVector3(btScalar(-0.757671), btScalar(0.216320), btScalar(0.615594)),
+ btVector3(btScalar(-0.826165), btScalar(0.348139), btScalar(0.442851)),
+ btVector3(btScalar(-0.671810), btScalar(-0.162803), btScalar(0.722557)),
+ btVector3(btScalar(-0.796504), btScalar(-0.004543), btScalar(0.604468)),
+ btVector3(btScalar(-0.676298), btScalar(-0.378223), btScalar(0.631794)),
+ btVector3(btScalar(-0.668883), btScalar(-0.558258), btScalar(0.490673)),
+ btVector3(btScalar(-0.821287), btScalar(-0.570118), btScalar(0.006994)),
+ btVector3(btScalar(-0.767428), btScalar(-0.587810), btScalar(0.255470)),
+ btVector3(btScalar(-0.933296), btScalar(-0.349837), btScalar(-0.079865)),
+ btVector3(btScalar(-0.982667), btScalar(-0.100393), btScalar(-0.155208)),
+ btVector3(btScalar(-0.961396), btScalar(0.160910), btScalar(-0.222938)),
+ btVector3(btScalar(-0.934858), btScalar(0.354555), btScalar(-0.006864)),
+ btVector3(btScalar(-0.941687), btScalar(0.229736), btScalar(0.245711)),
+ btVector3(btScalar(-0.884317), btScalar(0.131552), btScalar(0.447536)),
+ btVector3(btScalar(-0.810359), btScalar(-0.219769), btScalar(0.542788)),
+ btVector3(btScalar(-0.915929), btScalar(-0.210048), btScalar(0.341743)),
+ btVector3(btScalar(-0.816799), btScalar(-0.407192), btScalar(0.408303)),
+ btVector3(btScalar(-0.903050), btScalar(-0.392416), btScalar(0.174076)),
+ btVector3(btScalar(-0.980325), btScalar(-0.170969), btScalar(0.096586)),
+ btVector3(btScalar(-0.995936), btScalar(0.084891), btScalar(0.029441)),
+ btVector3(btScalar(-0.960031), btScalar(0.002650), btScalar(0.279283)),
+ };
+ static btVector3 sUnitSpherePoints[NUM_UNITSPHERE_POINTS + MAX_PREFERRED_PENETRATION_DIRECTIONS * 2] =
{
btVector3(btScalar(0.000000) , btScalar(-0.000000),btScalar(-1.000000)),
btVector3(btScalar(0.723608) , btScalar(-0.525725),btScalar(-0.447219)),
@@ -165,6 +426,8 @@ btVector3* btShapeHull::getUnitSpherePoints()
btVector3(btScalar(-0.425323) , btScalar(0.309011),btScalar(0.850654)),
btVector3(btScalar(0.162456) , btScalar(0.499995),btScalar(0.850654))
};
+ if (highres)
+ return sUnitSpherePointsHighres;
return sUnitSpherePoints;
}
diff --git a/thirdparty/bullet/BulletCollision/CollisionShapes/btShapeHull.h b/thirdparty/bullet/BulletCollision/CollisionShapes/btShapeHull.h
index e959f198b6..78ea4b6501 100644
--- a/thirdparty/bullet/BulletCollision/CollisionShapes/btShapeHull.h
+++ b/thirdparty/bullet/BulletCollision/CollisionShapes/btShapeHull.h
@@ -34,7 +34,7 @@ protected:
unsigned int m_numIndices;
const btConvexShape* m_shape;
- static btVector3* getUnitSpherePoints();
+ static btVector3* getUnitSpherePoints(int highres=0);
public:
BT_DECLARE_ALIGNED_ALLOCATOR();
@@ -42,7 +42,7 @@ public:
btShapeHull (const btConvexShape* shape);
~btShapeHull ();
- bool buildHull (btScalar margin);
+ bool buildHull (btScalar margin, int highres=0);
int numTriangles () const;
int numVertices () const;
diff --git a/thirdparty/bullet/BulletCollision/CollisionShapes/btStaticPlaneShape.cpp b/thirdparty/bullet/BulletCollision/CollisionShapes/btStaticPlaneShape.cpp
index d17141e3f2..b5e0e716d4 100644
--- a/thirdparty/bullet/BulletCollision/CollisionShapes/btStaticPlaneShape.cpp
+++ b/thirdparty/bullet/BulletCollision/CollisionShapes/btStaticPlaneShape.cpp
@@ -69,8 +69,6 @@ void btStaticPlaneShape::processAllTriangles(btTriangleCallback* callback,const
//tangentDir0/tangentDir1 can be precalculated
btPlaneSpace1(m_planeNormal,tangentDir0,tangentDir1);
- btVector3 supVertex0,supVertex1;
-
btVector3 projectedCenter = center - (m_planeNormal.dot(center) - m_planeConstant)*m_planeNormal;
btVector3 triangle[3];
diff --git a/thirdparty/bullet/BulletCollision/CollisionShapes/btTriangleIndexVertexArray.h b/thirdparty/bullet/BulletCollision/CollisionShapes/btTriangleIndexVertexArray.h
index 9e1544e87a..b7a6f74361 100644
--- a/thirdparty/bullet/BulletCollision/CollisionShapes/btTriangleIndexVertexArray.h
+++ b/thirdparty/bullet/BulletCollision/CollisionShapes/btTriangleIndexVertexArray.h
@@ -63,7 +63,7 @@ typedef btAlignedObjectArray<btIndexedMesh> IndexedMeshArray;
///The btTriangleIndexVertexArray allows to access multiple triangle meshes, by indexing into existing triangle/index arrays.
///Additional meshes can be added using addIndexedMesh
-///No duplcate is made of the vertex/index data, it only indexes into external vertex/index arrays.
+///No duplicate is made of the vertex/index data, it only indexes into external vertex/index arrays.
///So keep those arrays around during the lifetime of this btTriangleIndexVertexArray.
ATTRIBUTE_ALIGNED16( class) btTriangleIndexVertexArray : public btStridingMeshInterface
{
diff --git a/thirdparty/bullet/BulletCollision/NarrowPhaseCollision/btContinuousConvexCollision.cpp b/thirdparty/bullet/BulletCollision/NarrowPhaseCollision/btContinuousConvexCollision.cpp
index 940282f576..3481fec850 100644
--- a/thirdparty/bullet/BulletCollision/NarrowPhaseCollision/btContinuousConvexCollision.cpp
+++ b/thirdparty/bullet/BulletCollision/NarrowPhaseCollision/btContinuousConvexCollision.cpp
@@ -113,12 +113,7 @@ bool btContinuousConvexCollision::calcTimeOfImpact(
if ((relLinVelocLength+maxAngularProjectedVelocity) == 0.f)
return false;
-
-
btScalar lambda = btScalar(0.);
- btVector3 v(1,0,0);
-
- int maxIter = MAX_ITERATIONS;
btVector3 n;
n.setValue(btScalar(0.),btScalar(0.),btScalar(0.));
@@ -137,8 +132,7 @@ bool btContinuousConvexCollision::calcTimeOfImpact(
btPointCollector pointCollector1;
- {
-
+ {
computeClosestPoints(fromA,fromB,pointCollector1);
hasResult = pointCollector1.m_hasResult;
@@ -172,28 +166,20 @@ bool btContinuousConvexCollision::calcTimeOfImpact(
dLambda = dist / (projectedLinearVelocity+ maxAngularProjectedVelocity);
-
-
- lambda = lambda + dLambda;
+ lambda += dLambda;
- if (lambda > btScalar(1.))
+ if (lambda > btScalar(1.) || lambda < btScalar(0.))
return false;
- if (lambda < btScalar(0.))
- return false;
-
-
//todo: next check with relative epsilon
if (lambda <= lastLambda)
{
return false;
//n.setValue(0,0,0);
- break;
+ //break;
}
lastLambda = lambda;
-
-
//interpolate to next lambda
btTransform interpolatedTransA,interpolatedTransB,relativeTrans;
@@ -223,7 +209,7 @@ bool btContinuousConvexCollision::calcTimeOfImpact(
}
numIter++;
- if (numIter > maxIter)
+ if (numIter > MAX_ITERATIONS)
{
result.reportFailure(-2, numIter);
return false;
@@ -237,6 +223,5 @@ bool btContinuousConvexCollision::calcTimeOfImpact(
}
return false;
-
}
diff --git a/thirdparty/bullet/BulletCollision/NarrowPhaseCollision/btContinuousConvexCollision.h b/thirdparty/bullet/BulletCollision/NarrowPhaseCollision/btContinuousConvexCollision.h
index bdc0572f75..528b5e0101 100644
--- a/thirdparty/bullet/BulletCollision/NarrowPhaseCollision/btContinuousConvexCollision.h
+++ b/thirdparty/bullet/BulletCollision/NarrowPhaseCollision/btContinuousConvexCollision.h
@@ -25,7 +25,7 @@ class btStaticPlaneShape;
/// btContinuousConvexCollision implements angular and linear time of impact for convex objects.
/// Based on Brian Mirtich's Conservative Advancement idea (PhD thesis).
-/// Algorithm operates in worldspace, in order to keep inbetween motion globally consistent.
+/// Algorithm operates in worldspace, in order to keep in between motion globally consistent.
/// It uses GJK at the moment. Future improvement would use minkowski sum / supporting vertex, merging innerloops
class btContinuousConvexCollision : public btConvexCast
{
diff --git a/thirdparty/bullet/BulletCollision/NarrowPhaseCollision/btGjkEpaPenetrationDepthSolver.cpp b/thirdparty/bullet/BulletCollision/NarrowPhaseCollision/btGjkEpaPenetrationDepthSolver.cpp
index 572ec36f56..b79f49d611 100644
--- a/thirdparty/bullet/BulletCollision/NarrowPhaseCollision/btGjkEpaPenetrationDepthSolver.cpp
+++ b/thirdparty/bullet/BulletCollision/NarrowPhaseCollision/btGjkEpaPenetrationDepthSolver.cpp
@@ -21,46 +21,64 @@ subject to the following restrictions:
#include "BulletCollision/NarrowPhaseCollision/btGjkEpa2.h"
-bool btGjkEpaPenetrationDepthSolver::calcPenDepth( btSimplexSolverInterface& simplexSolver,
- const btConvexShape* pConvexA, const btConvexShape* pConvexB,
- const btTransform& transformA, const btTransform& transformB,
- btVector3& v, btVector3& wWitnessOnA, btVector3& wWitnessOnB,
- class btIDebugDraw* debugDraw)
+bool btGjkEpaPenetrationDepthSolver::calcPenDepth(btSimplexSolverInterface& simplexSolver,
+ const btConvexShape* pConvexA, const btConvexShape* pConvexB,
+ const btTransform& transformA, const btTransform& transformB,
+ btVector3& v, btVector3& wWitnessOnA, btVector3& wWitnessOnB,
+ class btIDebugDraw* debugDraw)
{
(void)debugDraw;
(void)v;
(void)simplexSolver;
-// const btScalar radialmargin(btScalar(0.));
-
- btVector3 guessVector(transformB.getOrigin()-transformA.getOrigin());
- btGjkEpaSolver2::sResults results;
-
+ btVector3 guessVectors[] = {
+ btVector3(transformB.getOrigin() - transformA.getOrigin()).normalized(),
+ btVector3(transformA.getOrigin() - transformB.getOrigin()).normalized(),
+ btVector3(0, 0, 1),
+ btVector3(0, 1, 0),
+ btVector3(1, 0, 0),
+ btVector3(1, 1, 0),
+ btVector3(1, 1, 1),
+ btVector3(0, 1, 1),
+ btVector3(1, 0, 1),
+ };
- if(btGjkEpaSolver2::Penetration(pConvexA,transformA,
- pConvexB,transformB,
- guessVector,results))
-
- {
- // debugDraw->drawLine(results.witnesses[1],results.witnesses[1]+results.normal,btVector3(255,0,0));
- //resultOut->addContactPoint(results.normal,results.witnesses[1],-results.depth);
- wWitnessOnA = results.witnesses[0];
- wWitnessOnB = results.witnesses[1];
- v = results.normal;
- return true;
- } else
+ int numVectors = sizeof(guessVectors) / sizeof(btVector3);
+
+ for (int i = 0; i < numVectors; i++)
{
- if(btGjkEpaSolver2::Distance(pConvexA,transformA,pConvexB,transformB,guessVector,results))
+ simplexSolver.reset();
+ btVector3 guessVector = guessVectors[i];
+
+ btGjkEpaSolver2::sResults results;
+
+ if (btGjkEpaSolver2::Penetration(pConvexA, transformA,
+ pConvexB, transformB,
+ guessVector, results))
+
{
wWitnessOnA = results.witnesses[0];
wWitnessOnB = results.witnesses[1];
v = results.normal;
- return false;
+ return true;
+ }
+ else
+ {
+ if (btGjkEpaSolver2::Distance(pConvexA, transformA, pConvexB, transformB, guessVector, results))
+ {
+ wWitnessOnA = results.witnesses[0];
+ wWitnessOnB = results.witnesses[1];
+ v = results.normal;
+ return false;
+ }
}
}
+ //failed to find a distance/penetration
+ wWitnessOnA.setValue(0, 0, 0);
+ wWitnessOnB.setValue(0, 0, 0);
+ v.setValue(0, 0, 0);
return false;
}
-
diff --git a/thirdparty/bullet/BulletCollision/NarrowPhaseCollision/btGjkPairDetector.cpp b/thirdparty/bullet/BulletCollision/NarrowPhaseCollision/btGjkPairDetector.cpp
index 257b026d9b..a0b825f0e8 100644
--- a/thirdparty/bullet/BulletCollision/NarrowPhaseCollision/btGjkPairDetector.cpp
+++ b/thirdparty/bullet/BulletCollision/NarrowPhaseCollision/btGjkPairDetector.cpp
@@ -1,4 +1,4 @@
-/*
+/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
@@ -32,7 +32,7 @@ subject to the following restrictions:
//must be above the machine epsilon
#ifdef BT_USE_DOUBLE_PRECISION
#define REL_ERROR2 btScalar(1.0e-12)
- btScalar gGjkEpaPenetrationTolerance = 1e-7;
+ btScalar gGjkEpaPenetrationTolerance = 1.0e-12;
#else
#define REL_ERROR2 btScalar(1.0e-6)
btScalar gGjkEpaPenetrationTolerance = 0.001;
@@ -83,6 +83,593 @@ void btGjkPairDetector::getClosestPoints(const ClosestPointInput& input,Result&
getClosestPointsNonVirtual(input,output,debugDraw);
}
+static void btComputeSupport(const btConvexShape* convexA, const btTransform& localTransA, const btConvexShape* convexB, const btTransform& localTransB, const btVector3& dir, bool check2d, btVector3& supAworld, btVector3& supBworld, btVector3& aMinb)
+{
+ btVector3 seperatingAxisInA = (dir)* localTransA.getBasis();
+ btVector3 seperatingAxisInB = (-dir)* localTransB.getBasis();
+
+ btVector3 pInANoMargin = convexA->localGetSupportVertexWithoutMarginNonVirtual(seperatingAxisInA);
+ btVector3 qInBNoMargin = convexB->localGetSupportVertexWithoutMarginNonVirtual(seperatingAxisInB);
+
+ btVector3 pInA = pInANoMargin;
+ btVector3 qInB = qInBNoMargin;
+
+ supAworld = localTransA(pInA);
+ supBworld = localTransB(qInB);
+
+ if (check2d)
+ {
+ supAworld[2] = 0.f;
+ supBworld[2] = 0.f;
+ }
+
+ aMinb = supAworld - supBworld;
+}
+
+struct btSupportVector
+{
+ btVector3 v; //!< Support point in minkowski sum
+ btVector3 v1; //!< Support point in obj1
+ btVector3 v2; //!< Support point in obj2
+};
+
+struct btSimplex
+{
+ btSupportVector ps[4];
+ int last; //!< index of last added point
+};
+
+static btVector3 ccd_vec3_origin(0, 0, 0);
+
+
+inline void btSimplexInit(btSimplex *s)
+{
+ s->last = -1;
+}
+
+inline int btSimplexSize(const btSimplex *s)
+{
+ return s->last + 1;
+}
+
+inline const btSupportVector *btSimplexPoint(const btSimplex *s, int idx)
+{
+ // here is no check on boundaries
+ return &s->ps[idx];
+}
+inline void btSupportCopy(btSupportVector *d, const btSupportVector *s)
+{
+ *d = *s;
+}
+
+inline void btVec3Copy(btVector3 *v, const btVector3* w)
+{
+ *v = *w;
+}
+
+inline void ccdVec3Add(btVector3*v, const btVector3*w)
+{
+ v->m_floats[0] += w->m_floats[0];
+ v->m_floats[1] += w->m_floats[1];
+ v->m_floats[2] += w->m_floats[2];
+}
+
+
+inline void ccdVec3Sub(btVector3 *v, const btVector3 *w)
+{
+ *v -= *w;
+}
+inline void btVec3Sub2(btVector3 *d, const btVector3 *v, const btVector3 *w)
+{
+ *d = (*v) - (*w);
+
+}
+inline btScalar btVec3Dot(const btVector3 *a, const btVector3 *b)
+{
+ btScalar dot;
+ dot = a->dot(*b);
+
+ return dot;
+}
+
+inline btScalar ccdVec3Dist2(const btVector3 *a, const btVector3*b)
+{
+ btVector3 ab;
+ btVec3Sub2(&ab, a, b);
+ return btVec3Dot(&ab, &ab);
+}
+
+
+inline void btVec3Scale(btVector3 *d, btScalar k)
+{
+ d->m_floats[0] *= k;
+ d->m_floats[1] *= k;
+ d->m_floats[2] *= k;
+}
+
+inline void btVec3Cross(btVector3 *d, const btVector3 *a, const btVector3 *b)
+{
+ d->m_floats[0] = (a->m_floats[1] * b->m_floats[2]) - (a->m_floats[2] * b->m_floats[1]);
+ d->m_floats[1] = (a->m_floats[2] * b->m_floats[0]) - (a->m_floats[0] * b->m_floats[2]);
+ d->m_floats[2] = (a->m_floats[0] * b->m_floats[1]) - (a->m_floats[1] * b->m_floats[0]);
+}
+
+inline void btTripleCross(const btVector3 *a, const btVector3 *b,
+ const btVector3 *c, btVector3 *d)
+{
+ btVector3 e;
+ btVec3Cross(&e, a, b);
+ btVec3Cross(d, &e, c);
+}
+
+inline int ccdEq(btScalar _a, btScalar _b)
+{
+ btScalar ab;
+ btScalar a, b;
+
+ ab = btFabs(_a - _b);
+ if (btFabs(ab) < SIMD_EPSILON)
+ return 1;
+
+ a = btFabs(_a);
+ b = btFabs(_b);
+ if (b > a) {
+ return ab < SIMD_EPSILON * b;
+ }
+ else {
+ return ab < SIMD_EPSILON * a;
+ }
+}
+
+btScalar ccdVec3X(const btVector3* v)
+{
+ return v->x();
+}
+
+btScalar ccdVec3Y(const btVector3* v)
+{
+ return v->y();
+}
+
+btScalar ccdVec3Z(const btVector3* v)
+{
+ return v->z();
+}
+inline int btVec3Eq(const btVector3 *a, const btVector3 *b)
+{
+ return ccdEq(ccdVec3X(a), ccdVec3X(b))
+ && ccdEq(ccdVec3Y(a), ccdVec3Y(b))
+ && ccdEq(ccdVec3Z(a), ccdVec3Z(b));
+}
+
+
+inline void btSimplexAdd(btSimplex *s, const btSupportVector *v)
+{
+ // here is no check on boundaries in sake of speed
+ ++s->last;
+ btSupportCopy(s->ps + s->last, v);
+}
+
+
+inline void btSimplexSet(btSimplex *s, size_t pos, const btSupportVector *a)
+{
+ btSupportCopy(s->ps + pos, a);
+}
+
+inline void btSimplexSetSize(btSimplex *s, int size)
+{
+ s->last = size - 1;
+}
+
+inline const btSupportVector *ccdSimplexLast(const btSimplex *s)
+{
+ return btSimplexPoint(s, s->last);
+}
+
+inline int ccdSign(btScalar val)
+{
+ if (btFuzzyZero(val)) {
+ return 0;
+ }
+ else if (val < btScalar(0)) {
+ return -1;
+ }
+ return 1;
+}
+
+
+inline btScalar btVec3PointSegmentDist2(const btVector3 *P,
+ const btVector3 *x0,
+ const btVector3 *b,
+ btVector3 *witness)
+{
+ // The computation comes from solving equation of segment:
+ // S(t) = x0 + t.d
+ // where - x0 is initial point of segment
+ // - d is direction of segment from x0 (|d| > 0)
+ // - t belongs to <0, 1> interval
+ //
+ // Than, distance from a segment to some point P can be expressed:
+ // D(t) = |x0 + t.d - P|^2
+ // which is distance from any point on segment. Minimization
+ // of this function brings distance from P to segment.
+ // Minimization of D(t) leads to simple quadratic equation that's
+ // solving is straightforward.
+ //
+ // Bonus of this method is witness point for free.
+
+ btScalar dist, t;
+ btVector3 d, a;
+
+ // direction of segment
+ btVec3Sub2(&d, b, x0);
+
+ // precompute vector from P to x0
+ btVec3Sub2(&a, x0, P);
+
+ t = -btScalar(1.) * btVec3Dot(&a, &d);
+ t /= btVec3Dot(&d, &d);
+
+ if (t < btScalar(0) || btFuzzyZero(t)) {
+ dist = ccdVec3Dist2(x0, P);
+ if (witness)
+ btVec3Copy(witness, x0);
+ }
+ else if (t > btScalar(1) || ccdEq(t, btScalar(1))) {
+ dist = ccdVec3Dist2(b, P);
+ if (witness)
+ btVec3Copy(witness, b);
+ }
+ else {
+ if (witness) {
+ btVec3Copy(witness, &d);
+ btVec3Scale(witness, t);
+ ccdVec3Add(witness, x0);
+ dist = ccdVec3Dist2(witness, P);
+ }
+ else {
+ // recycling variables
+ btVec3Scale(&d, t);
+ ccdVec3Add(&d, &a);
+ dist = btVec3Dot(&d, &d);
+ }
+ }
+
+ return dist;
+}
+
+
+btScalar btVec3PointTriDist2(const btVector3 *P,
+ const btVector3 *x0, const btVector3 *B,
+ const btVector3 *C,
+ btVector3 *witness)
+{
+ // Computation comes from analytic expression for triangle (x0, B, C)
+ // T(s, t) = x0 + s.d1 + t.d2, where d1 = B - x0 and d2 = C - x0 and
+ // Then equation for distance is:
+ // D(s, t) = | T(s, t) - P |^2
+ // This leads to minimization of quadratic function of two variables.
+ // The solution from is taken only if s is between 0 and 1, t is
+ // between 0 and 1 and t + s < 1, otherwise distance from segment is
+ // computed.
+
+ btVector3 d1, d2, a;
+ double u, v, w, p, q, r;
+ double s, t, dist, dist2;
+ btVector3 witness2;
+
+ btVec3Sub2(&d1, B, x0);
+ btVec3Sub2(&d2, C, x0);
+ btVec3Sub2(&a, x0, P);
+
+ u = btVec3Dot(&a, &a);
+ v = btVec3Dot(&d1, &d1);
+ w = btVec3Dot(&d2, &d2);
+ p = btVec3Dot(&a, &d1);
+ q = btVec3Dot(&a, &d2);
+ r = btVec3Dot(&d1, &d2);
+
+ s = (q * r - w * p) / (w * v - r * r);
+ t = (-s * r - q) / w;
+
+ if ((btFuzzyZero(s) || s > btScalar(0))
+ && (ccdEq(s, btScalar(1)) || s < btScalar(1))
+ && (btFuzzyZero(t) || t > btScalar(0))
+ && (ccdEq(t, btScalar(1)) || t < btScalar(1))
+ && (ccdEq(t + s, btScalar(1)) || t + s < btScalar(1))) {
+
+ if (witness)
+ {
+ btVec3Scale(&d1, s);
+ btVec3Scale(&d2, t);
+ btVec3Copy(witness, x0);
+ ccdVec3Add(witness, &d1);
+ ccdVec3Add(witness, &d2);
+
+ dist = ccdVec3Dist2(witness, P);
+ }
+ else
+ {
+ dist = s * s * v;
+ dist += t * t * w;
+ dist += btScalar(2.) * s * t * r;
+ dist += btScalar(2.) * s * p;
+ dist += btScalar(2.) * t * q;
+ dist += u;
+ }
+ }
+ else {
+ dist = btVec3PointSegmentDist2(P, x0, B, witness);
+
+ dist2 = btVec3PointSegmentDist2(P, x0, C, &witness2);
+ if (dist2 < dist) {
+ dist = dist2;
+ if (witness)
+ btVec3Copy(witness, &witness2);
+ }
+
+ dist2 = btVec3PointSegmentDist2(P, B, C, &witness2);
+ if (dist2 < dist) {
+ dist = dist2;
+ if (witness)
+ btVec3Copy(witness, &witness2);
+ }
+ }
+
+ return dist;
+}
+
+
+static int btDoSimplex2(btSimplex *simplex, btVector3 *dir)
+{
+ const btSupportVector *A, *B;
+ btVector3 AB, AO, tmp;
+ btScalar dot;
+
+ // get last added as A
+ A = ccdSimplexLast(simplex);
+ // get the other point
+ B = btSimplexPoint(simplex, 0);
+ // compute AB oriented segment
+ btVec3Sub2(&AB, &B->v, &A->v);
+ // compute AO vector
+ btVec3Copy(&AO, &A->v);
+ btVec3Scale(&AO, -btScalar(1));
+
+ // dot product AB . AO
+ dot = btVec3Dot(&AB, &AO);
+
+ // check if origin doesn't lie on AB segment
+ btVec3Cross(&tmp, &AB, &AO);
+ if (btFuzzyZero(btVec3Dot(&tmp, &tmp)) && dot > btScalar(0)) {
+ return 1;
+ }
+
+ // check if origin is in area where AB segment is
+ if (btFuzzyZero(dot) || dot < btScalar(0)) {
+ // origin is in outside are of A
+ btSimplexSet(simplex, 0, A);
+ btSimplexSetSize(simplex, 1);
+ btVec3Copy(dir, &AO);
+ }
+ else {
+ // origin is in area where AB segment is
+
+ // keep simplex untouched and set direction to
+ // AB x AO x AB
+ btTripleCross(&AB, &AO, &AB, dir);
+ }
+
+ return 0;
+}
+
+
+
+static int btDoSimplex3(btSimplex *simplex, btVector3 *dir)
+{
+ const btSupportVector *A, *B, *C;
+ btVector3 AO, AB, AC, ABC, tmp;
+ btScalar dot, dist;
+
+ // get last added as A
+ A = ccdSimplexLast(simplex);
+ // get the other points
+ B = btSimplexPoint(simplex, 1);
+ C = btSimplexPoint(simplex, 0);
+
+ // check touching contact
+ dist = btVec3PointTriDist2(&ccd_vec3_origin, &A->v, &B->v, &C->v, 0);
+ if (btFuzzyZero(dist)) {
+ return 1;
+ }
+
+ // check if triangle is really triangle (has area > 0)
+ // if not simplex can't be expanded and thus no itersection is found
+ if (btVec3Eq(&A->v, &B->v) || btVec3Eq(&A->v, &C->v)) {
+ return -1;
+ }
+
+ // compute AO vector
+ btVec3Copy(&AO, &A->v);
+ btVec3Scale(&AO, -btScalar(1));
+
+ // compute AB and AC segments and ABC vector (perpendircular to triangle)
+ btVec3Sub2(&AB, &B->v, &A->v);
+ btVec3Sub2(&AC, &C->v, &A->v);
+ btVec3Cross(&ABC, &AB, &AC);
+
+ btVec3Cross(&tmp, &ABC, &AC);
+ dot = btVec3Dot(&tmp, &AO);
+ if (btFuzzyZero(dot) || dot > btScalar(0)) {
+ dot = btVec3Dot(&AC, &AO);
+ if (btFuzzyZero(dot) || dot > btScalar(0)) {
+ // C is already in place
+ btSimplexSet(simplex, 1, A);
+ btSimplexSetSize(simplex, 2);
+ btTripleCross(&AC, &AO, &AC, dir);
+ }
+ else {
+
+ dot = btVec3Dot(&AB, &AO);
+ if (btFuzzyZero(dot) || dot > btScalar(0)) {
+ btSimplexSet(simplex, 0, B);
+ btSimplexSet(simplex, 1, A);
+ btSimplexSetSize(simplex, 2);
+ btTripleCross(&AB, &AO, &AB, dir);
+ }
+ else {
+ btSimplexSet(simplex, 0, A);
+ btSimplexSetSize(simplex, 1);
+ btVec3Copy(dir, &AO);
+ }
+ }
+ }
+ else {
+ btVec3Cross(&tmp, &AB, &ABC);
+ dot = btVec3Dot(&tmp, &AO);
+ if (btFuzzyZero(dot) || dot > btScalar(0))
+ {
+ dot = btVec3Dot(&AB, &AO);
+ if (btFuzzyZero(dot) || dot > btScalar(0)) {
+ btSimplexSet(simplex, 0, B);
+ btSimplexSet(simplex, 1, A);
+ btSimplexSetSize(simplex, 2);
+ btTripleCross(&AB, &AO, &AB, dir);
+ }
+ else {
+ btSimplexSet(simplex, 0, A);
+ btSimplexSetSize(simplex, 1);
+ btVec3Copy(dir, &AO);
+ }
+ }
+ else {
+ dot = btVec3Dot(&ABC, &AO);
+ if (btFuzzyZero(dot) || dot > btScalar(0)) {
+ btVec3Copy(dir, &ABC);
+ }
+ else {
+ btSupportVector tmp;
+ btSupportCopy(&tmp, C);
+ btSimplexSet(simplex, 0, B);
+ btSimplexSet(simplex, 1, &tmp);
+
+ btVec3Copy(dir, &ABC);
+ btVec3Scale(dir, -btScalar(1));
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int btDoSimplex4(btSimplex *simplex, btVector3 *dir)
+{
+ const btSupportVector *A, *B, *C, *D;
+ btVector3 AO, AB, AC, AD, ABC, ACD, ADB;
+ int B_on_ACD, C_on_ADB, D_on_ABC;
+ int AB_O, AC_O, AD_O;
+ btScalar dist;
+
+ // get last added as A
+ A = ccdSimplexLast(simplex);
+ // get the other points
+ B = btSimplexPoint(simplex, 2);
+ C = btSimplexPoint(simplex, 1);
+ D = btSimplexPoint(simplex, 0);
+
+ // check if tetrahedron is really tetrahedron (has volume > 0)
+ // if it is not simplex can't be expanded and thus no intersection is
+ // found
+ dist = btVec3PointTriDist2(&A->v, &B->v, &C->v, &D->v, 0);
+ if (btFuzzyZero(dist)) {
+ return -1;
+ }
+
+ // check if origin lies on some of tetrahedron's face - if so objects
+ // intersect
+ dist = btVec3PointTriDist2(&ccd_vec3_origin, &A->v, &B->v, &C->v, 0);
+ if (btFuzzyZero(dist))
+ return 1;
+ dist = btVec3PointTriDist2(&ccd_vec3_origin, &A->v, &C->v, &D->v, 0);
+ if (btFuzzyZero(dist))
+ return 1;
+ dist = btVec3PointTriDist2(&ccd_vec3_origin, &A->v, &B->v, &D->v, 0);
+ if (btFuzzyZero(dist))
+ return 1;
+ dist = btVec3PointTriDist2(&ccd_vec3_origin, &B->v, &C->v, &D->v, 0);
+ if (btFuzzyZero(dist))
+ return 1;
+
+ // compute AO, AB, AC, AD segments and ABC, ACD, ADB normal vectors
+ btVec3Copy(&AO, &A->v);
+ btVec3Scale(&AO, -btScalar(1));
+ btVec3Sub2(&AB, &B->v, &A->v);
+ btVec3Sub2(&AC, &C->v, &A->v);
+ btVec3Sub2(&AD, &D->v, &A->v);
+ btVec3Cross(&ABC, &AB, &AC);
+ btVec3Cross(&ACD, &AC, &AD);
+ btVec3Cross(&ADB, &AD, &AB);
+
+ // side (positive or negative) of B, C, D relative to planes ACD, ADB
+ // and ABC respectively
+ B_on_ACD = ccdSign(btVec3Dot(&ACD, &AB));
+ C_on_ADB = ccdSign(btVec3Dot(&ADB, &AC));
+ D_on_ABC = ccdSign(btVec3Dot(&ABC, &AD));
+
+ // whether origin is on same side of ACD, ADB, ABC as B, C, D
+ // respectively
+ AB_O = ccdSign(btVec3Dot(&ACD, &AO)) == B_on_ACD;
+ AC_O = ccdSign(btVec3Dot(&ADB, &AO)) == C_on_ADB;
+ AD_O = ccdSign(btVec3Dot(&ABC, &AO)) == D_on_ABC;
+
+ if (AB_O && AC_O && AD_O) {
+ // origin is in tetrahedron
+ return 1;
+ // rearrange simplex to triangle and call btDoSimplex3()
+ }
+ else if (!AB_O) {
+ // B is farthest from the origin among all of the tetrahedron's
+ // points, so remove it from the list and go on with the triangle
+ // case
+
+ // D and C are in place
+ btSimplexSet(simplex, 2, A);
+ btSimplexSetSize(simplex, 3);
+ }
+ else if (!AC_O) {
+ // C is farthest
+ btSimplexSet(simplex, 1, D);
+ btSimplexSet(simplex, 0, B);
+ btSimplexSet(simplex, 2, A);
+ btSimplexSetSize(simplex, 3);
+ }
+ else { // (!AD_O)
+ btSimplexSet(simplex, 0, C);
+ btSimplexSet(simplex, 1, B);
+ btSimplexSet(simplex, 2, A);
+ btSimplexSetSize(simplex, 3);
+ }
+
+ return btDoSimplex3(simplex, dir);
+}
+
+static int btDoSimplex(btSimplex *simplex, btVector3 *dir)
+{
+ if (btSimplexSize(simplex) == 2) {
+ // simplex contains segment only one segment
+ return btDoSimplex2(simplex, dir);
+ }
+ else if (btSimplexSize(simplex) == 3) {
+ // simplex contains triangle
+ return btDoSimplex3(simplex, dir);
+ }
+ else { // btSimplexSize(simplex) == 4
+ // tetrahedron - this is the only shape which can encapsule origin
+ // so btDoSimplex4() also contains test on it
+ return btDoSimplex4(simplex, dir);
+ }
+}
+
#ifdef __SPU__
void btGjkPairDetector::getClosestPointsNonVirtual(const ClosestPointInput& input,Result& output,class btIDebugDraw* debugDraw)
#else
@@ -123,193 +710,308 @@ void btGjkPairDetector::getClosestPointsNonVirtual(const ClosestPointInput& inpu
bool checkSimplex = false;
bool checkPenetration = true;
m_degenerateSimplex = 0;
-
+
m_lastUsedMethod = -1;
-
+ int status = -2;
+ btVector3 orgNormalInB(0, 0, 0);
+ btScalar margin = marginA + marginB;
+
+ //we add a separate implementation to check if the convex shapes intersect
+ //See also "Real-time Collision Detection with Implicit Objects" by Leif Olvang
+ //Todo: integrate the simplex penetration check directly inside the Bullet btVoronoiSimplexSolver
+ //and remove this temporary code from libCCD
+ //this fixes issue https://github.com/bulletphysics/bullet3/issues/1703
+ //note, for large differences in shapes, use double precision build!
{
btScalar squaredDistance = BT_LARGE_FLOAT;
btScalar delta = btScalar(0.);
-
- btScalar margin = marginA + marginB;
-
-
- m_simplexSolver->reset();
+
+
- for ( ; ; )
- //while (true)
- {
+ btSimplex simplex1;
+ btSimplex* simplex = &simplex1;
+ btSimplexInit(simplex);
- btVector3 seperatingAxisInA = (-m_cachedSeparatingAxis)* input.m_transformA.getBasis();
- btVector3 seperatingAxisInB = m_cachedSeparatingAxis* input.m_transformB.getBasis();
+ btVector3 dir(1, 0, 0);
+ {
- btVector3 pInA = m_minkowskiA->localGetSupportVertexWithoutMarginNonVirtual(seperatingAxisInA);
- btVector3 qInB = m_minkowskiB->localGetSupportVertexWithoutMarginNonVirtual(seperatingAxisInB);
+ btVector3 lastSupV;
+ btVector3 supAworld;
+ btVector3 supBworld;
+ btComputeSupport(m_minkowskiA, localTransA, m_minkowskiB, localTransB, dir, check2d, supAworld, supBworld, lastSupV);
+
+ btSupportVector last;
+ last.v = lastSupV;
+ last.v1 = supAworld;
+ last.v2 = supBworld;
- btVector3 pWorld = localTransA(pInA);
- btVector3 qWorld = localTransB(qInB);
+ btSimplexAdd(simplex, &last);
+ dir = -lastSupV;
- if (check2d)
+
+
+ // start iterations
+ for (int iterations = 0; iterations <gGjkMaxIter; iterations++)
{
- pWorld[2] = 0.f;
- qWorld[2] = 0.f;
- }
+ // obtain support point
+ btComputeSupport(m_minkowskiA, localTransA, m_minkowskiB, localTransB, dir, check2d, supAworld, supBworld, lastSupV);
+
+ // check if farthest point in Minkowski difference in direction dir
+ // isn't somewhere before origin (the test on negative dot product)
+ // - because if it is, objects are not intersecting at all.
+ btScalar delta = lastSupV.dot(dir);
+ if (delta < 0)
+ {
+ //no intersection, besides margin
+ status = -1;
+ break;
+ }
+
+ // add last support vector to simplex
+ last.v = lastSupV;
+ last.v1 = supAworld;
+ last.v2 = supBworld;
- btVector3 w = pWorld - qWorld;
- delta = m_cachedSeparatingAxis.dot(w);
+ btSimplexAdd(simplex, &last);
- // potential exit, they don't overlap
- if ((delta > btScalar(0.0)) && (delta * delta > squaredDistance * input.m_maximumDistanceSquared))
- {
- m_degenerateSimplex = 10;
- checkSimplex=true;
- //checkPenetration = false;
- break;
- }
+ // if btDoSimplex returns 1 if objects intersect, -1 if objects don't
+ // intersect and 0 if algorithm should continue
- //exit 0: the new point is already in the simplex, or we didn't come any closer
- if (m_simplexSolver->inSimplex(w))
- {
- m_degenerateSimplex = 1;
- checkSimplex = true;
- break;
- }
- // are we getting any closer ?
- btScalar f0 = squaredDistance - delta;
- btScalar f1 = squaredDistance * REL_ERROR2;
+ btVector3 newDir;
+ int do_simplex_res = btDoSimplex(simplex, &dir);
- if (f0 <= f1)
- {
- if (f0 <= btScalar(0.))
+ if (do_simplex_res == 1)
{
- m_degenerateSimplex = 2;
- } else
+ status = 0; // intersection found
+ break;
+ }
+ else if (do_simplex_res == -1)
+ {
+ // intersection not found
+ status = -1;
+ break;
+ }
+
+ if (btFuzzyZero(btVec3Dot(&dir, &dir)))
+ {
+ // intersection not found
+ status = -1;
+ }
+
+ if (dir.length2() < SIMD_EPSILON)
{
- m_degenerateSimplex = 11;
+ //no intersection, besides margin
+ status = -1;
+ break;
+ }
+
+ if (dir.fuzzyZero())
+ {
+ // intersection not found
+ status = -1;
+ break;
}
- checkSimplex = true;
- break;
}
- //add current vertex to simplex
- m_simplexSolver->addVertex(w, pWorld, qWorld);
- btVector3 newCachedSeparatingAxis;
+ }
+
+ m_simplexSolver->reset();
+ if (status == 0)
+ {
+ //status = 0;
+ //printf("Intersect!\n");
+ }
- //calculate the closest point to the origin (update vector v)
- if (!m_simplexSolver->closest(newCachedSeparatingAxis))
+ if (status==-1)
+ {
+ //printf("not intersect\n");
+ }
+ //printf("dir=%f,%f,%f\n",dir[0],dir[1],dir[2]);
+ if (1)
+ {
+ for (; ; )
+ //while (true)
{
- m_degenerateSimplex = 3;
- checkSimplex = true;
- break;
- }
- if(newCachedSeparatingAxis.length2()<REL_ERROR2)
- {
- m_cachedSeparatingAxis = newCachedSeparatingAxis;
- m_degenerateSimplex = 6;
- checkSimplex = true;
- break;
- }
+ btVector3 seperatingAxisInA = (-m_cachedSeparatingAxis)* localTransA.getBasis();
+ btVector3 seperatingAxisInB = m_cachedSeparatingAxis* localTransB.getBasis();
+
+
+ btVector3 pInA = m_minkowskiA->localGetSupportVertexWithoutMarginNonVirtual(seperatingAxisInA);
+ btVector3 qInB = m_minkowskiB->localGetSupportVertexWithoutMarginNonVirtual(seperatingAxisInB);
+
+ btVector3 pWorld = localTransA(pInA);
+ btVector3 qWorld = localTransB(qInB);
- btScalar previousSquaredDistance = squaredDistance;
- squaredDistance = newCachedSeparatingAxis.length2();
+
+ if (check2d)
+ {
+ pWorld[2] = 0.f;
+ qWorld[2] = 0.f;
+ }
+
+ btVector3 w = pWorld - qWorld;
+ delta = m_cachedSeparatingAxis.dot(w);
+
+ // potential exit, they don't overlap
+ if ((delta > btScalar(0.0)) && (delta * delta > squaredDistance * input.m_maximumDistanceSquared))
+ {
+ m_degenerateSimplex = 10;
+ checkSimplex = true;
+ //checkPenetration = false;
+ break;
+ }
+
+ //exit 0: the new point is already in the simplex, or we didn't come any closer
+ if (m_simplexSolver->inSimplex(w))
+ {
+ m_degenerateSimplex = 1;
+ checkSimplex = true;
+ break;
+ }
+ // are we getting any closer ?
+ btScalar f0 = squaredDistance - delta;
+ btScalar f1 = squaredDistance * REL_ERROR2;
+
+ if (f0 <= f1)
+ {
+ if (f0 <= btScalar(0.))
+ {
+ m_degenerateSimplex = 2;
+ }
+ else
+ {
+ m_degenerateSimplex = 11;
+ }
+ checkSimplex = true;
+ break;
+ }
+
+ //add current vertex to simplex
+ m_simplexSolver->addVertex(w, pWorld, qWorld);
+ btVector3 newCachedSeparatingAxis;
+
+ //calculate the closest point to the origin (update vector v)
+ if (!m_simplexSolver->closest(newCachedSeparatingAxis))
+ {
+ m_degenerateSimplex = 3;
+ checkSimplex = true;
+ break;
+ }
+
+ if (newCachedSeparatingAxis.length2() < REL_ERROR2)
+ {
+ m_cachedSeparatingAxis = newCachedSeparatingAxis;
+ m_degenerateSimplex = 6;
+ checkSimplex = true;
+ break;
+ }
+
+ btScalar previousSquaredDistance = squaredDistance;
+ squaredDistance = newCachedSeparatingAxis.length2();
#if 0
-///warning: this termination condition leads to some problems in 2d test case see Bullet/Demos/Box2dDemo
- if (squaredDistance>previousSquaredDistance)
- {
- m_degenerateSimplex = 7;
- squaredDistance = previousSquaredDistance;
- checkSimplex = false;
- break;
- }
+ ///warning: this termination condition leads to some problems in 2d test case see Bullet/Demos/Box2dDemo
+ if (squaredDistance > previousSquaredDistance)
+ {
+ m_degenerateSimplex = 7;
+ squaredDistance = previousSquaredDistance;
+ checkSimplex = false;
+ break;
+ }
#endif //
-
- //redundant m_simplexSolver->compute_points(pointOnA, pointOnB);
- //are we getting any closer ?
- if (previousSquaredDistance - squaredDistance <= SIMD_EPSILON * previousSquaredDistance)
- {
-// m_simplexSolver->backup_closest(m_cachedSeparatingAxis);
- checkSimplex = true;
- m_degenerateSimplex = 12;
-
- break;
- }
+ //redundant m_simplexSolver->compute_points(pointOnA, pointOnB);
- m_cachedSeparatingAxis = newCachedSeparatingAxis;
+ //are we getting any closer ?
+ if (previousSquaredDistance - squaredDistance <= SIMD_EPSILON * previousSquaredDistance)
+ {
+ // m_simplexSolver->backup_closest(m_cachedSeparatingAxis);
+ checkSimplex = true;
+ m_degenerateSimplex = 12;
+
+ break;
+ }
- //degeneracy, this is typically due to invalid/uninitialized worldtransforms for a btCollisionObject
- if (m_curIter++ > gGjkMaxIter)
- {
- #if defined(DEBUG) || defined (_DEBUG)
+ m_cachedSeparatingAxis = newCachedSeparatingAxis;
- printf("btGjkPairDetector maxIter exceeded:%i\n",m_curIter);
- printf("sepAxis=(%f,%f,%f), squaredDistance = %f, shapeTypeA=%i,shapeTypeB=%i\n",
- m_cachedSeparatingAxis.getX(),
- m_cachedSeparatingAxis.getY(),
- m_cachedSeparatingAxis.getZ(),
- squaredDistance,
- m_minkowskiA->getShapeType(),
- m_minkowskiB->getShapeType());
+ //degeneracy, this is typically due to invalid/uninitialized worldtransforms for a btCollisionObject
+ if (m_curIter++ > gGjkMaxIter)
+ {
+#if defined(DEBUG) || defined (_DEBUG)
- #endif
- break;
+ printf("btGjkPairDetector maxIter exceeded:%i\n", m_curIter);
+ printf("sepAxis=(%f,%f,%f), squaredDistance = %f, shapeTypeA=%i,shapeTypeB=%i\n",
+ m_cachedSeparatingAxis.getX(),
+ m_cachedSeparatingAxis.getY(),
+ m_cachedSeparatingAxis.getZ(),
+ squaredDistance,
+ m_minkowskiA->getShapeType(),
+ m_minkowskiB->getShapeType());
- }
+#endif
+ break;
+ }
- bool check = (!m_simplexSolver->fullSimplex());
- //bool check = (!m_simplexSolver->fullSimplex() && squaredDistance > SIMD_EPSILON * m_simplexSolver->maxVertex());
- if (!check)
- {
- //do we need this backup_closest here ?
-// m_simplexSolver->backup_closest(m_cachedSeparatingAxis);
- m_degenerateSimplex = 13;
- break;
+ bool check = (!m_simplexSolver->fullSimplex());
+ //bool check = (!m_simplexSolver->fullSimplex() && squaredDistance > SIMD_EPSILON * m_simplexSolver->maxVertex());
+
+ if (!check)
+ {
+ //do we need this backup_closest here ?
+ // m_simplexSolver->backup_closest(m_cachedSeparatingAxis);
+ m_degenerateSimplex = 13;
+ break;
+ }
}
- }
- if (checkSimplex)
- {
+ if (checkSimplex)
+ {
m_simplexSolver->compute_points(pointOnA, pointOnB);
normalInB = m_cachedSeparatingAxis;
btScalar lenSqr =m_cachedSeparatingAxis.length2();
- //valid normal
- if (lenSqr < REL_ERROR2)
- {
- m_degenerateSimplex = 5;
- }
- if (lenSqr > SIMD_EPSILON*SIMD_EPSILON)
- {
- btScalar rlen = btScalar(1.) / btSqrt(lenSqr );
- normalInB *= rlen; //normalize
+ //valid normal
+ if (lenSqr < REL_ERROR2)
+ {
+ m_degenerateSimplex = 5;
+ }
+ if (lenSqr > SIMD_EPSILON*SIMD_EPSILON)
+ {
+ btScalar rlen = btScalar(1.) / btSqrt(lenSqr);
+ normalInB *= rlen; //normalize
- btScalar s = btSqrt(squaredDistance);
-
- btAssert(s > btScalar(0.0));
- pointOnA -= m_cachedSeparatingAxis * (marginA / s);
- pointOnB += m_cachedSeparatingAxis * (marginB / s);
- distance = ((btScalar(1.)/rlen) - margin);
- isValid = true;
-
- m_lastUsedMethod = 1;
- } else
- {
- m_lastUsedMethod = 2;
+ btScalar s = btSqrt(squaredDistance);
+
+ btAssert(s > btScalar(0.0));
+ pointOnA -= m_cachedSeparatingAxis * (marginA / s);
+ pointOnB += m_cachedSeparatingAxis * (marginB / s);
+ distance = ((btScalar(1.) / rlen) - margin);
+ isValid = true;
+ orgNormalInB = normalInB;
+
+ m_lastUsedMethod = 1;
+ }
+ else
+ {
+ m_lastUsedMethod = 2;
+ }
}
}
+
+
bool catchDegeneratePenetrationCase =
(m_catchDegeneracies && m_penetrationDepthSolver && m_degenerateSimplex && ((distance+margin) < gGjkEpaPenetrationTolerance));
//if (checkPenetration && !isValid)
- if (checkPenetration && (!isValid || catchDegeneratePenetrationCase ))
+ if ((checkPenetration && (!isValid || catchDegeneratePenetrationCase )) || (status == 0))
{
//penetration case
@@ -331,70 +1033,79 @@ void btGjkPairDetector::getClosestPointsNonVirtual(const ClosestPointInput& inpu
);
- if (isValid2)
+ if (m_cachedSeparatingAxis.length2())
{
- btVector3 tmpNormalInB = tmpPointOnB-tmpPointOnA;
- btScalar lenSqr = tmpNormalInB.length2();
- if (lenSqr <= (SIMD_EPSILON*SIMD_EPSILON))
+ if (isValid2)
{
- tmpNormalInB = m_cachedSeparatingAxis;
- lenSqr = m_cachedSeparatingAxis.length2();
- }
+ btVector3 tmpNormalInB = tmpPointOnB - tmpPointOnA;
+ btScalar lenSqr = tmpNormalInB.length2();
+ if (lenSqr <= (SIMD_EPSILON*SIMD_EPSILON))
+ {
+ tmpNormalInB = m_cachedSeparatingAxis;
+ lenSqr = m_cachedSeparatingAxis.length2();
+ }
- if (lenSqr > (SIMD_EPSILON*SIMD_EPSILON))
- {
- tmpNormalInB /= btSqrt(lenSqr);
- btScalar distance2 = -(tmpPointOnA-tmpPointOnB).length();
- m_lastUsedMethod = 3;
- //only replace valid penetrations when the result is deeper (check)
- if (!isValid || (distance2 < distance))
+ if (lenSqr > (SIMD_EPSILON*SIMD_EPSILON))
{
- distance = distance2;
- pointOnA = tmpPointOnA;
- pointOnB = tmpPointOnB;
- normalInB = tmpNormalInB;
-
- isValid = true;
-
- } else
+ tmpNormalInB /= btSqrt(lenSqr);
+ btScalar distance2 = -(tmpPointOnA - tmpPointOnB).length();
+ m_lastUsedMethod = 3;
+ //only replace valid penetrations when the result is deeper (check)
+ if (!isValid || (distance2 < distance))
+ {
+ distance = distance2;
+ pointOnA = tmpPointOnA;
+ pointOnB = tmpPointOnB;
+ normalInB = tmpNormalInB;
+ isValid = true;
+
+ }
+ else
+ {
+ m_lastUsedMethod = 8;
+ }
+ }
+ else
{
- m_lastUsedMethod = 8;
+ m_lastUsedMethod = 9;
}
- } else
- {
- m_lastUsedMethod = 9;
}
- } else
-
- {
- ///this is another degenerate case, where the initial GJK calculation reports a degenerate case
- ///EPA reports no penetration, and the second GJK (using the supporting vector without margin)
- ///reports a valid positive distance. Use the results of the second GJK instead of failing.
- ///thanks to Jacob.Langford for the reproduction case
- ///http://code.google.com/p/bullet/issues/detail?id=250
+ else
-
- if (m_cachedSeparatingAxis.length2() > btScalar(0.))
{
- btScalar distance2 = (tmpPointOnA-tmpPointOnB).length()-margin;
- //only replace valid distances when the distance is less
- if (!isValid || (distance2 < distance))
- {
- distance = distance2;
- pointOnA = tmpPointOnA;
- pointOnB = tmpPointOnB;
- pointOnA -= m_cachedSeparatingAxis * marginA ;
- pointOnB += m_cachedSeparatingAxis * marginB ;
- normalInB = m_cachedSeparatingAxis;
- normalInB.normalize();
-
- isValid = true;
- m_lastUsedMethod = 6;
- } else
+ ///this is another degenerate case, where the initial GJK calculation reports a degenerate case
+ ///EPA reports no penetration, and the second GJK (using the supporting vector without margin)
+ ///reports a valid positive distance. Use the results of the second GJK instead of failing.
+ ///thanks to Jacob.Langford for the reproduction case
+ ///http://code.google.com/p/bullet/issues/detail?id=250
+
+
+ if (m_cachedSeparatingAxis.length2() > btScalar(0.))
{
- m_lastUsedMethod = 5;
+ btScalar distance2 = (tmpPointOnA - tmpPointOnB).length() - margin;
+ //only replace valid distances when the distance is less
+ if (!isValid || (distance2 < distance))
+ {
+ distance = distance2;
+ pointOnA = tmpPointOnA;
+ pointOnB = tmpPointOnB;
+ pointOnA -= m_cachedSeparatingAxis * marginA;
+ pointOnB += m_cachedSeparatingAxis * marginB;
+ normalInB = m_cachedSeparatingAxis;
+ normalInB.normalize();
+
+ isValid = true;
+ m_lastUsedMethod = 6;
+ }
+ else
+ {
+ m_lastUsedMethod = 5;
+ }
}
}
+ } else
+ {
+ //printf("EPA didn't return a valid value\n");
}
}
@@ -409,17 +1120,33 @@ void btGjkPairDetector::getClosestPointsNonVirtual(const ClosestPointInput& inpu
m_cachedSeparatingAxis = normalInB;
m_cachedSeparatingDistance = distance;
-
+ if (1)
{
///todo: need to track down this EPA penetration solver degeneracy
///the penetration solver reports penetration but the contact normal
///connecting the contact points is pointing in the opposite direction
///until then, detect the issue and revert the normal
+ btScalar d2 = 0.f;
+ {
+ btVector3 seperatingAxisInA = (-orgNormalInB)* localTransA.getBasis();
+ btVector3 seperatingAxisInB = orgNormalInB* localTransB.getBasis();
+
+
+ btVector3 pInA = m_minkowskiA->localGetSupportVertexWithoutMarginNonVirtual(seperatingAxisInA);
+ btVector3 qInB = m_minkowskiB->localGetSupportVertexWithoutMarginNonVirtual(seperatingAxisInB);
+
+ btVector3 pWorld = localTransA(pInA);
+ btVector3 qWorld = localTransB(qInB);
+ btVector3 w = pWorld - qWorld;
+ d2 = orgNormalInB.dot(w)- margin;
+ }
+
btScalar d1=0;
{
- btVector3 seperatingAxisInA = (normalInB)* input.m_transformA.getBasis();
- btVector3 seperatingAxisInB = -normalInB* input.m_transformB.getBasis();
+
+ btVector3 seperatingAxisInA = (normalInB)* localTransA.getBasis();
+ btVector3 seperatingAxisInB = -normalInB* localTransB.getBasis();
btVector3 pInA = m_minkowskiA->localGetSupportVertexWithoutMarginNonVirtual(seperatingAxisInA);
@@ -428,7 +1155,8 @@ void btGjkPairDetector::getClosestPointsNonVirtual(const ClosestPointInput& inpu
btVector3 pWorld = localTransA(pInA);
btVector3 qWorld = localTransB(qInB);
btVector3 w = pWorld - qWorld;
- d1 = (-normalInB).dot(w);
+ d1 = (-normalInB).dot(w)- margin;
+
}
btScalar d0 = 0.f;
{
@@ -442,21 +1170,37 @@ void btGjkPairDetector::getClosestPointsNonVirtual(const ClosestPointInput& inpu
btVector3 pWorld = localTransA(pInA);
btVector3 qWorld = localTransB(qInB);
btVector3 w = pWorld - qWorld;
- d0 = normalInB.dot(w);
+ d0 = normalInB.dot(w)-margin;
}
+
if (d1>d0)
{
m_lastUsedMethod = 10;
normalInB*=-1;
}
+ if (orgNormalInB.length2())
+ {
+ if (d2 > d0 && d2 > d1 && d2 > distance)
+ {
+
+ normalInB = orgNormalInB;
+ distance = d2;
+ }
+ }
}
+
+
output.addContactPoint(
normalInB,
pointOnB+positionOffset,
distance);
}
+ else
+ {
+ //printf("invalid gjk query\n");
+ }
}
diff --git a/thirdparty/bullet/BulletCollision/NarrowPhaseCollision/btPersistentManifold.cpp b/thirdparty/bullet/BulletCollision/NarrowPhaseCollision/btPersistentManifold.cpp
index 23aaece22b..9603a8bbdc 100644
--- a/thirdparty/bullet/BulletCollision/NarrowPhaseCollision/btPersistentManifold.cpp
+++ b/thirdparty/bullet/BulletCollision/NarrowPhaseCollision/btPersistentManifold.cpp
@@ -16,7 +16,13 @@ subject to the following restrictions:
#include "btPersistentManifold.h"
#include "LinearMath/btTransform.h"
+#include "LinearMath/btSerializer.h"
+#ifdef BT_USE_DOUBLE_PRECISION
+#define btCollisionObjectData btCollisionObjectDoubleData
+#else
+#define btCollisionObjectData btCollisionObjectFloatData
+#endif
btScalar gContactBreakingThreshold = btScalar(0.02);
ContactDestroyedCallback gContactDestroyedCallback = 0;
@@ -33,6 +39,8 @@ btPersistentManifold::btPersistentManifold()
m_body0(0),
m_body1(0),
m_cachedPoints (0),
+m_companionIdA(0),
+m_companionIdB(0),
m_index1a(0)
{
}
@@ -303,6 +311,149 @@ void btPersistentManifold::refreshContactPoints(const btTransform& trA,const btT
}
+int btPersistentManifold::calculateSerializeBufferSize() const
+{
+ return sizeof(btPersistentManifoldData);
+}
+
+const char* btPersistentManifold::serialize(const class btPersistentManifold* manifold, void* dataBuffer, class btSerializer* serializer) const
+{
+ btPersistentManifoldData* dataOut = (btPersistentManifoldData*)dataBuffer;
+ memset(dataOut, 0, sizeof(btPersistentManifoldData));
+
+ dataOut->m_body0 = (btCollisionObjectData*)serializer->getUniquePointer((void*)manifold->getBody0());
+ dataOut->m_body1 = (btCollisionObjectData*)serializer->getUniquePointer((void*)manifold->getBody1());
+ dataOut->m_contactBreakingThreshold = manifold->getContactBreakingThreshold();
+ dataOut->m_contactProcessingThreshold = manifold->getContactProcessingThreshold();
+ dataOut->m_numCachedPoints = manifold->getNumContacts();
+ dataOut->m_companionIdA = manifold->m_companionIdA;
+ dataOut->m_companionIdB = manifold->m_companionIdB;
+ dataOut->m_index1a = manifold->m_index1a;
+ dataOut->m_objectType = manifold->m_objectType;
+
+ for (int i = 0; i < this->getNumContacts(); i++)
+ {
+ const btManifoldPoint& pt = manifold->getContactPoint(i);
+ dataOut->m_pointCacheAppliedImpulse[i] = pt.m_appliedImpulse;
+ dataOut->m_pointCacheAppliedImpulseLateral1[i] = pt.m_appliedImpulseLateral1;
+ dataOut->m_pointCacheAppliedImpulseLateral2[i] = pt.m_appliedImpulseLateral2;
+ pt.m_localPointA.serialize(dataOut->m_pointCacheLocalPointA[i]);
+ pt.m_localPointB.serialize(dataOut->m_pointCacheLocalPointB[i]);
+ pt.m_normalWorldOnB.serialize(dataOut->m_pointCacheNormalWorldOnB[i]);
+ dataOut->m_pointCacheDistance[i] = pt.m_distance1;
+ dataOut->m_pointCacheCombinedContactDamping1[i] = pt.m_combinedContactDamping1;
+ dataOut->m_pointCacheCombinedContactStiffness1[i] = pt.m_combinedContactStiffness1;
+ dataOut->m_pointCacheLifeTime[i] = pt.m_lifeTime;
+ dataOut->m_pointCacheFrictionCFM[i] = pt.m_frictionCFM;
+ dataOut->m_pointCacheContactERP[i] = pt.m_contactERP;
+ dataOut->m_pointCacheContactCFM[i] = pt.m_contactCFM;
+ dataOut->m_pointCacheContactPointFlags[i] = pt.m_contactPointFlags;
+ dataOut->m_pointCacheIndex0[i] = pt.m_index0;
+ dataOut->m_pointCacheIndex1[i] = pt.m_index1;
+ dataOut->m_pointCachePartId0[i] = pt.m_partId0;
+ dataOut->m_pointCachePartId1[i] = pt.m_partId1;
+ pt.m_positionWorldOnA.serialize(dataOut->m_pointCachePositionWorldOnA[i]);
+ pt.m_positionWorldOnB.serialize(dataOut->m_pointCachePositionWorldOnB[i]);
+ dataOut->m_pointCacheCombinedFriction[i] = pt.m_combinedFriction;
+ pt.m_lateralFrictionDir1.serialize(dataOut->m_pointCacheLateralFrictionDir1[i]);
+ pt.m_lateralFrictionDir2.serialize(dataOut->m_pointCacheLateralFrictionDir2[i]);
+ dataOut->m_pointCacheCombinedRollingFriction[i] = pt.m_combinedRollingFriction;
+ dataOut->m_pointCacheCombinedSpinningFriction[i] = pt.m_combinedSpinningFriction;
+ dataOut->m_pointCacheCombinedRestitution[i] = pt.m_combinedRestitution;
+ dataOut->m_pointCacheContactMotion1[i] = pt.m_contactMotion1;
+ dataOut->m_pointCacheContactMotion2[i] = pt.m_contactMotion2;
+ }
+ return btPersistentManifoldDataName;
+}
+
+void btPersistentManifold::deSerialize(const struct btPersistentManifoldDoubleData* manifoldDataPtr)
+{
+ m_contactBreakingThreshold = manifoldDataPtr->m_contactBreakingThreshold;
+ m_contactProcessingThreshold = manifoldDataPtr->m_contactProcessingThreshold;
+ m_cachedPoints = manifoldDataPtr->m_numCachedPoints;
+ m_companionIdA = manifoldDataPtr->m_companionIdA;
+ m_companionIdB = manifoldDataPtr->m_companionIdB;
+ //m_index1a = manifoldDataPtr->m_index1a;
+ m_objectType = manifoldDataPtr->m_objectType;
+
+ for (int i = 0; i < this->getNumContacts(); i++)
+ {
+ btManifoldPoint& pt = m_pointCache[i];
+
+ pt.m_appliedImpulse = manifoldDataPtr->m_pointCacheAppliedImpulse[i];
+ pt.m_appliedImpulseLateral1 = manifoldDataPtr->m_pointCacheAppliedImpulseLateral1[i];
+ pt.m_appliedImpulseLateral2 = manifoldDataPtr->m_pointCacheAppliedImpulseLateral2[i];
+ pt.m_localPointA.deSerializeDouble(manifoldDataPtr->m_pointCacheLocalPointA[i]);
+ pt.m_localPointB.deSerializeDouble(manifoldDataPtr->m_pointCacheLocalPointB[i]);
+ pt.m_normalWorldOnB.deSerializeDouble(manifoldDataPtr->m_pointCacheNormalWorldOnB[i]);
+ pt.m_distance1 = manifoldDataPtr->m_pointCacheDistance[i];
+ pt.m_combinedContactDamping1 = manifoldDataPtr->m_pointCacheCombinedContactDamping1[i];
+ pt.m_combinedContactStiffness1 = manifoldDataPtr->m_pointCacheCombinedContactStiffness1[i];
+ pt.m_lifeTime = manifoldDataPtr->m_pointCacheLifeTime[i];
+ pt.m_frictionCFM = manifoldDataPtr->m_pointCacheFrictionCFM[i];
+ pt.m_contactERP = manifoldDataPtr->m_pointCacheContactERP[i];
+ pt.m_contactCFM = manifoldDataPtr->m_pointCacheContactCFM[i];
+ pt.m_contactPointFlags = manifoldDataPtr->m_pointCacheContactPointFlags[i];
+ pt.m_index0 = manifoldDataPtr->m_pointCacheIndex0[i];
+ pt.m_index1 = manifoldDataPtr->m_pointCacheIndex1[i];
+ pt.m_partId0 = manifoldDataPtr->m_pointCachePartId0[i];
+ pt.m_partId1 = manifoldDataPtr->m_pointCachePartId1[i];
+ pt.m_positionWorldOnA.deSerializeDouble(manifoldDataPtr->m_pointCachePositionWorldOnA[i]);
+ pt.m_positionWorldOnB.deSerializeDouble(manifoldDataPtr->m_pointCachePositionWorldOnB[i]);
+ pt.m_combinedFriction = manifoldDataPtr->m_pointCacheCombinedFriction[i];
+ pt.m_lateralFrictionDir1.deSerializeDouble(manifoldDataPtr->m_pointCacheLateralFrictionDir1[i]);
+ pt.m_lateralFrictionDir2.deSerializeDouble(manifoldDataPtr->m_pointCacheLateralFrictionDir2[i]);
+ pt.m_combinedRollingFriction = manifoldDataPtr->m_pointCacheCombinedRollingFriction[i];
+ pt.m_combinedSpinningFriction = manifoldDataPtr->m_pointCacheCombinedSpinningFriction[i];
+ pt.m_combinedRestitution = manifoldDataPtr->m_pointCacheCombinedRestitution[i];
+ pt.m_contactMotion1 = manifoldDataPtr->m_pointCacheContactMotion1[i];
+ pt.m_contactMotion2 = manifoldDataPtr->m_pointCacheContactMotion2[i];
+ }
+}
+void btPersistentManifold::deSerialize(const struct btPersistentManifoldFloatData* manifoldDataPtr)
+{
+ m_contactBreakingThreshold = manifoldDataPtr->m_contactBreakingThreshold;
+ m_contactProcessingThreshold = manifoldDataPtr->m_contactProcessingThreshold;
+ m_cachedPoints = manifoldDataPtr->m_numCachedPoints;
+ m_companionIdA = manifoldDataPtr->m_companionIdA;
+ m_companionIdB = manifoldDataPtr->m_companionIdB;
+ //m_index1a = manifoldDataPtr->m_index1a;
+ m_objectType = manifoldDataPtr->m_objectType;
+
+ for (int i = 0; i < this->getNumContacts(); i++)
+ {
+ btManifoldPoint& pt = m_pointCache[i];
+
+ pt.m_appliedImpulse = manifoldDataPtr->m_pointCacheAppliedImpulse[i];
+ pt.m_appliedImpulseLateral1 = manifoldDataPtr->m_pointCacheAppliedImpulseLateral1[i];
+ pt.m_appliedImpulseLateral2 = manifoldDataPtr->m_pointCacheAppliedImpulseLateral2[i];
+ pt.m_localPointA.deSerialize(manifoldDataPtr->m_pointCacheLocalPointA[i]);
+ pt.m_localPointB.deSerialize(manifoldDataPtr->m_pointCacheLocalPointB[i]);
+ pt.m_normalWorldOnB.deSerialize(manifoldDataPtr->m_pointCacheNormalWorldOnB[i]);
+ pt.m_distance1 = manifoldDataPtr->m_pointCacheDistance[i];
+ pt.m_combinedContactDamping1 = manifoldDataPtr->m_pointCacheCombinedContactDamping1[i];
+ pt.m_combinedContactStiffness1 = manifoldDataPtr->m_pointCacheCombinedContactStiffness1[i];
+ pt.m_lifeTime = manifoldDataPtr->m_pointCacheLifeTime[i];
+ pt.m_frictionCFM = manifoldDataPtr->m_pointCacheFrictionCFM[i];
+ pt.m_contactERP = manifoldDataPtr->m_pointCacheContactERP[i];
+ pt.m_contactCFM = manifoldDataPtr->m_pointCacheContactCFM[i];
+ pt.m_contactPointFlags = manifoldDataPtr->m_pointCacheContactPointFlags[i];
+ pt.m_index0 = manifoldDataPtr->m_pointCacheIndex0[i];
+ pt.m_index1 = manifoldDataPtr->m_pointCacheIndex1[i];
+ pt.m_partId0 = manifoldDataPtr->m_pointCachePartId0[i];
+ pt.m_partId1 = manifoldDataPtr->m_pointCachePartId1[i];
+ pt.m_positionWorldOnA.deSerialize(manifoldDataPtr->m_pointCachePositionWorldOnA[i]);
+ pt.m_positionWorldOnB.deSerialize(manifoldDataPtr->m_pointCachePositionWorldOnB[i]);
+ pt.m_combinedFriction = manifoldDataPtr->m_pointCacheCombinedFriction[i];
+ pt.m_lateralFrictionDir1.deSerialize(manifoldDataPtr->m_pointCacheLateralFrictionDir1[i]);
+ pt.m_lateralFrictionDir2.deSerialize(manifoldDataPtr->m_pointCacheLateralFrictionDir2[i]);
+ pt.m_combinedRollingFriction = manifoldDataPtr->m_pointCacheCombinedRollingFriction[i];
+ pt.m_combinedSpinningFriction = manifoldDataPtr->m_pointCacheCombinedSpinningFriction[i];
+ pt.m_combinedRestitution = manifoldDataPtr->m_pointCacheCombinedRestitution[i];
+ pt.m_contactMotion1 = manifoldDataPtr->m_pointCacheContactMotion1[i];
+ pt.m_contactMotion2 = manifoldDataPtr->m_pointCacheContactMotion2[i];
+ }
+} \ No newline at end of file
diff --git a/thirdparty/bullet/BulletCollision/NarrowPhaseCollision/btPersistentManifold.h b/thirdparty/bullet/BulletCollision/NarrowPhaseCollision/btPersistentManifold.h
index f872c8e1c9..67be0c48eb 100644
--- a/thirdparty/bullet/BulletCollision/NarrowPhaseCollision/btPersistentManifold.h
+++ b/thirdparty/bullet/BulletCollision/NarrowPhaseCollision/btPersistentManifold.h
@@ -24,6 +24,8 @@ class btCollisionObject;
#include "LinearMath/btAlignedAllocator.h"
struct btCollisionResult;
+struct btCollisionObjectDoubleData;
+struct btCollisionObjectFloatData;
///maximum contact breaking and merging threshold
extern btScalar gContactBreakingThreshold;
@@ -95,7 +97,10 @@ public:
: btTypedObject(BT_PERSISTENT_MANIFOLD_TYPE),
m_body0(body0),m_body1(body1),m_cachedPoints(0),
m_contactBreakingThreshold(contactBreakingThreshold),
- m_contactProcessingThreshold(contactProcessingThreshold)
+ m_contactProcessingThreshold(contactProcessingThreshold),
+ m_companionIdA(0),
+ m_companionIdB(0),
+ m_index1a(0)
{
}
@@ -256,10 +261,115 @@ public:
m_cachedPoints = 0;
}
+ int calculateSerializeBufferSize() const;
+ const char* serialize(const class btPersistentManifold* manifold, void* dataBuffer, class btSerializer* serializer) const;
+ void deSerialize(const struct btPersistentManifoldDoubleData* manifoldDataPtr);
+ void deSerialize(const struct btPersistentManifoldFloatData* manifoldDataPtr);
-}
-;
+};
+
+
+
+struct btPersistentManifoldDoubleData
+{
+ btVector3DoubleData m_pointCacheLocalPointA[4];
+ btVector3DoubleData m_pointCacheLocalPointB[4];
+ btVector3DoubleData m_pointCachePositionWorldOnA[4];
+ btVector3DoubleData m_pointCachePositionWorldOnB[4];
+ btVector3DoubleData m_pointCacheNormalWorldOnB[4];
+ btVector3DoubleData m_pointCacheLateralFrictionDir1[4];
+ btVector3DoubleData m_pointCacheLateralFrictionDir2[4];
+ double m_pointCacheDistance[4];
+ double m_pointCacheAppliedImpulse[4];
+ double m_pointCacheCombinedFriction[4];
+ double m_pointCacheCombinedRollingFriction[4];
+ double m_pointCacheCombinedSpinningFriction[4];
+ double m_pointCacheCombinedRestitution[4];
+ int m_pointCachePartId0[4];
+ int m_pointCachePartId1[4];
+ int m_pointCacheIndex0[4];
+ int m_pointCacheIndex1[4];
+ int m_pointCacheContactPointFlags[4];
+ double m_pointCacheAppliedImpulseLateral1[4];
+ double m_pointCacheAppliedImpulseLateral2[4];
+ double m_pointCacheContactMotion1[4];
+ double m_pointCacheContactMotion2[4];
+ double m_pointCacheContactCFM[4];
+ double m_pointCacheCombinedContactStiffness1[4];
+ double m_pointCacheContactERP[4];
+ double m_pointCacheCombinedContactDamping1[4];
+ double m_pointCacheFrictionCFM[4];
+ int m_pointCacheLifeTime[4];
+
+ int m_numCachedPoints;
+ int m_companionIdA;
+ int m_companionIdB;
+ int m_index1a;
+
+ int m_objectType;
+ double m_contactBreakingThreshold;
+ double m_contactProcessingThreshold;
+ int m_padding;
+
+ btCollisionObjectDoubleData *m_body0;
+ btCollisionObjectDoubleData *m_body1;
+};
+
+
+struct btPersistentManifoldFloatData
+{
+ btVector3FloatData m_pointCacheLocalPointA[4];
+ btVector3FloatData m_pointCacheLocalPointB[4];
+ btVector3FloatData m_pointCachePositionWorldOnA[4];
+ btVector3FloatData m_pointCachePositionWorldOnB[4];
+ btVector3FloatData m_pointCacheNormalWorldOnB[4];
+ btVector3FloatData m_pointCacheLateralFrictionDir1[4];
+ btVector3FloatData m_pointCacheLateralFrictionDir2[4];
+ float m_pointCacheDistance[4];
+ float m_pointCacheAppliedImpulse[4];
+ float m_pointCacheCombinedFriction[4];
+ float m_pointCacheCombinedRollingFriction[4];
+ float m_pointCacheCombinedSpinningFriction[4];
+ float m_pointCacheCombinedRestitution[4];
+ int m_pointCachePartId0[4];
+ int m_pointCachePartId1[4];
+ int m_pointCacheIndex0[4];
+ int m_pointCacheIndex1[4];
+ int m_pointCacheContactPointFlags[4];
+ float m_pointCacheAppliedImpulseLateral1[4];
+ float m_pointCacheAppliedImpulseLateral2[4];
+ float m_pointCacheContactMotion1[4];
+ float m_pointCacheContactMotion2[4];
+ float m_pointCacheContactCFM[4];
+ float m_pointCacheCombinedContactStiffness1[4];
+ float m_pointCacheContactERP[4];
+ float m_pointCacheCombinedContactDamping1[4];
+ float m_pointCacheFrictionCFM[4];
+ int m_pointCacheLifeTime[4];
+
+ int m_numCachedPoints;
+ int m_companionIdA;
+ int m_companionIdB;
+ int m_index1a;
+
+ int m_objectType;
+ float m_contactBreakingThreshold;
+ float m_contactProcessingThreshold;
+ int m_padding;
+
+ btCollisionObjectFloatData *m_body0;
+ btCollisionObjectFloatData *m_body1;
+};
+
+#ifdef BT_USE_DOUBLE_PRECISION
+#define btPersistentManifoldData btPersistentManifoldDoubleData
+#define btPersistentManifoldDataName "btPersistentManifoldDoubleData"
+#else
+#define btPersistentManifoldData btPersistentManifoldFloatData
+#define btPersistentManifoldDataName "btPersistentManifoldFloatData"
+#endif //BT_USE_DOUBLE_PRECISION
+
diff --git a/thirdparty/bullet/BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.cpp b/thirdparty/bullet/BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.cpp
index ec638f60ba..08d6e6de86 100644
--- a/thirdparty/bullet/BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.cpp
+++ b/thirdparty/bullet/BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.cpp
@@ -72,11 +72,18 @@ bool btSubsimplexConvexCast::calcTimeOfImpact(
btScalar dist2 = v.length2();
+
#ifdef BT_USE_DOUBLE_PRECISION
- btScalar epsilon = btScalar(0.0001);
+ btScalar epsilon = SIMD_EPSILON * 10;
#else
+//todo: epsilon kept for backward compatibility of unit tests.
+//will need to digg deeper to make the algorithm more robust
+//since, a large epsilon can cause an early termination with false
+//positive results (ray intersections that shouldn't be there)
btScalar epsilon = btScalar(0.0001);
#endif //BT_USE_DOUBLE_PRECISION
+
+
btVector3 w,p;
btScalar VdotR;
diff --git a/thirdparty/bullet/BulletDynamics/ConstraintSolver/btBatchedConstraints.cpp b/thirdparty/bullet/BulletDynamics/ConstraintSolver/btBatchedConstraints.cpp
new file mode 100644
index 0000000000..c82ba87f9f
--- /dev/null
+++ b/thirdparty/bullet/BulletDynamics/ConstraintSolver/btBatchedConstraints.cpp
@@ -0,0 +1,1128 @@
+/*
+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 "btBatchedConstraints.h"
+
+#include "LinearMath/btIDebugDraw.h"
+#include "LinearMath/btMinMax.h"
+#include "LinearMath/btStackAlloc.h"
+#include "LinearMath/btQuickprof.h"
+
+#include <string.h> //for memset
+
+const int kNoMerge = -1;
+
+bool btBatchedConstraints::s_debugDrawBatches = false;
+
+
+struct btBatchedConstraintInfo
+{
+ int constraintIndex;
+ int numConstraintRows;
+ int bodyIds[2];
+};
+
+
+struct btBatchInfo
+{
+ int numConstraints;
+ int mergeIndex;
+
+ btBatchInfo() : numConstraints(0), mergeIndex(kNoMerge) {}
+};
+
+
+bool btBatchedConstraints::validate(btConstraintArray* constraints, const btAlignedObjectArray<btSolverBody>& bodies) const
+{
+ //
+ // validate: for debugging only. Verify coloring of bodies, that no body is touched by more than one batch in any given phase
+ //
+ int errors = 0;
+ const int kUnassignedBatch = -1;
+
+ btAlignedObjectArray<int> bodyBatchId;
+ for (int iPhase = 0; iPhase < m_phases.size(); ++iPhase)
+ {
+ bodyBatchId.resizeNoInitialize(0);
+ bodyBatchId.resize( bodies.size(), kUnassignedBatch );
+ const Range& phase = m_phases[iPhase];
+ for (int iBatch = phase.begin; iBatch < phase.end; ++iBatch)
+ {
+ const Range& batch = m_batches[iBatch];
+ for (int iiCons = batch.begin; iiCons < batch.end; ++iiCons)
+ {
+ int iCons = m_constraintIndices[iiCons];
+ const btSolverConstraint& cons = constraints->at(iCons);
+ const btSolverBody& bodyA = bodies[cons.m_solverBodyIdA];
+ const btSolverBody& bodyB = bodies[cons.m_solverBodyIdB];
+ if (! bodyA.internalGetInvMass().isZero())
+ {
+ int thisBodyBatchId = bodyBatchId[cons.m_solverBodyIdA];
+ if (thisBodyBatchId == kUnassignedBatch)
+ {
+ bodyBatchId[cons.m_solverBodyIdA] = iBatch;
+ }
+ else if (thisBodyBatchId != iBatch)
+ {
+ btAssert( !"dynamic body is used in 2 different batches in the same phase" );
+ errors++;
+ }
+ }
+ if (! bodyB.internalGetInvMass().isZero())
+ {
+ int thisBodyBatchId = bodyBatchId[cons.m_solverBodyIdB];
+ if (thisBodyBatchId == kUnassignedBatch)
+ {
+ bodyBatchId[cons.m_solverBodyIdB] = iBatch;
+ }
+ else if (thisBodyBatchId != iBatch)
+ {
+ btAssert( !"dynamic body is used in 2 different batches in the same phase" );
+ errors++;
+ }
+ }
+ }
+ }
+ }
+ return errors == 0;
+}
+
+
+static void debugDrawSingleBatch( const btBatchedConstraints* bc,
+ btConstraintArray* constraints,
+ const btAlignedObjectArray<btSolverBody>& bodies,
+ int iBatch,
+ const btVector3& color,
+ const btVector3& offset
+ )
+{
+ if (bc && bc->m_debugDrawer && iBatch < bc->m_batches.size())
+ {
+ const btBatchedConstraints::Range& b = bc->m_batches[iBatch];
+ for (int iiCon = b.begin; iiCon < b.end; ++iiCon)
+ {
+ int iCon = bc->m_constraintIndices[iiCon];
+ const btSolverConstraint& con = constraints->at(iCon);
+ int iBody0 = con.m_solverBodyIdA;
+ int iBody1 = con.m_solverBodyIdB;
+ btVector3 pos0 = bodies[iBody0].getWorldTransform().getOrigin() + offset;
+ btVector3 pos1 = bodies[iBody1].getWorldTransform().getOrigin() + offset;
+ bc->m_debugDrawer->drawLine(pos0, pos1, color);
+ }
+ }
+}
+
+
+static void debugDrawPhase( const btBatchedConstraints* bc,
+ btConstraintArray* constraints,
+ const btAlignedObjectArray<btSolverBody>& bodies,
+ int iPhase,
+ const btVector3& color0,
+ const btVector3& color1,
+ const btVector3& offset
+ )
+{
+ BT_PROFILE( "debugDrawPhase" );
+ if ( bc && bc->m_debugDrawer && iPhase < bc->m_phases.size() )
+ {
+ const btBatchedConstraints::Range& phase = bc->m_phases[iPhase];
+ for (int iBatch = phase.begin; iBatch < phase.end; ++iBatch)
+ {
+ float tt = float(iBatch - phase.begin) / float(btMax(1, phase.end - phase.begin - 1));
+ btVector3 col = lerp(color0, color1, tt);
+ debugDrawSingleBatch(bc, constraints, bodies, iBatch, col, offset);
+ }
+ }
+}
+
+
+static void debugDrawAllBatches( const btBatchedConstraints* bc,
+ btConstraintArray* constraints,
+ const btAlignedObjectArray<btSolverBody>& bodies
+ )
+{
+ BT_PROFILE( "debugDrawAllBatches" );
+ if ( bc && bc->m_debugDrawer && bc->m_phases.size() > 0 )
+ {
+ btVector3 bboxMin(BT_LARGE_FLOAT, BT_LARGE_FLOAT, BT_LARGE_FLOAT);
+ btVector3 bboxMax = -bboxMin;
+ for (int iBody = 0; iBody < bodies.size(); ++iBody)
+ {
+ const btVector3& pos = bodies[iBody].getWorldTransform().getOrigin();
+ bboxMin.setMin(pos);
+ bboxMax.setMax(pos);
+ }
+ btVector3 bboxExtent = bboxMax - bboxMin;
+ btVector3 offsetBase = btVector3( 0, bboxExtent.y()*1.1f, 0 );
+ btVector3 offsetStep = btVector3( 0, 0, bboxExtent.z()*1.1f );
+ int numPhases = bc->m_phases.size();
+ for (int iPhase = 0; iPhase < numPhases; ++iPhase)
+ {
+ float b = float(iPhase)/float(numPhases-1);
+ btVector3 color0 = btVector3(1,0,b);
+ btVector3 color1 = btVector3(0,1,b);
+ btVector3 offset = offsetBase + offsetStep*(float(iPhase) - float(numPhases-1)*0.5);
+ debugDrawPhase(bc, constraints, bodies, iPhase, color0, color1, offset);
+ }
+ }
+}
+
+
+static void initBatchedBodyDynamicFlags(btAlignedObjectArray<bool>* outBodyDynamicFlags, const btAlignedObjectArray<btSolverBody>& bodies)
+{
+ BT_PROFILE("initBatchedBodyDynamicFlags");
+ btAlignedObjectArray<bool>& bodyDynamicFlags = *outBodyDynamicFlags;
+ bodyDynamicFlags.resizeNoInitialize(bodies.size());
+ for (int i = 0; i < bodies.size(); ++i)
+ {
+ const btSolverBody& body = bodies[ i ];
+ bodyDynamicFlags[i] = ( body.internalGetInvMass().x() > btScalar( 0 ) );
+ }
+}
+
+
+static int runLengthEncodeConstraintInfo(btBatchedConstraintInfo* outConInfos, int numConstraints)
+{
+ BT_PROFILE("runLengthEncodeConstraintInfo");
+ // detect and run-length encode constraint rows that repeat the same bodies
+ int iDest = 0;
+ int iSrc = 0;
+ while (iSrc < numConstraints)
+ {
+ const btBatchedConstraintInfo& srcConInfo = outConInfos[iSrc];
+ btBatchedConstraintInfo& conInfo = outConInfos[iDest];
+ conInfo.constraintIndex = iSrc;
+ conInfo.bodyIds[0] = srcConInfo.bodyIds[0];
+ conInfo.bodyIds[1] = srcConInfo.bodyIds[1];
+ while (iSrc < numConstraints && outConInfos[iSrc].bodyIds[0] == srcConInfo.bodyIds[0] && outConInfos[iSrc].bodyIds[1] == srcConInfo.bodyIds[1])
+ {
+ ++iSrc;
+ }
+ conInfo.numConstraintRows = iSrc - conInfo.constraintIndex;
+ ++iDest;
+ }
+ return iDest;
+}
+
+
+struct ReadSolverConstraintsLoop : public btIParallelForBody
+{
+ btBatchedConstraintInfo* m_outConInfos;
+ btConstraintArray* m_constraints;
+
+ ReadSolverConstraintsLoop( btBatchedConstraintInfo* outConInfos, btConstraintArray* constraints )
+ {
+ m_outConInfos = outConInfos;
+ m_constraints = constraints;
+ }
+ void forLoop( int iBegin, int iEnd ) const BT_OVERRIDE
+ {
+ for (int i = iBegin; i < iEnd; ++i)
+ {
+ btBatchedConstraintInfo& conInfo = m_outConInfos[i];
+ const btSolverConstraint& con = m_constraints->at( i );
+ conInfo.bodyIds[0] = con.m_solverBodyIdA;
+ conInfo.bodyIds[1] = con.m_solverBodyIdB;
+ conInfo.constraintIndex = i;
+ conInfo.numConstraintRows = 1;
+ }
+ }
+};
+
+
+static int initBatchedConstraintInfo(btBatchedConstraintInfo* outConInfos, btConstraintArray* constraints)
+{
+ BT_PROFILE("initBatchedConstraintInfo");
+ int numConstraints = constraints->size();
+ bool inParallel = true;
+ if (inParallel)
+ {
+ ReadSolverConstraintsLoop loop(outConInfos, constraints);
+ int grainSize = 1200;
+ btParallelFor(0, numConstraints, grainSize, loop);
+ }
+ else
+ {
+ for (int i = 0; i < numConstraints; ++i)
+ {
+ btBatchedConstraintInfo& conInfo = outConInfos[i];
+ const btSolverConstraint& con = constraints->at( i );
+ conInfo.bodyIds[0] = con.m_solverBodyIdA;
+ conInfo.bodyIds[1] = con.m_solverBodyIdB;
+ conInfo.constraintIndex = i;
+ conInfo.numConstraintRows = 1;
+ }
+ }
+ bool useRunLengthEncoding = true;
+ if (useRunLengthEncoding)
+ {
+ numConstraints = runLengthEncodeConstraintInfo(outConInfos, numConstraints);
+ }
+ return numConstraints;
+}
+
+
+static void expandConstraintRowsInPlace(int* constraintBatchIds, const btBatchedConstraintInfo* conInfos, int numConstraints, int numConstraintRows)
+{
+ BT_PROFILE("expandConstraintRowsInPlace");
+ if (numConstraintRows > numConstraints)
+ {
+ // we walk the array in reverse to avoid overwriteing
+ for (int iCon = numConstraints - 1; iCon >= 0; --iCon)
+ {
+ const btBatchedConstraintInfo& conInfo = conInfos[iCon];
+ int iBatch = constraintBatchIds[iCon];
+ for (int i = conInfo.numConstraintRows - 1; i >= 0; --i)
+ {
+ int iDest = conInfo.constraintIndex + i;
+ btAssert(iDest >= iCon);
+ btAssert(iDest >= 0 && iDest < numConstraintRows);
+ constraintBatchIds[iDest] = iBatch;
+ }
+ }
+ }
+}
+
+
+static void expandConstraintRows(int* destConstraintBatchIds, const int* srcConstraintBatchIds, const btBatchedConstraintInfo* conInfos, int numConstraints, int numConstraintRows)
+{
+ BT_PROFILE("expandConstraintRows");
+ for ( int iCon = 0; iCon < numConstraints; ++iCon )
+ {
+ const btBatchedConstraintInfo& conInfo = conInfos[ iCon ];
+ int iBatch = srcConstraintBatchIds[ iCon ];
+ for ( int i = 0; i < conInfo.numConstraintRows; ++i )
+ {
+ int iDest = conInfo.constraintIndex + i;
+ btAssert( iDest >= iCon );
+ btAssert( iDest >= 0 && iDest < numConstraintRows );
+ destConstraintBatchIds[ iDest ] = iBatch;
+ }
+ }
+}
+
+
+struct ExpandConstraintRowsLoop : public btIParallelForBody
+{
+ int* m_destConstraintBatchIds;
+ const int* m_srcConstraintBatchIds;
+ const btBatchedConstraintInfo* m_conInfos;
+ int m_numConstraintRows;
+
+ ExpandConstraintRowsLoop( int* destConstraintBatchIds, const int* srcConstraintBatchIds, const btBatchedConstraintInfo* conInfos, int numConstraintRows)
+ {
+ m_destConstraintBatchIds = destConstraintBatchIds;
+ m_srcConstraintBatchIds = srcConstraintBatchIds;
+ m_conInfos = conInfos;
+ m_numConstraintRows = numConstraintRows;
+ }
+ void forLoop( int iBegin, int iEnd ) const BT_OVERRIDE
+ {
+ expandConstraintRows(m_destConstraintBatchIds, m_srcConstraintBatchIds + iBegin, m_conInfos + iBegin, iEnd - iBegin, m_numConstraintRows);
+ }
+};
+
+
+static void expandConstraintRowsMt(int* destConstraintBatchIds, const int* srcConstraintBatchIds, const btBatchedConstraintInfo* conInfos, int numConstraints, int numConstraintRows)
+{
+ BT_PROFILE("expandConstraintRowsMt");
+ ExpandConstraintRowsLoop loop(destConstraintBatchIds, srcConstraintBatchIds, conInfos, numConstraintRows);
+ int grainSize = 600;
+ btParallelFor(0, numConstraints, grainSize, loop);
+}
+
+
+static void initBatchedConstraintInfoArray(btAlignedObjectArray<btBatchedConstraintInfo>* outConInfos, btConstraintArray* constraints)
+{
+ BT_PROFILE("initBatchedConstraintInfoArray");
+ btAlignedObjectArray<btBatchedConstraintInfo>& conInfos = *outConInfos;
+ int numConstraints = constraints->size();
+ conInfos.resizeNoInitialize(numConstraints);
+
+ int newSize = initBatchedConstraintInfo(&outConInfos->at(0), constraints);
+ conInfos.resizeNoInitialize(newSize);
+}
+
+
+static void mergeSmallBatches(btBatchInfo* batches, int iBeginBatch, int iEndBatch, int minBatchSize, int maxBatchSize)
+{
+ BT_PROFILE("mergeSmallBatches");
+ for ( int iBatch = iEndBatch - 1; iBatch >= iBeginBatch; --iBatch )
+ {
+ btBatchInfo& batch = batches[ iBatch ];
+ if ( batch.mergeIndex == kNoMerge && batch.numConstraints > 0 && batch.numConstraints < minBatchSize )
+ {
+ for ( int iDestBatch = iBatch - 1; iDestBatch >= iBeginBatch; --iDestBatch )
+ {
+ btBatchInfo& destBatch = batches[ iDestBatch ];
+ if ( destBatch.mergeIndex == kNoMerge && ( destBatch.numConstraints + batch.numConstraints ) < maxBatchSize )
+ {
+ destBatch.numConstraints += batch.numConstraints;
+ batch.numConstraints = 0;
+ batch.mergeIndex = iDestBatch;
+ break;
+ }
+ }
+ }
+ }
+ // flatten mergeIndexes
+ // e.g. in case where A was merged into B and then B was merged into C, we need A to point to C instead of B
+ // Note: loop goes forward through batches because batches always merge from higher indexes to lower,
+ // so by going from low to high it reduces the amount of trail-following
+ for ( int iBatch = iBeginBatch; iBatch < iEndBatch; ++iBatch )
+ {
+ btBatchInfo& batch = batches[ iBatch ];
+ if ( batch.mergeIndex != kNoMerge )
+ {
+ int iMergeDest = batches[ batch.mergeIndex ].mergeIndex;
+ // follow trail of merges to the end
+ while ( iMergeDest != kNoMerge )
+ {
+ int iNext = batches[ iMergeDest ].mergeIndex;
+ if ( iNext == kNoMerge )
+ {
+ batch.mergeIndex = iMergeDest;
+ break;
+ }
+ iMergeDest = iNext;
+ }
+ }
+ }
+}
+
+
+static void updateConstraintBatchIdsForMerges(int* constraintBatchIds, int numConstraints, const btBatchInfo* batches, int numBatches)
+{
+ BT_PROFILE("updateConstraintBatchIdsForMerges");
+ // update batchIds to account for merges
+ for (int i = 0; i < numConstraints; ++i)
+ {
+ int iBatch = constraintBatchIds[i];
+ btAssert(iBatch < numBatches);
+ // if this constraint references a batch that was merged into another batch
+ if (batches[iBatch].mergeIndex != kNoMerge)
+ {
+ // update batchId
+ constraintBatchIds[i] = batches[iBatch].mergeIndex;
+ }
+ }
+}
+
+
+struct UpdateConstraintBatchIdsForMergesLoop : public btIParallelForBody
+{
+ int* m_constraintBatchIds;
+ const btBatchInfo* m_batches;
+ int m_numBatches;
+
+ UpdateConstraintBatchIdsForMergesLoop( int* constraintBatchIds, const btBatchInfo* batches, int numBatches )
+ {
+ m_constraintBatchIds = constraintBatchIds;
+ m_batches = batches;
+ m_numBatches = numBatches;
+ }
+ void forLoop( int iBegin, int iEnd ) const BT_OVERRIDE
+ {
+ BT_PROFILE( "UpdateConstraintBatchIdsForMergesLoop" );
+ updateConstraintBatchIdsForMerges( m_constraintBatchIds + iBegin, iEnd - iBegin, m_batches, m_numBatches );
+ }
+};
+
+
+static void updateConstraintBatchIdsForMergesMt(int* constraintBatchIds, int numConstraints, const btBatchInfo* batches, int numBatches)
+{
+ BT_PROFILE( "updateConstraintBatchIdsForMergesMt" );
+ UpdateConstraintBatchIdsForMergesLoop loop(constraintBatchIds, batches, numBatches);
+ int grainSize = 800;
+ btParallelFor(0, numConstraints, grainSize, loop);
+}
+
+
+inline bool BatchCompare(const btBatchedConstraints::Range& a, const btBatchedConstraints::Range& b)
+{
+ int lenA = a.end - a.begin;
+ int lenB = b.end - b.begin;
+ return lenA > lenB;
+}
+
+
+static void writeOutConstraintIndicesForRangeOfBatches(btBatchedConstraints* bc,
+ const int* constraintBatchIds,
+ int numConstraints,
+ int* constraintIdPerBatch,
+ int batchBegin,
+ int batchEnd
+ )
+{
+ BT_PROFILE("writeOutConstraintIndicesForRangeOfBatches");
+ for ( int iCon = 0; iCon < numConstraints; ++iCon )
+ {
+ int iBatch = constraintBatchIds[ iCon ];
+ if (iBatch >= batchBegin && iBatch < batchEnd)
+ {
+ int iDestCon = constraintIdPerBatch[ iBatch ];
+ constraintIdPerBatch[ iBatch ] = iDestCon + 1;
+ bc->m_constraintIndices[ iDestCon ] = iCon;
+ }
+ }
+}
+
+
+struct WriteOutConstraintIndicesLoop : public btIParallelForBody
+{
+ btBatchedConstraints* m_batchedConstraints;
+ const int* m_constraintBatchIds;
+ int m_numConstraints;
+ int* m_constraintIdPerBatch;
+ int m_maxNumBatchesPerPhase;
+
+ WriteOutConstraintIndicesLoop( btBatchedConstraints* bc, const int* constraintBatchIds, int numConstraints, int* constraintIdPerBatch, int maxNumBatchesPerPhase )
+ {
+ m_batchedConstraints = bc;
+ m_constraintBatchIds = constraintBatchIds;
+ m_numConstraints = numConstraints;
+ m_constraintIdPerBatch = constraintIdPerBatch;
+ m_maxNumBatchesPerPhase = maxNumBatchesPerPhase;
+ }
+ void forLoop( int iBegin, int iEnd ) const BT_OVERRIDE
+ {
+ BT_PROFILE( "WriteOutConstraintIndicesLoop" );
+ int batchBegin = iBegin * m_maxNumBatchesPerPhase;
+ int batchEnd = iEnd * m_maxNumBatchesPerPhase;
+ writeOutConstraintIndicesForRangeOfBatches(m_batchedConstraints,
+ m_constraintBatchIds,
+ m_numConstraints,
+ m_constraintIdPerBatch,
+ batchBegin,
+ batchEnd
+ );
+ }
+};
+
+
+static void writeOutConstraintIndicesMt(btBatchedConstraints* bc,
+ const int* constraintBatchIds,
+ int numConstraints,
+ int* constraintIdPerBatch,
+ int maxNumBatchesPerPhase,
+ int numPhases
+ )
+{
+ BT_PROFILE("writeOutConstraintIndicesMt");
+ bool inParallel = true;
+ if (inParallel)
+ {
+ WriteOutConstraintIndicesLoop loop( bc, constraintBatchIds, numConstraints, constraintIdPerBatch, maxNumBatchesPerPhase );
+ btParallelFor( 0, numPhases, 1, loop );
+ }
+ else
+ {
+ for ( int iCon = 0; iCon < numConstraints; ++iCon )
+ {
+ int iBatch = constraintBatchIds[ iCon ];
+ int iDestCon = constraintIdPerBatch[ iBatch ];
+ constraintIdPerBatch[ iBatch ] = iDestCon + 1;
+ bc->m_constraintIndices[ iDestCon ] = iCon;
+ }
+ }
+}
+
+
+static void writeGrainSizes(btBatchedConstraints* bc)
+{
+ typedef btBatchedConstraints::Range Range;
+ int numPhases = bc->m_phases.size();
+ bc->m_phaseGrainSize.resizeNoInitialize(numPhases);
+ int numThreads = btGetTaskScheduler()->getNumThreads();
+ for (int iPhase = 0; iPhase < numPhases; ++iPhase)
+ {
+ const Range& phase = bc->m_phases[ iPhase ];
+ int numBatches = phase.end - phase.begin;
+ float grainSize = floor((0.25f*numBatches / float(numThreads)) + 0.0f);
+ bc->m_phaseGrainSize[ iPhase ] = btMax(1, int(grainSize));
+ }
+}
+
+
+static void writeOutBatches(btBatchedConstraints* bc,
+ const int* constraintBatchIds,
+ int numConstraints,
+ const btBatchInfo* batches,
+ int* batchWork,
+ int maxNumBatchesPerPhase,
+ int numPhases
+)
+{
+ BT_PROFILE("writeOutBatches");
+ typedef btBatchedConstraints::Range Range;
+ bc->m_constraintIndices.reserve( numConstraints );
+ bc->m_batches.resizeNoInitialize( 0 );
+ bc->m_phases.resizeNoInitialize( 0 );
+
+ //int maxNumBatches = numPhases * maxNumBatchesPerPhase;
+ {
+ int* constraintIdPerBatch = batchWork; // for each batch, keep an index into the next available slot in the m_constraintIndices array
+ int iConstraint = 0;
+ for (int iPhase = 0; iPhase < numPhases; ++iPhase)
+ {
+ int curPhaseBegin = bc->m_batches.size();
+ int iBegin = iPhase * maxNumBatchesPerPhase;
+ int iEnd = iBegin + maxNumBatchesPerPhase;
+ for ( int i = iBegin; i < iEnd; ++i )
+ {
+ const btBatchInfo& batch = batches[ i ];
+ int curBatchBegin = iConstraint;
+ constraintIdPerBatch[ i ] = curBatchBegin; // record the start of each batch in m_constraintIndices array
+ int numConstraints = batch.numConstraints;
+ iConstraint += numConstraints;
+ if ( numConstraints > 0 )
+ {
+ bc->m_batches.push_back( Range( curBatchBegin, iConstraint ) );
+ }
+ }
+ // if any batches were emitted this phase,
+ if ( bc->m_batches.size() > curPhaseBegin )
+ {
+ // output phase
+ bc->m_phases.push_back( Range( curPhaseBegin, bc->m_batches.size() ) );
+ }
+ }
+
+ btAssert(iConstraint == numConstraints);
+ bc->m_constraintIndices.resizeNoInitialize( numConstraints );
+ writeOutConstraintIndicesMt( bc, constraintBatchIds, numConstraints, constraintIdPerBatch, maxNumBatchesPerPhase, numPhases );
+ }
+ // for each phase
+ for (int iPhase = 0; iPhase < bc->m_phases.size(); ++iPhase)
+ {
+ // sort the batches from largest to smallest (can be helpful to some task schedulers)
+ const Range& curBatches = bc->m_phases[iPhase];
+ bc->m_batches.quickSortInternal(BatchCompare, curBatches.begin, curBatches.end-1);
+ }
+ bc->m_phaseOrder.resize(bc->m_phases.size());
+ for (int i = 0; i < bc->m_phases.size(); ++i)
+ {
+ bc->m_phaseOrder[i] = i;
+ }
+ writeGrainSizes(bc);
+}
+
+
+//
+// PreallocatedMemoryHelper -- helper object for allocating a number of chunks of memory in a single contiguous block.
+// It is generally more efficient to do a single larger allocation than many smaller allocations.
+//
+// Example Usage:
+//
+// btVector3* bodyPositions = NULL;
+// btBatchedConstraintInfo* conInfos = NULL;
+// {
+// PreallocatedMemoryHelper<8> memHelper;
+// memHelper.addChunk( (void**) &bodyPositions, sizeof( btVector3 ) * bodies.size() );
+// memHelper.addChunk( (void**) &conInfos, sizeof( btBatchedConstraintInfo ) * numConstraints );
+// void* memPtr = malloc( memHelper.getSizeToAllocate() ); // allocate the memory
+// memHelper.setChunkPointers( memPtr ); // update pointers to chunks
+// }
+template <int N>
+class PreallocatedMemoryHelper
+{
+ struct Chunk
+ {
+ void** ptr;
+ size_t size;
+ };
+ Chunk m_chunks[N];
+ int m_numChunks;
+public:
+ PreallocatedMemoryHelper() {m_numChunks=0;}
+ void addChunk( void** ptr, size_t sz )
+ {
+ btAssert( m_numChunks < N );
+ if ( m_numChunks < N )
+ {
+ Chunk& chunk = m_chunks[ m_numChunks ];
+ chunk.ptr = ptr;
+ chunk.size = sz;
+ m_numChunks++;
+ }
+ }
+ size_t getSizeToAllocate() const
+ {
+ size_t totalSize = 0;
+ for (int i = 0; i < m_numChunks; ++i)
+ {
+ totalSize += m_chunks[i].size;
+ }
+ return totalSize;
+ }
+ void setChunkPointers(void* mem) const
+ {
+ size_t totalSize = 0;
+ for (int i = 0; i < m_numChunks; ++i)
+ {
+ const Chunk& chunk = m_chunks[ i ];
+ char* chunkPtr = static_cast<char*>(mem) + totalSize;
+ *chunk.ptr = chunkPtr;
+ totalSize += chunk.size;
+ }
+ }
+};
+
+
+
+static btVector3 findMaxDynamicConstraintExtent(
+ btVector3* bodyPositions,
+ bool* bodyDynamicFlags,
+ btBatchedConstraintInfo* conInfos,
+ int numConstraints,
+ int numBodies
+ )
+{
+ BT_PROFILE("findMaxDynamicConstraintExtent");
+ btVector3 consExtent = btVector3(1,1,1) * 0.001;
+ for (int iCon = 0; iCon < numConstraints; ++iCon)
+ {
+ const btBatchedConstraintInfo& con = conInfos[ iCon ];
+ int iBody0 = con.bodyIds[0];
+ int iBody1 = con.bodyIds[1];
+ btAssert(iBody0 >= 0 && iBody0 < numBodies);
+ btAssert(iBody1 >= 0 && iBody1 < numBodies);
+ // is it a dynamic constraint?
+ if (bodyDynamicFlags[iBody0] && bodyDynamicFlags[iBody1])
+ {
+ btVector3 delta = bodyPositions[iBody1] - bodyPositions[iBody0];
+ consExtent.setMax(delta.absolute());
+ }
+ }
+ return consExtent;
+}
+
+
+struct btIntVec3
+{
+ int m_ints[ 3 ];
+
+ SIMD_FORCE_INLINE const int& operator[](int i) const {return m_ints[i];}
+ SIMD_FORCE_INLINE int& operator[](int i) {return m_ints[i];}
+};
+
+
+struct AssignConstraintsToGridBatchesParams
+{
+ bool* bodyDynamicFlags;
+ btIntVec3* bodyGridCoords;
+ int numBodies;
+ btBatchedConstraintInfo* conInfos;
+ int* constraintBatchIds;
+ btIntVec3 gridChunkDim;
+ int maxNumBatchesPerPhase;
+ int numPhases;
+ int phaseMask;
+
+ AssignConstraintsToGridBatchesParams()
+ {
+ memset(this, 0, sizeof(*this));
+ }
+};
+
+
+static void assignConstraintsToGridBatches(const AssignConstraintsToGridBatchesParams& params, int iConBegin, int iConEnd)
+{
+ BT_PROFILE("assignConstraintsToGridBatches");
+ // (can be done in parallel)
+ for ( int iCon = iConBegin; iCon < iConEnd; ++iCon )
+ {
+ const btBatchedConstraintInfo& con = params.conInfos[ iCon ];
+ int iBody0 = con.bodyIds[ 0 ];
+ int iBody1 = con.bodyIds[ 1 ];
+ int iPhase = iCon; //iBody0; // pseudorandom choice to distribute evenly amongst phases
+ iPhase &= params.phaseMask;
+ int gridCoord[ 3 ];
+ // is it a dynamic constraint?
+ if ( params.bodyDynamicFlags[ iBody0 ] && params.bodyDynamicFlags[ iBody1 ] )
+ {
+ const btIntVec3& body0Coords = params.bodyGridCoords[iBody0];
+ const btIntVec3& body1Coords = params.bodyGridCoords[iBody1];
+ // for each dimension x,y,z,
+ for (int i = 0; i < 3; ++i)
+ {
+ int coordMin = btMin(body0Coords.m_ints[i], body1Coords.m_ints[i]);
+ int coordMax = btMax(body0Coords.m_ints[i], body1Coords.m_ints[i]);
+ if (coordMin != coordMax)
+ {
+ btAssert( coordMax == coordMin + 1 );
+ if ((coordMin&1) == 0)
+ {
+ iPhase &= ~(1 << i); // force bit off
+ }
+ else
+ {
+ iPhase |= (1 << i); // force bit on
+ iPhase &= params.phaseMask;
+ }
+ }
+ gridCoord[ i ] = coordMin;
+ }
+ }
+ else
+ {
+ if ( !params.bodyDynamicFlags[ iBody0 ] )
+ {
+ iBody0 = con.bodyIds[ 1 ];
+ }
+ btAssert(params.bodyDynamicFlags[ iBody0 ]);
+ const btIntVec3& body0Coords = params.bodyGridCoords[iBody0];
+ // for each dimension x,y,z,
+ for ( int i = 0; i < 3; ++i )
+ {
+ gridCoord[ i ] = body0Coords.m_ints[ i ];
+ }
+ }
+ // calculate chunk coordinates
+ int chunkCoord[ 3 ];
+ btIntVec3 gridChunkDim = params.gridChunkDim;
+ // for each dimension x,y,z,
+ for ( int i = 0; i < 3; ++i )
+ {
+ int coordOffset = ( iPhase >> i ) & 1;
+ chunkCoord[ i ] = (gridCoord[ i ] - coordOffset)/2;
+ btClamp( chunkCoord[ i ], 0, gridChunkDim[ i ] - 1);
+ btAssert( chunkCoord[ i ] < gridChunkDim[ i ] );
+ }
+ int iBatch = iPhase * params.maxNumBatchesPerPhase + chunkCoord[ 0 ] + chunkCoord[ 1 ] * gridChunkDim[ 0 ] + chunkCoord[ 2 ] * gridChunkDim[ 0 ] * gridChunkDim[ 1 ];
+ btAssert(iBatch >= 0 && iBatch < params.maxNumBatchesPerPhase*params.numPhases);
+ params.constraintBatchIds[ iCon ] = iBatch;
+ }
+}
+
+
+struct AssignConstraintsToGridBatchesLoop : public btIParallelForBody
+{
+ const AssignConstraintsToGridBatchesParams* m_params;
+
+ AssignConstraintsToGridBatchesLoop( const AssignConstraintsToGridBatchesParams& params )
+ {
+ m_params = &params;
+ }
+ void forLoop( int iBegin, int iEnd ) const BT_OVERRIDE
+ {
+ assignConstraintsToGridBatches(*m_params, iBegin, iEnd);
+ }
+};
+
+
+//
+// setupSpatialGridBatchesMt -- generate batches using a uniform 3D grid
+//
+/*
+
+Bodies are treated as 3D points at their center of mass. We only consider dynamic bodies at this stage,
+because only dynamic bodies are mutated when a constraint is solved, thus subject to race conditions.
+
+1. Compute a bounding box around all dynamic bodies
+2. Compute the maximum extent of all dynamic constraints. Each dynamic constraint is treated as a line segment, and we need the size of
+ box that will fully enclose any single dynamic constraint
+
+3. Establish the cell size of our grid, the cell size in each dimension must be at least as large as the dynamic constraints max-extent,
+ so that no dynamic constraint can span more than 2 cells of our grid on any axis of the grid. The cell size should be adjusted
+ larger in order to keep the total number of cells from being excessively high
+
+Key idea: Given that each constraint spans 1 or 2 grid cells in each dimension, we can handle all constraints by processing
+ in chunks of 2x2x2 cells with 8 different 1-cell offsets ((0,0,0),(0,0,1),(0,1,0),(0,1,1),(1,0,0)...).
+ For each of the 8 offsets, we create a phase, and for each 2x2x2 chunk with dynamic constraints becomes a batch in that phase.
+
+4. Once the grid is established, we can calculate for each constraint which phase and batch it belongs in.
+
+5. Do a merge small batches on the batches of each phase separately, to try to even out the sizes of batches
+
+Optionally, we can "collapse" one dimension of our 3D grid to turn it into a 2D grid, which reduces the number of phases
+to 4. With fewer phases, there are more constraints per phase and this makes it easier to create batches of a useful size.
+*/
+//
+static void setupSpatialGridBatchesMt(
+ btBatchedConstraints* batchedConstraints,
+ btAlignedObjectArray<char>* scratchMemory,
+ btConstraintArray* constraints,
+ const btAlignedObjectArray<btSolverBody>& bodies,
+ int minBatchSize,
+ int maxBatchSize,
+ bool use2DGrid
+)
+{
+ BT_PROFILE("setupSpatialGridBatchesMt");
+ const int numPhases = 8;
+ int numConstraints = constraints->size();
+ int numConstraintRows = constraints->size();
+
+ const int maxGridChunkCount = 128;
+ int allocNumBatchesPerPhase = maxGridChunkCount;
+ int minNumBatchesPerPhase = 16;
+ int allocNumBatches = allocNumBatchesPerPhase * numPhases;
+
+ btVector3* bodyPositions = NULL;
+ bool* bodyDynamicFlags = NULL;
+ btIntVec3* bodyGridCoords = NULL;
+ btBatchInfo* batches = NULL;
+ int* batchWork = NULL;
+ btBatchedConstraintInfo* conInfos = NULL;
+ int* constraintBatchIds = NULL;
+ int* constraintRowBatchIds = NULL;
+ {
+ PreallocatedMemoryHelper<10> memHelper;
+ memHelper.addChunk( (void**) &bodyPositions, sizeof( btVector3 ) * bodies.size() );
+ memHelper.addChunk( (void**) &bodyDynamicFlags, sizeof( bool ) * bodies.size() );
+ memHelper.addChunk( (void**) &bodyGridCoords, sizeof( btIntVec3 ) * bodies.size() );
+ memHelper.addChunk( (void**) &batches, sizeof( btBatchInfo )* allocNumBatches );
+ memHelper.addChunk( (void**) &batchWork, sizeof( int )* allocNumBatches );
+ memHelper.addChunk( (void**) &conInfos, sizeof( btBatchedConstraintInfo ) * numConstraints );
+ memHelper.addChunk( (void**) &constraintBatchIds, sizeof( int ) * numConstraints );
+ memHelper.addChunk( (void**) &constraintRowBatchIds, sizeof( int ) * numConstraintRows );
+ size_t scratchSize = memHelper.getSizeToAllocate();
+ // if we need to reallocate
+ if (scratchMemory->capacity() < scratchSize)
+ {
+ // allocate 6.25% extra to avoid repeated reallocs
+ scratchMemory->reserve( scratchSize + scratchSize/16 );
+ }
+ scratchMemory->resizeNoInitialize( scratchSize );
+ char* memPtr = &scratchMemory->at(0);
+ memHelper.setChunkPointers( memPtr );
+ }
+
+ numConstraints = initBatchedConstraintInfo(conInfos, constraints);
+
+ // compute bounding box around all dynamic bodies
+ // (could be done in parallel)
+ btVector3 bboxMin(BT_LARGE_FLOAT, BT_LARGE_FLOAT, BT_LARGE_FLOAT);
+ btVector3 bboxMax = -bboxMin;
+ //int dynamicBodyCount = 0;
+ for (int i = 0; i < bodies.size(); ++i)
+ {
+ const btSolverBody& body = bodies[i];
+ btVector3 bodyPos = body.getWorldTransform().getOrigin();
+ bool isDynamic = ( body.internalGetInvMass().x() > btScalar( 0 ) );
+ bodyPositions[i] = bodyPos;
+ bodyDynamicFlags[i] = isDynamic;
+ if (isDynamic)
+ {
+ //dynamicBodyCount++;
+ bboxMin.setMin(bodyPos);
+ bboxMax.setMax(bodyPos);
+ }
+ }
+
+ // find max extent of all dynamic constraints
+ // (could be done in parallel)
+ btVector3 consExtent = findMaxDynamicConstraintExtent(bodyPositions, bodyDynamicFlags, conInfos, numConstraints, bodies.size());
+
+ btVector3 gridExtent = bboxMax - bboxMin;
+
+ btVector3 gridCellSize = consExtent;
+ int gridDim[3];
+ gridDim[ 0 ] = int( 1.0 + gridExtent.x() / gridCellSize.x() );
+ gridDim[ 1 ] = int( 1.0 + gridExtent.y() / gridCellSize.y() );
+ gridDim[ 2 ] = int( 1.0 + gridExtent.z() / gridCellSize.z() );
+
+ // if we can collapse an axis, it will cut our number of phases in half which could be more efficient
+ int phaseMask = 7;
+ bool collapseAxis = use2DGrid;
+ if ( collapseAxis )
+ {
+ // pick the smallest axis to collapse, leaving us with the greatest number of cells in our grid
+ int iAxisToCollapse = 0;
+ int axisDim = gridDim[iAxisToCollapse];
+ //for each dimension
+ for ( int i = 0; i < 3; ++i )
+ {
+ if (gridDim[i] < axisDim)
+ {
+ iAxisToCollapse = i;
+ axisDim = gridDim[i];
+ }
+ }
+ // collapse it
+ gridCellSize[iAxisToCollapse] = gridExtent[iAxisToCollapse] * 2.0f;
+ phaseMask &= ~(1 << iAxisToCollapse);
+ }
+
+ int numGridChunks = 0;
+ btIntVec3 gridChunkDim; // each chunk is 2x2x2 group of cells
+ while (true)
+ {
+ gridDim[0] = int( 1.0 + gridExtent.x() / gridCellSize.x() );
+ gridDim[1] = int( 1.0 + gridExtent.y() / gridCellSize.y() );
+ gridDim[2] = int( 1.0 + gridExtent.z() / gridCellSize.z() );
+ gridChunkDim[ 0 ] = btMax( 1, ( gridDim[ 0 ] + 0 ) / 2 );
+ gridChunkDim[ 1 ] = btMax( 1, ( gridDim[ 1 ] + 0 ) / 2 );
+ gridChunkDim[ 2 ] = btMax( 1, ( gridDim[ 2 ] + 0 ) / 2 );
+ numGridChunks = gridChunkDim[ 0 ] * gridChunkDim[ 1 ] * gridChunkDim[ 2 ];
+ float nChunks = float(gridChunkDim[0]) * float(gridChunkDim[1]) * float(gridChunkDim[2]); // suceptible to integer overflow
+ if ( numGridChunks <= maxGridChunkCount && nChunks <= maxGridChunkCount )
+ {
+ break;
+ }
+ gridCellSize *= 1.25; // should roughly cut numCells in half
+ }
+ btAssert(numGridChunks <= maxGridChunkCount );
+ int maxNumBatchesPerPhase = numGridChunks;
+
+ // for each dynamic body, compute grid coords
+ btVector3 invGridCellSize = btVector3(1,1,1)/gridCellSize;
+ // (can be done in parallel)
+ for (int iBody = 0; iBody < bodies.size(); ++iBody)
+ {
+ btIntVec3& coords = bodyGridCoords[iBody];
+ if (bodyDynamicFlags[iBody])
+ {
+ btVector3 v = ( bodyPositions[ iBody ] - bboxMin )*invGridCellSize;
+ coords.m_ints[0] = int(v.x());
+ coords.m_ints[1] = int(v.y());
+ coords.m_ints[2] = int(v.z());
+ btAssert(coords.m_ints[0] >= 0 && coords.m_ints[0] < gridDim[0]);
+ btAssert(coords.m_ints[1] >= 0 && coords.m_ints[1] < gridDim[1]);
+ btAssert(coords.m_ints[2] >= 0 && coords.m_ints[2] < gridDim[2]);
+ }
+ else
+ {
+ coords.m_ints[0] = -1;
+ coords.m_ints[1] = -1;
+ coords.m_ints[2] = -1;
+ }
+ }
+
+ for (int iPhase = 0; iPhase < numPhases; ++iPhase)
+ {
+ int batchBegin = iPhase * maxNumBatchesPerPhase;
+ int batchEnd = batchBegin + maxNumBatchesPerPhase;
+ for ( int iBatch = batchBegin; iBatch < batchEnd; ++iBatch )
+ {
+ btBatchInfo& batch = batches[ iBatch ];
+ batch = btBatchInfo();
+ }
+ }
+
+ {
+ AssignConstraintsToGridBatchesParams params;
+ params.bodyDynamicFlags = bodyDynamicFlags;
+ params.bodyGridCoords = bodyGridCoords;
+ params.numBodies = bodies.size();
+ params.conInfos = conInfos;
+ params.constraintBatchIds = constraintBatchIds;
+ params.gridChunkDim = gridChunkDim;
+ params.maxNumBatchesPerPhase = maxNumBatchesPerPhase;
+ params.numPhases = numPhases;
+ params.phaseMask = phaseMask;
+ bool inParallel = true;
+ if (inParallel)
+ {
+ AssignConstraintsToGridBatchesLoop loop(params);
+ int grainSize = 250;
+ btParallelFor(0, numConstraints, grainSize, loop);
+ }
+ else
+ {
+ assignConstraintsToGridBatches( params, 0, numConstraints );
+ }
+ }
+ for ( int iCon = 0; iCon < numConstraints; ++iCon )
+ {
+ const btBatchedConstraintInfo& con = conInfos[ iCon ];
+ int iBatch = constraintBatchIds[ iCon ];
+ btBatchInfo& batch = batches[iBatch];
+ batch.numConstraints += con.numConstraintRows;
+ }
+
+ for (int iPhase = 0; iPhase < numPhases; ++iPhase)
+ {
+ // if phase is legit,
+ if (iPhase == (iPhase&phaseMask))
+ {
+ int iBeginBatch = iPhase * maxNumBatchesPerPhase;
+ int iEndBatch = iBeginBatch + maxNumBatchesPerPhase;
+ mergeSmallBatches( batches, iBeginBatch, iEndBatch, minBatchSize, maxBatchSize );
+ }
+ }
+ // all constraints have been assigned a batchId
+ updateConstraintBatchIdsForMergesMt(constraintBatchIds, numConstraints, batches, maxNumBatchesPerPhase*numPhases);
+
+ if (numConstraintRows > numConstraints)
+ {
+ expandConstraintRowsMt(&constraintRowBatchIds[0], &constraintBatchIds[0], &conInfos[0], numConstraints, numConstraintRows);
+ }
+ else
+ {
+ constraintRowBatchIds = constraintBatchIds;
+ }
+
+ writeOutBatches(batchedConstraints, constraintRowBatchIds, numConstraintRows, batches, batchWork, maxNumBatchesPerPhase, numPhases);
+ btAssert(batchedConstraints->validate(constraints, bodies));
+}
+
+
+static void setupSingleBatch(
+ btBatchedConstraints* bc,
+ int numConstraints
+)
+{
+ BT_PROFILE("setupSingleBatch");
+ typedef btBatchedConstraints::Range Range;
+
+ bc->m_constraintIndices.resize( numConstraints );
+ for ( int i = 0; i < numConstraints; ++i )
+ {
+ bc->m_constraintIndices[ i ] = i;
+ }
+
+ bc->m_batches.resizeNoInitialize( 0 );
+ bc->m_phases.resizeNoInitialize( 0 );
+ bc->m_phaseOrder.resizeNoInitialize( 0 );
+ bc->m_phaseGrainSize.resizeNoInitialize( 0 );
+
+ if (numConstraints > 0)
+ {
+ bc->m_batches.push_back( Range( 0, numConstraints ) );
+ bc->m_phases.push_back( Range( 0, 1 ) );
+ bc->m_phaseOrder.push_back(0);
+ bc->m_phaseGrainSize.push_back(1);
+ }
+}
+
+
+void btBatchedConstraints::setup(
+ btConstraintArray* constraints,
+ const btAlignedObjectArray<btSolverBody>& bodies,
+ BatchingMethod batchingMethod,
+ int minBatchSize,
+ int maxBatchSize,
+ btAlignedObjectArray<char>* scratchMemory
+ )
+{
+ if (constraints->size() >= minBatchSize*4)
+ {
+ bool use2DGrid = batchingMethod == BATCHING_METHOD_SPATIAL_GRID_2D;
+ setupSpatialGridBatchesMt( this, scratchMemory, constraints, bodies, minBatchSize, maxBatchSize, use2DGrid );
+ if (s_debugDrawBatches)
+ {
+ debugDrawAllBatches( this, constraints, bodies );
+ }
+ }
+ else
+ {
+ setupSingleBatch( this, constraints->size() );
+ }
+}
+
+
diff --git a/thirdparty/bullet/BulletDynamics/ConstraintSolver/btBatchedConstraints.h b/thirdparty/bullet/BulletDynamics/ConstraintSolver/btBatchedConstraints.h
new file mode 100644
index 0000000000..0fd8f31dd4
--- /dev/null
+++ b/thirdparty/bullet/BulletDynamics/ConstraintSolver/btBatchedConstraints.h
@@ -0,0 +1,66 @@
+/*
+Bullet Continuous Collision Detection and Physics Library
+Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
+
+This software is provided 'as-is', without any express or implied warranty.
+In no event will the authors be held liable for any damages arising from the use of this software.
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it freely,
+subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
+2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
+3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef BT_BATCHED_CONSTRAINTS_H
+#define BT_BATCHED_CONSTRAINTS_H
+
+#include "LinearMath/btThreads.h"
+#include "LinearMath/btAlignedObjectArray.h"
+#include "BulletDynamics/ConstraintSolver/btSolverBody.h"
+#include "BulletDynamics/ConstraintSolver/btSolverConstraint.h"
+
+
+class btIDebugDraw;
+
+struct btBatchedConstraints
+{
+ enum BatchingMethod
+ {
+ BATCHING_METHOD_SPATIAL_GRID_2D,
+ BATCHING_METHOD_SPATIAL_GRID_3D,
+ BATCHING_METHOD_COUNT
+ };
+ struct Range
+ {
+ int begin;
+ int end;
+
+ Range() : begin( 0 ), end( 0 ) {}
+ Range( int _beg, int _end ) : begin( _beg ), end( _end ) {}
+ };
+
+ btAlignedObjectArray<int> m_constraintIndices;
+ btAlignedObjectArray<Range> m_batches; // each batch is a range of indices in the m_constraintIndices array
+ btAlignedObjectArray<Range> m_phases; // each phase is range of indices in the m_batches array
+ btAlignedObjectArray<char> m_phaseGrainSize; // max grain size for each phase
+ btAlignedObjectArray<int> m_phaseOrder; // phases can be done in any order, so we can randomize the order here
+ btIDebugDraw* m_debugDrawer;
+
+ static bool s_debugDrawBatches;
+
+ btBatchedConstraints() {m_debugDrawer=NULL;}
+ void setup( btConstraintArray* constraints,
+ const btAlignedObjectArray<btSolverBody>& bodies,
+ BatchingMethod batchingMethod,
+ int minBatchSize,
+ int maxBatchSize,
+ btAlignedObjectArray<char>* scratchMemory
+ );
+ bool validate( btConstraintArray* constraints, const btAlignedObjectArray<btSolverBody>& bodies ) const;
+};
+
+
+#endif // BT_BATCHED_CONSTRAINTS_H
+
diff --git a/thirdparty/bullet/BulletDynamics/ConstraintSolver/btConstraintSolver.h b/thirdparty/bullet/BulletDynamics/ConstraintSolver/btConstraintSolver.h
index 890afe6da4..0491639f70 100644
--- a/thirdparty/bullet/BulletDynamics/ConstraintSolver/btConstraintSolver.h
+++ b/thirdparty/bullet/BulletDynamics/ConstraintSolver/btConstraintSolver.h
@@ -34,7 +34,8 @@ enum btConstraintSolverType
{
BT_SEQUENTIAL_IMPULSE_SOLVER=1,
BT_MLCP_SOLVER=2,
- BT_NNCG_SOLVER=4
+ BT_NNCG_SOLVER=4,
+ BT_MULTIBODY_SOLVER=8,
};
class btConstraintSolver
diff --git a/thirdparty/bullet/BulletDynamics/ConstraintSolver/btContactSolverInfo.h b/thirdparty/bullet/BulletDynamics/ConstraintSolver/btContactSolverInfo.h
index 28d0c1dd48..93865cbc59 100644
--- a/thirdparty/bullet/BulletDynamics/ConstraintSolver/btContactSolverInfo.h
+++ b/thirdparty/bullet/BulletDynamics/ConstraintSolver/btContactSolverInfo.h
@@ -29,7 +29,8 @@ enum btSolverMode
SOLVER_CACHE_FRIENDLY = 128,
SOLVER_SIMD = 256,
SOLVER_INTERLEAVE_CONTACT_AND_FRICTION_CONSTRAINTS = 512,
- SOLVER_ALLOW_ZERO_LENGTH_FRICTION_DIRECTIONS = 1024
+ SOLVER_ALLOW_ZERO_LENGTH_FRICTION_DIRECTIONS = 1024,
+ SOLVER_DISABLE_IMPLICIT_CONE_FRICTION = 2048
};
struct btContactSolverInfoData
diff --git a/thirdparty/bullet/BulletDynamics/ConstraintSolver/btGeneric6DofConstraint.cpp b/thirdparty/bullet/BulletDynamics/ConstraintSolver/btGeneric6DofConstraint.cpp
index fa17254ec3..c38b8353f0 100644
--- a/thirdparty/bullet/BulletDynamics/ConstraintSolver/btGeneric6DofConstraint.cpp
+++ b/thirdparty/bullet/BulletDynamics/ConstraintSolver/btGeneric6DofConstraint.cpp
@@ -855,8 +855,8 @@ int btGeneric6DofConstraint::get_limit_motor_info2(
tag_vel,
info->fps * limot->m_stopERP);
info->m_constraintError[srow] += mot_fact * limot->m_targetVelocity;
- info->m_lowerLimit[srow] = -limot->m_maxMotorForce;
- info->m_upperLimit[srow] = limot->m_maxMotorForce;
+ info->m_lowerLimit[srow] = -limot->m_maxMotorForce / info->fps;
+ info->m_upperLimit[srow] = limot->m_maxMotorForce / info->fps;
}
}
if(limit)
diff --git a/thirdparty/bullet/BulletDynamics/ConstraintSolver/btGeneric6DofConstraint.h b/thirdparty/bullet/BulletDynamics/ConstraintSolver/btGeneric6DofConstraint.h
index bea8629c32..b2ad45f749 100644
--- a/thirdparty/bullet/BulletDynamics/ConstraintSolver/btGeneric6DofConstraint.h
+++ b/thirdparty/bullet/BulletDynamics/ConstraintSolver/btGeneric6DofConstraint.h
@@ -77,7 +77,7 @@ public:
{
m_accumulatedImpulse = 0.f;
m_targetVelocity = 0;
- m_maxMotorForce = 0.1f;
+ m_maxMotorForce = 6.0f;
m_maxLimitForce = 300.0f;
m_loLimit = 1.0f;
m_hiLimit = -1.0f;
diff --git a/thirdparty/bullet/BulletDynamics/ConstraintSolver/btGeneric6DofSpring2Constraint.cpp b/thirdparty/bullet/BulletDynamics/ConstraintSolver/btGeneric6DofSpring2Constraint.cpp
index f0976ee493..540dcd18f7 100644
--- a/thirdparty/bullet/BulletDynamics/ConstraintSolver/btGeneric6DofSpring2Constraint.cpp
+++ b/thirdparty/bullet/BulletDynamics/ConstraintSolver/btGeneric6DofSpring2Constraint.cpp
@@ -719,8 +719,8 @@ int btGeneric6DofSpring2Constraint::get_limit_motor_info2(
tag_vel,
info->fps * limot->m_motorERP);
info->m_constraintError[srow] = mot_fact * limot->m_targetVelocity;
- info->m_lowerLimit[srow] = -limot->m_maxMotorForce;
- info->m_upperLimit[srow] = limot->m_maxMotorForce;
+ info->m_lowerLimit[srow] = -limot->m_maxMotorForce / info->fps;
+ info->m_upperLimit[srow] = limot->m_maxMotorForce / info->fps;
info->cfm[srow] = limot->m_motorCFM;
srow += info->rowskip;
++count;
@@ -769,8 +769,8 @@ int btGeneric6DofSpring2Constraint::get_limit_motor_info2(
mot_fact = 0;
}
info->m_constraintError[srow] = mot_fact * targetvelocity * (rotational ? -1 : 1);
- info->m_lowerLimit[srow] = -limot->m_maxMotorForce;
- info->m_upperLimit[srow] = limot->m_maxMotorForce;
+ info->m_lowerLimit[srow] = -limot->m_maxMotorForce / info->fps;
+ info->m_upperLimit[srow] = limot->m_maxMotorForce / info->fps;
info->cfm[srow] = limot->m_motorCFM;
srow += info->rowskip;
++count;
@@ -797,6 +797,12 @@ int btGeneric6DofSpring2Constraint::get_limit_motor_info2(
btScalar cfm = BT_ZERO;
btScalar mA = BT_ONE / m_rbA.getInvMass();
btScalar mB = BT_ONE / m_rbB.getInvMass();
+ if (rotational) {
+ btScalar rrA = (m_calculatedTransformA.getOrigin() - transA.getOrigin()).length2();
+ btScalar rrB = (m_calculatedTransformB.getOrigin() - transB.getOrigin()).length2();
+ if (m_rbA.getInvMass()) mA = mA * rrA + 1 / (m_rbA.getInvInertiaTensorWorld() * ax1).length();
+ if (m_rbB.getInvMass()) mB = mB * rrB + 1 / (m_rbB.getInvInertiaTensorWorld() * ax1).length();
+ }
btScalar m = mA > mB ? mB : mA;
btScalar angularfreq = sqrt(ks / m);
@@ -815,7 +821,18 @@ int btGeneric6DofSpring2Constraint::get_limit_motor_info2(
btScalar fd = -kd * (vel) * (rotational ? -1 : 1) * dt;
btScalar f = (fs+fd);
- info->m_constraintError[srow] = (vel + f * (rotational ? -1 : 1)) ;
+ // after the spring force affecting the body(es) the new velocity will be
+ // vel + f / m * (rotational ? -1 : 1)
+ // so in theory this should be set here for m_constraintError
+ // (with m_constraintError we set a desired velocity for the affected body(es))
+ // however in practice any value is fine as long as it is greater then the "proper" velocity,
+ // because the m_lowerLimit and the m_upperLimit will determinate the strength of the final pulling force
+ // so it is much simpler (and more robust) just to simply use inf (with the proper sign)
+ // you may also wonder what if the current velocity (vel) so high that the pulling force will not change its direction (in this iteration)
+ // will we not request a velocity with the wrong direction ?
+ // and the answare is not, because in practice during the solving the current velocity is subtracted from the m_constraintError
+ // so the sign of the force that is really matters
+ info->m_constraintError[srow] = (rotational ? -1 : 1) * (f < 0 ? -SIMD_INFINITY : SIMD_INFINITY);
btScalar minf = f < fd ? f : fd;
btScalar maxf = f < fd ? fd : f;
diff --git a/thirdparty/bullet/BulletDynamics/ConstraintSolver/btGeneric6DofSpring2Constraint.h b/thirdparty/bullet/BulletDynamics/ConstraintSolver/btGeneric6DofSpring2Constraint.h
index 66d1769583..1b8d0eace9 100644
--- a/thirdparty/bullet/BulletDynamics/ConstraintSolver/btGeneric6DofSpring2Constraint.h
+++ b/thirdparty/bullet/BulletDynamics/ConstraintSolver/btGeneric6DofSpring2Constraint.h
@@ -107,7 +107,7 @@ public:
m_motorCFM = 0.f;
m_enableMotor = false;
m_targetVelocity = 0;
- m_maxMotorForce = 0.1f;
+ m_maxMotorForce = 6.0f;
m_servoMotor = false;
m_servoTarget = 0;
m_enableSpring = false;
diff --git a/thirdparty/bullet/BulletDynamics/ConstraintSolver/btGeneric6DofSpringConstraint.cpp b/thirdparty/bullet/BulletDynamics/ConstraintSolver/btGeneric6DofSpringConstraint.cpp
index 6f765884ec..3f875989ea 100644
--- a/thirdparty/bullet/BulletDynamics/ConstraintSolver/btGeneric6DofSpringConstraint.cpp
+++ b/thirdparty/bullet/BulletDynamics/ConstraintSolver/btGeneric6DofSpringConstraint.cpp
@@ -131,7 +131,7 @@ void btGeneric6DofSpringConstraint::internalUpdateSprings(btConstraintInfo2* inf
btScalar force = delta * m_springStiffness[i];
btScalar velFactor = info->fps * m_springDamping[i] / btScalar(info->m_numIterations);
m_linearLimits.m_targetVelocity[i] = velFactor * force;
- m_linearLimits.m_maxMotorForce[i] = btFabs(force) / info->fps;
+ m_linearLimits.m_maxMotorForce[i] = btFabs(force);
}
}
for(i = 0; i < 3; i++)
@@ -146,7 +146,7 @@ void btGeneric6DofSpringConstraint::internalUpdateSprings(btConstraintInfo2* inf
btScalar force = -delta * m_springStiffness[i+3];
btScalar velFactor = info->fps * m_springDamping[i+3] / btScalar(info->m_numIterations);
m_angularLimits[i].m_targetVelocity = velFactor * force;
- m_angularLimits[i].m_maxMotorForce = btFabs(force) / info->fps;
+ m_angularLimits[i].m_maxMotorForce = btFabs(force);
}
}
}
diff --git a/thirdparty/bullet/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.cpp b/thirdparty/bullet/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.cpp
index b0d57a3e87..63174a6ec0 100644
--- a/thirdparty/bullet/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.cpp
+++ b/thirdparty/bullet/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.cpp
@@ -21,6 +21,7 @@ subject to the following restrictions:
#include "btSequentialImpulseConstraintSolver.h"
#include "BulletCollision/NarrowPhaseCollision/btPersistentManifold.h"
+
#include "LinearMath/btIDebugDraw.h"
#include "LinearMath/btCpuFeatureUtility.h"
@@ -42,11 +43,11 @@ int gNumSplitImpulseRecoveries = 0;
//#define VERBOSE_RESIDUAL_PRINTF 1
///This is the scalar reference implementation of solving a single constraint row, the innerloop of the Projected Gauss Seidel/Sequential Impulse constraint solver
///Below are optional SSE2 and SSE4/FMA3 versions. We assume most hardware has SSE2. For SSE4/FMA3 we perform a CPU feature check.
-static btSimdScalar gResolveSingleConstraintRowGeneric_scalar_reference(btSolverBody& body1, btSolverBody& body2, const btSolverConstraint& c)
+static btScalar gResolveSingleConstraintRowGeneric_scalar_reference(btSolverBody& bodyA, btSolverBody& bodyB, const btSolverConstraint& c)
{
btScalar deltaImpulse = c.m_rhs - btScalar(c.m_appliedImpulse)*c.m_cfm;
- const btScalar deltaVel1Dotn = c.m_contactNormal1.dot(body1.internalGetDeltaLinearVelocity()) + c.m_relpos1CrossNormal.dot(body1.internalGetDeltaAngularVelocity());
- const btScalar deltaVel2Dotn = c.m_contactNormal2.dot(body2.internalGetDeltaLinearVelocity()) + c.m_relpos2CrossNormal.dot(body2.internalGetDeltaAngularVelocity());
+ const btScalar deltaVel1Dotn = c.m_contactNormal1.dot(bodyA.internalGetDeltaLinearVelocity()) + c.m_relpos1CrossNormal.dot(bodyA.internalGetDeltaAngularVelocity());
+ const btScalar deltaVel2Dotn = c.m_contactNormal2.dot(bodyB.internalGetDeltaLinearVelocity()) + c.m_relpos2CrossNormal.dot(bodyB.internalGetDeltaAngularVelocity());
// const btScalar delta_rel_vel = deltaVel1Dotn-deltaVel2Dotn;
deltaImpulse -= deltaVel1Dotn*c.m_jacDiagABInv;
@@ -68,18 +69,18 @@ static btSimdScalar gResolveSingleConstraintRowGeneric_scalar_reference(btSolver
c.m_appliedImpulse = sum;
}
- body1.internalApplyImpulse(c.m_contactNormal1*body1.internalGetInvMass(), c.m_angularComponentA, deltaImpulse);
- body2.internalApplyImpulse(c.m_contactNormal2*body2.internalGetInvMass(), c.m_angularComponentB, deltaImpulse);
+ bodyA.internalApplyImpulse(c.m_contactNormal1*bodyA.internalGetInvMass(), c.m_angularComponentA, deltaImpulse);
+ bodyB.internalApplyImpulse(c.m_contactNormal2*bodyB.internalGetInvMass(), c.m_angularComponentB, deltaImpulse);
- return deltaImpulse;
+ return deltaImpulse*(1./c.m_jacDiagABInv);
}
-static btSimdScalar gResolveSingleConstraintRowLowerLimit_scalar_reference(btSolverBody& body1, btSolverBody& body2, const btSolverConstraint& c)
+static btScalar gResolveSingleConstraintRowLowerLimit_scalar_reference(btSolverBody& bodyA, btSolverBody& bodyB, const btSolverConstraint& c)
{
btScalar deltaImpulse = c.m_rhs - btScalar(c.m_appliedImpulse)*c.m_cfm;
- const btScalar deltaVel1Dotn = c.m_contactNormal1.dot(body1.internalGetDeltaLinearVelocity()) + c.m_relpos1CrossNormal.dot(body1.internalGetDeltaAngularVelocity());
- const btScalar deltaVel2Dotn = c.m_contactNormal2.dot(body2.internalGetDeltaLinearVelocity()) + c.m_relpos2CrossNormal.dot(body2.internalGetDeltaAngularVelocity());
+ const btScalar deltaVel1Dotn = c.m_contactNormal1.dot(bodyA.internalGetDeltaLinearVelocity()) + c.m_relpos1CrossNormal.dot(bodyA.internalGetDeltaAngularVelocity());
+ const btScalar deltaVel2Dotn = c.m_contactNormal2.dot(bodyB.internalGetDeltaLinearVelocity()) + c.m_relpos2CrossNormal.dot(bodyB.internalGetDeltaAngularVelocity());
deltaImpulse -= deltaVel1Dotn*c.m_jacDiagABInv;
deltaImpulse -= deltaVel2Dotn*c.m_jacDiagABInv;
@@ -93,10 +94,10 @@ static btSimdScalar gResolveSingleConstraintRowLowerLimit_scalar_reference(btSol
{
c.m_appliedImpulse = sum;
}
- body1.internalApplyImpulse(c.m_contactNormal1*body1.internalGetInvMass(), c.m_angularComponentA, deltaImpulse);
- body2.internalApplyImpulse(c.m_contactNormal2*body2.internalGetInvMass(), c.m_angularComponentB, deltaImpulse);
+ bodyA.internalApplyImpulse(c.m_contactNormal1*bodyA.internalGetInvMass(), c.m_angularComponentA, deltaImpulse);
+ bodyB.internalApplyImpulse(c.m_contactNormal2*bodyB.internalGetInvMass(), c.m_angularComponentB, deltaImpulse);
- return deltaImpulse;
+ return deltaImpulse*(1./c.m_jacDiagABInv);
}
@@ -149,14 +150,14 @@ static inline __m128 btSimdDot3( __m128 vec0, __m128 vec1 )
#endif
// Project Gauss Seidel or the equivalent Sequential Impulse
-static btSimdScalar gResolveSingleConstraintRowGeneric_sse2(btSolverBody& body1, btSolverBody& body2, const btSolverConstraint& c)
+static btScalar gResolveSingleConstraintRowGeneric_sse2(btSolverBody& bodyA, btSolverBody& bodyB, const btSolverConstraint& c)
{
__m128 cpAppliedImp = _mm_set1_ps(c.m_appliedImpulse);
__m128 lowerLimit1 = _mm_set1_ps(c.m_lowerLimit);
__m128 upperLimit1 = _mm_set1_ps(c.m_upperLimit);
btSimdScalar deltaImpulse = _mm_sub_ps(_mm_set1_ps(c.m_rhs), _mm_mul_ps(_mm_set1_ps(c.m_appliedImpulse), _mm_set1_ps(c.m_cfm)));
- __m128 deltaVel1Dotn = _mm_add_ps(btSimdDot3(c.m_contactNormal1.mVec128, body1.internalGetDeltaLinearVelocity().mVec128), btSimdDot3(c.m_relpos1CrossNormal.mVec128, body1.internalGetDeltaAngularVelocity().mVec128));
- __m128 deltaVel2Dotn = _mm_add_ps(btSimdDot3(c.m_contactNormal2.mVec128, body2.internalGetDeltaLinearVelocity().mVec128), btSimdDot3(c.m_relpos2CrossNormal.mVec128, body2.internalGetDeltaAngularVelocity().mVec128));
+ __m128 deltaVel1Dotn = _mm_add_ps(btSimdDot3(c.m_contactNormal1.mVec128, bodyA.internalGetDeltaLinearVelocity().mVec128), btSimdDot3(c.m_relpos1CrossNormal.mVec128, bodyA.internalGetDeltaAngularVelocity().mVec128));
+ __m128 deltaVel2Dotn = _mm_add_ps(btSimdDot3(c.m_contactNormal2.mVec128, bodyB.internalGetDeltaLinearVelocity().mVec128), btSimdDot3(c.m_relpos2CrossNormal.mVec128, bodyB.internalGetDeltaAngularVelocity().mVec128));
deltaImpulse = _mm_sub_ps(deltaImpulse, _mm_mul_ps(deltaVel1Dotn, _mm_set1_ps(c.m_jacDiagABInv)));
deltaImpulse = _mm_sub_ps(deltaImpulse, _mm_mul_ps(deltaVel2Dotn, _mm_set1_ps(c.m_jacDiagABInv)));
btSimdScalar sum = _mm_add_ps(cpAppliedImp, deltaImpulse);
@@ -169,27 +170,27 @@ static btSimdScalar gResolveSingleConstraintRowGeneric_sse2(btSolverBody& body1,
__m128 upperMinApplied = _mm_sub_ps(upperLimit1, cpAppliedImp);
deltaImpulse = _mm_or_ps(_mm_and_ps(resultUpperLess, deltaImpulse), _mm_andnot_ps(resultUpperLess, upperMinApplied));
c.m_appliedImpulse = _mm_or_ps(_mm_and_ps(resultUpperLess, c.m_appliedImpulse), _mm_andnot_ps(resultUpperLess, upperLimit1));
- __m128 linearComponentA = _mm_mul_ps(c.m_contactNormal1.mVec128, body1.internalGetInvMass().mVec128);
- __m128 linearComponentB = _mm_mul_ps((c.m_contactNormal2).mVec128, body2.internalGetInvMass().mVec128);
+ __m128 linearComponentA = _mm_mul_ps(c.m_contactNormal1.mVec128, bodyA.internalGetInvMass().mVec128);
+ __m128 linearComponentB = _mm_mul_ps((c.m_contactNormal2).mVec128, bodyB.internalGetInvMass().mVec128);
__m128 impulseMagnitude = deltaImpulse;
- body1.internalGetDeltaLinearVelocity().mVec128 = _mm_add_ps(body1.internalGetDeltaLinearVelocity().mVec128, _mm_mul_ps(linearComponentA, impulseMagnitude));
- body1.internalGetDeltaAngularVelocity().mVec128 = _mm_add_ps(body1.internalGetDeltaAngularVelocity().mVec128, _mm_mul_ps(c.m_angularComponentA.mVec128, impulseMagnitude));
- body2.internalGetDeltaLinearVelocity().mVec128 = _mm_add_ps(body2.internalGetDeltaLinearVelocity().mVec128, _mm_mul_ps(linearComponentB, impulseMagnitude));
- body2.internalGetDeltaAngularVelocity().mVec128 = _mm_add_ps(body2.internalGetDeltaAngularVelocity().mVec128, _mm_mul_ps(c.m_angularComponentB.mVec128, impulseMagnitude));
- return deltaImpulse;
+ bodyA.internalGetDeltaLinearVelocity().mVec128 = _mm_add_ps(bodyA.internalGetDeltaLinearVelocity().mVec128, _mm_mul_ps(linearComponentA, impulseMagnitude));
+ bodyA.internalGetDeltaAngularVelocity().mVec128 = _mm_add_ps(bodyA.internalGetDeltaAngularVelocity().mVec128, _mm_mul_ps(c.m_angularComponentA.mVec128, impulseMagnitude));
+ bodyB.internalGetDeltaLinearVelocity().mVec128 = _mm_add_ps(bodyB.internalGetDeltaLinearVelocity().mVec128, _mm_mul_ps(linearComponentB, impulseMagnitude));
+ bodyB.internalGetDeltaAngularVelocity().mVec128 = _mm_add_ps(bodyB.internalGetDeltaAngularVelocity().mVec128, _mm_mul_ps(c.m_angularComponentB.mVec128, impulseMagnitude));
+ return deltaImpulse.m_floats[0]/c.m_jacDiagABInv;
}
// Enhanced version of gResolveSingleConstraintRowGeneric_sse2 with SSE4.1 and FMA3
-static btSimdScalar gResolveSingleConstraintRowGeneric_sse4_1_fma3(btSolverBody& body1, btSolverBody& body2, const btSolverConstraint& c)
+static btScalar gResolveSingleConstraintRowGeneric_sse4_1_fma3(btSolverBody& bodyA, btSolverBody& bodyB, const btSolverConstraint& c)
{
#if defined (BT_ALLOW_SSE4)
__m128 tmp = _mm_set_ps1(c.m_jacDiagABInv);
__m128 deltaImpulse = _mm_set_ps1(c.m_rhs - btScalar(c.m_appliedImpulse)*c.m_cfm);
const __m128 lowerLimit = _mm_set_ps1(c.m_lowerLimit);
const __m128 upperLimit = _mm_set_ps1(c.m_upperLimit);
- const __m128 deltaVel1Dotn = _mm_add_ps(DOT_PRODUCT(c.m_contactNormal1.mVec128, body1.internalGetDeltaLinearVelocity().mVec128), DOT_PRODUCT(c.m_relpos1CrossNormal.mVec128, body1.internalGetDeltaAngularVelocity().mVec128));
- const __m128 deltaVel2Dotn = _mm_add_ps(DOT_PRODUCT(c.m_contactNormal2.mVec128, body2.internalGetDeltaLinearVelocity().mVec128), DOT_PRODUCT(c.m_relpos2CrossNormal.mVec128, body2.internalGetDeltaAngularVelocity().mVec128));
+ const __m128 deltaVel1Dotn = _mm_add_ps(DOT_PRODUCT(c.m_contactNormal1.mVec128, bodyA.internalGetDeltaLinearVelocity().mVec128), DOT_PRODUCT(c.m_relpos1CrossNormal.mVec128, bodyA.internalGetDeltaAngularVelocity().mVec128));
+ const __m128 deltaVel2Dotn = _mm_add_ps(DOT_PRODUCT(c.m_contactNormal2.mVec128, bodyB.internalGetDeltaLinearVelocity().mVec128), DOT_PRODUCT(c.m_relpos2CrossNormal.mVec128, bodyB.internalGetDeltaAngularVelocity().mVec128));
deltaImpulse = FMNADD(deltaVel1Dotn, tmp, deltaImpulse);
deltaImpulse = FMNADD(deltaVel2Dotn, tmp, deltaImpulse);
tmp = _mm_add_ps(c.m_appliedImpulse, deltaImpulse); // sum
@@ -197,26 +198,27 @@ static btSimdScalar gResolveSingleConstraintRowGeneric_sse4_1_fma3(btSolverBody&
const __m128 maskUpper = _mm_cmpgt_ps(upperLimit, tmp);
deltaImpulse = _mm_blendv_ps(_mm_sub_ps(lowerLimit, c.m_appliedImpulse), _mm_blendv_ps(_mm_sub_ps(upperLimit, c.m_appliedImpulse), deltaImpulse, maskUpper), maskLower);
c.m_appliedImpulse = _mm_blendv_ps(lowerLimit, _mm_blendv_ps(upperLimit, tmp, maskUpper), maskLower);
- body1.internalGetDeltaLinearVelocity().mVec128 = FMADD(_mm_mul_ps(c.m_contactNormal1.mVec128, body1.internalGetInvMass().mVec128), deltaImpulse, body1.internalGetDeltaLinearVelocity().mVec128);
- body1.internalGetDeltaAngularVelocity().mVec128 = FMADD(c.m_angularComponentA.mVec128, deltaImpulse, body1.internalGetDeltaAngularVelocity().mVec128);
- body2.internalGetDeltaLinearVelocity().mVec128 = FMADD(_mm_mul_ps(c.m_contactNormal2.mVec128, body2.internalGetInvMass().mVec128), deltaImpulse, body2.internalGetDeltaLinearVelocity().mVec128);
- body2.internalGetDeltaAngularVelocity().mVec128 = FMADD(c.m_angularComponentB.mVec128, deltaImpulse, body2.internalGetDeltaAngularVelocity().mVec128);
- return deltaImpulse;
+ bodyA.internalGetDeltaLinearVelocity().mVec128 = FMADD(_mm_mul_ps(c.m_contactNormal1.mVec128, bodyA.internalGetInvMass().mVec128), deltaImpulse, bodyA.internalGetDeltaLinearVelocity().mVec128);
+ bodyA.internalGetDeltaAngularVelocity().mVec128 = FMADD(c.m_angularComponentA.mVec128, deltaImpulse, bodyA.internalGetDeltaAngularVelocity().mVec128);
+ bodyB.internalGetDeltaLinearVelocity().mVec128 = FMADD(_mm_mul_ps(c.m_contactNormal2.mVec128, bodyB.internalGetInvMass().mVec128), deltaImpulse, bodyB.internalGetDeltaLinearVelocity().mVec128);
+ bodyB.internalGetDeltaAngularVelocity().mVec128 = FMADD(c.m_angularComponentB.mVec128, deltaImpulse, bodyB.internalGetDeltaAngularVelocity().mVec128);
+ btSimdScalar deltaImp = deltaImpulse;
+ return deltaImp.m_floats[0]*(1./c.m_jacDiagABInv);
#else
- return gResolveSingleConstraintRowGeneric_sse2(body1,body2,c);
+ return gResolveSingleConstraintRowGeneric_sse2(bodyA,bodyB,c);
#endif
}
-static btSimdScalar gResolveSingleConstraintRowLowerLimit_sse2(btSolverBody& body1, btSolverBody& body2, const btSolverConstraint& c)
+static btScalar gResolveSingleConstraintRowLowerLimit_sse2(btSolverBody& bodyA, btSolverBody& bodyB, const btSolverConstraint& c)
{
__m128 cpAppliedImp = _mm_set1_ps(c.m_appliedImpulse);
__m128 lowerLimit1 = _mm_set1_ps(c.m_lowerLimit);
__m128 upperLimit1 = _mm_set1_ps(c.m_upperLimit);
btSimdScalar deltaImpulse = _mm_sub_ps(_mm_set1_ps(c.m_rhs), _mm_mul_ps(_mm_set1_ps(c.m_appliedImpulse), _mm_set1_ps(c.m_cfm)));
- __m128 deltaVel1Dotn = _mm_add_ps(btSimdDot3(c.m_contactNormal1.mVec128, body1.internalGetDeltaLinearVelocity().mVec128), btSimdDot3(c.m_relpos1CrossNormal.mVec128, body1.internalGetDeltaAngularVelocity().mVec128));
- __m128 deltaVel2Dotn = _mm_add_ps(btSimdDot3(c.m_contactNormal2.mVec128, body2.internalGetDeltaLinearVelocity().mVec128), btSimdDot3(c.m_relpos2CrossNormal.mVec128, body2.internalGetDeltaAngularVelocity().mVec128));
+ __m128 deltaVel1Dotn = _mm_add_ps(btSimdDot3(c.m_contactNormal1.mVec128, bodyA.internalGetDeltaLinearVelocity().mVec128), btSimdDot3(c.m_relpos1CrossNormal.mVec128, bodyA.internalGetDeltaAngularVelocity().mVec128));
+ __m128 deltaVel2Dotn = _mm_add_ps(btSimdDot3(c.m_contactNormal2.mVec128, bodyB.internalGetDeltaLinearVelocity().mVec128), btSimdDot3(c.m_relpos2CrossNormal.mVec128, bodyB.internalGetDeltaAngularVelocity().mVec128));
deltaImpulse = _mm_sub_ps(deltaImpulse, _mm_mul_ps(deltaVel1Dotn, _mm_set1_ps(c.m_jacDiagABInv)));
deltaImpulse = _mm_sub_ps(deltaImpulse, _mm_mul_ps(deltaVel2Dotn, _mm_set1_ps(c.m_jacDiagABInv)));
btSimdScalar sum = _mm_add_ps(cpAppliedImp, deltaImpulse);
@@ -226,39 +228,40 @@ static btSimdScalar gResolveSingleConstraintRowLowerLimit_sse2(btSolverBody& bod
__m128 lowMinApplied = _mm_sub_ps(lowerLimit1, cpAppliedImp);
deltaImpulse = _mm_or_ps(_mm_and_ps(resultLowerLess, lowMinApplied), _mm_andnot_ps(resultLowerLess, deltaImpulse));
c.m_appliedImpulse = _mm_or_ps(_mm_and_ps(resultLowerLess, lowerLimit1), _mm_andnot_ps(resultLowerLess, sum));
- __m128 linearComponentA = _mm_mul_ps(c.m_contactNormal1.mVec128, body1.internalGetInvMass().mVec128);
- __m128 linearComponentB = _mm_mul_ps(c.m_contactNormal2.mVec128, body2.internalGetInvMass().mVec128);
+ __m128 linearComponentA = _mm_mul_ps(c.m_contactNormal1.mVec128, bodyA.internalGetInvMass().mVec128);
+ __m128 linearComponentB = _mm_mul_ps(c.m_contactNormal2.mVec128, bodyB.internalGetInvMass().mVec128);
__m128 impulseMagnitude = deltaImpulse;
- body1.internalGetDeltaLinearVelocity().mVec128 = _mm_add_ps(body1.internalGetDeltaLinearVelocity().mVec128, _mm_mul_ps(linearComponentA, impulseMagnitude));
- body1.internalGetDeltaAngularVelocity().mVec128 = _mm_add_ps(body1.internalGetDeltaAngularVelocity().mVec128, _mm_mul_ps(c.m_angularComponentA.mVec128, impulseMagnitude));
- body2.internalGetDeltaLinearVelocity().mVec128 = _mm_add_ps(body2.internalGetDeltaLinearVelocity().mVec128, _mm_mul_ps(linearComponentB, impulseMagnitude));
- body2.internalGetDeltaAngularVelocity().mVec128 = _mm_add_ps(body2.internalGetDeltaAngularVelocity().mVec128, _mm_mul_ps(c.m_angularComponentB.mVec128, impulseMagnitude));
- return deltaImpulse;
+ bodyA.internalGetDeltaLinearVelocity().mVec128 = _mm_add_ps(bodyA.internalGetDeltaLinearVelocity().mVec128, _mm_mul_ps(linearComponentA, impulseMagnitude));
+ bodyA.internalGetDeltaAngularVelocity().mVec128 = _mm_add_ps(bodyA.internalGetDeltaAngularVelocity().mVec128, _mm_mul_ps(c.m_angularComponentA.mVec128, impulseMagnitude));
+ bodyB.internalGetDeltaLinearVelocity().mVec128 = _mm_add_ps(bodyB.internalGetDeltaLinearVelocity().mVec128, _mm_mul_ps(linearComponentB, impulseMagnitude));
+ bodyB.internalGetDeltaAngularVelocity().mVec128 = _mm_add_ps(bodyB.internalGetDeltaAngularVelocity().mVec128, _mm_mul_ps(c.m_angularComponentB.mVec128, impulseMagnitude));
+ return deltaImpulse.m_floats[0]/c.m_jacDiagABInv;
}
// Enhanced version of gResolveSingleConstraintRowGeneric_sse2 with SSE4.1 and FMA3
-static btSimdScalar gResolveSingleConstraintRowLowerLimit_sse4_1_fma3(btSolverBody& body1, btSolverBody& body2, const btSolverConstraint& c)
+static btScalar gResolveSingleConstraintRowLowerLimit_sse4_1_fma3(btSolverBody& bodyA, btSolverBody& bodyB, const btSolverConstraint& c)
{
#ifdef BT_ALLOW_SSE4
__m128 tmp = _mm_set_ps1(c.m_jacDiagABInv);
__m128 deltaImpulse = _mm_set_ps1(c.m_rhs - btScalar(c.m_appliedImpulse)*c.m_cfm);
const __m128 lowerLimit = _mm_set_ps1(c.m_lowerLimit);
- const __m128 deltaVel1Dotn = _mm_add_ps(DOT_PRODUCT(c.m_contactNormal1.mVec128, body1.internalGetDeltaLinearVelocity().mVec128), DOT_PRODUCT(c.m_relpos1CrossNormal.mVec128, body1.internalGetDeltaAngularVelocity().mVec128));
- const __m128 deltaVel2Dotn = _mm_add_ps(DOT_PRODUCT(c.m_contactNormal2.mVec128, body2.internalGetDeltaLinearVelocity().mVec128), DOT_PRODUCT(c.m_relpos2CrossNormal.mVec128, body2.internalGetDeltaAngularVelocity().mVec128));
+ const __m128 deltaVel1Dotn = _mm_add_ps(DOT_PRODUCT(c.m_contactNormal1.mVec128, bodyA.internalGetDeltaLinearVelocity().mVec128), DOT_PRODUCT(c.m_relpos1CrossNormal.mVec128, bodyA.internalGetDeltaAngularVelocity().mVec128));
+ const __m128 deltaVel2Dotn = _mm_add_ps(DOT_PRODUCT(c.m_contactNormal2.mVec128, bodyB.internalGetDeltaLinearVelocity().mVec128), DOT_PRODUCT(c.m_relpos2CrossNormal.mVec128, bodyB.internalGetDeltaAngularVelocity().mVec128));
deltaImpulse = FMNADD(deltaVel1Dotn, tmp, deltaImpulse);
deltaImpulse = FMNADD(deltaVel2Dotn, tmp, deltaImpulse);
tmp = _mm_add_ps(c.m_appliedImpulse, deltaImpulse);
const __m128 mask = _mm_cmpgt_ps(tmp, lowerLimit);
deltaImpulse = _mm_blendv_ps(_mm_sub_ps(lowerLimit, c.m_appliedImpulse), deltaImpulse, mask);
c.m_appliedImpulse = _mm_blendv_ps(lowerLimit, tmp, mask);
- body1.internalGetDeltaLinearVelocity().mVec128 = FMADD(_mm_mul_ps(c.m_contactNormal1.mVec128, body1.internalGetInvMass().mVec128), deltaImpulse, body1.internalGetDeltaLinearVelocity().mVec128);
- body1.internalGetDeltaAngularVelocity().mVec128 = FMADD(c.m_angularComponentA.mVec128, deltaImpulse, body1.internalGetDeltaAngularVelocity().mVec128);
- body2.internalGetDeltaLinearVelocity().mVec128 = FMADD(_mm_mul_ps(c.m_contactNormal2.mVec128, body2.internalGetInvMass().mVec128), deltaImpulse, body2.internalGetDeltaLinearVelocity().mVec128);
- body2.internalGetDeltaAngularVelocity().mVec128 = FMADD(c.m_angularComponentB.mVec128, deltaImpulse, body2.internalGetDeltaAngularVelocity().mVec128);
- return deltaImpulse;
+ bodyA.internalGetDeltaLinearVelocity().mVec128 = FMADD(_mm_mul_ps(c.m_contactNormal1.mVec128, bodyA.internalGetInvMass().mVec128), deltaImpulse, bodyA.internalGetDeltaLinearVelocity().mVec128);
+ bodyA.internalGetDeltaAngularVelocity().mVec128 = FMADD(c.m_angularComponentA.mVec128, deltaImpulse, bodyA.internalGetDeltaAngularVelocity().mVec128);
+ bodyB.internalGetDeltaLinearVelocity().mVec128 = FMADD(_mm_mul_ps(c.m_contactNormal2.mVec128, bodyB.internalGetInvMass().mVec128), deltaImpulse, bodyB.internalGetDeltaLinearVelocity().mVec128);
+ bodyB.internalGetDeltaAngularVelocity().mVec128 = FMADD(c.m_angularComponentB.mVec128, deltaImpulse, bodyB.internalGetDeltaAngularVelocity().mVec128);
+ btSimdScalar deltaImp = deltaImpulse;
+ return deltaImp.m_floats[0]*(1./c.m_jacDiagABInv);
#else
- return gResolveSingleConstraintRowLowerLimit_sse2(body1,body2,c);
+ return gResolveSingleConstraintRowLowerLimit_sse2(bodyA,bodyB,c);
#endif //BT_ALLOW_SSE4
}
@@ -267,32 +270,32 @@ static btSimdScalar gResolveSingleConstraintRowLowerLimit_sse4_1_fma3(btSolverBo
-btSimdScalar btSequentialImpulseConstraintSolver::resolveSingleConstraintRowGenericSIMD(btSolverBody& body1,btSolverBody& body2,const btSolverConstraint& c)
+btScalar btSequentialImpulseConstraintSolver::resolveSingleConstraintRowGenericSIMD(btSolverBody& bodyA,btSolverBody& bodyB,const btSolverConstraint& c)
{
- return m_resolveSingleConstraintRowGeneric(body1, body2, c);
+ return m_resolveSingleConstraintRowGeneric(bodyA, bodyB, c);
}
// Project Gauss Seidel or the equivalent Sequential Impulse
-btSimdScalar btSequentialImpulseConstraintSolver::resolveSingleConstraintRowGeneric(btSolverBody& body1,btSolverBody& body2,const btSolverConstraint& c)
+btScalar btSequentialImpulseConstraintSolver::resolveSingleConstraintRowGeneric(btSolverBody& bodyA,btSolverBody& bodyB,const btSolverConstraint& c)
{
- return m_resolveSingleConstraintRowGeneric(body1, body2, c);
+ return m_resolveSingleConstraintRowGeneric(bodyA, bodyB, c);
}
-btSimdScalar btSequentialImpulseConstraintSolver::resolveSingleConstraintRowLowerLimitSIMD(btSolverBody& body1,btSolverBody& body2,const btSolverConstraint& c)
+btScalar btSequentialImpulseConstraintSolver::resolveSingleConstraintRowLowerLimitSIMD(btSolverBody& bodyA,btSolverBody& bodyB,const btSolverConstraint& c)
{
- return m_resolveSingleConstraintRowLowerLimit(body1, body2, c);
+ return m_resolveSingleConstraintRowLowerLimit(bodyA, bodyB, c);
}
-btSimdScalar btSequentialImpulseConstraintSolver::resolveSingleConstraintRowLowerLimit(btSolverBody& body1,btSolverBody& body2,const btSolverConstraint& c)
+btScalar btSequentialImpulseConstraintSolver::resolveSingleConstraintRowLowerLimit(btSolverBody& bodyA,btSolverBody& bodyB,const btSolverConstraint& c)
{
- return m_resolveSingleConstraintRowLowerLimit(body1, body2, c);
+ return m_resolveSingleConstraintRowLowerLimit(bodyA, bodyB, c);
}
-static btSimdScalar gResolveSplitPenetrationImpulse_scalar_reference(
- btSolverBody& body1,
- btSolverBody& body2,
+static btScalar gResolveSplitPenetrationImpulse_scalar_reference(
+ btSolverBody& bodyA,
+ btSolverBody& bodyB,
const btSolverConstraint& c)
{
btScalar deltaImpulse = 0.f;
@@ -301,8 +304,8 @@ static btSimdScalar gResolveSplitPenetrationImpulse_scalar_reference(
{
gNumSplitImpulseRecoveries++;
deltaImpulse = c.m_rhsPenetration-btScalar(c.m_appliedPushImpulse)*c.m_cfm;
- const btScalar deltaVel1Dotn = c.m_contactNormal1.dot(body1.internalGetPushVelocity()) + c.m_relpos1CrossNormal.dot(body1.internalGetTurnVelocity());
- const btScalar deltaVel2Dotn = c.m_contactNormal2.dot(body2.internalGetPushVelocity()) + c.m_relpos2CrossNormal.dot(body2.internalGetTurnVelocity());
+ const btScalar deltaVel1Dotn = c.m_contactNormal1.dot(bodyA.internalGetPushVelocity()) + c.m_relpos1CrossNormal.dot(bodyA.internalGetTurnVelocity());
+ const btScalar deltaVel2Dotn = c.m_contactNormal2.dot(bodyB.internalGetPushVelocity()) + c.m_relpos2CrossNormal.dot(bodyB.internalGetTurnVelocity());
deltaImpulse -= deltaVel1Dotn*c.m_jacDiagABInv;
deltaImpulse -= deltaVel2Dotn*c.m_jacDiagABInv;
@@ -316,13 +319,13 @@ static btSimdScalar gResolveSplitPenetrationImpulse_scalar_reference(
{
c.m_appliedPushImpulse = sum;
}
- body1.internalApplyPushImpulse(c.m_contactNormal1*body1.internalGetInvMass(),c.m_angularComponentA,deltaImpulse);
- body2.internalApplyPushImpulse(c.m_contactNormal2*body2.internalGetInvMass(),c.m_angularComponentB,deltaImpulse);
+ bodyA.internalApplyPushImpulse(c.m_contactNormal1*bodyA.internalGetInvMass(),c.m_angularComponentA,deltaImpulse);
+ bodyB.internalApplyPushImpulse(c.m_contactNormal2*bodyB.internalGetInvMass(),c.m_angularComponentB,deltaImpulse);
}
- return deltaImpulse;
+ return deltaImpulse*(1./c.m_jacDiagABInv);
}
-static btSimdScalar gResolveSplitPenetrationImpulse_sse2(btSolverBody& body1,btSolverBody& body2,const btSolverConstraint& c)
+static btScalar gResolveSplitPenetrationImpulse_sse2(btSolverBody& bodyA,btSolverBody& bodyB,const btSolverConstraint& c)
{
#ifdef USE_SIMD
if (!c.m_rhsPenetration)
@@ -334,8 +337,8 @@ static btSimdScalar gResolveSplitPenetrationImpulse_sse2(btSolverBody& body1,btS
__m128 lowerLimit1 = _mm_set1_ps(c.m_lowerLimit);
__m128 upperLimit1 = _mm_set1_ps(c.m_upperLimit);
__m128 deltaImpulse = _mm_sub_ps(_mm_set1_ps(c.m_rhsPenetration), _mm_mul_ps(_mm_set1_ps(c.m_appliedPushImpulse),_mm_set1_ps(c.m_cfm)));
- __m128 deltaVel1Dotn = _mm_add_ps(btSimdDot3(c.m_contactNormal1.mVec128,body1.internalGetPushVelocity().mVec128), btSimdDot3(c.m_relpos1CrossNormal.mVec128,body1.internalGetTurnVelocity().mVec128));
- __m128 deltaVel2Dotn = _mm_add_ps(btSimdDot3(c.m_contactNormal2.mVec128,body2.internalGetPushVelocity().mVec128), btSimdDot3(c.m_relpos2CrossNormal.mVec128,body2.internalGetTurnVelocity().mVec128));
+ __m128 deltaVel1Dotn = _mm_add_ps(btSimdDot3(c.m_contactNormal1.mVec128,bodyA.internalGetPushVelocity().mVec128), btSimdDot3(c.m_relpos1CrossNormal.mVec128,bodyA.internalGetTurnVelocity().mVec128));
+ __m128 deltaVel2Dotn = _mm_add_ps(btSimdDot3(c.m_contactNormal2.mVec128,bodyB.internalGetPushVelocity().mVec128), btSimdDot3(c.m_relpos2CrossNormal.mVec128,bodyB.internalGetTurnVelocity().mVec128));
deltaImpulse = _mm_sub_ps(deltaImpulse,_mm_mul_ps(deltaVel1Dotn,_mm_set1_ps(c.m_jacDiagABInv)));
deltaImpulse = _mm_sub_ps(deltaImpulse,_mm_mul_ps(deltaVel2Dotn,_mm_set1_ps(c.m_jacDiagABInv)));
btSimdScalar sum = _mm_add_ps(cpAppliedImp,deltaImpulse);
@@ -345,16 +348,17 @@ static btSimdScalar gResolveSplitPenetrationImpulse_sse2(btSolverBody& body1,btS
__m128 lowMinApplied = _mm_sub_ps(lowerLimit1,cpAppliedImp);
deltaImpulse = _mm_or_ps( _mm_and_ps(resultLowerLess, lowMinApplied), _mm_andnot_ps(resultLowerLess, deltaImpulse) );
c.m_appliedPushImpulse = _mm_or_ps( _mm_and_ps(resultLowerLess, lowerLimit1), _mm_andnot_ps(resultLowerLess, sum) );
- __m128 linearComponentA = _mm_mul_ps(c.m_contactNormal1.mVec128,body1.internalGetInvMass().mVec128);
- __m128 linearComponentB = _mm_mul_ps(c.m_contactNormal2.mVec128,body2.internalGetInvMass().mVec128);
+ __m128 linearComponentA = _mm_mul_ps(c.m_contactNormal1.mVec128,bodyA.internalGetInvMass().mVec128);
+ __m128 linearComponentB = _mm_mul_ps(c.m_contactNormal2.mVec128,bodyB.internalGetInvMass().mVec128);
__m128 impulseMagnitude = deltaImpulse;
- body1.internalGetPushVelocity().mVec128 = _mm_add_ps(body1.internalGetPushVelocity().mVec128,_mm_mul_ps(linearComponentA,impulseMagnitude));
- body1.internalGetTurnVelocity().mVec128 = _mm_add_ps(body1.internalGetTurnVelocity().mVec128 ,_mm_mul_ps(c.m_angularComponentA.mVec128,impulseMagnitude));
- body2.internalGetPushVelocity().mVec128 = _mm_add_ps(body2.internalGetPushVelocity().mVec128,_mm_mul_ps(linearComponentB,impulseMagnitude));
- body2.internalGetTurnVelocity().mVec128 = _mm_add_ps(body2.internalGetTurnVelocity().mVec128 ,_mm_mul_ps(c.m_angularComponentB.mVec128,impulseMagnitude));
- return deltaImpulse;
+ bodyA.internalGetPushVelocity().mVec128 = _mm_add_ps(bodyA.internalGetPushVelocity().mVec128,_mm_mul_ps(linearComponentA,impulseMagnitude));
+ bodyA.internalGetTurnVelocity().mVec128 = _mm_add_ps(bodyA.internalGetTurnVelocity().mVec128 ,_mm_mul_ps(c.m_angularComponentA.mVec128,impulseMagnitude));
+ bodyB.internalGetPushVelocity().mVec128 = _mm_add_ps(bodyB.internalGetPushVelocity().mVec128,_mm_mul_ps(linearComponentB,impulseMagnitude));
+ bodyB.internalGetTurnVelocity().mVec128 = _mm_add_ps(bodyB.internalGetTurnVelocity().mVec128 ,_mm_mul_ps(c.m_angularComponentB.mVec128,impulseMagnitude));
+ btSimdScalar deltaImp = deltaImpulse;
+ return deltaImp.m_floats[0] * (1. / c.m_jacDiagABInv);
#else
- return gResolveSplitPenetrationImpulse_scalar_reference(body1,body2,c);
+ return gResolveSplitPenetrationImpulse_scalar_reference(bodyA,bodyB,c);
#endif
}
@@ -548,7 +552,7 @@ void btSequentialImpulseConstraintSolver::setupFrictionConstraint(btSolverConstr
btSolverBody& solverBodyB = m_tmpSolverBodyPool[solverBodyIdB];
btRigidBody* body0 = m_tmpSolverBodyPool[solverBodyIdA].m_originalBody;
- btRigidBody* body1 = m_tmpSolverBodyPool[solverBodyIdB].m_originalBody;
+ btRigidBody* bodyA = m_tmpSolverBodyPool[solverBodyIdB].m_originalBody;
solverConstraint.m_solverBodyIdA = solverBodyIdA;
solverConstraint.m_solverBodyIdB = solverBodyIdB;
@@ -572,12 +576,12 @@ void btSequentialImpulseConstraintSolver::setupFrictionConstraint(btSolverConstr
solverConstraint.m_angularComponentA .setZero();
}
- if (body1)
+ if (bodyA)
{
solverConstraint.m_contactNormal2 = -normalAxis;
btVector3 ftorqueAxis1 = rel_pos2.cross(solverConstraint.m_contactNormal2);
solverConstraint.m_relpos2CrossNormal = ftorqueAxis1;
- solverConstraint.m_angularComponentB = body1->getInvInertiaTensorWorld()*ftorqueAxis1*body1->getAngularFactor();
+ solverConstraint.m_angularComponentB = bodyA->getInvInertiaTensorWorld()*ftorqueAxis1*bodyA->getAngularFactor();
} else
{
solverConstraint.m_contactNormal2.setZero();
@@ -594,10 +598,10 @@ void btSequentialImpulseConstraintSolver::setupFrictionConstraint(btSolverConstr
vec = ( solverConstraint.m_angularComponentA).cross(rel_pos1);
denom0 = body0->getInvMass() + normalAxis.dot(vec);
}
- if (body1)
+ if (bodyA)
{
vec = ( -solverConstraint.m_angularComponentB).cross(rel_pos2);
- denom1 = body1->getInvMass() + normalAxis.dot(vec);
+ denom1 = bodyA->getInvMass() + normalAxis.dot(vec);
}
btScalar denom = relaxation/(denom0+denom1);
solverConstraint.m_jacDiagABInv = denom;
@@ -609,8 +613,8 @@ void btSequentialImpulseConstraintSolver::setupFrictionConstraint(btSolverConstr
btScalar rel_vel;
btScalar vel1Dotn = solverConstraint.m_contactNormal1.dot(body0?solverBodyA.m_linearVelocity+solverBodyA.m_externalForceImpulse:btVector3(0,0,0))
+ solverConstraint.m_relpos1CrossNormal.dot(body0?solverBodyA.m_angularVelocity:btVector3(0,0,0));
- btScalar vel2Dotn = solverConstraint.m_contactNormal2.dot(body1?solverBodyB.m_linearVelocity+solverBodyB.m_externalForceImpulse:btVector3(0,0,0))
- + solverConstraint.m_relpos2CrossNormal.dot(body1?solverBodyB.m_angularVelocity:btVector3(0,0,0));
+ btScalar vel2Dotn = solverConstraint.m_contactNormal2.dot(bodyA?solverBodyB.m_linearVelocity+solverBodyB.m_externalForceImpulse:btVector3(0,0,0))
+ + solverConstraint.m_relpos2CrossNormal.dot(bodyA?solverBodyB.m_angularVelocity:btVector3(0,0,0));
rel_vel = vel1Dotn+vel2Dotn;
@@ -662,7 +666,7 @@ void btSequentialImpulseConstraintSolver::setupTorsionalFrictionConstraint( btSo
btSolverBody& solverBodyB = m_tmpSolverBodyPool[solverBodyIdB];
btRigidBody* body0 = m_tmpSolverBodyPool[solverBodyIdA].m_originalBody;
- btRigidBody* body1 = m_tmpSolverBodyPool[solverBodyIdB].m_originalBody;
+ btRigidBody* bodyA = m_tmpSolverBodyPool[solverBodyIdB].m_originalBody;
solverConstraint.m_solverBodyIdA = solverBodyIdA;
solverConstraint.m_solverBodyIdB = solverBodyIdB;
@@ -681,13 +685,13 @@ void btSequentialImpulseConstraintSolver::setupTorsionalFrictionConstraint( btSo
{
btVector3 ftorqueAxis1 = normalAxis1;
solverConstraint.m_relpos2CrossNormal = ftorqueAxis1;
- solverConstraint.m_angularComponentB = body1 ? body1->getInvInertiaTensorWorld()*ftorqueAxis1*body1->getAngularFactor() : btVector3(0,0,0);
+ solverConstraint.m_angularComponentB = bodyA ? bodyA->getInvInertiaTensorWorld()*ftorqueAxis1*bodyA->getAngularFactor() : btVector3(0,0,0);
}
{
btVector3 iMJaA = body0?body0->getInvInertiaTensorWorld()*solverConstraint.m_relpos1CrossNormal:btVector3(0,0,0);
- btVector3 iMJaB = body1?body1->getInvInertiaTensorWorld()*solverConstraint.m_relpos2CrossNormal:btVector3(0,0,0);
+ btVector3 iMJaB = bodyA?bodyA->getInvInertiaTensorWorld()*solverConstraint.m_relpos2CrossNormal:btVector3(0,0,0);
btScalar sum = 0;
sum += iMJaA.dot(solverConstraint.m_relpos1CrossNormal);
sum += iMJaB.dot(solverConstraint.m_relpos2CrossNormal);
@@ -700,8 +704,8 @@ void btSequentialImpulseConstraintSolver::setupTorsionalFrictionConstraint( btSo
btScalar rel_vel;
btScalar vel1Dotn = solverConstraint.m_contactNormal1.dot(body0?solverBodyA.m_linearVelocity+solverBodyA.m_externalForceImpulse:btVector3(0,0,0))
+ solverConstraint.m_relpos1CrossNormal.dot(body0?solverBodyA.m_angularVelocity:btVector3(0,0,0));
- btScalar vel2Dotn = solverConstraint.m_contactNormal2.dot(body1?solverBodyB.m_linearVelocity+solverBodyB.m_externalForceImpulse:btVector3(0,0,0))
- + solverConstraint.m_relpos2CrossNormal.dot(body1?solverBodyB.m_angularVelocity:btVector3(0,0,0));
+ btScalar vel2Dotn = solverConstraint.m_contactNormal2.dot(bodyA?solverBodyB.m_linearVelocity+solverBodyB.m_externalForceImpulse:btVector3(0,0,0))
+ + solverConstraint.m_relpos2CrossNormal.dot(bodyA?solverBodyB.m_angularVelocity:btVector3(0,0,0));
rel_vel = vel1Dotn+vel2Dotn;
@@ -738,23 +742,21 @@ int btSequentialImpulseConstraintSolver::getOrInitSolverBody(btCollisionObject&
{
#if BT_THREADSAFE
int solverBodyId = -1;
- if ( !body.isStaticOrKinematicObject() )
+ bool isRigidBodyType = btRigidBody::upcast( &body ) != NULL;
+ if ( isRigidBodyType && !body.isStaticOrKinematicObject() )
{
// dynamic body
// Dynamic bodies can only be in one island, so it's safe to write to the companionId
solverBodyId = body.getCompanionId();
if ( solverBodyId < 0 )
{
- if ( btRigidBody* rb = btRigidBody::upcast( &body ) )
- {
- solverBodyId = m_tmpSolverBodyPool.size();
- btSolverBody& solverBody = m_tmpSolverBodyPool.expand();
- initSolverBody( &solverBody, &body, timeStep );
- body.setCompanionId( solverBodyId );
- }
+ solverBodyId = m_tmpSolverBodyPool.size();
+ btSolverBody& solverBody = m_tmpSolverBodyPool.expand();
+ initSolverBody( &solverBody, &body, timeStep );
+ body.setCompanionId( solverBodyId );
}
}
- else if (body.isKinematicObject())
+ else if (isRigidBodyType && body.isKinematicObject())
{
//
// NOTE: must test for kinematic before static because some kinematic objects also
@@ -774,7 +776,6 @@ int btSequentialImpulseConstraintSolver::getOrInitSolverBody(btCollisionObject&
if ( solverBodyId == INVALID_SOLVER_BODY_ID )
{
// create a table entry for this body
- btRigidBody* rb = btRigidBody::upcast( &body );
solverBodyId = m_tmpSolverBodyPool.size();
btSolverBody& solverBody = m_tmpSolverBodyPool.expand();
initSolverBody( &solverBody, &body, timeStep );
@@ -783,6 +784,13 @@ int btSequentialImpulseConstraintSolver::getOrInitSolverBody(btCollisionObject&
}
else
{
+ bool isMultiBodyType = (body.getInternalType()&btCollisionObject::CO_FEATHERSTONE_LINK);
+ // Incorrectly set collision object flags can degrade performance in various ways.
+ if (!isMultiBodyType)
+ {
+ btAssert( body.isStaticOrKinematicObject() );
+ }
+ //it could be a multibody link collider
// all fixed bodies (inf mass) get mapped to a single solver id
if ( m_fixedBodyId < 0 )
{
@@ -792,7 +800,7 @@ int btSequentialImpulseConstraintSolver::getOrInitSolverBody(btCollisionObject&
}
solverBodyId = m_fixedBodyId;
}
- btAssert( solverBodyId < m_tmpSolverBodyPool.size() );
+ btAssert( solverBodyId >= 0 && solverBodyId < m_tmpSolverBodyPool.size() );
return solverBodyId;
#else // BT_THREADSAFE
@@ -1258,6 +1266,256 @@ void btSequentialImpulseConstraintSolver::convertContacts(btPersistentManifold**
}
}
+
+void btSequentialImpulseConstraintSolver::convertJoint(btSolverConstraint* currentConstraintRow,
+ btTypedConstraint* constraint,
+ const btTypedConstraint::btConstraintInfo1& info1,
+ int solverBodyIdA,
+ int solverBodyIdB,
+ const btContactSolverInfo& infoGlobal
+ )
+{
+ const btRigidBody& rbA = constraint->getRigidBodyA();
+ const btRigidBody& rbB = constraint->getRigidBodyB();
+
+ const btSolverBody* bodyAPtr = &m_tmpSolverBodyPool[solverBodyIdA];
+ const btSolverBody* bodyBPtr = &m_tmpSolverBodyPool[solverBodyIdB];
+
+ int overrideNumSolverIterations = constraint->getOverrideNumSolverIterations() > 0 ? constraint->getOverrideNumSolverIterations() : infoGlobal.m_numIterations;
+ if (overrideNumSolverIterations>m_maxOverrideNumSolverIterations)
+ m_maxOverrideNumSolverIterations = overrideNumSolverIterations;
+
+ for (int j=0;j<info1.m_numConstraintRows;j++)
+ {
+ memset(&currentConstraintRow[j],0,sizeof(btSolverConstraint));
+ currentConstraintRow[j].m_lowerLimit = -SIMD_INFINITY;
+ currentConstraintRow[j].m_upperLimit = SIMD_INFINITY;
+ currentConstraintRow[j].m_appliedImpulse = 0.f;
+ currentConstraintRow[j].m_appliedPushImpulse = 0.f;
+ currentConstraintRow[j].m_solverBodyIdA = solverBodyIdA;
+ currentConstraintRow[j].m_solverBodyIdB = solverBodyIdB;
+ currentConstraintRow[j].m_overrideNumSolverIterations = overrideNumSolverIterations;
+ }
+
+ // these vectors are already cleared in initSolverBody, no need to redundantly clear again
+ btAssert(bodyAPtr->getDeltaLinearVelocity().isZero());
+ btAssert(bodyAPtr->getDeltaAngularVelocity().isZero());
+ btAssert(bodyAPtr->getPushVelocity().isZero());
+ btAssert(bodyAPtr->getTurnVelocity().isZero());
+ btAssert(bodyBPtr->getDeltaLinearVelocity().isZero());
+ btAssert(bodyBPtr->getDeltaAngularVelocity().isZero());
+ btAssert(bodyBPtr->getPushVelocity().isZero());
+ btAssert(bodyBPtr->getTurnVelocity().isZero());
+ //bodyAPtr->internalGetDeltaLinearVelocity().setValue(0.f,0.f,0.f);
+ //bodyAPtr->internalGetDeltaAngularVelocity().setValue(0.f,0.f,0.f);
+ //bodyAPtr->internalGetPushVelocity().setValue(0.f,0.f,0.f);
+ //bodyAPtr->internalGetTurnVelocity().setValue(0.f,0.f,0.f);
+ //bodyBPtr->internalGetDeltaLinearVelocity().setValue(0.f,0.f,0.f);
+ //bodyBPtr->internalGetDeltaAngularVelocity().setValue(0.f,0.f,0.f);
+ //bodyBPtr->internalGetPushVelocity().setValue(0.f,0.f,0.f);
+ //bodyBPtr->internalGetTurnVelocity().setValue(0.f,0.f,0.f);
+
+
+ btTypedConstraint::btConstraintInfo2 info2;
+ info2.fps = 1.f/infoGlobal.m_timeStep;
+ info2.erp = infoGlobal.m_erp;
+ info2.m_J1linearAxis = currentConstraintRow->m_contactNormal1;
+ info2.m_J1angularAxis = currentConstraintRow->m_relpos1CrossNormal;
+ info2.m_J2linearAxis = currentConstraintRow->m_contactNormal2;
+ info2.m_J2angularAxis = currentConstraintRow->m_relpos2CrossNormal;
+ info2.rowskip = sizeof(btSolverConstraint)/sizeof(btScalar);//check this
+ ///the size of btSolverConstraint needs be a multiple of btScalar
+ btAssert(info2.rowskip*sizeof(btScalar)== sizeof(btSolverConstraint));
+ info2.m_constraintError = &currentConstraintRow->m_rhs;
+ currentConstraintRow->m_cfm = infoGlobal.m_globalCfm;
+ info2.m_damping = infoGlobal.m_damping;
+ info2.cfm = &currentConstraintRow->m_cfm;
+ info2.m_lowerLimit = &currentConstraintRow->m_lowerLimit;
+ info2.m_upperLimit = &currentConstraintRow->m_upperLimit;
+ info2.m_numIterations = infoGlobal.m_numIterations;
+ constraint->getInfo2(&info2);
+
+ ///finalize the constraint setup
+ for (int j=0;j<info1.m_numConstraintRows;j++)
+ {
+ btSolverConstraint& solverConstraint = currentConstraintRow[j];
+
+ if (solverConstraint.m_upperLimit>=constraint->getBreakingImpulseThreshold())
+ {
+ solverConstraint.m_upperLimit = constraint->getBreakingImpulseThreshold();
+ }
+
+ if (solverConstraint.m_lowerLimit<=-constraint->getBreakingImpulseThreshold())
+ {
+ solverConstraint.m_lowerLimit = -constraint->getBreakingImpulseThreshold();
+ }
+
+ solverConstraint.m_originalContactPoint = constraint;
+
+ {
+ const btVector3& ftorqueAxis1 = solverConstraint.m_relpos1CrossNormal;
+ solverConstraint.m_angularComponentA = constraint->getRigidBodyA().getInvInertiaTensorWorld()*ftorqueAxis1*constraint->getRigidBodyA().getAngularFactor();
+ }
+ {
+ const btVector3& ftorqueAxis2 = solverConstraint.m_relpos2CrossNormal;
+ solverConstraint.m_angularComponentB = constraint->getRigidBodyB().getInvInertiaTensorWorld()*ftorqueAxis2*constraint->getRigidBodyB().getAngularFactor();
+ }
+
+ {
+ btVector3 iMJlA = solverConstraint.m_contactNormal1*rbA.getInvMass();
+ btVector3 iMJaA = rbA.getInvInertiaTensorWorld()*solverConstraint.m_relpos1CrossNormal;
+ btVector3 iMJlB = solverConstraint.m_contactNormal2*rbB.getInvMass();//sign of normal?
+ btVector3 iMJaB = rbB.getInvInertiaTensorWorld()*solverConstraint.m_relpos2CrossNormal;
+
+ btScalar sum = iMJlA.dot(solverConstraint.m_contactNormal1);
+ sum += iMJaA.dot(solverConstraint.m_relpos1CrossNormal);
+ sum += iMJlB.dot(solverConstraint.m_contactNormal2);
+ sum += iMJaB.dot(solverConstraint.m_relpos2CrossNormal);
+ btScalar fsum = btFabs(sum);
+ btAssert(fsum > SIMD_EPSILON);
+ btScalar sorRelaxation = 1.f;//todo: get from globalInfo?
+ solverConstraint.m_jacDiagABInv = fsum>SIMD_EPSILON?sorRelaxation/sum : 0.f;
+ }
+
+ {
+ btScalar rel_vel;
+ btVector3 externalForceImpulseA = bodyAPtr->m_originalBody ? bodyAPtr->m_externalForceImpulse : btVector3(0,0,0);
+ btVector3 externalTorqueImpulseA = bodyAPtr->m_originalBody ? bodyAPtr->m_externalTorqueImpulse : btVector3(0,0,0);
+
+ btVector3 externalForceImpulseB = bodyBPtr->m_originalBody ? bodyBPtr->m_externalForceImpulse : btVector3(0,0,0);
+ btVector3 externalTorqueImpulseB = bodyBPtr->m_originalBody ?bodyBPtr->m_externalTorqueImpulse : btVector3(0,0,0);
+
+ btScalar vel1Dotn = solverConstraint.m_contactNormal1.dot(rbA.getLinearVelocity()+externalForceImpulseA)
+ + solverConstraint.m_relpos1CrossNormal.dot(rbA.getAngularVelocity()+externalTorqueImpulseA);
+
+ btScalar vel2Dotn = solverConstraint.m_contactNormal2.dot(rbB.getLinearVelocity()+externalForceImpulseB)
+ + solverConstraint.m_relpos2CrossNormal.dot(rbB.getAngularVelocity()+externalTorqueImpulseB);
+
+ rel_vel = vel1Dotn+vel2Dotn;
+ btScalar restitution = 0.f;
+ btScalar positionalError = solverConstraint.m_rhs;//already filled in by getConstraintInfo2
+ btScalar velocityError = restitution - rel_vel * info2.m_damping;
+ btScalar penetrationImpulse = positionalError*solverConstraint.m_jacDiagABInv;
+ btScalar velocityImpulse = velocityError *solverConstraint.m_jacDiagABInv;
+ solverConstraint.m_rhs = penetrationImpulse+velocityImpulse;
+ solverConstraint.m_appliedImpulse = 0.f;
+ }
+ }
+}
+
+
+void btSequentialImpulseConstraintSolver::convertJoints(btTypedConstraint** constraints,int numConstraints,const btContactSolverInfo& infoGlobal)
+{
+ BT_PROFILE("convertJoints");
+ for (int j=0;j<numConstraints;j++)
+ {
+ btTypedConstraint* constraint = constraints[j];
+ constraint->buildJacobian();
+ constraint->internalSetAppliedImpulse(0.0f);
+ }
+
+ int totalNumRows = 0;
+
+ m_tmpConstraintSizesPool.resizeNoInitialize(numConstraints);
+ //calculate the total number of contraint rows
+ for (int i=0;i<numConstraints;i++)
+ {
+ btTypedConstraint::btConstraintInfo1& info1 = m_tmpConstraintSizesPool[i];
+ btJointFeedback* fb = constraints[i]->getJointFeedback();
+ if (fb)
+ {
+ fb->m_appliedForceBodyA.setZero();
+ fb->m_appliedTorqueBodyA.setZero();
+ fb->m_appliedForceBodyB.setZero();
+ fb->m_appliedTorqueBodyB.setZero();
+ }
+
+ if (constraints[i]->isEnabled())
+ {
+ constraints[i]->getInfo1(&info1);
+ } else
+ {
+ info1.m_numConstraintRows = 0;
+ info1.nub = 0;
+ }
+ totalNumRows += info1.m_numConstraintRows;
+ }
+ m_tmpSolverNonContactConstraintPool.resizeNoInitialize(totalNumRows);
+
+
+ ///setup the btSolverConstraints
+ int currentRow = 0;
+
+ for (int i=0;i<numConstraints;i++)
+ {
+ const btTypedConstraint::btConstraintInfo1& info1 = m_tmpConstraintSizesPool[i];
+
+ if (info1.m_numConstraintRows)
+ {
+ btAssert(currentRow<totalNumRows);
+
+ btSolverConstraint* currentConstraintRow = &m_tmpSolverNonContactConstraintPool[currentRow];
+ btTypedConstraint* constraint = constraints[i];
+ btRigidBody& rbA = constraint->getRigidBodyA();
+ btRigidBody& rbB = constraint->getRigidBodyB();
+
+ int solverBodyIdA = getOrInitSolverBody(rbA,infoGlobal.m_timeStep);
+ int solverBodyIdB = getOrInitSolverBody(rbB,infoGlobal.m_timeStep);
+
+ convertJoint(currentConstraintRow, constraint, info1, solverBodyIdA, solverBodyIdB, infoGlobal);
+ }
+ currentRow+=info1.m_numConstraintRows;
+ }
+}
+
+
+void btSequentialImpulseConstraintSolver::convertBodies(btCollisionObject** bodies, int numBodies, const btContactSolverInfo& infoGlobal)
+{
+ BT_PROFILE("convertBodies");
+ for (int i = 0; i < numBodies; i++)
+ {
+ bodies[i]->setCompanionId(-1);
+ }
+#if BT_THREADSAFE
+ m_kinematicBodyUniqueIdToSolverBodyTable.resize( 0 );
+#endif // BT_THREADSAFE
+
+ m_tmpSolverBodyPool.reserve(numBodies+1);
+ m_tmpSolverBodyPool.resize(0);
+
+ //btSolverBody& fixedBody = m_tmpSolverBodyPool.expand();
+ //initSolverBody(&fixedBody,0);
+
+ for (int i=0;i<numBodies;i++)
+ {
+ int bodyId = getOrInitSolverBody(*bodies[i],infoGlobal.m_timeStep);
+
+ btRigidBody* body = btRigidBody::upcast(bodies[i]);
+ if (body && body->getInvMass())
+ {
+ btSolverBody& solverBody = m_tmpSolverBodyPool[bodyId];
+ btVector3 gyroForce (0,0,0);
+ if (body->getFlags()&BT_ENABLE_GYROSCOPIC_FORCE_EXPLICIT)
+ {
+ gyroForce = body->computeGyroscopicForceExplicit(infoGlobal.m_maxGyroscopicForce);
+ solverBody.m_externalTorqueImpulse -= gyroForce*body->getInvInertiaTensorWorld()*infoGlobal.m_timeStep;
+ }
+ if (body->getFlags()&BT_ENABLE_GYROSCOPIC_FORCE_IMPLICIT_WORLD)
+ {
+ gyroForce = body->computeGyroscopicImpulseImplicit_World(infoGlobal.m_timeStep);
+ solverBody.m_externalTorqueImpulse += gyroForce;
+ }
+ if (body->getFlags()&BT_ENABLE_GYROSCOPIC_FORCE_IMPLICIT_BODY)
+ {
+ gyroForce = body->computeGyroscopicImpulseImplicit_Body(infoGlobal.m_timeStep);
+ solverBody.m_externalTorqueImpulse += gyroForce;
+
+ }
+ }
+ }
+}
+
+
btScalar btSequentialImpulseConstraintSolver::solveGroupCacheFriendlySetup(btCollisionObject** bodies, int numBodies, btPersistentManifold** manifoldPtr, int numManifolds,btTypedConstraint** constraints,int numConstraints,const btContactSolverInfo& infoGlobal,btIDebugDraw* debugDrawer)
{
m_fixedBodyId = -1;
@@ -1344,254 +1602,14 @@ btScalar btSequentialImpulseConstraintSolver::solveGroupCacheFriendlySetup(btCol
#endif //BT_ADDITIONAL_DEBUG
- for (int i = 0; i < numBodies; i++)
- {
- bodies[i]->setCompanionId(-1);
- }
-#if BT_THREADSAFE
- m_kinematicBodyUniqueIdToSolverBodyTable.resize( 0 );
-#endif // BT_THREADSAFE
-
- m_tmpSolverBodyPool.reserve(numBodies+1);
- m_tmpSolverBodyPool.resize(0);
-
- //btSolverBody& fixedBody = m_tmpSolverBodyPool.expand();
- //initSolverBody(&fixedBody,0);
-
//convert all bodies
+ convertBodies(bodies, numBodies, infoGlobal);
+ convertJoints(constraints, numConstraints, infoGlobal);
- for (int i=0;i<numBodies;i++)
- {
- int bodyId = getOrInitSolverBody(*bodies[i],infoGlobal.m_timeStep);
-
- btRigidBody* body = btRigidBody::upcast(bodies[i]);
- if (body && body->getInvMass())
- {
- btSolverBody& solverBody = m_tmpSolverBodyPool[bodyId];
- btVector3 gyroForce (0,0,0);
- if (body->getFlags()&BT_ENABLE_GYROSCOPIC_FORCE_EXPLICIT)
- {
- gyroForce = body->computeGyroscopicForceExplicit(infoGlobal.m_maxGyroscopicForce);
- solverBody.m_externalTorqueImpulse -= gyroForce*body->getInvInertiaTensorWorld()*infoGlobal.m_timeStep;
- }
- if (body->getFlags()&BT_ENABLE_GYROSCOPIC_FORCE_IMPLICIT_WORLD)
- {
- gyroForce = body->computeGyroscopicImpulseImplicit_World(infoGlobal.m_timeStep);
- solverBody.m_externalTorqueImpulse += gyroForce;
- }
- if (body->getFlags()&BT_ENABLE_GYROSCOPIC_FORCE_IMPLICIT_BODY)
- {
- gyroForce = body->computeGyroscopicImpulseImplicit_Body(infoGlobal.m_timeStep);
- solverBody.m_externalTorqueImpulse += gyroForce;
-
- }
-
-
- }
- }
-
- if (1)
- {
- int j;
- for (j=0;j<numConstraints;j++)
- {
- btTypedConstraint* constraint = constraints[j];
- constraint->buildJacobian();
- constraint->internalSetAppliedImpulse(0.0f);
- }
- }
-
- //btRigidBody* rb0=0,*rb1=0;
-
- //if (1)
- {
- {
-
- int totalNumRows = 0;
- int i;
-
- m_tmpConstraintSizesPool.resizeNoInitialize(numConstraints);
- //calculate the total number of contraint rows
- for (i=0;i<numConstraints;i++)
- {
- btTypedConstraint::btConstraintInfo1& info1 = m_tmpConstraintSizesPool[i];
- btJointFeedback* fb = constraints[i]->getJointFeedback();
- if (fb)
- {
- fb->m_appliedForceBodyA.setZero();
- fb->m_appliedTorqueBodyA.setZero();
- fb->m_appliedForceBodyB.setZero();
- fb->m_appliedTorqueBodyB.setZero();
- }
-
- if (constraints[i]->isEnabled())
- {
- }
- if (constraints[i]->isEnabled())
- {
- constraints[i]->getInfo1(&info1);
- } else
- {
- info1.m_numConstraintRows = 0;
- info1.nub = 0;
- }
- totalNumRows += info1.m_numConstraintRows;
- }
- m_tmpSolverNonContactConstraintPool.resizeNoInitialize(totalNumRows);
-
-
- ///setup the btSolverConstraints
- int currentRow = 0;
-
- for (i=0;i<numConstraints;i++)
- {
- const btTypedConstraint::btConstraintInfo1& info1 = m_tmpConstraintSizesPool[i];
-
- if (info1.m_numConstraintRows)
- {
- btAssert(currentRow<totalNumRows);
-
- btSolverConstraint* currentConstraintRow = &m_tmpSolverNonContactConstraintPool[currentRow];
- btTypedConstraint* constraint = constraints[i];
- btRigidBody& rbA = constraint->getRigidBodyA();
- btRigidBody& rbB = constraint->getRigidBodyB();
-
- int solverBodyIdA = getOrInitSolverBody(rbA,infoGlobal.m_timeStep);
- int solverBodyIdB = getOrInitSolverBody(rbB,infoGlobal.m_timeStep);
-
- btSolverBody* bodyAPtr = &m_tmpSolverBodyPool[solverBodyIdA];
- btSolverBody* bodyBPtr = &m_tmpSolverBodyPool[solverBodyIdB];
+ convertContacts(manifoldPtr,numManifolds,infoGlobal);
-
-
- int overrideNumSolverIterations = constraint->getOverrideNumSolverIterations() > 0 ? constraint->getOverrideNumSolverIterations() : infoGlobal.m_numIterations;
- if (overrideNumSolverIterations>m_maxOverrideNumSolverIterations)
- m_maxOverrideNumSolverIterations = overrideNumSolverIterations;
-
-
- int j;
- for ( j=0;j<info1.m_numConstraintRows;j++)
- {
- memset(&currentConstraintRow[j],0,sizeof(btSolverConstraint));
- currentConstraintRow[j].m_lowerLimit = -SIMD_INFINITY;
- currentConstraintRow[j].m_upperLimit = SIMD_INFINITY;
- currentConstraintRow[j].m_appliedImpulse = 0.f;
- currentConstraintRow[j].m_appliedPushImpulse = 0.f;
- currentConstraintRow[j].m_solverBodyIdA = solverBodyIdA;
- currentConstraintRow[j].m_solverBodyIdB = solverBodyIdB;
- currentConstraintRow[j].m_overrideNumSolverIterations = overrideNumSolverIterations;
- }
-
- bodyAPtr->internalGetDeltaLinearVelocity().setValue(0.f,0.f,0.f);
- bodyAPtr->internalGetDeltaAngularVelocity().setValue(0.f,0.f,0.f);
- bodyAPtr->internalGetPushVelocity().setValue(0.f,0.f,0.f);
- bodyAPtr->internalGetTurnVelocity().setValue(0.f,0.f,0.f);
- bodyBPtr->internalGetDeltaLinearVelocity().setValue(0.f,0.f,0.f);
- bodyBPtr->internalGetDeltaAngularVelocity().setValue(0.f,0.f,0.f);
- bodyBPtr->internalGetPushVelocity().setValue(0.f,0.f,0.f);
- bodyBPtr->internalGetTurnVelocity().setValue(0.f,0.f,0.f);
-
-
- btTypedConstraint::btConstraintInfo2 info2;
- info2.fps = 1.f/infoGlobal.m_timeStep;
- info2.erp = infoGlobal.m_erp;
- info2.m_J1linearAxis = currentConstraintRow->m_contactNormal1;
- info2.m_J1angularAxis = currentConstraintRow->m_relpos1CrossNormal;
- info2.m_J2linearAxis = currentConstraintRow->m_contactNormal2;
- info2.m_J2angularAxis = currentConstraintRow->m_relpos2CrossNormal;
- info2.rowskip = sizeof(btSolverConstraint)/sizeof(btScalar);//check this
- ///the size of btSolverConstraint needs be a multiple of btScalar
- btAssert(info2.rowskip*sizeof(btScalar)== sizeof(btSolverConstraint));
- info2.m_constraintError = &currentConstraintRow->m_rhs;
- currentConstraintRow->m_cfm = infoGlobal.m_globalCfm;
- info2.m_damping = infoGlobal.m_damping;
- info2.cfm = &currentConstraintRow->m_cfm;
- info2.m_lowerLimit = &currentConstraintRow->m_lowerLimit;
- info2.m_upperLimit = &currentConstraintRow->m_upperLimit;
- info2.m_numIterations = infoGlobal.m_numIterations;
- constraints[i]->getInfo2(&info2);
-
- ///finalize the constraint setup
- for ( j=0;j<info1.m_numConstraintRows;j++)
- {
- btSolverConstraint& solverConstraint = currentConstraintRow[j];
-
- if (solverConstraint.m_upperLimit>=constraints[i]->getBreakingImpulseThreshold())
- {
- solverConstraint.m_upperLimit = constraints[i]->getBreakingImpulseThreshold();
- }
-
- if (solverConstraint.m_lowerLimit<=-constraints[i]->getBreakingImpulseThreshold())
- {
- solverConstraint.m_lowerLimit = -constraints[i]->getBreakingImpulseThreshold();
- }
-
- solverConstraint.m_originalContactPoint = constraint;
-
- {
- const btVector3& ftorqueAxis1 = solverConstraint.m_relpos1CrossNormal;
- solverConstraint.m_angularComponentA = constraint->getRigidBodyA().getInvInertiaTensorWorld()*ftorqueAxis1*constraint->getRigidBodyA().getAngularFactor();
- }
- {
- const btVector3& ftorqueAxis2 = solverConstraint.m_relpos2CrossNormal;
- solverConstraint.m_angularComponentB = constraint->getRigidBodyB().getInvInertiaTensorWorld()*ftorqueAxis2*constraint->getRigidBodyB().getAngularFactor();
- }
-
- {
- btVector3 iMJlA = solverConstraint.m_contactNormal1*rbA.getInvMass();
- btVector3 iMJaA = rbA.getInvInertiaTensorWorld()*solverConstraint.m_relpos1CrossNormal;
- btVector3 iMJlB = solverConstraint.m_contactNormal2*rbB.getInvMass();//sign of normal?
- btVector3 iMJaB = rbB.getInvInertiaTensorWorld()*solverConstraint.m_relpos2CrossNormal;
-
- btScalar sum = iMJlA.dot(solverConstraint.m_contactNormal1);
- sum += iMJaA.dot(solverConstraint.m_relpos1CrossNormal);
- sum += iMJlB.dot(solverConstraint.m_contactNormal2);
- sum += iMJaB.dot(solverConstraint.m_relpos2CrossNormal);
- btScalar fsum = btFabs(sum);
- btAssert(fsum > SIMD_EPSILON);
- btScalar sorRelaxation = 1.f;//todo: get from globalInfo?
- solverConstraint.m_jacDiagABInv = fsum>SIMD_EPSILON?sorRelaxation/sum : 0.f;
- }
-
-
-
- {
- btScalar rel_vel;
- btVector3 externalForceImpulseA = bodyAPtr->m_originalBody ? bodyAPtr->m_externalForceImpulse : btVector3(0,0,0);
- btVector3 externalTorqueImpulseA = bodyAPtr->m_originalBody ? bodyAPtr->m_externalTorqueImpulse : btVector3(0,0,0);
-
- btVector3 externalForceImpulseB = bodyBPtr->m_originalBody ? bodyBPtr->m_externalForceImpulse : btVector3(0,0,0);
- btVector3 externalTorqueImpulseB = bodyBPtr->m_originalBody ?bodyBPtr->m_externalTorqueImpulse : btVector3(0,0,0);
-
- btScalar vel1Dotn = solverConstraint.m_contactNormal1.dot(rbA.getLinearVelocity()+externalForceImpulseA)
- + solverConstraint.m_relpos1CrossNormal.dot(rbA.getAngularVelocity()+externalTorqueImpulseA);
-
- btScalar vel2Dotn = solverConstraint.m_contactNormal2.dot(rbB.getLinearVelocity()+externalForceImpulseB)
- + solverConstraint.m_relpos2CrossNormal.dot(rbB.getAngularVelocity()+externalTorqueImpulseB);
-
- rel_vel = vel1Dotn+vel2Dotn;
- btScalar restitution = 0.f;
- btScalar positionalError = solverConstraint.m_rhs;//already filled in by getConstraintInfo2
- btScalar velocityError = restitution - rel_vel * info2.m_damping;
- btScalar penetrationImpulse = positionalError*solverConstraint.m_jacDiagABInv;
- btScalar velocityImpulse = velocityError *solverConstraint.m_jacDiagABInv;
- solverConstraint.m_rhs = penetrationImpulse+velocityImpulse;
- solverConstraint.m_appliedImpulse = 0.f;
-
-
- }
- }
- }
- currentRow+=m_tmpConstraintSizesPool[i].m_numConstraintRows;
- }
- }
-
- convertContacts(manifoldPtr,numManifolds,infoGlobal);
-
- }
-
// btContactSolverInfo info = infoGlobal;
@@ -1630,6 +1648,7 @@ btScalar btSequentialImpulseConstraintSolver::solveGroupCacheFriendlySetup(btCol
btScalar btSequentialImpulseConstraintSolver::solveSingleIteration(int iteration, btCollisionObject** /*bodies */,int /*numBodies*/,btPersistentManifold** /*manifoldPtr*/, int /*numManifolds*/,btTypedConstraint** constraints,int numConstraints,const btContactSolverInfo& infoGlobal,btIDebugDraw* /*debugDrawer*/)
{
+ BT_PROFILE("solveSingleIteration");
btScalar leastSquaresResidual = 0.f;
int numNonContactPool = m_tmpSolverNonContactConstraintPool.size();
@@ -1675,7 +1694,7 @@ btScalar btSequentialImpulseConstraintSolver::solveSingleIteration(int iteration
if (iteration < constraint.m_overrideNumSolverIterations)
{
btScalar residual = resolveSingleConstraintRowGeneric(m_tmpSolverBodyPool[constraint.m_solverBodyIdA],m_tmpSolverBodyPool[constraint.m_solverBodyIdB],constraint);
- leastSquaresResidual += residual*residual;
+ leastSquaresResidual = btMax(leastSquaresResidual, residual*residual);
}
}
@@ -1706,7 +1725,7 @@ btScalar btSequentialImpulseConstraintSolver::solveSingleIteration(int iteration
{
const btSolverConstraint& solveManifold = m_tmpSolverContactConstraintPool[m_orderTmpConstraintPool[c]];
btScalar residual = resolveSingleConstraintRowLowerLimit(m_tmpSolverBodyPool[solveManifold.m_solverBodyIdA],m_tmpSolverBodyPool[solveManifold.m_solverBodyIdB],solveManifold);
- leastSquaresResidual += residual*residual;
+ leastSquaresResidual = btMax(leastSquaresResidual, residual*residual);
totalImpulse = solveManifold.m_appliedImpulse;
}
@@ -1723,7 +1742,7 @@ btScalar btSequentialImpulseConstraintSolver::solveSingleIteration(int iteration
solveManifold.m_upperLimit = solveManifold.m_friction*totalImpulse;
btScalar residual = resolveSingleConstraintRowGeneric(m_tmpSolverBodyPool[solveManifold.m_solverBodyIdA],m_tmpSolverBodyPool[solveManifold.m_solverBodyIdB],solveManifold);
- leastSquaresResidual += residual*residual;
+ leastSquaresResidual = btMax(leastSquaresResidual, residual*residual);
}
}
@@ -1738,7 +1757,7 @@ btScalar btSequentialImpulseConstraintSolver::solveSingleIteration(int iteration
solveManifold.m_upperLimit = solveManifold.m_friction*totalImpulse;
btScalar residual = resolveSingleConstraintRowGeneric(m_tmpSolverBodyPool[solveManifold.m_solverBodyIdA],m_tmpSolverBodyPool[solveManifold.m_solverBodyIdB],solveManifold);
- leastSquaresResidual += residual*residual;
+ leastSquaresResidual = btMax(leastSquaresResidual, residual*residual);
}
}
}
@@ -1755,7 +1774,7 @@ btScalar btSequentialImpulseConstraintSolver::solveSingleIteration(int iteration
{
const btSolverConstraint& solveManifold = m_tmpSolverContactConstraintPool[m_orderTmpConstraintPool[j]];
btScalar residual = resolveSingleConstraintRowLowerLimit(m_tmpSolverBodyPool[solveManifold.m_solverBodyIdA],m_tmpSolverBodyPool[solveManifold.m_solverBodyIdB],solveManifold);
- leastSquaresResidual += residual*residual;
+ leastSquaresResidual = btMax(leastSquaresResidual, residual*residual);
}
@@ -1774,7 +1793,7 @@ btScalar btSequentialImpulseConstraintSolver::solveSingleIteration(int iteration
solveManifold.m_upperLimit = solveManifold.m_friction*totalImpulse;
btScalar residual = resolveSingleConstraintRowGeneric(m_tmpSolverBodyPool[solveManifold.m_solverBodyIdA],m_tmpSolverBodyPool[solveManifold.m_solverBodyIdB],solveManifold);
- leastSquaresResidual += residual*residual;
+ leastSquaresResidual = btMax(leastSquaresResidual, residual*residual);
}
}
}
@@ -1796,7 +1815,7 @@ btScalar btSequentialImpulseConstraintSolver::solveSingleIteration(int iteration
rollingFrictionConstraint.m_upperLimit = rollingFrictionMagnitude;
btScalar residual = resolveSingleConstraintRowGeneric(m_tmpSolverBodyPool[rollingFrictionConstraint.m_solverBodyIdA],m_tmpSolverBodyPool[rollingFrictionConstraint.m_solverBodyIdB],rollingFrictionConstraint);
- leastSquaresResidual += residual*residual;
+ leastSquaresResidual = btMax(leastSquaresResidual, residual*residual);
}
}
@@ -1808,6 +1827,7 @@ btScalar btSequentialImpulseConstraintSolver::solveSingleIteration(int iteration
void btSequentialImpulseConstraintSolver::solveGroupCacheFriendlySplitImpulseIterations(btCollisionObject** bodies,int numBodies,btPersistentManifold** manifoldPtr, int numManifolds,btTypedConstraint** constraints,int numConstraints,const btContactSolverInfo& infoGlobal,btIDebugDraw* debugDrawer)
{
+ BT_PROFILE("solveGroupCacheFriendlySplitImpulseIterations");
int iteration;
if (infoGlobal.m_splitImpulse)
{
@@ -1823,7 +1843,7 @@ void btSequentialImpulseConstraintSolver::solveGroupCacheFriendlySplitImpulseIte
const btSolverConstraint& solveManifold = m_tmpSolverContactConstraintPool[m_orderTmpConstraintPool[j]];
btScalar residual = resolveSplitPenetrationImpulse(m_tmpSolverBodyPool[solveManifold.m_solverBodyIdA],m_tmpSolverBodyPool[solveManifold.m_solverBodyIdB],solveManifold);
- leastSquaresResidual += residual*residual;
+ leastSquaresResidual = btMax(leastSquaresResidual, residual*residual);
}
}
if (leastSquaresResidual <= infoGlobal.m_leastSquaresResidualThreshold || iteration>=(infoGlobal.m_numIterations-1))
@@ -1866,14 +1886,9 @@ btScalar btSequentialImpulseConstraintSolver::solveGroupCacheFriendlyIterations(
return 0.f;
}
-btScalar btSequentialImpulseConstraintSolver::solveGroupCacheFriendlyFinish(btCollisionObject** bodies,int numBodies,const btContactSolverInfo& infoGlobal)
+void btSequentialImpulseConstraintSolver::writeBackContacts(int iBegin, int iEnd, const btContactSolverInfo& infoGlobal)
{
- int numPoolConstraints = m_tmpSolverContactConstraintPool.size();
- int i,j;
-
- if (infoGlobal.m_solverMode & SOLVER_USE_WARMSTARTING)
- {
- for (j=0;j<numPoolConstraints;j++)
+ for (int j=iBegin; j<iEnd; j++)
{
const btSolverConstraint& solveManifold = m_tmpSolverContactConstraintPool[j];
btManifoldPoint* pt = (btManifoldPoint*) solveManifold.m_originalContactPoint;
@@ -1889,10 +1904,11 @@ btScalar btSequentialImpulseConstraintSolver::solveGroupCacheFriendlyFinish(btCo
}
//do a callback here?
}
- }
+}
- numPoolConstraints = m_tmpSolverNonContactConstraintPool.size();
- for (j=0;j<numPoolConstraints;j++)
+void btSequentialImpulseConstraintSolver::writeBackJoints(int iBegin, int iEnd, const btContactSolverInfo& infoGlobal)
+{
+ for (int j=iBegin; j<iEnd; j++)
{
const btSolverConstraint& solverConstr = m_tmpSolverNonContactConstraintPool[j];
btTypedConstraint* constr = (btTypedConstraint*)solverConstr.m_originalContactPoint;
@@ -1912,10 +1928,12 @@ btScalar btSequentialImpulseConstraintSolver::solveGroupCacheFriendlyFinish(btCo
constr->setEnabled(false);
}
}
+}
-
- for ( i=0;i<m_tmpSolverBodyPool.size();i++)
+void btSequentialImpulseConstraintSolver::writeBackBodies(int iBegin, int iEnd, const btContactSolverInfo& infoGlobal)
+{
+ for (int i=iBegin; i<iEnd; i++)
{
btRigidBody* body = m_tmpSolverBodyPool[i].m_originalBody;
if (body)
@@ -1939,6 +1957,19 @@ btScalar btSequentialImpulseConstraintSolver::solveGroupCacheFriendlyFinish(btCo
m_tmpSolverBodyPool[i].m_originalBody->setCompanionId(-1);
}
}
+}
+
+btScalar btSequentialImpulseConstraintSolver::solveGroupCacheFriendlyFinish(btCollisionObject** bodies,int numBodies,const btContactSolverInfo& infoGlobal)
+{
+ BT_PROFILE("solveGroupCacheFriendlyFinish");
+
+ if (infoGlobal.m_solverMode & SOLVER_USE_WARMSTARTING)
+ {
+ writeBackContacts(0, m_tmpSolverContactConstraintPool.size(), infoGlobal);
+ }
+
+ writeBackJoints(0, m_tmpSolverNonContactConstraintPool.size(), infoGlobal);
+ writeBackBodies(0, m_tmpSolverBodyPool.size(), infoGlobal);
m_tmpSolverContactConstraintPool.resizeNoInitialize(0);
m_tmpSolverNonContactConstraintPool.resizeNoInitialize(0);
diff --git a/thirdparty/bullet/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.h b/thirdparty/bullet/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.h
index 16c7eb74c1..b834c3dac3 100644
--- a/thirdparty/bullet/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.h
+++ b/thirdparty/bullet/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.h
@@ -4,8 +4,8 @@ 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,
+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.
@@ -27,7 +27,7 @@ class btCollisionObject;
#include "BulletCollision/NarrowPhaseCollision/btManifoldPoint.h"
#include "BulletDynamics/ConstraintSolver/btConstraintSolver.h"
-typedef btSimdScalar(*btSingleConstraintRowSolver)(btSolverBody&, btSolverBody&, const btSolverConstraint&);
+typedef btScalar(*btSingleConstraintRowSolver)(btSolverBody&, btSolverBody&, const btSolverConstraint&);
///The btSequentialImpulseConstraintSolver is a fast SIMD implementation of the Projected Gauss Seidel (iterative LCP) method.
ATTRIBUTE_ALIGNED16(class) btSequentialImpulseConstraintSolver : public btConstraintSolver
@@ -64,44 +64,48 @@ protected:
void setupFrictionConstraint( btSolverConstraint& solverConstraint, const btVector3& normalAxis,int solverBodyIdA,int solverBodyIdB,
btManifoldPoint& cp,const btVector3& rel_pos1,const btVector3& rel_pos2,
- btCollisionObject* colObj0,btCollisionObject* colObj1, btScalar relaxation,
+ btCollisionObject* colObj0,btCollisionObject* colObj1, btScalar relaxation,
const btContactSolverInfo& infoGlobal,
btScalar desiredVelocity=0., btScalar cfmSlip=0.);
void setupTorsionalFrictionConstraint( btSolverConstraint& solverConstraint, const btVector3& normalAxis,int solverBodyIdA,int solverBodyIdB,
btManifoldPoint& cp,btScalar combinedTorsionalFriction, const btVector3& rel_pos1,const btVector3& rel_pos2,
- btCollisionObject* colObj0,btCollisionObject* colObj1, btScalar relaxation,
+ btCollisionObject* colObj0,btCollisionObject* colObj1, btScalar relaxation,
btScalar desiredVelocity=0., btScalar cfmSlip=0.);
btSolverConstraint& addFrictionConstraint(const btVector3& normalAxis,int solverBodyIdA,int solverBodyIdB,int frictionIndex,btManifoldPoint& cp,const btVector3& rel_pos1,const btVector3& rel_pos2,btCollisionObject* colObj0,btCollisionObject* colObj1, btScalar relaxation, const btContactSolverInfo& infoGlobal, btScalar desiredVelocity=0., btScalar cfmSlip=0.);
btSolverConstraint& addTorsionalFrictionConstraint(const btVector3& normalAxis,int solverBodyIdA,int solverBodyIdB,int frictionIndex,btManifoldPoint& cp,btScalar torsionalFriction, const btVector3& rel_pos1,const btVector3& rel_pos2,btCollisionObject* colObj0,btCollisionObject* colObj1, btScalar relaxation, btScalar desiredVelocity=0, btScalar cfmSlip=0.f);
-
- void setupContactConstraint(btSolverConstraint& solverConstraint, int solverBodyIdA, int solverBodyIdB, btManifoldPoint& cp,
+
+ void setupContactConstraint(btSolverConstraint& solverConstraint, int solverBodyIdA, int solverBodyIdB, btManifoldPoint& cp,
const btContactSolverInfo& infoGlobal,btScalar& relaxation, const btVector3& rel_pos1, const btVector3& rel_pos2);
static void applyAnisotropicFriction(btCollisionObject* colObj,btVector3& frictionDirection, int frictionMode);
- void setFrictionConstraintImpulse( btSolverConstraint& solverConstraint, int solverBodyIdA,int solverBodyIdB,
+ void setFrictionConstraintImpulse( btSolverConstraint& solverConstraint, int solverBodyIdA,int solverBodyIdB,
btManifoldPoint& cp, const btContactSolverInfo& infoGlobal);
///m_btSeed2 is used for re-arranging the constraint rows. improves convergence/quality of friction
unsigned long m_btSeed2;
-
+
btScalar restitutionCurve(btScalar rel_vel, btScalar restitution, btScalar velocityThreshold);
virtual void convertContacts(btPersistentManifold** manifoldPtr, int numManifolds, const btContactSolverInfo& infoGlobal);
void convertContact(btPersistentManifold* manifold,const btContactSolverInfo& infoGlobal);
+ virtual void convertJoints(btTypedConstraint** constraints,int numConstraints,const btContactSolverInfo& infoGlobal);
+ void convertJoint(btSolverConstraint* currentConstraintRow, btTypedConstraint* constraint, const btTypedConstraint::btConstraintInfo1& info1, int solverBodyIdA, int solverBodyIdB, const btContactSolverInfo& infoGlobal);
+
+ virtual void convertBodies(btCollisionObject** bodies, int numBodies, const btContactSolverInfo& infoGlobal);
- btSimdScalar resolveSplitPenetrationSIMD(btSolverBody& bodyA,btSolverBody& bodyB, const btSolverConstraint& contactConstraint)
+ btScalar resolveSplitPenetrationSIMD(btSolverBody& bodyA,btSolverBody& bodyB, const btSolverConstraint& contactConstraint)
{
return m_resolveSplitPenetrationImpulse( bodyA, bodyB, contactConstraint );
}
- btSimdScalar resolveSplitPenetrationImpulseCacheFriendly(btSolverBody& bodyA,btSolverBody& bodyB, const btSolverConstraint& contactConstraint)
+ btScalar resolveSplitPenetrationImpulseCacheFriendly(btSolverBody& bodyA,btSolverBody& bodyB, const btSolverConstraint& contactConstraint)
{
return m_resolveSplitPenetrationImpulse( bodyA, bodyB, contactConstraint );
}
@@ -110,18 +114,20 @@ protected:
int getOrInitSolverBody(btCollisionObject& body,btScalar timeStep);
void initSolverBody(btSolverBody* solverBody, btCollisionObject* collisionObject, btScalar timeStep);
- btSimdScalar resolveSingleConstraintRowGeneric(btSolverBody& bodyA,btSolverBody& bodyB,const btSolverConstraint& contactConstraint);
- btSimdScalar resolveSingleConstraintRowGenericSIMD(btSolverBody& bodyA,btSolverBody& bodyB,const btSolverConstraint& contactConstraint);
- btSimdScalar resolveSingleConstraintRowLowerLimit(btSolverBody& bodyA,btSolverBody& bodyB,const btSolverConstraint& contactConstraint);
- btSimdScalar resolveSingleConstraintRowLowerLimitSIMD(btSolverBody& bodyA,btSolverBody& bodyB,const btSolverConstraint& contactConstraint);
- btSimdScalar resolveSplitPenetrationImpulse(btSolverBody& bodyA,btSolverBody& bodyB, const btSolverConstraint& contactConstraint)
+ btScalar resolveSingleConstraintRowGeneric(btSolverBody& bodyA,btSolverBody& bodyB,const btSolverConstraint& contactConstraint);
+ btScalar resolveSingleConstraintRowGenericSIMD(btSolverBody& bodyA,btSolverBody& bodyB,const btSolverConstraint& contactConstraint);
+ btScalar resolveSingleConstraintRowLowerLimit(btSolverBody& bodyA,btSolverBody& bodyB,const btSolverConstraint& contactConstraint);
+ btScalar resolveSingleConstraintRowLowerLimitSIMD(btSolverBody& bodyA,btSolverBody& bodyB,const btSolverConstraint& contactConstraint);
+ btScalar resolveSplitPenetrationImpulse(btSolverBody& bodyA,btSolverBody& bodyB, const btSolverConstraint& contactConstraint)
{
return m_resolveSplitPenetrationImpulse( bodyA, bodyB, contactConstraint );
}
-
+
protected:
-
-
+
+ void writeBackContacts(int iBegin, int iEnd, const btContactSolverInfo& infoGlobal);
+ void writeBackJoints(int iBegin, int iEnd, const btContactSolverInfo& infoGlobal);
+ void writeBackBodies(int iBegin, int iEnd, const btContactSolverInfo& infoGlobal);
virtual void solveGroupCacheFriendlySplitImpulseIterations(btCollisionObject** bodies,int numBodies,btPersistentManifold** manifoldPtr, int numManifolds,btTypedConstraint** constraints,int numConstraints,const btContactSolverInfo& infoGlobal,btIDebugDraw* debugDrawer);
virtual btScalar solveGroupCacheFriendlyFinish(btCollisionObject** bodies,int numBodies,const btContactSolverInfo& infoGlobal);
virtual btScalar solveSingleIteration(int iteration, btCollisionObject** bodies ,int numBodies,btPersistentManifold** manifoldPtr, int numManifolds,btTypedConstraint** constraints,int numConstraints,const btContactSolverInfo& infoGlobal,btIDebugDraw* debugDrawer);
@@ -133,15 +139,15 @@ protected:
public:
BT_DECLARE_ALIGNED_ALLOCATOR();
-
+
btSequentialImpulseConstraintSolver();
virtual ~btSequentialImpulseConstraintSolver();
virtual btScalar solveGroup(btCollisionObject** bodies,int numBodies,btPersistentManifold** manifold,int numManifolds,btTypedConstraint** constraints,int numConstraints,const btContactSolverInfo& info, btIDebugDraw* debugDrawer,btDispatcher* dispatcher);
-
+
///clear internal cached data and reset random seed
virtual void reset();
-
+
unsigned long btRand2();
int btRandInt2 (int n);
@@ -155,7 +161,7 @@ public:
return m_btSeed2;
}
-
+
virtual btConstraintSolverType getSolverType() const
{
return BT_SEQUENTIAL_IMPULSE_SOLVER;
diff --git a/thirdparty/bullet/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolverMt.cpp b/thirdparty/bullet/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolverMt.cpp
new file mode 100644
index 0000000000..4306c37e49
--- /dev/null
+++ b/thirdparty/bullet/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolverMt.cpp
@@ -0,0 +1,1621 @@
+/*
+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 "btSequentialImpulseConstraintSolverMt.h"
+
+#include "LinearMath/btQuickprof.h"
+
+#include "BulletCollision/NarrowPhaseCollision/btPersistentManifold.h"
+
+#include "BulletDynamics/ConstraintSolver/btTypedConstraint.h"
+#include "BulletDynamics/Dynamics/btRigidBody.h"
+
+
+
+bool btSequentialImpulseConstraintSolverMt::s_allowNestedParallelForLoops = false; // some task schedulers don't like nested loops
+int btSequentialImpulseConstraintSolverMt::s_minimumContactManifoldsForBatching = 250;
+int btSequentialImpulseConstraintSolverMt::s_minBatchSize = 50;
+int btSequentialImpulseConstraintSolverMt::s_maxBatchSize = 100;
+btBatchedConstraints::BatchingMethod btSequentialImpulseConstraintSolverMt::s_contactBatchingMethod = btBatchedConstraints::BATCHING_METHOD_SPATIAL_GRID_2D;
+btBatchedConstraints::BatchingMethod btSequentialImpulseConstraintSolverMt::s_jointBatchingMethod = btBatchedConstraints::BATCHING_METHOD_SPATIAL_GRID_2D;
+
+
+btSequentialImpulseConstraintSolverMt::btSequentialImpulseConstraintSolverMt()
+{
+ m_numFrictionDirections = 1;
+ m_useBatching = false;
+ m_useObsoleteJointConstraints = false;
+}
+
+
+btSequentialImpulseConstraintSolverMt::~btSequentialImpulseConstraintSolverMt()
+{
+}
+
+
+void btSequentialImpulseConstraintSolverMt::setupBatchedContactConstraints()
+{
+ BT_PROFILE("setupBatchedContactConstraints");
+ m_batchedContactConstraints.setup( &m_tmpSolverContactConstraintPool,
+ m_tmpSolverBodyPool,
+ s_contactBatchingMethod,
+ s_minBatchSize,
+ s_maxBatchSize,
+ &m_scratchMemory
+ );
+}
+
+
+void btSequentialImpulseConstraintSolverMt::setupBatchedJointConstraints()
+{
+ BT_PROFILE("setupBatchedJointConstraints");
+ m_batchedJointConstraints.setup( &m_tmpSolverNonContactConstraintPool,
+ m_tmpSolverBodyPool,
+ s_jointBatchingMethod,
+ s_minBatchSize,
+ s_maxBatchSize,
+ &m_scratchMemory
+ );
+}
+
+
+void btSequentialImpulseConstraintSolverMt::internalSetupContactConstraints(int iContactConstraint, const btContactSolverInfo& infoGlobal)
+{
+ btSolverConstraint& contactConstraint = m_tmpSolverContactConstraintPool[iContactConstraint];
+
+ btVector3 rel_pos1;
+ btVector3 rel_pos2;
+ btScalar relaxation;
+
+ int solverBodyIdA = contactConstraint.m_solverBodyIdA;
+ int solverBodyIdB = contactConstraint.m_solverBodyIdB;
+
+ btSolverBody* solverBodyA = &m_tmpSolverBodyPool[ solverBodyIdA ];
+ btSolverBody* solverBodyB = &m_tmpSolverBodyPool[ solverBodyIdB ];
+
+ btRigidBody* colObj0 = solverBodyA->m_originalBody;
+ btRigidBody* colObj1 = solverBodyB->m_originalBody;
+
+ btManifoldPoint& cp = *static_cast<btManifoldPoint*>( contactConstraint.m_originalContactPoint );
+
+ const btVector3& pos1 = cp.getPositionWorldOnA();
+ const btVector3& pos2 = cp.getPositionWorldOnB();
+
+ rel_pos1 = pos1 - solverBodyA->getWorldTransform().getOrigin();
+ rel_pos2 = pos2 - solverBodyB->getWorldTransform().getOrigin();
+
+ btVector3 vel1;
+ btVector3 vel2;
+
+ solverBodyA->getVelocityInLocalPointNoDelta( rel_pos1, vel1 );
+ solverBodyB->getVelocityInLocalPointNoDelta( rel_pos2, vel2 );
+
+ btVector3 vel = vel1 - vel2;
+ btScalar rel_vel = cp.m_normalWorldOnB.dot( vel );
+
+ setupContactConstraint( contactConstraint, solverBodyIdA, solverBodyIdB, cp, infoGlobal, relaxation, rel_pos1, rel_pos2 );
+
+ // setup rolling friction constraints
+ int rollingFrictionIndex = m_rollingFrictionIndexTable[iContactConstraint];
+ if (rollingFrictionIndex >= 0)
+ {
+ btSolverConstraint& spinningFrictionConstraint = m_tmpSolverContactRollingFrictionConstraintPool[ rollingFrictionIndex ];
+ btAssert( spinningFrictionConstraint.m_frictionIndex == iContactConstraint );
+ setupTorsionalFrictionConstraint( spinningFrictionConstraint,
+ cp.m_normalWorldOnB,
+ solverBodyIdA,
+ solverBodyIdB,
+ cp,
+ cp.m_combinedSpinningFriction,
+ rel_pos1,
+ rel_pos2,
+ colObj0,
+ colObj1,
+ relaxation,
+ 0.0f,
+ 0.0f
+ );
+ btVector3 axis[2];
+ btPlaneSpace1( cp.m_normalWorldOnB, axis[0], axis[1] );
+ axis[0].normalize();
+ axis[1].normalize();
+
+ applyAnisotropicFriction( colObj0, axis[0], btCollisionObject::CF_ANISOTROPIC_ROLLING_FRICTION );
+ applyAnisotropicFriction( colObj1, axis[0], btCollisionObject::CF_ANISOTROPIC_ROLLING_FRICTION );
+ applyAnisotropicFriction( colObj0, axis[1], btCollisionObject::CF_ANISOTROPIC_ROLLING_FRICTION );
+ applyAnisotropicFriction( colObj1, axis[1], btCollisionObject::CF_ANISOTROPIC_ROLLING_FRICTION );
+ // put the largest axis first
+ if (axis[1].length2() > axis[0].length2())
+ {
+ btSwap(axis[0], axis[1]);
+ }
+ const btScalar kRollingFrictionThreshold = 0.001f;
+ for (int i = 0; i < 2; ++i)
+ {
+ int iRollingFric = rollingFrictionIndex + 1 + i;
+ btSolverConstraint& rollingFrictionConstraint = m_tmpSolverContactRollingFrictionConstraintPool[ iRollingFric ];
+ btAssert(rollingFrictionConstraint.m_frictionIndex == iContactConstraint);
+ btVector3 dir = axis[i];
+ if ( dir.length() > kRollingFrictionThreshold )
+ {
+ setupTorsionalFrictionConstraint( rollingFrictionConstraint,
+ dir,
+ solverBodyIdA,
+ solverBodyIdB,
+ cp,
+ cp.m_combinedRollingFriction,
+ rel_pos1,
+ rel_pos2,
+ colObj0,
+ colObj1,
+ relaxation,
+ 0.0f,
+ 0.0f
+ );
+ }
+ else
+ {
+ rollingFrictionConstraint.m_frictionIndex = -1; // disable constraint
+ }
+ }
+ }
+
+ // setup friction constraints
+ // setupFrictionConstraint(solverConstraint, normalAxis, solverBodyIdA, solverBodyIdB, cp, rel_pos1, rel_pos2, colObj0, colObj1, relaxation, infoGlobal, desiredVelocity, cfmSlip);
+ {
+ ///Bullet has several options to set the friction directions
+ ///By default, each contact has only a single friction direction that is recomputed automatically very frame
+ ///based on the relative linear velocity.
+ ///If the relative velocity it zero, it will automatically compute a friction direction.
+
+ ///You can also enable two friction directions, using the SOLVER_USE_2_FRICTION_DIRECTIONS.
+ ///In that case, the second friction direction will be orthogonal to both contact normal and first friction direction.
+ ///
+ ///If you choose SOLVER_DISABLE_VELOCITY_DEPENDENT_FRICTION_DIRECTION, then the friction will be independent from the relative projected velocity.
+ ///
+ ///The user can manually override the friction directions for certain contacts using a contact callback,
+ ///and set the cp.m_lateralFrictionInitialized to true
+ ///In that case, you can set the target relative motion in each friction direction (cp.m_contactMotion1 and cp.m_contactMotion2)
+ ///this will give a conveyor belt effect
+ ///
+ btSolverConstraint* frictionConstraint1 = &m_tmpSolverContactFrictionConstraintPool[contactConstraint.m_frictionIndex];
+ btAssert(frictionConstraint1->m_frictionIndex == iContactConstraint);
+
+ btSolverConstraint* frictionConstraint2 = NULL;
+ if ( infoGlobal.m_solverMode & SOLVER_USE_2_FRICTION_DIRECTIONS )
+ {
+ frictionConstraint2 = &m_tmpSolverContactFrictionConstraintPool[contactConstraint.m_frictionIndex + 1];
+ btAssert( frictionConstraint2->m_frictionIndex == iContactConstraint );
+ }
+
+ if ( !( infoGlobal.m_solverMode & SOLVER_ENABLE_FRICTION_DIRECTION_CACHING ) || !( cp.m_contactPointFlags&BT_CONTACT_FLAG_LATERAL_FRICTION_INITIALIZED ) )
+ {
+ cp.m_lateralFrictionDir1 = vel - cp.m_normalWorldOnB * rel_vel;
+ btScalar lat_rel_vel = cp.m_lateralFrictionDir1.length2();
+ if ( !( infoGlobal.m_solverMode & SOLVER_DISABLE_VELOCITY_DEPENDENT_FRICTION_DIRECTION ) && lat_rel_vel > SIMD_EPSILON )
+ {
+ cp.m_lateralFrictionDir1 *= 1.f / btSqrt( lat_rel_vel );
+ applyAnisotropicFriction( colObj0, cp.m_lateralFrictionDir1, btCollisionObject::CF_ANISOTROPIC_FRICTION );
+ applyAnisotropicFriction( colObj1, cp.m_lateralFrictionDir1, btCollisionObject::CF_ANISOTROPIC_FRICTION );
+ setupFrictionConstraint( *frictionConstraint1, cp.m_lateralFrictionDir1, solverBodyIdA, solverBodyIdB, cp, rel_pos1, rel_pos2, colObj0, colObj1, relaxation, infoGlobal );
+
+ if ( frictionConstraint2 )
+ {
+ cp.m_lateralFrictionDir2 = cp.m_lateralFrictionDir1.cross( cp.m_normalWorldOnB );
+ cp.m_lateralFrictionDir2.normalize();//??
+ applyAnisotropicFriction( colObj0, cp.m_lateralFrictionDir2, btCollisionObject::CF_ANISOTROPIC_FRICTION );
+ applyAnisotropicFriction( colObj1, cp.m_lateralFrictionDir2, btCollisionObject::CF_ANISOTROPIC_FRICTION );
+ setupFrictionConstraint( *frictionConstraint2, cp.m_lateralFrictionDir2, solverBodyIdA, solverBodyIdB, cp, rel_pos1, rel_pos2, colObj0, colObj1, relaxation, infoGlobal );
+ }
+ }
+ else
+ {
+ btPlaneSpace1( cp.m_normalWorldOnB, cp.m_lateralFrictionDir1, cp.m_lateralFrictionDir2 );
+
+ applyAnisotropicFriction( colObj0, cp.m_lateralFrictionDir1, btCollisionObject::CF_ANISOTROPIC_FRICTION );
+ applyAnisotropicFriction( colObj1, cp.m_lateralFrictionDir1, btCollisionObject::CF_ANISOTROPIC_FRICTION );
+ setupFrictionConstraint( *frictionConstraint1, cp.m_lateralFrictionDir1, solverBodyIdA, solverBodyIdB, cp, rel_pos1, rel_pos2, colObj0, colObj1, relaxation, infoGlobal );
+
+ if ( frictionConstraint2 )
+ {
+ applyAnisotropicFriction( colObj0, cp.m_lateralFrictionDir2, btCollisionObject::CF_ANISOTROPIC_FRICTION );
+ applyAnisotropicFriction( colObj1, cp.m_lateralFrictionDir2, btCollisionObject::CF_ANISOTROPIC_FRICTION );
+ setupFrictionConstraint( *frictionConstraint2, cp.m_lateralFrictionDir2, solverBodyIdA, solverBodyIdB, cp, rel_pos1, rel_pos2, colObj0, colObj1, relaxation, infoGlobal );
+ }
+
+ if ( ( infoGlobal.m_solverMode & SOLVER_USE_2_FRICTION_DIRECTIONS ) && ( infoGlobal.m_solverMode & SOLVER_DISABLE_VELOCITY_DEPENDENT_FRICTION_DIRECTION ) )
+ {
+ cp.m_contactPointFlags |= BT_CONTACT_FLAG_LATERAL_FRICTION_INITIALIZED;
+ }
+ }
+ }
+ else
+ {
+ setupFrictionConstraint( *frictionConstraint1, cp.m_lateralFrictionDir1, solverBodyIdA, solverBodyIdB, cp, rel_pos1, rel_pos2, colObj0, colObj1, relaxation, infoGlobal, cp.m_contactMotion1, cp.m_frictionCFM );
+ if ( frictionConstraint2 )
+ {
+ setupFrictionConstraint( *frictionConstraint2, cp.m_lateralFrictionDir2, solverBodyIdA, solverBodyIdB, cp, rel_pos1, rel_pos2, colObj0, colObj1, relaxation, infoGlobal, cp.m_contactMotion2, cp.m_frictionCFM );
+ }
+ }
+ }
+
+ setFrictionConstraintImpulse( contactConstraint, solverBodyIdA, solverBodyIdB, cp, infoGlobal );
+}
+
+
+struct SetupContactConstraintsLoop : public btIParallelForBody
+{
+ btSequentialImpulseConstraintSolverMt* m_solver;
+ const btBatchedConstraints* m_bc;
+ const btContactSolverInfo* m_infoGlobal;
+
+ SetupContactConstraintsLoop( btSequentialImpulseConstraintSolverMt* solver, const btBatchedConstraints* bc, const btContactSolverInfo& infoGlobal )
+ {
+ m_solver = solver;
+ m_bc = bc;
+ m_infoGlobal = &infoGlobal;
+ }
+ void forLoop( int iBegin, int iEnd ) const BT_OVERRIDE
+ {
+ BT_PROFILE( "SetupContactConstraintsLoop" );
+ for ( int iBatch = iBegin; iBatch < iEnd; ++iBatch )
+ {
+ const btBatchedConstraints::Range& batch = m_bc->m_batches[ iBatch ];
+ for (int i = batch.begin; i < batch.end; ++i)
+ {
+ int iContact = m_bc->m_constraintIndices[i];
+ m_solver->internalSetupContactConstraints( iContact, *m_infoGlobal );
+ }
+ }
+ }
+};
+
+
+void btSequentialImpulseConstraintSolverMt::setupAllContactConstraints(const btContactSolverInfo& infoGlobal)
+{
+ BT_PROFILE( "setupAllContactConstraints" );
+ if ( m_useBatching )
+ {
+ const btBatchedConstraints& batchedCons = m_batchedContactConstraints;
+ SetupContactConstraintsLoop loop( this, &batchedCons, infoGlobal );
+ for ( int iiPhase = 0; iiPhase < batchedCons.m_phases.size(); ++iiPhase )
+ {
+ int iPhase = batchedCons.m_phaseOrder[ iiPhase ];
+ const btBatchedConstraints::Range& phase = batchedCons.m_phases[ iPhase ];
+ int grainSize = 1;
+ btParallelFor( phase.begin, phase.end, grainSize, loop );
+ }
+ }
+ else
+ {
+ for ( int i = 0; i < m_tmpSolverContactConstraintPool.size(); ++i )
+ {
+ internalSetupContactConstraints( i, infoGlobal );
+ }
+ }
+}
+
+
+int btSequentialImpulseConstraintSolverMt::getOrInitSolverBodyThreadsafe(btCollisionObject& body,btScalar timeStep)
+{
+ //
+ // getOrInitSolverBody is threadsafe only for a single thread per solver (with potentially multiple solvers)
+ //
+ // getOrInitSolverBodyThreadsafe -- attempts to be fully threadsafe (however may affect determinism)
+ //
+ int solverBodyId = -1;
+ bool isRigidBodyType = btRigidBody::upcast( &body ) != NULL;
+ if ( isRigidBodyType && !body.isStaticOrKinematicObject() )
+ {
+ // dynamic body
+ // Dynamic bodies can only be in one island, so it's safe to write to the companionId
+ solverBodyId = body.getCompanionId();
+ if ( solverBodyId < 0 )
+ {
+ m_bodySolverArrayMutex.lock();
+ // now that we have the lock, check again
+ solverBodyId = body.getCompanionId();
+ if ( solverBodyId < 0 )
+ {
+ solverBodyId = m_tmpSolverBodyPool.size();
+ btSolverBody& solverBody = m_tmpSolverBodyPool.expand();
+ initSolverBody( &solverBody, &body, timeStep );
+ body.setCompanionId( solverBodyId );
+ }
+ m_bodySolverArrayMutex.unlock();
+ }
+ }
+ else if (isRigidBodyType && body.isKinematicObject())
+ {
+ //
+ // NOTE: must test for kinematic before static because some kinematic objects also
+ // identify as "static"
+ //
+ // Kinematic bodies can be in multiple islands at once, so it is a
+ // race condition to write to them, so we use an alternate method
+ // to record the solverBodyId
+ int uniqueId = body.getWorldArrayIndex();
+ const int INVALID_SOLVER_BODY_ID = -1;
+ if (m_kinematicBodyUniqueIdToSolverBodyTable.size() <= uniqueId )
+ {
+ m_kinematicBodyUniqueIdToSolverBodyTableMutex.lock();
+ // now that we have the lock, check again
+ if ( m_kinematicBodyUniqueIdToSolverBodyTable.size() <= uniqueId )
+ {
+ m_kinematicBodyUniqueIdToSolverBodyTable.resize( uniqueId + 1, INVALID_SOLVER_BODY_ID );
+ }
+ m_kinematicBodyUniqueIdToSolverBodyTableMutex.unlock();
+ }
+ solverBodyId = m_kinematicBodyUniqueIdToSolverBodyTable[ uniqueId ];
+ // if no table entry yet,
+ if ( INVALID_SOLVER_BODY_ID == solverBodyId )
+ {
+ // need to acquire both locks
+ m_kinematicBodyUniqueIdToSolverBodyTableMutex.lock();
+ m_bodySolverArrayMutex.lock();
+ // now that we have the lock, check again
+ solverBodyId = m_kinematicBodyUniqueIdToSolverBodyTable[ uniqueId ];
+ if ( INVALID_SOLVER_BODY_ID == solverBodyId )
+ {
+ // create a table entry for this body
+ solverBodyId = m_tmpSolverBodyPool.size();
+ btSolverBody& solverBody = m_tmpSolverBodyPool.expand();
+ initSolverBody( &solverBody, &body, timeStep );
+ m_kinematicBodyUniqueIdToSolverBodyTable[ uniqueId ] = solverBodyId;
+ }
+ m_bodySolverArrayMutex.unlock();
+ m_kinematicBodyUniqueIdToSolverBodyTableMutex.unlock();
+ }
+ }
+ else
+ {
+ // all fixed bodies (inf mass) get mapped to a single solver id
+ if ( m_fixedBodyId < 0 )
+ {
+ m_bodySolverArrayMutex.lock();
+ // now that we have the lock, check again
+ if ( m_fixedBodyId < 0 )
+ {
+ m_fixedBodyId = m_tmpSolverBodyPool.size();
+ btSolverBody& fixedBody = m_tmpSolverBodyPool.expand();
+ initSolverBody( &fixedBody, 0, timeStep );
+ }
+ m_bodySolverArrayMutex.unlock();
+ }
+ solverBodyId = m_fixedBodyId;
+ }
+ btAssert( solverBodyId >= 0 && solverBodyId < m_tmpSolverBodyPool.size() );
+ return solverBodyId;
+}
+
+
+void btSequentialImpulseConstraintSolverMt::internalCollectContactManifoldCachedInfo(btContactManifoldCachedInfo* cachedInfoArray, btPersistentManifold** manifoldPtr, int numManifolds, const btContactSolverInfo& infoGlobal)
+{
+ BT_PROFILE("internalCollectContactManifoldCachedInfo");
+ for (int i = 0; i < numManifolds; ++i)
+ {
+ btContactManifoldCachedInfo* cachedInfo = &cachedInfoArray[i];
+ btPersistentManifold* manifold = manifoldPtr[i];
+ btCollisionObject* colObj0 = (btCollisionObject*) manifold->getBody0();
+ btCollisionObject* colObj1 = (btCollisionObject*) manifold->getBody1();
+
+ int solverBodyIdA = getOrInitSolverBodyThreadsafe( *colObj0, infoGlobal.m_timeStep );
+ int solverBodyIdB = getOrInitSolverBodyThreadsafe( *colObj1, infoGlobal.m_timeStep );
+
+ cachedInfo->solverBodyIds[ 0 ] = solverBodyIdA;
+ cachedInfo->solverBodyIds[ 1 ] = solverBodyIdB;
+ cachedInfo->numTouchingContacts = 0;
+
+ btSolverBody* solverBodyA = &m_tmpSolverBodyPool[ solverBodyIdA ];
+ btSolverBody* solverBodyB = &m_tmpSolverBodyPool[ solverBodyIdB ];
+
+ // A contact manifold between 2 static object should not exist!
+ // check the collision flags of your objects if this assert fires.
+ // Incorrectly set collision object flags can degrade performance in various ways.
+ btAssert( !m_tmpSolverBodyPool[ solverBodyIdA ].m_invMass.isZero() || !m_tmpSolverBodyPool[ solverBodyIdB ].m_invMass.isZero() );
+
+ int iContact = 0;
+ for ( int j = 0; j < manifold->getNumContacts(); j++ )
+ {
+ btManifoldPoint& cp = manifold->getContactPoint( j );
+
+ if ( cp.getDistance() <= manifold->getContactProcessingThreshold() )
+ {
+ cachedInfo->contactPoints[ iContact ] = &cp;
+ cachedInfo->contactHasRollingFriction[ iContact ] = ( cp.m_combinedRollingFriction > 0.f );
+ iContact++;
+ }
+ }
+ cachedInfo->numTouchingContacts = iContact;
+ }
+}
+
+
+struct CollectContactManifoldCachedInfoLoop : public btIParallelForBody
+{
+ btSequentialImpulseConstraintSolverMt* m_solver;
+ btSequentialImpulseConstraintSolverMt::btContactManifoldCachedInfo* m_cachedInfoArray;
+ btPersistentManifold** m_manifoldPtr;
+ const btContactSolverInfo* m_infoGlobal;
+
+ CollectContactManifoldCachedInfoLoop( btSequentialImpulseConstraintSolverMt* solver, btSequentialImpulseConstraintSolverMt::btContactManifoldCachedInfo* cachedInfoArray, btPersistentManifold** manifoldPtr, const btContactSolverInfo& infoGlobal )
+ {
+ m_solver = solver;
+ m_cachedInfoArray = cachedInfoArray;
+ m_manifoldPtr = manifoldPtr;
+ m_infoGlobal = &infoGlobal;
+ }
+ void forLoop( int iBegin, int iEnd ) const BT_OVERRIDE
+ {
+ m_solver->internalCollectContactManifoldCachedInfo( m_cachedInfoArray + iBegin, m_manifoldPtr + iBegin, iEnd - iBegin, *m_infoGlobal );
+ }
+};
+
+
+void btSequentialImpulseConstraintSolverMt::internalAllocContactConstraints(const btContactManifoldCachedInfo* cachedInfoArray, int numManifolds)
+{
+ BT_PROFILE("internalAllocContactConstraints");
+ // possibly parallel part
+ for ( int iManifold = 0; iManifold < numManifolds; ++iManifold )
+ {
+ const btContactManifoldCachedInfo& cachedInfo = cachedInfoArray[ iManifold ];
+ int contactIndex = cachedInfo.contactIndex;
+ int frictionIndex = contactIndex * m_numFrictionDirections;
+ int rollingFrictionIndex = cachedInfo.rollingFrictionIndex;
+ for ( int i = 0; i < cachedInfo.numTouchingContacts; i++ )
+ {
+ btSolverConstraint& contactConstraint = m_tmpSolverContactConstraintPool[contactIndex];
+ contactConstraint.m_solverBodyIdA = cachedInfo.solverBodyIds[ 0 ];
+ contactConstraint.m_solverBodyIdB = cachedInfo.solverBodyIds[ 1 ];
+ contactConstraint.m_originalContactPoint = cachedInfo.contactPoints[ i ];
+
+ // allocate the friction constraints
+ contactConstraint.m_frictionIndex = frictionIndex;
+ for ( int iDir = 0; iDir < m_numFrictionDirections; ++iDir )
+ {
+ btSolverConstraint& frictionConstraint = m_tmpSolverContactFrictionConstraintPool[frictionIndex];
+ frictionConstraint.m_frictionIndex = contactIndex;
+ frictionIndex++;
+ }
+
+ // allocate rolling friction constraints
+ if ( cachedInfo.contactHasRollingFriction[ i ] )
+ {
+ m_rollingFrictionIndexTable[ contactIndex ] = rollingFrictionIndex;
+ // allocate 3 (although we may use only 2 sometimes)
+ for ( int i = 0; i < 3; i++ )
+ {
+ m_tmpSolverContactRollingFrictionConstraintPool[ rollingFrictionIndex ].m_frictionIndex = contactIndex;
+ rollingFrictionIndex++;
+ }
+ }
+ else
+ {
+ // indicate there is no rolling friction for this contact point
+ m_rollingFrictionIndexTable[ contactIndex ] = -1;
+ }
+ contactIndex++;
+ }
+ }
+}
+
+
+struct AllocContactConstraintsLoop : public btIParallelForBody
+{
+ btSequentialImpulseConstraintSolverMt* m_solver;
+ const btSequentialImpulseConstraintSolverMt::btContactManifoldCachedInfo* m_cachedInfoArray;
+
+ AllocContactConstraintsLoop( btSequentialImpulseConstraintSolverMt* solver, btSequentialImpulseConstraintSolverMt::btContactManifoldCachedInfo* cachedInfoArray )
+ {
+ m_solver = solver;
+ m_cachedInfoArray = cachedInfoArray;
+ }
+ void forLoop( int iBegin, int iEnd ) const BT_OVERRIDE
+ {
+ m_solver->internalAllocContactConstraints( m_cachedInfoArray + iBegin, iEnd - iBegin );
+ }
+};
+
+
+void btSequentialImpulseConstraintSolverMt::allocAllContactConstraints(btPersistentManifold** manifoldPtr, int numManifolds, const btContactSolverInfo& infoGlobal)
+{
+ BT_PROFILE( "allocAllContactConstraints" );
+ btAlignedObjectArray<btContactManifoldCachedInfo> cachedInfoArray; // = m_manifoldCachedInfoArray;
+ cachedInfoArray.resizeNoInitialize( numManifolds );
+ if (/* DISABLES CODE */ (false))
+ {
+ // sequential
+ internalCollectContactManifoldCachedInfo(&cachedInfoArray[ 0 ], manifoldPtr, numManifolds, infoGlobal);
+ }
+ else
+ {
+ // may alter ordering of bodies which affects determinism
+ CollectContactManifoldCachedInfoLoop loop( this, &cachedInfoArray[ 0 ], manifoldPtr, infoGlobal );
+ int grainSize = 200;
+ btParallelFor( 0, numManifolds, grainSize, loop );
+ }
+
+ {
+ // serial part
+ int numContacts = 0;
+ int numRollingFrictionConstraints = 0;
+ for ( int iManifold = 0; iManifold < numManifolds; ++iManifold )
+ {
+ btContactManifoldCachedInfo& cachedInfo = cachedInfoArray[ iManifold ];
+ cachedInfo.contactIndex = numContacts;
+ cachedInfo.rollingFrictionIndex = numRollingFrictionConstraints;
+ numContacts += cachedInfo.numTouchingContacts;
+ for (int i = 0; i < cachedInfo.numTouchingContacts; ++i)
+ {
+ if (cachedInfo.contactHasRollingFriction[i])
+ {
+ numRollingFrictionConstraints += 3;
+ }
+ }
+ }
+ {
+ BT_PROFILE( "allocPools" );
+ if ( m_tmpSolverContactConstraintPool.capacity() < numContacts )
+ {
+ // if we need to reallocate, reserve some extra so we don't have to reallocate again next frame
+ int extraReserve = numContacts / 16;
+ m_tmpSolverContactConstraintPool.reserve( numContacts + extraReserve );
+ m_rollingFrictionIndexTable.reserve( numContacts + extraReserve );
+ m_tmpSolverContactFrictionConstraintPool.reserve( ( numContacts + extraReserve )*m_numFrictionDirections );
+ m_tmpSolverContactRollingFrictionConstraintPool.reserve( numRollingFrictionConstraints + extraReserve );
+ }
+ m_tmpSolverContactConstraintPool.resizeNoInitialize( numContacts );
+ m_rollingFrictionIndexTable.resizeNoInitialize( numContacts );
+ m_tmpSolverContactFrictionConstraintPool.resizeNoInitialize( numContacts*m_numFrictionDirections );
+ m_tmpSolverContactRollingFrictionConstraintPool.resizeNoInitialize( numRollingFrictionConstraints );
+ }
+ }
+ {
+ AllocContactConstraintsLoop loop(this, &cachedInfoArray[0]);
+ int grainSize = 200;
+ btParallelFor( 0, numManifolds, grainSize, loop );
+ }
+}
+
+
+void btSequentialImpulseConstraintSolverMt::convertContacts(btPersistentManifold** manifoldPtr, int numManifolds, const btContactSolverInfo& infoGlobal)
+{
+ if (!m_useBatching)
+ {
+ btSequentialImpulseConstraintSolver::convertContacts(manifoldPtr, numManifolds, infoGlobal);
+ return;
+ }
+ BT_PROFILE( "convertContacts" );
+ if (numManifolds > 0)
+ {
+ if ( m_fixedBodyId < 0 )
+ {
+ m_fixedBodyId = m_tmpSolverBodyPool.size();
+ btSolverBody& fixedBody = m_tmpSolverBodyPool.expand();
+ initSolverBody( &fixedBody, 0, infoGlobal.m_timeStep );
+ }
+ allocAllContactConstraints( manifoldPtr, numManifolds, infoGlobal );
+ if ( m_useBatching )
+ {
+ setupBatchedContactConstraints();
+ }
+ setupAllContactConstraints( infoGlobal );
+ }
+}
+
+
+void btSequentialImpulseConstraintSolverMt::internalInitMultipleJoints( btTypedConstraint** constraints, int iBegin, int iEnd )
+{
+ BT_PROFILE("internalInitMultipleJoints");
+ for ( int i = iBegin; i < iEnd; i++ )
+ {
+ btTypedConstraint* constraint = constraints[i];
+ btTypedConstraint::btConstraintInfo1& info1 = m_tmpConstraintSizesPool[i];
+ if (constraint->isEnabled())
+ {
+ constraint->buildJacobian();
+ constraint->internalSetAppliedImpulse( 0.0f );
+ btJointFeedback* fb = constraint->getJointFeedback();
+ if ( fb )
+ {
+ fb->m_appliedForceBodyA.setZero();
+ fb->m_appliedTorqueBodyA.setZero();
+ fb->m_appliedForceBodyB.setZero();
+ fb->m_appliedTorqueBodyB.setZero();
+ }
+ constraint->getInfo1( &info1 );
+ }
+ else
+ {
+ info1.m_numConstraintRows = 0;
+ info1.nub = 0;
+ }
+ }
+}
+
+
+struct InitJointsLoop : public btIParallelForBody
+{
+ btSequentialImpulseConstraintSolverMt* m_solver;
+ btTypedConstraint** m_constraints;
+
+ InitJointsLoop( btSequentialImpulseConstraintSolverMt* solver, btTypedConstraint** constraints )
+ {
+ m_solver = solver;
+ m_constraints = constraints;
+ }
+ void forLoop( int iBegin, int iEnd ) const BT_OVERRIDE
+ {
+ m_solver->internalInitMultipleJoints( m_constraints, iBegin, iEnd );
+ }
+};
+
+
+void btSequentialImpulseConstraintSolverMt::internalConvertMultipleJoints( const btAlignedObjectArray<JointParams>& jointParamsArray, btTypedConstraint** constraints, int iBegin, int iEnd, const btContactSolverInfo& infoGlobal )
+{
+ BT_PROFILE("internalConvertMultipleJoints");
+ for ( int i = iBegin; i < iEnd; ++i )
+ {
+ const JointParams& jointParams = jointParamsArray[ i ];
+ int currentRow = jointParams.m_solverConstraint;
+ if ( currentRow != -1 )
+ {
+ const btTypedConstraint::btConstraintInfo1& info1 = m_tmpConstraintSizesPool[ i ];
+ btAssert( currentRow < m_tmpSolverNonContactConstraintPool.size() );
+ btAssert( info1.m_numConstraintRows > 0 );
+
+ btSolverConstraint* currentConstraintRow = &m_tmpSolverNonContactConstraintPool[ currentRow ];
+ btTypedConstraint* constraint = constraints[ i ];
+
+ convertJoint( currentConstraintRow, constraint, info1, jointParams.m_solverBodyA, jointParams.m_solverBodyB, infoGlobal );
+ }
+ }
+}
+
+
+struct ConvertJointsLoop : public btIParallelForBody
+{
+ btSequentialImpulseConstraintSolverMt* m_solver;
+ const btAlignedObjectArray<btSequentialImpulseConstraintSolverMt::JointParams>& m_jointParamsArray;
+ btTypedConstraint** m_srcConstraints;
+ const btContactSolverInfo& m_infoGlobal;
+
+ ConvertJointsLoop( btSequentialImpulseConstraintSolverMt* solver,
+ const btAlignedObjectArray<btSequentialImpulseConstraintSolverMt::JointParams>& jointParamsArray,
+ btTypedConstraint** srcConstraints,
+ const btContactSolverInfo& infoGlobal
+ ) :
+ m_jointParamsArray(jointParamsArray),
+ m_infoGlobal(infoGlobal)
+ {
+ m_solver = solver;
+ m_srcConstraints = srcConstraints;
+ }
+ void forLoop( int iBegin, int iEnd ) const BT_OVERRIDE
+ {
+ m_solver->internalConvertMultipleJoints( m_jointParamsArray, m_srcConstraints, iBegin, iEnd, m_infoGlobal );
+ }
+};
+
+
+void btSequentialImpulseConstraintSolverMt::convertJoints(btTypedConstraint** constraints, int numConstraints, const btContactSolverInfo& infoGlobal)
+{
+ if ( !m_useBatching )
+ {
+ btSequentialImpulseConstraintSolver::convertJoints(constraints, numConstraints, infoGlobal);
+ return;
+ }
+ BT_PROFILE("convertJoints");
+ bool parallelJointSetup = true;
+ m_tmpConstraintSizesPool.resizeNoInitialize(numConstraints);
+ if (parallelJointSetup)
+ {
+ InitJointsLoop loop(this, constraints);
+ int grainSize = 40;
+ btParallelFor(0, numConstraints, grainSize, loop);
+ }
+ else
+ {
+ internalInitMultipleJoints( constraints, 0, numConstraints );
+ }
+
+ int totalNumRows = 0;
+ btAlignedObjectArray<JointParams> jointParamsArray;
+ jointParamsArray.resizeNoInitialize(numConstraints);
+
+ //calculate the total number of contraint rows
+ for (int i=0;i<numConstraints;i++)
+ {
+ btTypedConstraint* constraint = constraints[ i ];
+
+ JointParams& params = jointParamsArray[ i ];
+ const btTypedConstraint::btConstraintInfo1& info1 = m_tmpConstraintSizesPool[i];
+
+ if (info1.m_numConstraintRows)
+ {
+ params.m_solverConstraint = totalNumRows;
+ params.m_solverBodyA = getOrInitSolverBody( constraint->getRigidBodyA(), infoGlobal.m_timeStep );
+ params.m_solverBodyB = getOrInitSolverBody( constraint->getRigidBodyB(), infoGlobal.m_timeStep );
+ }
+ else
+ {
+ params.m_solverConstraint = -1;
+ }
+ totalNumRows += info1.m_numConstraintRows;
+ }
+ m_tmpSolverNonContactConstraintPool.resizeNoInitialize(totalNumRows);
+
+ ///setup the btSolverConstraints
+ if ( parallelJointSetup )
+ {
+ ConvertJointsLoop loop(this, jointParamsArray, constraints, infoGlobal);
+ int grainSize = 20;
+ btParallelFor(0, numConstraints, grainSize, loop);
+ }
+ else
+ {
+ internalConvertMultipleJoints( jointParamsArray, constraints, 0, numConstraints, infoGlobal );
+ }
+ setupBatchedJointConstraints();
+}
+
+
+void btSequentialImpulseConstraintSolverMt::internalConvertBodies(btCollisionObject** bodies, int iBegin, int iEnd, const btContactSolverInfo& infoGlobal)
+{
+ BT_PROFILE("internalConvertBodies");
+ for (int i=iBegin; i < iEnd; i++)
+ {
+ btCollisionObject* obj = bodies[i];
+ obj->setCompanionId(i);
+ btSolverBody& solverBody = m_tmpSolverBodyPool[i];
+ initSolverBody(&solverBody, obj, infoGlobal.m_timeStep);
+
+ btRigidBody* body = btRigidBody::upcast(obj);
+ if (body && body->getInvMass())
+ {
+ btVector3 gyroForce (0,0,0);
+ if (body->getFlags()&BT_ENABLE_GYROSCOPIC_FORCE_EXPLICIT)
+ {
+ gyroForce = body->computeGyroscopicForceExplicit(infoGlobal.m_maxGyroscopicForce);
+ solverBody.m_externalTorqueImpulse -= gyroForce*body->getInvInertiaTensorWorld()*infoGlobal.m_timeStep;
+ }
+ if (body->getFlags()&BT_ENABLE_GYROSCOPIC_FORCE_IMPLICIT_WORLD)
+ {
+ gyroForce = body->computeGyroscopicImpulseImplicit_World(infoGlobal.m_timeStep);
+ solverBody.m_externalTorqueImpulse += gyroForce;
+ }
+ if (body->getFlags()&BT_ENABLE_GYROSCOPIC_FORCE_IMPLICIT_BODY)
+ {
+ gyroForce = body->computeGyroscopicImpulseImplicit_Body(infoGlobal.m_timeStep);
+ solverBody.m_externalTorqueImpulse += gyroForce;
+ }
+ }
+ }
+}
+
+
+struct ConvertBodiesLoop : public btIParallelForBody
+{
+ btSequentialImpulseConstraintSolverMt* m_solver;
+ btCollisionObject** m_bodies;
+ int m_numBodies;
+ const btContactSolverInfo& m_infoGlobal;
+
+ ConvertBodiesLoop( btSequentialImpulseConstraintSolverMt* solver,
+ btCollisionObject** bodies,
+ int numBodies,
+ const btContactSolverInfo& infoGlobal
+ ) :
+ m_infoGlobal(infoGlobal)
+ {
+ m_solver = solver;
+ m_bodies = bodies;
+ m_numBodies = numBodies;
+ }
+ void forLoop( int iBegin, int iEnd ) const BT_OVERRIDE
+ {
+ m_solver->internalConvertBodies( m_bodies, iBegin, iEnd, m_infoGlobal );
+ }
+};
+
+
+void btSequentialImpulseConstraintSolverMt::convertBodies(btCollisionObject** bodies, int numBodies, const btContactSolverInfo& infoGlobal)
+{
+ BT_PROFILE("convertBodies");
+ m_kinematicBodyUniqueIdToSolverBodyTable.resize( 0 );
+
+ m_tmpSolverBodyPool.resizeNoInitialize(numBodies+1);
+
+ m_fixedBodyId = numBodies;
+ {
+ btSolverBody& fixedBody = m_tmpSolverBodyPool[ m_fixedBodyId ];
+ initSolverBody( &fixedBody, NULL, infoGlobal.m_timeStep );
+ }
+
+ bool parallelBodySetup = true;
+ if (parallelBodySetup)
+ {
+ ConvertBodiesLoop loop(this, bodies, numBodies, infoGlobal);
+ int grainSize = 40;
+ btParallelFor(0, numBodies, grainSize, loop);
+ }
+ else
+ {
+ internalConvertBodies( bodies, 0, numBodies, infoGlobal );
+ }
+}
+
+
+btScalar btSequentialImpulseConstraintSolverMt::solveGroupCacheFriendlySetup(
+ btCollisionObject** bodies,
+ int numBodies,
+ btPersistentManifold** manifoldPtr,
+ int numManifolds,
+ btTypedConstraint** constraints,
+ int numConstraints,
+ const btContactSolverInfo& infoGlobal,
+ btIDebugDraw* debugDrawer
+ )
+{
+ m_numFrictionDirections = (infoGlobal.m_solverMode & SOLVER_USE_2_FRICTION_DIRECTIONS) ? 2 : 1;
+ m_useBatching = false;
+ if ( numManifolds >= s_minimumContactManifoldsForBatching &&
+ (s_allowNestedParallelForLoops || !btThreadsAreRunning())
+ )
+ {
+ m_useBatching = true;
+ m_batchedContactConstraints.m_debugDrawer = debugDrawer;
+ m_batchedJointConstraints.m_debugDrawer = debugDrawer;
+ }
+ btSequentialImpulseConstraintSolver::solveGroupCacheFriendlySetup( bodies,
+ numBodies,
+ manifoldPtr,
+ numManifolds,
+ constraints,
+ numConstraints,
+ infoGlobal,
+ debugDrawer
+ );
+ return 0.0f;
+}
+
+
+btScalar btSequentialImpulseConstraintSolverMt::resolveMultipleContactSplitPenetrationImpulseConstraints( const btAlignedObjectArray<int>& consIndices, int batchBegin, int batchEnd )
+{
+ btScalar leastSquaresResidual = 0.f;
+ for ( int iiCons = batchBegin; iiCons < batchEnd; ++iiCons )
+ {
+ int iCons = consIndices[ iiCons ];
+ const btSolverConstraint& solveManifold = m_tmpSolverContactConstraintPool[ iCons ];
+ btSolverBody& bodyA = m_tmpSolverBodyPool[ solveManifold.m_solverBodyIdA ];
+ btSolverBody& bodyB = m_tmpSolverBodyPool[ solveManifold.m_solverBodyIdB ];
+ btScalar residual = resolveSplitPenetrationImpulse( bodyA, bodyB, solveManifold );
+ leastSquaresResidual += residual*residual;
+ }
+ return leastSquaresResidual;
+}
+
+
+struct ContactSplitPenetrationImpulseSolverLoop : public btIParallelSumBody
+{
+ btSequentialImpulseConstraintSolverMt* m_solver;
+ const btBatchedConstraints* m_bc;
+
+ ContactSplitPenetrationImpulseSolverLoop( btSequentialImpulseConstraintSolverMt* solver, const btBatchedConstraints* bc )
+ {
+ m_solver = solver;
+ m_bc = bc;
+ }
+ btScalar sumLoop( int iBegin, int iEnd ) const BT_OVERRIDE
+ {
+ BT_PROFILE( "ContactSplitPenetrationImpulseSolverLoop" );
+ btScalar sum = 0;
+ for ( int iBatch = iBegin; iBatch < iEnd; ++iBatch )
+ {
+ const btBatchedConstraints::Range& batch = m_bc->m_batches[ iBatch ];
+ sum += m_solver->resolveMultipleContactSplitPenetrationImpulseConstraints( m_bc->m_constraintIndices, batch.begin, batch.end );
+ }
+ return sum;
+ }
+};
+
+
+void btSequentialImpulseConstraintSolverMt::solveGroupCacheFriendlySplitImpulseIterations(btCollisionObject** bodies,int numBodies,btPersistentManifold** manifoldPtr, int numManifolds,btTypedConstraint** constraints,int numConstraints,const btContactSolverInfo& infoGlobal,btIDebugDraw* debugDrawer)
+{
+ BT_PROFILE("solveGroupCacheFriendlySplitImpulseIterations");
+ if (infoGlobal.m_splitImpulse)
+ {
+ for ( int iteration = 0; iteration < infoGlobal.m_numIterations; iteration++ )
+ {
+ btScalar leastSquaresResidual = 0.f;
+ if (m_useBatching)
+ {
+ const btBatchedConstraints& batchedCons = m_batchedContactConstraints;
+ ContactSplitPenetrationImpulseSolverLoop loop( this, &batchedCons );
+ btScalar leastSquaresResidual = 0.f;
+ for ( int iiPhase = 0; iiPhase < batchedCons.m_phases.size(); ++iiPhase )
+ {
+ int iPhase = batchedCons.m_phaseOrder[ iiPhase ];
+ const btBatchedConstraints::Range& phase = batchedCons.m_phases[ iPhase ];
+ int grainSize = batchedCons.m_phaseGrainSize[iPhase];
+ leastSquaresResidual += btParallelSum( phase.begin, phase.end, grainSize, loop );
+ }
+ }
+ else
+ {
+ // non-batched
+ leastSquaresResidual = resolveMultipleContactSplitPenetrationImpulseConstraints(m_orderTmpConstraintPool, 0, m_tmpSolverContactConstraintPool.size());
+ }
+ if ( leastSquaresResidual <= infoGlobal.m_leastSquaresResidualThreshold || iteration >= ( infoGlobal.m_numIterations - 1 ) )
+ {
+#ifdef VERBOSE_RESIDUAL_PRINTF
+ printf( "residual = %f at iteration #%d\n", leastSquaresResidual, iteration );
+#endif
+ break;
+ }
+ }
+ }
+}
+
+
+btScalar btSequentialImpulseConstraintSolverMt::solveSingleIteration(int iteration, btCollisionObject** bodies, int numBodies, btPersistentManifold** manifoldPtr, int numManifolds, btTypedConstraint** constraints,int numConstraints,const btContactSolverInfo& infoGlobal,btIDebugDraw* debugDrawer)
+{
+ if ( !m_useBatching )
+ {
+ return btSequentialImpulseConstraintSolver::solveSingleIteration( iteration, bodies, numBodies, manifoldPtr, numManifolds, constraints, numConstraints, infoGlobal, debugDrawer );
+ }
+ BT_PROFILE( "solveSingleIterationMt" );
+ btScalar leastSquaresResidual = 0.f;
+
+ if (infoGlobal.m_solverMode & SOLVER_RANDMIZE_ORDER)
+ {
+ if (1) // uncomment this for a bit less random ((iteration & 7) == 0)
+ {
+ randomizeConstraintOrdering(iteration, infoGlobal.m_numIterations);
+ }
+ }
+
+ {
+ ///solve all joint constraints
+ leastSquaresResidual += resolveAllJointConstraints(iteration);
+
+ if (iteration< infoGlobal.m_numIterations)
+ {
+ // this loop is only used for cone-twist constraints,
+ // it would be nice to skip this loop if none of the constraints need it
+ if ( m_useObsoleteJointConstraints )
+ {
+ for ( int j = 0; j<numConstraints; j++ )
+ {
+ if ( constraints[ j ]->isEnabled() )
+ {
+ int bodyAid = getOrInitSolverBody( constraints[ j ]->getRigidBodyA(), infoGlobal.m_timeStep );
+ int bodyBid = getOrInitSolverBody( constraints[ j ]->getRigidBodyB(), infoGlobal.m_timeStep );
+ btSolverBody& bodyA = m_tmpSolverBodyPool[ bodyAid ];
+ btSolverBody& bodyB = m_tmpSolverBodyPool[ bodyBid ];
+ constraints[ j ]->solveConstraintObsolete( bodyA, bodyB, infoGlobal.m_timeStep );
+ }
+ }
+ }
+
+ if (infoGlobal.m_solverMode & SOLVER_INTERLEAVE_CONTACT_AND_FRICTION_CONSTRAINTS)
+ {
+ // solve all contact, contact-friction, and rolling friction constraints interleaved
+ leastSquaresResidual += resolveAllContactConstraintsInterleaved();
+ }
+ else//SOLVER_INTERLEAVE_CONTACT_AND_FRICTION_CONSTRAINTS
+ {
+ // don't interleave them
+ // solve all contact constraints
+ leastSquaresResidual += resolveAllContactConstraints();
+
+ // solve all contact friction constraints
+ leastSquaresResidual += resolveAllContactFrictionConstraints();
+
+ // solve all rolling friction constraints
+ leastSquaresResidual += resolveAllRollingFrictionConstraints();
+ }
+ }
+ }
+ return leastSquaresResidual;
+}
+
+
+btScalar btSequentialImpulseConstraintSolverMt::resolveMultipleJointConstraints( const btAlignedObjectArray<int>& consIndices, int batchBegin, int batchEnd, int iteration )
+{
+ btScalar leastSquaresResidual = 0.f;
+ for ( int iiCons = batchBegin; iiCons < batchEnd; ++iiCons )
+ {
+ int iCons = consIndices[ iiCons ];
+ const btSolverConstraint& constraint = m_tmpSolverNonContactConstraintPool[ iCons ];
+ if ( iteration < constraint.m_overrideNumSolverIterations )
+ {
+ btSolverBody& bodyA = m_tmpSolverBodyPool[ constraint.m_solverBodyIdA ];
+ btSolverBody& bodyB = m_tmpSolverBodyPool[ constraint.m_solverBodyIdB ];
+ btScalar residual = resolveSingleConstraintRowGeneric( bodyA, bodyB, constraint );
+ leastSquaresResidual += residual*residual;
+ }
+ }
+ return leastSquaresResidual;
+}
+
+
+btScalar btSequentialImpulseConstraintSolverMt::resolveMultipleContactConstraints( const btAlignedObjectArray<int>& consIndices, int batchBegin, int batchEnd )
+{
+ btScalar leastSquaresResidual = 0.f;
+ for ( int iiCons = batchBegin; iiCons < batchEnd; ++iiCons )
+ {
+ int iCons = consIndices[ iiCons ];
+ const btSolverConstraint& solveManifold = m_tmpSolverContactConstraintPool[ iCons ];
+ btSolverBody& bodyA = m_tmpSolverBodyPool[ solveManifold.m_solverBodyIdA ];
+ btSolverBody& bodyB = m_tmpSolverBodyPool[ solveManifold.m_solverBodyIdB ];
+ btScalar residual = resolveSingleConstraintRowLowerLimit( bodyA, bodyB, solveManifold );
+ leastSquaresResidual += residual*residual;
+ }
+ return leastSquaresResidual;
+}
+
+
+btScalar btSequentialImpulseConstraintSolverMt::resolveMultipleContactFrictionConstraints( const btAlignedObjectArray<int>& consIndices, int batchBegin, int batchEnd )
+{
+ btScalar leastSquaresResidual = 0.f;
+ for ( int iiCons = batchBegin; iiCons < batchEnd; ++iiCons )
+ {
+ int iContact = consIndices[ iiCons ];
+ btScalar totalImpulse = m_tmpSolverContactConstraintPool[ iContact ].m_appliedImpulse;
+
+ // apply sliding friction
+ if ( totalImpulse > 0.0f )
+ {
+ int iBegin = iContact * m_numFrictionDirections;
+ int iEnd = iBegin + m_numFrictionDirections;
+ for ( int iFriction = iBegin; iFriction < iEnd; ++iFriction )
+ {
+ btSolverConstraint& solveManifold = m_tmpSolverContactFrictionConstraintPool[ iFriction++ ];
+ btAssert( solveManifold.m_frictionIndex == iContact );
+
+ solveManifold.m_lowerLimit = -( solveManifold.m_friction*totalImpulse );
+ solveManifold.m_upperLimit = solveManifold.m_friction*totalImpulse;
+
+ btSolverBody& bodyA = m_tmpSolverBodyPool[ solveManifold.m_solverBodyIdA ];
+ btSolverBody& bodyB = m_tmpSolverBodyPool[ solveManifold.m_solverBodyIdB ];
+ btScalar residual = resolveSingleConstraintRowGeneric( bodyA, bodyB, solveManifold );
+ leastSquaresResidual += residual*residual;
+ }
+ }
+ }
+ return leastSquaresResidual;
+}
+
+
+btScalar btSequentialImpulseConstraintSolverMt::resolveMultipleContactRollingFrictionConstraints( const btAlignedObjectArray<int>& consIndices, int batchBegin, int batchEnd )
+{
+ btScalar leastSquaresResidual = 0.f;
+ for ( int iiCons = batchBegin; iiCons < batchEnd; ++iiCons )
+ {
+ int iContact = consIndices[ iiCons ];
+ int iFirstRollingFriction = m_rollingFrictionIndexTable[ iContact ];
+ if ( iFirstRollingFriction >= 0 )
+ {
+ btScalar totalImpulse = m_tmpSolverContactConstraintPool[ iContact ].m_appliedImpulse;
+ // apply rolling friction
+ if ( totalImpulse > 0.0f )
+ {
+ int iBegin = iFirstRollingFriction;
+ int iEnd = iBegin + 3;
+ for ( int iRollingFric = iBegin; iRollingFric < iEnd; ++iRollingFric )
+ {
+ btSolverConstraint& rollingFrictionConstraint = m_tmpSolverContactRollingFrictionConstraintPool[ iRollingFric ];
+ if ( rollingFrictionConstraint.m_frictionIndex != iContact )
+ {
+ break;
+ }
+ btScalar rollingFrictionMagnitude = rollingFrictionConstraint.m_friction*totalImpulse;
+ if ( rollingFrictionMagnitude > rollingFrictionConstraint.m_friction )
+ {
+ rollingFrictionMagnitude = rollingFrictionConstraint.m_friction;
+ }
+
+ rollingFrictionConstraint.m_lowerLimit = -rollingFrictionMagnitude;
+ rollingFrictionConstraint.m_upperLimit = rollingFrictionMagnitude;
+
+ btScalar residual = resolveSingleConstraintRowGeneric( m_tmpSolverBodyPool[ rollingFrictionConstraint.m_solverBodyIdA ], m_tmpSolverBodyPool[ rollingFrictionConstraint.m_solverBodyIdB ], rollingFrictionConstraint );
+ leastSquaresResidual += residual*residual;
+ }
+ }
+ }
+ }
+ return leastSquaresResidual;
+}
+
+
+btScalar btSequentialImpulseConstraintSolverMt::resolveMultipleContactConstraintsInterleaved( const btAlignedObjectArray<int>& contactIndices,
+ int batchBegin,
+ int batchEnd
+ )
+{
+ btScalar leastSquaresResidual = 0.f;
+ int numPoolConstraints = m_tmpSolverContactConstraintPool.size();
+
+ for ( int iiCons = batchBegin; iiCons < batchEnd; iiCons++ )
+ {
+ btScalar totalImpulse = 0;
+ int iContact = contactIndices[ iiCons ];
+ // apply penetration constraint
+ {
+ const btSolverConstraint& solveManifold = m_tmpSolverContactConstraintPool[ iContact ];
+ btScalar residual = resolveSingleConstraintRowLowerLimit( m_tmpSolverBodyPool[ solveManifold.m_solverBodyIdA ], m_tmpSolverBodyPool[ solveManifold.m_solverBodyIdB ], solveManifold );
+ leastSquaresResidual += residual*residual;
+ totalImpulse = solveManifold.m_appliedImpulse;
+ }
+
+ // apply sliding friction
+ if ( totalImpulse > 0.0f )
+ {
+ int iBegin = iContact * m_numFrictionDirections;
+ int iEnd = iBegin + m_numFrictionDirections;
+ for ( int iFriction = iBegin; iFriction < iEnd; ++iFriction )
+ {
+ btSolverConstraint& solveManifold = m_tmpSolverContactFrictionConstraintPool[ iFriction ];
+ btAssert( solveManifold.m_frictionIndex == iContact );
+
+ solveManifold.m_lowerLimit = -( solveManifold.m_friction*totalImpulse );
+ solveManifold.m_upperLimit = solveManifold.m_friction*totalImpulse;
+
+ btSolverBody& bodyA = m_tmpSolverBodyPool[ solveManifold.m_solverBodyIdA ];
+ btSolverBody& bodyB = m_tmpSolverBodyPool[ solveManifold.m_solverBodyIdB ];
+ btScalar residual = resolveSingleConstraintRowGeneric( bodyA, bodyB, solveManifold );
+ leastSquaresResidual += residual*residual;
+ }
+ }
+
+ // apply rolling friction
+ int iFirstRollingFriction = m_rollingFrictionIndexTable[ iContact ];
+ if ( totalImpulse > 0.0f && iFirstRollingFriction >= 0)
+ {
+ int iBegin = iFirstRollingFriction;
+ int iEnd = iBegin + 3;
+ for ( int iRollingFric = iBegin; iRollingFric < iEnd; ++iRollingFric )
+ {
+ btSolverConstraint& rollingFrictionConstraint = m_tmpSolverContactRollingFrictionConstraintPool[ iRollingFric ];
+ if ( rollingFrictionConstraint.m_frictionIndex != iContact )
+ {
+ break;
+ }
+ btScalar rollingFrictionMagnitude = rollingFrictionConstraint.m_friction*totalImpulse;
+ if ( rollingFrictionMagnitude > rollingFrictionConstraint.m_friction )
+ {
+ rollingFrictionMagnitude = rollingFrictionConstraint.m_friction;
+ }
+
+ rollingFrictionConstraint.m_lowerLimit = -rollingFrictionMagnitude;
+ rollingFrictionConstraint.m_upperLimit = rollingFrictionMagnitude;
+
+ btScalar residual = resolveSingleConstraintRowGeneric( m_tmpSolverBodyPool[ rollingFrictionConstraint.m_solverBodyIdA ], m_tmpSolverBodyPool[ rollingFrictionConstraint.m_solverBodyIdB ], rollingFrictionConstraint );
+ leastSquaresResidual += residual*residual;
+ }
+ }
+ }
+ return leastSquaresResidual;
+}
+
+
+void btSequentialImpulseConstraintSolverMt::randomizeBatchedConstraintOrdering( btBatchedConstraints* batchedConstraints )
+{
+ btBatchedConstraints& bc = *batchedConstraints;
+ // randomize ordering of phases
+ for ( int ii = 1; ii < bc.m_phaseOrder.size(); ++ii )
+ {
+ int iSwap = btRandInt2( ii + 1 );
+ bc.m_phaseOrder.swap( ii, iSwap );
+ }
+
+ // for each batch,
+ for ( int iBatch = 0; iBatch < bc.m_batches.size(); ++iBatch )
+ {
+ // randomize ordering of constraints within the batch
+ const btBatchedConstraints::Range& batch = bc.m_batches[ iBatch ];
+ for ( int iiCons = batch.begin; iiCons < batch.end; ++iiCons )
+ {
+ int iSwap = batch.begin + btRandInt2( iiCons - batch.begin + 1 );
+ btAssert(iSwap >= batch.begin && iSwap < batch.end);
+ bc.m_constraintIndices.swap( iiCons, iSwap );
+ }
+ }
+}
+
+
+void btSequentialImpulseConstraintSolverMt::randomizeConstraintOrdering(int iteration, int numIterations)
+{
+ // randomize ordering of joint constraints
+ randomizeBatchedConstraintOrdering( &m_batchedJointConstraints );
+
+ //contact/friction constraints are not solved more than numIterations
+ if ( iteration < numIterations )
+ {
+ randomizeBatchedConstraintOrdering( &m_batchedContactConstraints );
+ }
+}
+
+
+struct JointSolverLoop : public btIParallelSumBody
+{
+ btSequentialImpulseConstraintSolverMt* m_solver;
+ const btBatchedConstraints* m_bc;
+ int m_iteration;
+
+ JointSolverLoop( btSequentialImpulseConstraintSolverMt* solver, const btBatchedConstraints* bc, int iteration )
+ {
+ m_solver = solver;
+ m_bc = bc;
+ m_iteration = iteration;
+ }
+ btScalar sumLoop( int iBegin, int iEnd ) const BT_OVERRIDE
+ {
+ BT_PROFILE( "JointSolverLoop" );
+ btScalar sum = 0;
+ for ( int iBatch = iBegin; iBatch < iEnd; ++iBatch )
+ {
+ const btBatchedConstraints::Range& batch = m_bc->m_batches[ iBatch ];
+ sum += m_solver->resolveMultipleJointConstraints( m_bc->m_constraintIndices, batch.begin, batch.end, m_iteration );
+ }
+ return sum;
+ }
+};
+
+
+btScalar btSequentialImpulseConstraintSolverMt::resolveAllJointConstraints(int iteration)
+{
+ BT_PROFILE( "resolveAllJointConstraints" );
+ const btBatchedConstraints& batchedCons = m_batchedJointConstraints;
+ JointSolverLoop loop( this, &batchedCons, iteration );
+ btScalar leastSquaresResidual = 0.f;
+ for ( int iiPhase = 0; iiPhase < batchedCons.m_phases.size(); ++iiPhase )
+ {
+ int iPhase = batchedCons.m_phaseOrder[ iiPhase ];
+ const btBatchedConstraints::Range& phase = batchedCons.m_phases[ iPhase ];
+ int grainSize = 1;
+ leastSquaresResidual += btParallelSum( phase.begin, phase.end, grainSize, loop );
+ }
+ return leastSquaresResidual;
+}
+
+
+struct ContactSolverLoop : public btIParallelSumBody
+{
+ btSequentialImpulseConstraintSolverMt* m_solver;
+ const btBatchedConstraints* m_bc;
+
+ ContactSolverLoop( btSequentialImpulseConstraintSolverMt* solver, const btBatchedConstraints* bc )
+ {
+ m_solver = solver;
+ m_bc = bc;
+ }
+ btScalar sumLoop( int iBegin, int iEnd ) const BT_OVERRIDE
+ {
+ BT_PROFILE( "ContactSolverLoop" );
+ btScalar sum = 0;
+ for ( int iBatch = iBegin; iBatch < iEnd; ++iBatch )
+ {
+ const btBatchedConstraints::Range& batch = m_bc->m_batches[ iBatch ];
+ sum += m_solver->resolveMultipleContactConstraints( m_bc->m_constraintIndices, batch.begin, batch.end );
+ }
+ return sum;
+ }
+};
+
+
+btScalar btSequentialImpulseConstraintSolverMt::resolveAllContactConstraints()
+{
+ BT_PROFILE( "resolveAllContactConstraints" );
+ const btBatchedConstraints& batchedCons = m_batchedContactConstraints;
+ ContactSolverLoop loop( this, &batchedCons );
+ btScalar leastSquaresResidual = 0.f;
+ for ( int iiPhase = 0; iiPhase < batchedCons.m_phases.size(); ++iiPhase )
+ {
+ int iPhase = batchedCons.m_phaseOrder[ iiPhase ];
+ const btBatchedConstraints::Range& phase = batchedCons.m_phases[ iPhase ];
+ int grainSize = batchedCons.m_phaseGrainSize[iPhase];
+ leastSquaresResidual += btParallelSum( phase.begin, phase.end, grainSize, loop );
+ }
+ return leastSquaresResidual;
+}
+
+
+struct ContactFrictionSolverLoop : public btIParallelSumBody
+{
+ btSequentialImpulseConstraintSolverMt* m_solver;
+ const btBatchedConstraints* m_bc;
+
+ ContactFrictionSolverLoop( btSequentialImpulseConstraintSolverMt* solver, const btBatchedConstraints* bc )
+ {
+ m_solver = solver;
+ m_bc = bc;
+ }
+ btScalar sumLoop( int iBegin, int iEnd ) const BT_OVERRIDE
+ {
+ BT_PROFILE( "ContactFrictionSolverLoop" );
+ btScalar sum = 0;
+ for ( int iBatch = iBegin; iBatch < iEnd; ++iBatch )
+ {
+ const btBatchedConstraints::Range& batch = m_bc->m_batches[ iBatch ];
+ sum += m_solver->resolveMultipleContactFrictionConstraints( m_bc->m_constraintIndices, batch.begin, batch.end );
+ }
+ return sum;
+ }
+};
+
+
+btScalar btSequentialImpulseConstraintSolverMt::resolveAllContactFrictionConstraints()
+{
+ BT_PROFILE( "resolveAllContactFrictionConstraints" );
+ const btBatchedConstraints& batchedCons = m_batchedContactConstraints;
+ ContactFrictionSolverLoop loop( this, &batchedCons );
+ btScalar leastSquaresResidual = 0.f;
+ for ( int iiPhase = 0; iiPhase < batchedCons.m_phases.size(); ++iiPhase )
+ {
+ int iPhase = batchedCons.m_phaseOrder[ iiPhase ];
+ const btBatchedConstraints::Range& phase = batchedCons.m_phases[ iPhase ];
+ int grainSize = batchedCons.m_phaseGrainSize[iPhase];
+ leastSquaresResidual += btParallelSum( phase.begin, phase.end, grainSize, loop );
+ }
+ return leastSquaresResidual;
+}
+
+
+struct InterleavedContactSolverLoop : public btIParallelSumBody
+{
+ btSequentialImpulseConstraintSolverMt* m_solver;
+ const btBatchedConstraints* m_bc;
+
+ InterleavedContactSolverLoop( btSequentialImpulseConstraintSolverMt* solver, const btBatchedConstraints* bc )
+ {
+ m_solver = solver;
+ m_bc = bc;
+ }
+ btScalar sumLoop( int iBegin, int iEnd ) const BT_OVERRIDE
+ {
+ BT_PROFILE( "InterleavedContactSolverLoop" );
+ btScalar sum = 0;
+ for ( int iBatch = iBegin; iBatch < iEnd; ++iBatch )
+ {
+ const btBatchedConstraints::Range& batch = m_bc->m_batches[ iBatch ];
+ sum += m_solver->resolveMultipleContactConstraintsInterleaved( m_bc->m_constraintIndices, batch.begin, batch.end );
+ }
+ return sum;
+ }
+};
+
+
+btScalar btSequentialImpulseConstraintSolverMt::resolveAllContactConstraintsInterleaved()
+{
+ BT_PROFILE( "resolveAllContactConstraintsInterleaved" );
+ const btBatchedConstraints& batchedCons = m_batchedContactConstraints;
+ InterleavedContactSolverLoop loop( this, &batchedCons );
+ btScalar leastSquaresResidual = 0.f;
+ for ( int iiPhase = 0; iiPhase < batchedCons.m_phases.size(); ++iiPhase )
+ {
+ int iPhase = batchedCons.m_phaseOrder[ iiPhase ];
+ const btBatchedConstraints::Range& phase = batchedCons.m_phases[ iPhase ];
+ int grainSize = 1;
+ leastSquaresResidual += btParallelSum( phase.begin, phase.end, grainSize, loop );
+ }
+ return leastSquaresResidual;
+}
+
+
+struct ContactRollingFrictionSolverLoop : public btIParallelSumBody
+{
+ btSequentialImpulseConstraintSolverMt* m_solver;
+ const btBatchedConstraints* m_bc;
+
+ ContactRollingFrictionSolverLoop( btSequentialImpulseConstraintSolverMt* solver, const btBatchedConstraints* bc )
+ {
+ m_solver = solver;
+ m_bc = bc;
+ }
+ btScalar sumLoop( int iBegin, int iEnd ) const BT_OVERRIDE
+ {
+ BT_PROFILE( "ContactFrictionSolverLoop" );
+ btScalar sum = 0;
+ for ( int iBatch = iBegin; iBatch < iEnd; ++iBatch )
+ {
+ const btBatchedConstraints::Range& batch = m_bc->m_batches[ iBatch ];
+ sum += m_solver->resolveMultipleContactRollingFrictionConstraints( m_bc->m_constraintIndices, batch.begin, batch.end );
+ }
+ return sum;
+ }
+};
+
+
+btScalar btSequentialImpulseConstraintSolverMt::resolveAllRollingFrictionConstraints()
+{
+ BT_PROFILE( "resolveAllRollingFrictionConstraints" );
+ btScalar leastSquaresResidual = 0.f;
+ //
+ // We do not generate batches for rolling friction constraints. We assume that
+ // one of two cases is true:
+ //
+ // 1. either most bodies in the simulation have rolling friction, in which case we can use the
+ // batches for contacts and use a lookup table to translate contact indices to rolling friction
+ // (ignoring any contact indices that don't map to a rolling friction constraint). As long as
+ // most contacts have a corresponding rolling friction constraint, this should parallelize well.
+ //
+ // -OR-
+ //
+ // 2. few bodies in the simulation have rolling friction, so it is not worth trying to use the
+ // batches from contacts as most of the contacts won't have corresponding rolling friction
+ // constraints and most threads would end up doing very little work. Most of the time would
+ // go to threading overhead, so we don't bother with threading.
+ //
+ int numRollingFrictionPoolConstraints = m_tmpSolverContactRollingFrictionConstraintPool.size();
+ if (numRollingFrictionPoolConstraints >= m_tmpSolverContactConstraintPool.size())
+ {
+ // use batching if there are many rolling friction constraints
+ const btBatchedConstraints& batchedCons = m_batchedContactConstraints;
+ ContactRollingFrictionSolverLoop loop( this, &batchedCons );
+ btScalar leastSquaresResidual = 0.f;
+ for ( int iiPhase = 0; iiPhase < batchedCons.m_phases.size(); ++iiPhase )
+ {
+ int iPhase = batchedCons.m_phaseOrder[ iiPhase ];
+ const btBatchedConstraints::Range& phase = batchedCons.m_phases[ iPhase ];
+ int grainSize = 1;
+ leastSquaresResidual += btParallelSum( phase.begin, phase.end, grainSize, loop );
+ }
+ }
+ else
+ {
+ // no batching, also ignores SOLVER_RANDMIZE_ORDER
+ for ( int j = 0; j < numRollingFrictionPoolConstraints; j++ )
+ {
+ btSolverConstraint& rollingFrictionConstraint = m_tmpSolverContactRollingFrictionConstraintPool[ j ];
+ if ( rollingFrictionConstraint.m_frictionIndex >= 0 )
+ {
+ btScalar totalImpulse = m_tmpSolverContactConstraintPool[ rollingFrictionConstraint.m_frictionIndex ].m_appliedImpulse;
+ if ( totalImpulse > 0.0f )
+ {
+ btScalar rollingFrictionMagnitude = rollingFrictionConstraint.m_friction*totalImpulse;
+ if ( rollingFrictionMagnitude > rollingFrictionConstraint.m_friction )
+ rollingFrictionMagnitude = rollingFrictionConstraint.m_friction;
+
+ rollingFrictionConstraint.m_lowerLimit = -rollingFrictionMagnitude;
+ rollingFrictionConstraint.m_upperLimit = rollingFrictionMagnitude;
+
+ btScalar residual = resolveSingleConstraintRowGeneric( m_tmpSolverBodyPool[ rollingFrictionConstraint.m_solverBodyIdA ], m_tmpSolverBodyPool[ rollingFrictionConstraint.m_solverBodyIdB ], rollingFrictionConstraint );
+ leastSquaresResidual += residual*residual;
+ }
+ }
+ }
+ }
+ return leastSquaresResidual;
+}
+
+
+void btSequentialImpulseConstraintSolverMt::internalWriteBackContacts( int iBegin, int iEnd, const btContactSolverInfo& infoGlobal )
+{
+ BT_PROFILE("internalWriteBackContacts");
+ writeBackContacts(iBegin, iEnd, infoGlobal);
+ //for ( int iContact = iBegin; iContact < iEnd; ++iContact)
+ //{
+ // const btSolverConstraint& contactConstraint = m_tmpSolverContactConstraintPool[ iContact ];
+ // btManifoldPoint* pt = (btManifoldPoint*) contactConstraint.m_originalContactPoint;
+ // btAssert( pt );
+ // pt->m_appliedImpulse = contactConstraint.m_appliedImpulse;
+ // pt->m_appliedImpulseLateral1 = m_tmpSolverContactFrictionConstraintPool[ contactConstraint.m_frictionIndex ].m_appliedImpulse;
+ // if ( m_numFrictionDirections == 2 )
+ // {
+ // pt->m_appliedImpulseLateral2 = m_tmpSolverContactFrictionConstraintPool[ contactConstraint.m_frictionIndex + 1 ].m_appliedImpulse;
+ // }
+ //}
+}
+
+
+void btSequentialImpulseConstraintSolverMt::internalWriteBackJoints( int iBegin, int iEnd, const btContactSolverInfo& infoGlobal )
+{
+ BT_PROFILE("internalWriteBackJoints");
+ writeBackJoints(iBegin, iEnd, infoGlobal);
+}
+
+
+void btSequentialImpulseConstraintSolverMt::internalWriteBackBodies( int iBegin, int iEnd, const btContactSolverInfo& infoGlobal )
+{
+ BT_PROFILE("internalWriteBackBodies");
+ writeBackBodies( iBegin, iEnd, infoGlobal );
+}
+
+
+struct WriteContactPointsLoop : public btIParallelForBody
+{
+ btSequentialImpulseConstraintSolverMt* m_solver;
+ const btContactSolverInfo* m_infoGlobal;
+
+ WriteContactPointsLoop( btSequentialImpulseConstraintSolverMt* solver, const btContactSolverInfo& infoGlobal )
+ {
+ m_solver = solver;
+ m_infoGlobal = &infoGlobal;
+ }
+ void forLoop( int iBegin, int iEnd ) const BT_OVERRIDE
+ {
+ m_solver->internalWriteBackContacts( iBegin, iEnd, *m_infoGlobal );
+ }
+};
+
+
+struct WriteJointsLoop : public btIParallelForBody
+{
+ btSequentialImpulseConstraintSolverMt* m_solver;
+ const btContactSolverInfo* m_infoGlobal;
+
+ WriteJointsLoop( btSequentialImpulseConstraintSolverMt* solver, const btContactSolverInfo& infoGlobal )
+ {
+ m_solver = solver;
+ m_infoGlobal = &infoGlobal;
+ }
+ void forLoop( int iBegin, int iEnd ) const BT_OVERRIDE
+ {
+ m_solver->internalWriteBackJoints( iBegin, iEnd, *m_infoGlobal );
+ }
+};
+
+
+struct WriteBodiesLoop : public btIParallelForBody
+{
+ btSequentialImpulseConstraintSolverMt* m_solver;
+ const btContactSolverInfo* m_infoGlobal;
+
+ WriteBodiesLoop( btSequentialImpulseConstraintSolverMt* solver, const btContactSolverInfo& infoGlobal )
+ {
+ m_solver = solver;
+ m_infoGlobal = &infoGlobal;
+ }
+ void forLoop( int iBegin, int iEnd ) const BT_OVERRIDE
+ {
+ m_solver->internalWriteBackBodies( iBegin, iEnd, *m_infoGlobal );
+ }
+};
+
+
+btScalar btSequentialImpulseConstraintSolverMt::solveGroupCacheFriendlyFinish(btCollisionObject** bodies, int numBodies, const btContactSolverInfo& infoGlobal)
+{
+ BT_PROFILE("solveGroupCacheFriendlyFinish");
+
+ if (infoGlobal.m_solverMode & SOLVER_USE_WARMSTARTING)
+ {
+ WriteContactPointsLoop loop( this, infoGlobal );
+ int grainSize = 500;
+ btParallelFor( 0, m_tmpSolverContactConstraintPool.size(), grainSize, loop );
+ }
+
+ {
+ WriteJointsLoop loop( this, infoGlobal );
+ int grainSize = 400;
+ btParallelFor( 0, m_tmpSolverNonContactConstraintPool.size(), grainSize, loop );
+ }
+ {
+ WriteBodiesLoop loop( this, infoGlobal );
+ int grainSize = 100;
+ btParallelFor( 0, m_tmpSolverBodyPool.size(), grainSize, loop );
+ }
+
+ m_tmpSolverContactConstraintPool.resizeNoInitialize(0);
+ m_tmpSolverNonContactConstraintPool.resizeNoInitialize(0);
+ m_tmpSolverContactFrictionConstraintPool.resizeNoInitialize(0);
+ m_tmpSolverContactRollingFrictionConstraintPool.resizeNoInitialize(0);
+
+ m_tmpSolverBodyPool.resizeNoInitialize(0);
+ return 0.f;
+}
+
diff --git a/thirdparty/bullet/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolverMt.h b/thirdparty/bullet/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolverMt.h
new file mode 100644
index 0000000000..55d53474c4
--- /dev/null
+++ b/thirdparty/bullet/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolverMt.h
@@ -0,0 +1,154 @@
+/*
+Bullet Continuous Collision Detection and Physics Library
+Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
+
+This software is provided 'as-is', without any express or implied warranty.
+In no event will the authors be held liable for any damages arising from the use of this software.
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it freely,
+subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
+2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
+3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef BT_SEQUENTIAL_IMPULSE_CONSTRAINT_SOLVER_MT_H
+#define BT_SEQUENTIAL_IMPULSE_CONSTRAINT_SOLVER_MT_H
+
+#include "btSequentialImpulseConstraintSolver.h"
+#include "btBatchedConstraints.h"
+#include "LinearMath/btThreads.h"
+
+///
+/// btSequentialImpulseConstraintSolverMt
+///
+/// A multithreaded variant of the sequential impulse constraint solver. The constraints to be solved are grouped into
+/// batches and phases where each batch of constraints within a given phase can be solved in parallel with the rest.
+/// Ideally we want as few phases as possible, and each phase should have many batches, and all of the batches should
+/// have about the same number of constraints.
+/// This method works best on a large island of many constraints.
+///
+/// Supports all of the features of the normal sequential impulse solver such as:
+/// - split penetration impulse
+/// - rolling friction
+/// - interleaving constraints
+/// - warmstarting
+/// - 2 friction directions
+/// - randomized constraint ordering
+/// - early termination when leastSquaresResidualThreshold is satisfied
+///
+/// When the SOLVER_INTERLEAVE_CONTACT_AND_FRICTION_CONSTRAINTS flag is enabled, unlike the normal SequentialImpulse solver,
+/// the rolling friction is interleaved as well.
+/// Interleaving the contact penetration constraints with friction reduces the number of parallel loops that need to be done,
+/// which reduces threading overhead so it can be a performance win, however, it does seem to produce a less stable simulation,
+/// at least on stacks of blocks.
+///
+/// When the SOLVER_RANDMIZE_ORDER flag is enabled, the ordering of phases, and the ordering of constraints within each batch
+/// is randomized, however it does not swap constraints between batches.
+/// This is to avoid regenerating the batches for each solver iteration which would be quite costly in performance.
+///
+/// Note that a non-zero leastSquaresResidualThreshold could possibly affect the determinism of the simulation
+/// if the task scheduler's parallelSum operation is non-deterministic. The parallelSum operation can be non-deterministic
+/// because floating point addition is not associative due to rounding errors.
+/// The task scheduler can and should ensure that the result of any parallelSum operation is deterministic.
+///
+ATTRIBUTE_ALIGNED16(class) btSequentialImpulseConstraintSolverMt : public btSequentialImpulseConstraintSolver
+{
+public:
+ virtual void solveGroupCacheFriendlySplitImpulseIterations(btCollisionObject** bodies,int numBodies,btPersistentManifold** manifoldPtr, int numManifolds,btTypedConstraint** constraints,int numConstraints,const btContactSolverInfo& infoGlobal,btIDebugDraw* debugDrawer) BT_OVERRIDE;
+ virtual btScalar solveSingleIteration(int iteration, btCollisionObject** bodies ,int numBodies,btPersistentManifold** manifoldPtr, int numManifolds,btTypedConstraint** constraints,int numConstraints,const btContactSolverInfo& infoGlobal,btIDebugDraw* debugDrawer) BT_OVERRIDE;
+ virtual btScalar solveGroupCacheFriendlySetup(btCollisionObject** bodies,int numBodies,btPersistentManifold** manifoldPtr, int numManifolds,btTypedConstraint** constraints,int numConstraints,const btContactSolverInfo& infoGlobal,btIDebugDraw* debugDrawer) BT_OVERRIDE;
+ virtual btScalar solveGroupCacheFriendlyFinish(btCollisionObject** bodies, int numBodies, const btContactSolverInfo& infoGlobal) BT_OVERRIDE;
+
+ // temp struct used to collect info from persistent manifolds into a cache-friendly struct using multiple threads
+ struct btContactManifoldCachedInfo
+ {
+ static const int MAX_NUM_CONTACT_POINTS = 4;
+
+ int numTouchingContacts;
+ int solverBodyIds[ 2 ];
+ int contactIndex;
+ int rollingFrictionIndex;
+ bool contactHasRollingFriction[ MAX_NUM_CONTACT_POINTS ];
+ btManifoldPoint* contactPoints[ MAX_NUM_CONTACT_POINTS ];
+ };
+ // temp struct used for setting up joint constraints in parallel
+ struct JointParams
+ {
+ int m_solverConstraint;
+ int m_solverBodyA;
+ int m_solverBodyB;
+ };
+ void internalInitMultipleJoints(btTypedConstraint** constraints, int iBegin, int iEnd);
+ void internalConvertMultipleJoints( const btAlignedObjectArray<JointParams>& jointParamsArray, btTypedConstraint** constraints, int iBegin, int iEnd, const btContactSolverInfo& infoGlobal );
+
+ // parameters to control batching
+ static bool s_allowNestedParallelForLoops; // whether to allow nested parallel operations
+ static int s_minimumContactManifoldsForBatching; // don't even try to batch if fewer manifolds than this
+ static btBatchedConstraints::BatchingMethod s_contactBatchingMethod;
+ static btBatchedConstraints::BatchingMethod s_jointBatchingMethod;
+ static int s_minBatchSize; // desired number of constraints per batch
+ static int s_maxBatchSize;
+
+protected:
+ static const int CACHE_LINE_SIZE = 64;
+
+ btBatchedConstraints m_batchedContactConstraints;
+ btBatchedConstraints m_batchedJointConstraints;
+ int m_numFrictionDirections;
+ bool m_useBatching;
+ bool m_useObsoleteJointConstraints;
+ btAlignedObjectArray<btContactManifoldCachedInfo> m_manifoldCachedInfoArray;
+ btAlignedObjectArray<int> m_rollingFrictionIndexTable; // lookup table mapping contact index to rolling friction index
+ btSpinMutex m_bodySolverArrayMutex;
+ char m_antiFalseSharingPadding[CACHE_LINE_SIZE]; // padding to keep mutexes in separate cachelines
+ btSpinMutex m_kinematicBodyUniqueIdToSolverBodyTableMutex;
+ btAlignedObjectArray<char> m_scratchMemory;
+
+ virtual void randomizeConstraintOrdering( int iteration, int numIterations );
+ virtual btScalar resolveAllJointConstraints( int iteration );
+ virtual btScalar resolveAllContactConstraints();
+ virtual btScalar resolveAllContactFrictionConstraints();
+ virtual btScalar resolveAllContactConstraintsInterleaved();
+ virtual btScalar resolveAllRollingFrictionConstraints();
+
+ virtual void setupBatchedContactConstraints();
+ virtual void setupBatchedJointConstraints();
+ virtual void convertJoints(btTypedConstraint** constraints,int numConstraints,const btContactSolverInfo& infoGlobal) BT_OVERRIDE;
+ virtual void convertContacts(btPersistentManifold** manifoldPtr, int numManifolds, const btContactSolverInfo& infoGlobal) BT_OVERRIDE;
+ virtual void convertBodies(btCollisionObject** bodies, int numBodies, const btContactSolverInfo& infoGlobal) BT_OVERRIDE;
+
+ int getOrInitSolverBodyThreadsafe(btCollisionObject& body, btScalar timeStep);
+ void allocAllContactConstraints(btPersistentManifold** manifoldPtr, int numManifolds, const btContactSolverInfo& infoGlobal);
+ void setupAllContactConstraints(const btContactSolverInfo& infoGlobal);
+ void randomizeBatchedConstraintOrdering( btBatchedConstraints* batchedConstraints );
+
+public:
+
+ BT_DECLARE_ALIGNED_ALLOCATOR();
+
+ btSequentialImpulseConstraintSolverMt();
+ virtual ~btSequentialImpulseConstraintSolverMt();
+
+ btScalar resolveMultipleJointConstraints( const btAlignedObjectArray<int>& consIndices, int batchBegin, int batchEnd, int iteration );
+ btScalar resolveMultipleContactConstraints( const btAlignedObjectArray<int>& consIndices, int batchBegin, int batchEnd );
+ btScalar resolveMultipleContactSplitPenetrationImpulseConstraints( const btAlignedObjectArray<int>& consIndices, int batchBegin, int batchEnd );
+ btScalar resolveMultipleContactFrictionConstraints( const btAlignedObjectArray<int>& consIndices, int batchBegin, int batchEnd );
+ btScalar resolveMultipleContactRollingFrictionConstraints( const btAlignedObjectArray<int>& consIndices, int batchBegin, int batchEnd );
+ btScalar resolveMultipleContactConstraintsInterleaved( const btAlignedObjectArray<int>& contactIndices, int batchBegin, int batchEnd );
+
+ void internalCollectContactManifoldCachedInfo(btContactManifoldCachedInfo* cachedInfoArray, btPersistentManifold** manifoldPtr, int numManifolds, const btContactSolverInfo& infoGlobal);
+ void internalAllocContactConstraints(const btContactManifoldCachedInfo* cachedInfoArray, int numManifolds);
+ void internalSetupContactConstraints(int iContactConstraint, const btContactSolverInfo& infoGlobal);
+ void internalConvertBodies(btCollisionObject** bodies, int iBegin, int iEnd, const btContactSolverInfo& infoGlobal);
+ void internalWriteBackContacts(int iBegin, int iEnd, const btContactSolverInfo& infoGlobal);
+ void internalWriteBackJoints(int iBegin, int iEnd, const btContactSolverInfo& infoGlobal);
+ void internalWriteBackBodies(int iBegin, int iEnd, const btContactSolverInfo& infoGlobal);
+};
+
+
+
+
+#endif //BT_SEQUENTIAL_IMPULSE_CONSTRAINT_SOLVER_MT_H
+
diff --git a/thirdparty/bullet/BulletDynamics/ConstraintSolver/btSliderConstraint.cpp b/thirdparty/bullet/BulletDynamics/ConstraintSolver/btSliderConstraint.cpp
index d63cef0316..d63cef0316 100644..100755
--- a/thirdparty/bullet/BulletDynamics/ConstraintSolver/btSliderConstraint.cpp
+++ b/thirdparty/bullet/BulletDynamics/ConstraintSolver/btSliderConstraint.cpp
diff --git a/thirdparty/bullet/BulletDynamics/ConstraintSolver/btSliderConstraint.h b/thirdparty/bullet/BulletDynamics/ConstraintSolver/btSliderConstraint.h
index 1957f08a96..1957f08a96 100644..100755
--- a/thirdparty/bullet/BulletDynamics/ConstraintSolver/btSliderConstraint.h
+++ b/thirdparty/bullet/BulletDynamics/ConstraintSolver/btSliderConstraint.h
diff --git a/thirdparty/bullet/BulletDynamics/Dynamics/btDiscreteDynamicsWorld.cpp b/thirdparty/bullet/BulletDynamics/Dynamics/btDiscreteDynamicsWorld.cpp
index a196d4522e..b9944c138b 100644
--- a/thirdparty/bullet/BulletDynamics/Dynamics/btDiscreteDynamicsWorld.cpp
+++ b/thirdparty/bullet/BulletDynamics/Dynamics/btDiscreteDynamicsWorld.cpp
@@ -842,6 +842,9 @@ public:
btCollisionObject* otherObj = (btCollisionObject*) proxy0->m_clientObject;
+ if(!m_dispatcher->needsCollision(m_me, otherObj))
+ return false;
+
//call needsResponse, see http://code.google.com/p/bullet/issues/detail?id=179
if (m_dispatcher->needsResponse(m_me,otherObj))
{
@@ -1342,9 +1345,12 @@ void btDiscreteDynamicsWorld::debugDrawConstraint(btTypedConstraint* constraint)
btVector3 axis = tr.getBasis().getColumn(0);
btScalar minTh = p6DOF->getRotationalLimitMotor(1)->m_loLimit;
btScalar maxTh = p6DOF->getRotationalLimitMotor(1)->m_hiLimit;
- btScalar minPs = p6DOF->getRotationalLimitMotor(2)->m_loLimit;
- btScalar maxPs = p6DOF->getRotationalLimitMotor(2)->m_hiLimit;
- getDebugDrawer()->drawSpherePatch(center, up, axis, dbgDrawSize * btScalar(.9f), minTh, maxTh, minPs, maxPs, btVector3(0, 0, 0));
+ if (minTh <= maxTh)
+ {
+ btScalar minPs = p6DOF->getRotationalLimitMotor(2)->m_loLimit;
+ btScalar maxPs = p6DOF->getRotationalLimitMotor(2)->m_hiLimit;
+ getDebugDrawer()->drawSpherePatch(center, up, axis, dbgDrawSize * btScalar(.9f), minTh, maxTh, minPs, maxPs, btVector3(0, 0, 0));
+ }
axis = tr.getBasis().getColumn(1);
btScalar ay = p6DOF->getAngle(1);
btScalar az = p6DOF->getAngle(2);
@@ -1533,6 +1539,8 @@ void btDiscreteDynamicsWorld::serialize(btSerializer* serializer)
serializeRigidBodies(serializer);
+ serializeContactManifolds(serializer);
+
serializer->finishSerialization();
}
diff --git a/thirdparty/bullet/BulletDynamics/Dynamics/btDiscreteDynamicsWorldMt.cpp b/thirdparty/bullet/BulletDynamics/Dynamics/btDiscreteDynamicsWorldMt.cpp
index 1d10bad922..d705bf2381 100644
--- a/thirdparty/bullet/BulletDynamics/Dynamics/btDiscreteDynamicsWorldMt.cpp
+++ b/thirdparty/bullet/BulletDynamics/Dynamics/btDiscreteDynamicsWorldMt.cpp
@@ -50,63 +50,6 @@ subject to the following restrictions:
#include "LinearMath/btSerializer.h"
-struct InplaceSolverIslandCallbackMt : public btSimulationIslandManagerMt::IslandCallback
-{
- btContactSolverInfo* m_solverInfo;
- btConstraintSolver* m_solver;
- btIDebugDraw* m_debugDrawer;
- btDispatcher* m_dispatcher;
-
- InplaceSolverIslandCallbackMt(
- btConstraintSolver* solver,
- btStackAlloc* stackAlloc,
- btDispatcher* dispatcher)
- :m_solverInfo(NULL),
- m_solver(solver),
- m_debugDrawer(NULL),
- m_dispatcher(dispatcher)
- {
-
- }
-
- InplaceSolverIslandCallbackMt& operator=(InplaceSolverIslandCallbackMt& other)
- {
- btAssert(0);
- (void)other;
- return *this;
- }
-
- SIMD_FORCE_INLINE void setup ( btContactSolverInfo* solverInfo, btIDebugDraw* debugDrawer)
- {
- btAssert(solverInfo);
- m_solverInfo = solverInfo;
- m_debugDrawer = debugDrawer;
- }
-
-
- virtual void processIsland( btCollisionObject** bodies,
- int numBodies,
- btPersistentManifold** manifolds,
- int numManifolds,
- btTypedConstraint** constraints,
- int numConstraints,
- int islandId
- )
- {
- m_solver->solveGroup( bodies,
- numBodies,
- manifolds,
- numManifolds,
- constraints,
- numConstraints,
- *m_solverInfo,
- m_debugDrawer,
- m_dispatcher
- );
- }
-
-};
-
///
/// btConstraintSolverPoolMt
@@ -209,7 +152,12 @@ void btConstraintSolverPoolMt::reset()
/// btDiscreteDynamicsWorldMt
///
-btDiscreteDynamicsWorldMt::btDiscreteDynamicsWorldMt(btDispatcher* dispatcher, btBroadphaseInterface* pairCache, btConstraintSolverPoolMt* constraintSolver, btCollisionConfiguration* collisionConfiguration)
+btDiscreteDynamicsWorldMt::btDiscreteDynamicsWorldMt(btDispatcher* dispatcher,
+ btBroadphaseInterface* pairCache,
+ btConstraintSolverPoolMt* constraintSolver,
+ btConstraintSolver* constraintSolverMt,
+ btCollisionConfiguration* collisionConfiguration
+)
: btDiscreteDynamicsWorld(dispatcher,pairCache,constraintSolver,collisionConfiguration)
{
if (m_ownsIslandManager)
@@ -217,31 +165,18 @@ btDiscreteDynamicsWorldMt::btDiscreteDynamicsWorldMt(btDispatcher* dispatcher, b
m_islandManager->~btSimulationIslandManager();
btAlignedFree( m_islandManager);
}
- {
- void* mem = btAlignedAlloc(sizeof(InplaceSolverIslandCallbackMt),16);
- m_solverIslandCallbackMt = new (mem) InplaceSolverIslandCallbackMt (m_constraintSolver, 0, dispatcher);
- }
{
void* mem = btAlignedAlloc(sizeof(btSimulationIslandManagerMt),16);
btSimulationIslandManagerMt* im = new (mem) btSimulationIslandManagerMt();
im->setMinimumSolverBatchSize( m_solverInfo.m_minimumSolverBatchSize );
m_islandManager = im;
}
+ m_constraintSolverMt = constraintSolverMt;
}
btDiscreteDynamicsWorldMt::~btDiscreteDynamicsWorldMt()
{
- if (m_solverIslandCallbackMt)
- {
- m_solverIslandCallbackMt->~InplaceSolverIslandCallbackMt();
- btAlignedFree(m_solverIslandCallbackMt);
- }
- if (m_ownsConstraintSolver)
- {
- m_constraintSolver->~btConstraintSolver();
- btAlignedFree(m_constraintSolver);
- }
}
@@ -249,12 +184,17 @@ void btDiscreteDynamicsWorldMt::solveConstraints(btContactSolverInfo& solverInfo
{
BT_PROFILE("solveConstraints");
- m_solverIslandCallbackMt->setup(&solverInfo, getDebugDrawer());
m_constraintSolver->prepareSolve(getCollisionWorld()->getNumCollisionObjects(), getCollisionWorld()->getDispatcher()->getNumManifolds());
/// solve all the constraints for this island
btSimulationIslandManagerMt* im = static_cast<btSimulationIslandManagerMt*>(m_islandManager);
- im->buildAndProcessIslands( getCollisionWorld()->getDispatcher(), getCollisionWorld(), m_constraints, m_solverIslandCallbackMt );
+ btSimulationIslandManagerMt::SolverParams solverParams;
+ solverParams.m_solverPool = m_constraintSolver;
+ solverParams.m_solverMt = m_constraintSolverMt;
+ solverParams.m_solverInfo = &solverInfo;
+ solverParams.m_debugDrawer = m_debugDrawer;
+ solverParams.m_dispatcher = getCollisionWorld()->getDispatcher();
+ im->buildAndProcessIslands( getCollisionWorld()->getDispatcher(), getCollisionWorld(), m_constraints, solverParams );
m_constraintSolver->allSolved(solverInfo, m_debugDrawer);
}
@@ -325,3 +265,14 @@ void btDiscreteDynamicsWorldMt::integrateTransforms( btScalar timeStep )
}
}
+
+int btDiscreteDynamicsWorldMt::stepSimulation( btScalar timeStep, int maxSubSteps, btScalar fixedTimeStep )
+{
+ int numSubSteps = btDiscreteDynamicsWorld::stepSimulation(timeStep, maxSubSteps, fixedTimeStep);
+ if (btITaskScheduler* scheduler = btGetTaskScheduler())
+ {
+ // tell Bullet's threads to sleep, so other threads can run
+ scheduler->sleepWorkerThreadsHint();
+ }
+ return numSubSteps;
+}
diff --git a/thirdparty/bullet/BulletDynamics/Dynamics/btDiscreteDynamicsWorldMt.h b/thirdparty/bullet/BulletDynamics/Dynamics/btDiscreteDynamicsWorldMt.h
index 2f144cdda4..667fe5800e 100644
--- a/thirdparty/bullet/BulletDynamics/Dynamics/btDiscreteDynamicsWorldMt.h
+++ b/thirdparty/bullet/BulletDynamics/Dynamics/btDiscreteDynamicsWorldMt.h
@@ -21,7 +21,6 @@ subject to the following restrictions:
#include "btSimulationIslandManagerMt.h"
#include "BulletDynamics/ConstraintSolver/btConstraintSolver.h"
-struct InplaceSolverIslandCallbackMt;
///
/// btConstraintSolverPoolMt - masquerades as a constraint solver, but really it is a threadsafe pool of them.
@@ -88,7 +87,7 @@ private:
ATTRIBUTE_ALIGNED16(class) btDiscreteDynamicsWorldMt : public btDiscreteDynamicsWorld
{
protected:
- InplaceSolverIslandCallbackMt* m_solverIslandCallbackMt;
+ btConstraintSolver* m_constraintSolverMt;
virtual void solveConstraints(btContactSolverInfo& solverInfo) BT_OVERRIDE;
@@ -126,9 +125,12 @@ public:
btDiscreteDynamicsWorldMt(btDispatcher* dispatcher,
btBroadphaseInterface* pairCache,
btConstraintSolverPoolMt* constraintSolver, // Note this should be a solver-pool for multi-threading
+ btConstraintSolver* constraintSolverMt, // single multi-threaded solver for large islands (or NULL)
btCollisionConfiguration* collisionConfiguration
);
virtual ~btDiscreteDynamicsWorldMt();
+
+ virtual int stepSimulation( btScalar timeStep, int maxSubSteps, btScalar fixedTimeStep ) BT_OVERRIDE;
};
#endif //BT_DISCRETE_DYNAMICS_WORLD_H
diff --git a/thirdparty/bullet/BulletDynamics/Dynamics/btSimulationIslandManagerMt.cpp b/thirdparty/bullet/BulletDynamics/Dynamics/btSimulationIslandManagerMt.cpp
index 99b34353c7..fc54f0ba6e 100644
--- a/thirdparty/bullet/BulletDynamics/Dynamics/btSimulationIslandManagerMt.cpp
+++ b/thirdparty/bullet/BulletDynamics/Dynamics/btSimulationIslandManagerMt.cpp
@@ -22,6 +22,7 @@ subject to the following restrictions:
#include "BulletCollision/CollisionDispatch/btCollisionObject.h"
#include "BulletCollision/CollisionDispatch/btCollisionWorld.h"
#include "BulletDynamics/ConstraintSolver/btTypedConstraint.h"
+#include "BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolverMt.h" // for s_minimumContactManifoldsForBatching
//#include <stdio.h>
#include "LinearMath/btQuickprof.h"
@@ -275,7 +276,7 @@ btSimulationIslandManagerMt::Island* btSimulationIslandManagerMt::allocateIsland
void btSimulationIslandManagerMt::buildIslands( btDispatcher* dispatcher, btCollisionWorld* collisionWorld )
{
- BT_PROFILE("islandUnionFindAndQuickSort");
+ BT_PROFILE("buildIslands");
btCollisionObjectArray& collisionObjects = collisionWorld->getCollisionObjectArray();
@@ -314,13 +315,11 @@ void btSimulationIslandManagerMt::buildIslands( btDispatcher* dispatcher, btColl
btAssert((colObj0->getIslandTag() == islandId) || (colObj0->getIslandTag() == -1));
if (colObj0->getIslandTag() == islandId)
{
- if (colObj0->getActivationState()== ACTIVE_TAG)
- {
- allSleeping = false;
- }
- if (colObj0->getActivationState()== DISABLE_DEACTIVATION)
+ if (colObj0->getActivationState()== ACTIVE_TAG ||
+ colObj0->getActivationState()== DISABLE_DEACTIVATION)
{
allSleeping = false;
+ break;
}
}
}
@@ -546,59 +545,103 @@ void btSimulationIslandManagerMt::mergeIslands()
}
-void btSimulationIslandManagerMt::serialIslandDispatch( btAlignedObjectArray<Island*>* islandsPtr, IslandCallback* callback )
+void btSimulationIslandManagerMt::solveIsland(btConstraintSolver* solver, Island& island, const SolverParams& solverParams)
+{
+ btPersistentManifold** manifolds = island.manifoldArray.size() ? &island.manifoldArray[ 0 ] : NULL;
+ btTypedConstraint** constraintsPtr = island.constraintArray.size() ? &island.constraintArray[ 0 ] : NULL;
+ solver->solveGroup( &island.bodyArray[ 0 ],
+ island.bodyArray.size(),
+ manifolds,
+ island.manifoldArray.size(),
+ constraintsPtr,
+ island.constraintArray.size(),
+ *solverParams.m_solverInfo,
+ solverParams.m_debugDrawer,
+ solverParams.m_dispatcher
+ );
+}
+
+
+void btSimulationIslandManagerMt::serialIslandDispatch( btAlignedObjectArray<Island*>* islandsPtr, const SolverParams& solverParams )
{
BT_PROFILE( "serialIslandDispatch" );
// serial dispatch
btAlignedObjectArray<Island*>& islands = *islandsPtr;
+ btConstraintSolver* solver = solverParams.m_solverMt ? solverParams.m_solverMt : solverParams.m_solverPool;
for ( int i = 0; i < islands.size(); ++i )
{
- Island* island = islands[ i ];
- btPersistentManifold** manifolds = island->manifoldArray.size() ? &island->manifoldArray[ 0 ] : NULL;
- btTypedConstraint** constraintsPtr = island->constraintArray.size() ? &island->constraintArray[ 0 ] : NULL;
- callback->processIsland( &island->bodyArray[ 0 ],
- island->bodyArray.size(),
- manifolds,
- island->manifoldArray.size(),
- constraintsPtr,
- island->constraintArray.size(),
- island->id
- );
+ solveIsland(solver, *islands[ i ], solverParams);
}
}
+
struct UpdateIslandDispatcher : public btIParallelForBody
{
- btAlignedObjectArray<btSimulationIslandManagerMt::Island*>* islandsPtr;
- btSimulationIslandManagerMt::IslandCallback* callback;
+ btAlignedObjectArray<btSimulationIslandManagerMt::Island*>& m_islandsPtr;
+ const btSimulationIslandManagerMt::SolverParams& m_solverParams;
+
+ UpdateIslandDispatcher(btAlignedObjectArray<btSimulationIslandManagerMt::Island*>& islandsPtr, const btSimulationIslandManagerMt::SolverParams& solverParams)
+ : m_islandsPtr(islandsPtr), m_solverParams(solverParams)
+ {}
void forLoop( int iBegin, int iEnd ) const BT_OVERRIDE
{
+ btConstraintSolver* solver = m_solverParams.m_solverPool;
for ( int i = iBegin; i < iEnd; ++i )
{
- btSimulationIslandManagerMt::Island* island = ( *islandsPtr )[ i ];
- btPersistentManifold** manifolds = island->manifoldArray.size() ? &island->manifoldArray[ 0 ] : NULL;
- btTypedConstraint** constraintsPtr = island->constraintArray.size() ? &island->constraintArray[ 0 ] : NULL;
- callback->processIsland( &island->bodyArray[ 0 ],
- island->bodyArray.size(),
- manifolds,
- island->manifoldArray.size(),
- constraintsPtr,
- island->constraintArray.size(),
- island->id
- );
+ btSimulationIslandManagerMt::Island* island = m_islandsPtr[ i ];
+ btSimulationIslandManagerMt::solveIsland( solver, *island, m_solverParams );
}
}
};
-void btSimulationIslandManagerMt::parallelIslandDispatch( btAlignedObjectArray<Island*>* islandsPtr, IslandCallback* callback )
+
+void btSimulationIslandManagerMt::parallelIslandDispatch( btAlignedObjectArray<Island*>* islandsPtr, const SolverParams& solverParams )
{
BT_PROFILE( "parallelIslandDispatch" );
- int grainSize = 1; // iterations per task
- UpdateIslandDispatcher dispatcher;
- dispatcher.islandsPtr = islandsPtr;
- dispatcher.callback = callback;
- btParallelFor( 0, islandsPtr->size(), grainSize, dispatcher );
+ //
+ // if there are islands with many contacts, it may be faster to submit these
+ // large islands *serially* to a single parallel constraint solver, and then later
+ // submit the remaining smaller islands in parallel to multiple sequential solvers.
+ //
+ // Some task schedulers do not deal well with nested parallelFor loops. One implementation
+ // of OpenMP was actually slower than doing everything single-threaded. Intel TBB
+ // on the other hand, seems to do a pretty respectable job with it.
+ //
+ // When solving islands in parallel, the worst case performance happens when there
+ // is one very large island and then perhaps a smattering of very small
+ // islands -- one worker thread takes the large island and the remaining workers
+ // tear through the smaller islands and then sit idle waiting for the first worker
+ // to finish. Solving islands in parallel works best when there are numerous small
+ // islands, roughly equal in size.
+ //
+ // By contrast, the other approach -- the parallel constraint solver -- is only
+ // able to deliver a worthwhile speedup when the island is large. For smaller islands,
+ // it is difficult to extract a useful amount of parallelism -- the overhead of grouping
+ // the constraints into batches and sending the batches to worker threads can nullify
+ // any gains from parallelism.
+ //
+
+ UpdateIslandDispatcher dispatcher(*islandsPtr, solverParams);
+ // We take advantage of the fact the islands are sorted in order of decreasing size
+ int iBegin = 0;
+ if (solverParams.m_solverMt)
+ {
+ while ( iBegin < islandsPtr->size() )
+ {
+ btSimulationIslandManagerMt::Island* island = ( *islandsPtr )[ iBegin ];
+ if ( island->manifoldArray.size() < btSequentialImpulseConstraintSolverMt::s_minimumContactManifoldsForBatching )
+ {
+ // OK to submit the rest of the array in parallel
+ break;
+ }
+ // serial dispatch to parallel solver for large islands (if any)
+ solveIsland(solverParams.m_solverMt, *island, solverParams);
+ ++iBegin;
+ }
+ }
+ // parallel dispatch to sequential solvers for rest
+ btParallelFor( iBegin, islandsPtr->size(), 1, dispatcher );
}
@@ -606,15 +649,14 @@ void btSimulationIslandManagerMt::parallelIslandDispatch( btAlignedObjectArray<I
void btSimulationIslandManagerMt::buildAndProcessIslands( btDispatcher* dispatcher,
btCollisionWorld* collisionWorld,
btAlignedObjectArray<btTypedConstraint*>& constraints,
- IslandCallback* callback
+ const SolverParams& solverParams
)
{
+ BT_PROFILE("buildAndProcessIslands");
btCollisionObjectArray& collisionObjects = collisionWorld->getCollisionObjectArray();
buildIslands(dispatcher,collisionWorld);
- BT_PROFILE("processIslands");
-
if(!getSplitIslands())
{
btPersistentManifold** manifolds = dispatcher->getInternalManifoldPointer();
@@ -646,14 +688,17 @@ void btSimulationIslandManagerMt::buildAndProcessIslands( btDispatcher* dispatch
}
}
btTypedConstraint** constraintsPtr = constraints.size() ? &constraints[ 0 ] : NULL;
- callback->processIsland(&collisionObjects[0],
- collisionObjects.size(),
- manifolds,
- maxNumManifolds,
- constraintsPtr,
- constraints.size(),
- -1
- );
+ btConstraintSolver* solver = solverParams.m_solverMt ? solverParams.m_solverMt : solverParams.m_solverPool;
+ solver->solveGroup(&collisionObjects[0],
+ collisionObjects.size(),
+ manifolds,
+ maxNumManifolds,
+ constraintsPtr,
+ constraints.size(),
+ *solverParams.m_solverInfo,
+ solverParams.m_debugDrawer,
+ solverParams.m_dispatcher
+ );
}
else
{
@@ -673,6 +718,6 @@ void btSimulationIslandManagerMt::buildAndProcessIslands( btDispatcher* dispatch
mergeIslands();
}
// dispatch islands to solver
- m_islandDispatch( &m_activeIslands, callback );
+ m_islandDispatch( &m_activeIslands, solverParams );
}
}
diff --git a/thirdparty/bullet/BulletDynamics/Dynamics/btSimulationIslandManagerMt.h b/thirdparty/bullet/BulletDynamics/Dynamics/btSimulationIslandManagerMt.h
index 9a781aaef1..563577a6f4 100644
--- a/thirdparty/bullet/BulletDynamics/Dynamics/btSimulationIslandManagerMt.h
+++ b/thirdparty/bullet/BulletDynamics/Dynamics/btSimulationIslandManagerMt.h
@@ -19,7 +19,9 @@ subject to the following restrictions:
#include "BulletCollision/CollisionDispatch/btSimulationIslandManager.h"
class btTypedConstraint;
-
+class btConstraintSolver;
+struct btContactSolverInfo;
+class btIDebugDraw;
///
/// SimulationIslandManagerMt -- Multithread capable version of SimulationIslandManager
@@ -45,22 +47,19 @@ public:
void append( const Island& other ); // add bodies, manifolds, constraints to my own
};
- struct IslandCallback
+ struct SolverParams
{
- virtual ~IslandCallback() {};
-
- virtual void processIsland( btCollisionObject** bodies,
- int numBodies,
- btPersistentManifold** manifolds,
- int numManifolds,
- btTypedConstraint** constraints,
- int numConstraints,
- int islandId
- ) = 0;
+ btConstraintSolver* m_solverPool;
+ btConstraintSolver* m_solverMt;
+ btContactSolverInfo* m_solverInfo;
+ btIDebugDraw* m_debugDrawer;
+ btDispatcher* m_dispatcher;
};
- typedef void( *IslandDispatchFunc ) ( btAlignedObjectArray<Island*>* islands, IslandCallback* callback );
- static void serialIslandDispatch( btAlignedObjectArray<Island*>* islandsPtr, IslandCallback* callback );
- static void parallelIslandDispatch( btAlignedObjectArray<Island*>* islandsPtr, IslandCallback* callback );
+ static void solveIsland(btConstraintSolver* solver, Island& island, const SolverParams& solverParams);
+
+ typedef void( *IslandDispatchFunc ) ( btAlignedObjectArray<Island*>* islands, const SolverParams& solverParams );
+ static void serialIslandDispatch( btAlignedObjectArray<Island*>* islandsPtr, const SolverParams& solverParams );
+ static void parallelIslandDispatch( btAlignedObjectArray<Island*>* islandsPtr, const SolverParams& solverParams );
protected:
btAlignedObjectArray<Island*> m_allocatedIslands; // owner of all Islands
btAlignedObjectArray<Island*> m_activeIslands; // islands actively in use
@@ -83,7 +82,11 @@ public:
btSimulationIslandManagerMt();
virtual ~btSimulationIslandManagerMt();
- virtual void buildAndProcessIslands( btDispatcher* dispatcher, btCollisionWorld* collisionWorld, btAlignedObjectArray<btTypedConstraint*>& constraints, IslandCallback* callback );
+ virtual void buildAndProcessIslands( btDispatcher* dispatcher,
+ btCollisionWorld* collisionWorld,
+ btAlignedObjectArray<btTypedConstraint*>& constraints,
+ const SolverParams& solverParams
+ );
virtual void buildIslands(btDispatcher* dispatcher,btCollisionWorld* colWorld);
@@ -106,5 +109,6 @@ public:
}
};
+
#endif //BT_SIMULATION_ISLAND_MANAGER_H
diff --git a/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBody.cpp b/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBody.cpp
index 62865e0c78..0e85b55728 100644
--- a/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBody.cpp
+++ b/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBody.cpp
@@ -112,14 +112,15 @@ btMultiBody::btMultiBody(int n_links,
m_userObjectPointer(0),
m_userIndex2(-1),
m_userIndex(-1),
+ m_companionId(-1),
m_linearDamping(0.04f),
m_angularDamping(0.04f),
m_useGyroTerm(true),
- m_maxAppliedImpulse(1000.f),
+ m_maxAppliedImpulse(1000.f),
m_maxCoordinateVelocity(100.f),
- m_hasSelfCollision(true),
+ m_hasSelfCollision(true),
__posUpdated(false),
- m_dofCount(0),
+ m_dofCount(0),
m_posVarCnt(0),
m_useRK4(false),
m_useGlobalVelocities(false),
@@ -136,6 +137,9 @@ btMultiBody::btMultiBody(int n_links,
m_baseForce.setValue(0, 0, 0);
m_baseTorque.setValue(0, 0, 0);
+
+ clearConstraintForces();
+ clearForcesAndTorques();
}
btMultiBody::~btMultiBody()
@@ -740,13 +744,13 @@ void btMultiBody::computeAccelerationsArticulatedBodyAlgorithmMultiDof(btScalar
const btScalar DAMPING_K1_ANGULAR = m_angularDamping;
const btScalar DAMPING_K2_ANGULAR= m_angularDamping;
- btVector3 base_vel = getBaseVel();
- btVector3 base_omega = getBaseOmega();
+ const btVector3 base_vel = getBaseVel();
+ const btVector3 base_omega = getBaseOmega();
// Temporary matrices/vectors -- use scratch space from caller
// so that we don't have to keep reallocating every frame
- scratch_r.resize(2*m_dofCount + 6); //multidof? ("Y"s use it and it is used to store qdd) => 2 x m_dofCount
+ scratch_r.resize(2*m_dofCount + 7); //multidof? ("Y"s use it and it is used to store qdd) => 2 x m_dofCount
scratch_v.resize(8*num_links + 6);
scratch_m.resize(4*num_links + 4);
@@ -777,7 +781,7 @@ void btMultiBody::computeAccelerationsArticulatedBodyAlgorithmMultiDof(btScalar
// hhat is NOT stored for the base (but ahat is)
btSpatialForceVector * h = (btSpatialForceVector *)(m_dofCount > 0 ? &m_vectorBuf[0] : 0);
btSpatialMotionVector * spatAcc = (btSpatialMotionVector *)v_ptr;
- v_ptr += num_links * 2 + 2;
+ v_ptr += num_links * 2 + 2;
//
// Y_i, invD_i
btScalar * invD = m_dofCount > 0 ? &m_realBuf[6 + m_dofCount] : 0;
@@ -815,13 +819,13 @@ void btMultiBody::computeAccelerationsArticulatedBodyAlgorithmMultiDof(btScalar
}
else
{
- btVector3 baseForce = isConstraintPass? m_baseConstraintForce : m_baseForce;
- btVector3 baseTorque = isConstraintPass? m_baseConstraintTorque : m_baseTorque;
+ const btVector3& baseForce = isConstraintPass? m_baseConstraintForce : m_baseForce;
+ const btVector3& baseTorque = isConstraintPass? m_baseConstraintTorque : m_baseTorque;
//external forces
zeroAccSpatFrc[0].setVector(-(rot_from_parent[0] * baseTorque), -(rot_from_parent[0] * baseForce));
//adding damping terms (only)
- btScalar linDampMult = 1., angDampMult = 1.;
+ const btScalar linDampMult = 1., angDampMult = 1.;
zeroAccSpatFrc[0].addVector(angDampMult * m_baseInertia * spatVel[0].getAngular() * (DAMPING_K1_ANGULAR + DAMPING_K2_ANGULAR * spatVel[0].getAngular().safeNorm()),
linDampMult * m_baseMass * spatVel[0].getLinear() * (DAMPING_K1_LINEAR + DAMPING_K2_LINEAR * spatVel[0].getLinear().safeNorm()));
@@ -963,16 +967,15 @@ void btMultiBody::computeAccelerationsArticulatedBodyAlgorithmMultiDof(btScalar
//
Y[m_links[i].m_dofOffset + dof] = m_links[i].m_jointTorque[dof]
- m_links[i].m_axes[dof].dot(zeroAccSpatFrc[i+1])
- - spatCoriolisAcc[i].dot(hDof)
- ;
- }
+ - spatCoriolisAcc[i].dot(hDof);
- for(int dof = 0; dof < m_links[i].m_dofCount; ++dof)
- {
- btScalar *D_row = &D[dof * m_links[i].m_dofCount];
+ }
+ for(int dof = 0; dof < m_links[i].m_dofCount; ++dof)
+ {
+ btScalar *D_row = &D[dof * m_links[i].m_dofCount];
for(int dof2 = 0; dof2 < m_links[i].m_dofCount; ++dof2)
{
- btSpatialForceVector &hDof2 = h[m_links[i].m_dofOffset + dof2];
+ const btSpatialForceVector &hDof2 = h[m_links[i].m_dofOffset + dof2];
D_row[dof2] = m_links[i].m_axes[dof].dot(hDof2);
}
}
@@ -983,14 +986,20 @@ void btMultiBody::computeAccelerationsArticulatedBodyAlgorithmMultiDof(btScalar
case btMultibodyLink::ePrismatic:
case btMultibodyLink::eRevolute:
{
- invDi[0] = 1.0f / D[0];
+ if (D[0]>=SIMD_EPSILON)
+ {
+ invDi[0] = 1.0f / D[0];
+ } else
+ {
+ invDi[0] = 0;
+ }
break;
}
case btMultibodyLink::eSpherical:
case btMultibodyLink::ePlanar:
{
- btMatrix3x3 D3x3; D3x3.setValue(D[0], D[1], D[2], D[3], D[4], D[5], D[6], D[7], D[8]);
- btMatrix3x3 invD3x3; invD3x3 = D3x3.inverse();
+ const btMatrix3x3 D3x3(D[0], D[1], D[2], D[3], D[4], D[5], D[6], D[7], D[8]);
+ const btMatrix3x3 invD3x3(D3x3.inverse());
//unroll the loop?
for(int row = 0; row < 3; ++row)
@@ -1016,7 +1025,7 @@ void btMultiBody::computeAccelerationsArticulatedBodyAlgorithmMultiDof(btScalar
for(int dof2 = 0; dof2 < m_links[i].m_dofCount; ++dof2)
{
- btSpatialForceVector &hDof2 = h[m_links[i].m_dofOffset + dof2];
+ const btSpatialForceVector &hDof2 = h[m_links[i].m_dofOffset + dof2];
//
spatForceVecTemps[dof] += hDof2 * invDi[dof2 * m_links[i].m_dofCount + dof];
}
@@ -1027,7 +1036,7 @@ void btMultiBody::computeAccelerationsArticulatedBodyAlgorithmMultiDof(btScalar
//determine (h*D^{-1}) * h^{T}
for(int dof = 0; dof < m_links[i].m_dofCount; ++dof)
{
- btSpatialForceVector &hDof = h[m_links[i].m_dofOffset + dof];
+ const btSpatialForceVector &hDof = h[m_links[i].m_dofOffset + dof];
//
dyadTemp -= symmetricSpatialOuterProduct(hDof, spatForceVecTemps[dof]);
}
@@ -1048,7 +1057,7 @@ void btMultiBody::computeAccelerationsArticulatedBodyAlgorithmMultiDof(btScalar
for(int dof = 0; dof < m_links[i].m_dofCount; ++dof)
{
- btSpatialForceVector &hDof = h[m_links[i].m_dofOffset + dof];
+ const btSpatialForceVector &hDof = h[m_links[i].m_dofOffset + dof];
//
spatForceVecTemps[0] += hDof * invD_times_Y[dof];
}
@@ -1099,7 +1108,7 @@ void btMultiBody::computeAccelerationsArticulatedBodyAlgorithmMultiDof(btScalar
for(int dof = 0; dof < m_links[i].m_dofCount; ++dof)
{
- btSpatialForceVector &hDof = h[m_links[i].m_dofOffset + dof];
+ const btSpatialForceVector &hDof = h[m_links[i].m_dofOffset + dof];
//
Y_minus_hT_a[dof] = Y[m_links[i].m_dofOffset + dof] - spatAcc[i+1].dot(hDof);
}
@@ -1159,12 +1168,12 @@ void btMultiBody::computeAccelerationsArticulatedBodyAlgorithmMultiDof(btScalar
}
// transform base accelerations back to the world frame.
- btVector3 omegadot_out = rot_from_parent[0].transpose() * spatAcc[0].getAngular();
+ const btVector3 omegadot_out = rot_from_parent[0].transpose() * spatAcc[0].getAngular();
output[0] = omegadot_out[0];
output[1] = omegadot_out[1];
output[2] = omegadot_out[2];
- btVector3 vdot_out = rot_from_parent[0].transpose() * (spatAcc[0].getLinear() + spatVel[0].getAngular().cross(spatVel[0].getLinear()));
+ const btVector3 vdot_out = rot_from_parent[0].transpose() * (spatAcc[0].getLinear() + spatVel[0].getAngular().cross(spatVel[0].getLinear()));
output[3] = vdot_out[0];
output[4] = vdot_out[1];
output[5] = vdot_out[2];
@@ -1266,12 +1275,29 @@ void btMultiBody::solveImatrix(const btVector3& rhs_top, const btVector3& rhs_bo
if (num_links == 0)
{
// in the case of 0 m_links (i.e. a plain rigid body, not a multibody) rhs * invI is easier
- result[0] = rhs_bot[0] / m_baseInertia[0];
- result[1] = rhs_bot[1] / m_baseInertia[1];
+
+ if ((m_baseInertia[0] >= SIMD_EPSILON) && (m_baseInertia[1] >= SIMD_EPSILON) && (m_baseInertia[2] >= SIMD_EPSILON))
+ {
+ result[0] = rhs_bot[0] / m_baseInertia[0];
+ result[1] = rhs_bot[1] / m_baseInertia[1];
result[2] = rhs_bot[2] / m_baseInertia[2];
- result[3] = rhs_top[0] / m_baseMass;
- result[4] = rhs_top[1] / m_baseMass;
- result[5] = rhs_top[2] / m_baseMass;
+ } else
+ {
+ result[0] = 0;
+ result[1] = 0;
+ result[2] = 0;
+ }
+ if (m_baseMass>=SIMD_EPSILON)
+ {
+ result[3] = rhs_top[0] / m_baseMass;
+ result[4] = rhs_top[1] / m_baseMass;
+ result[5] = rhs_top[2] / m_baseMass;
+ } else
+ {
+ result[3] = 0;
+ result[4] = 0;
+ result[5] = 0;
+ }
} else
{
if (!m_cachedInertiaValid)
@@ -1322,9 +1348,21 @@ void btMultiBody::solveImatrix(const btSpatialForceVector &rhs, btSpatialMotionV
if (num_links == 0)
{
// in the case of 0 m_links (i.e. a plain rigid body, not a multibody) rhs * invI is easier
- result.setAngular(rhs.getAngular() / m_baseInertia);
- result.setLinear(rhs.getLinear() / m_baseMass);
- } else
+ if ((m_baseInertia[0] >= SIMD_EPSILON) && (m_baseInertia[1] >= SIMD_EPSILON) && (m_baseInertia[2] >= SIMD_EPSILON))
+ {
+ result.setAngular(rhs.getAngular() / m_baseInertia);
+ } else
+ {
+ result.setAngular(btVector3(0,0,0));
+ }
+ if (m_baseMass>=SIMD_EPSILON)
+ {
+ result.setLinear(rhs.getLinear() / m_baseMass);
+ } else
+ {
+ result.setLinear(btVector3(0,0,0));
+ }
+ } else
{
/// Special routine for calculating the inverse of a spatial inertia matrix
///the 6x6 matrix is stored as 4 blocks of 3x3 matrices
@@ -1808,6 +1846,7 @@ void btMultiBody::fillConstraintJacobianMultiDof(int link,
void btMultiBody::wakeUp()
{
+ m_sleepTimer = 0;
m_awake = true;
}
@@ -1956,7 +1995,11 @@ int btMultiBody::calculateSerializeBufferSize() const
const char* btMultiBody::serialize(void* dataBuffer, class btSerializer* serializer) const
{
btMultiBodyData* mbd = (btMultiBodyData*) dataBuffer;
- getBaseWorldTransform().serialize(mbd->m_baseWorldTransform);
+ getBasePos().serialize(mbd->m_baseWorldPosition);
+ getWorldToBaseRot().inverse().serialize(mbd->m_baseWorldOrientation);
+ getBaseVel().serialize(mbd->m_baseLinearVelocity);
+ getBaseOmega().serialize(mbd->m_baseAngularVelocity);
+
mbd->m_baseMass = this->getBaseMass();
getBaseInertia().serialize(mbd->m_baseInertia);
{
@@ -1982,6 +2025,12 @@ const char* btMultiBody::serialize(void* dataBuffer, class btSerializer* seriali
memPtr->m_posVarCount = getLink(i).m_posVarCount;
getLink(i).m_inertiaLocal.serialize(memPtr->m_linkInertia);
+
+ getLink(i).m_absFrameTotVelocity.m_topVec.serialize(memPtr->m_absFrameTotVelocityTop);
+ getLink(i).m_absFrameTotVelocity.m_bottomVec.serialize(memPtr->m_absFrameTotVelocityBottom);
+ getLink(i).m_absFrameLocVelocity.m_topVec.serialize(memPtr->m_absFrameLocVelocityTop);
+ getLink(i).m_absFrameLocVelocity.m_bottomVec.serialize(memPtr->m_absFrameLocVelocityBottom);
+
memPtr->m_linkMass = getLink(i).m_mass;
memPtr->m_parentIndex = getLink(i).m_parent;
memPtr->m_jointDamping = getLink(i).m_jointDamping;
@@ -1991,7 +2040,7 @@ const char* btMultiBody::serialize(void* dataBuffer, class btSerializer* seriali
memPtr->m_jointMaxForce = getLink(i).m_jointMaxForce;
memPtr->m_jointMaxVelocity = getLink(i).m_jointMaxVelocity;
- getLink(i).m_eVector.serialize(memPtr->m_parentComToThisComOffset);
+ getLink(i).m_eVector.serialize(memPtr->m_parentComToThisPivotOffset);
getLink(i).m_dVector.serialize(memPtr->m_thisPivotToThisComOffset);
getLink(i).m_zeroRotParentToThis.serialize(memPtr->m_zeroRotParentToThis);
btAssert(memPtr->m_dofCount<=3);
diff --git a/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBody.h b/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBody.h
index 655165ac18..5cd00e5173 100644
--- a/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBody.h
+++ b/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBody.h
@@ -702,15 +702,18 @@ private:
int m_companionId;
btScalar m_linearDamping;
btScalar m_angularDamping;
- bool m_useGyroTerm;
+ bool m_useGyroTerm;
btScalar m_maxAppliedImpulse;
btScalar m_maxCoordinateVelocity;
bool m_hasSelfCollision;
- bool __posUpdated;
- int m_dofCount, m_posVarCnt;
+ bool __posUpdated;
+ int m_dofCount, m_posVarCnt;
+
bool m_useRK4, m_useGlobalVelocities;
-
+ //for global velocities, see 8.3.2B Proposed resolution in Jakub Stepien PhD Thesis
+ //https://drive.google.com/file/d/0Bz3vEa19XOYGNWdZWGpMdUdqVmZ5ZVBOaEh4ZnpNaUxxZFNV/view?usp=sharing
+
///the m_needsJointFeedback gets updated/computed during the stepVelocitiesMultiDof and it for internal usage only
bool m_internalNeedsJointFeedback;
};
@@ -718,12 +721,17 @@ private:
struct btMultiBodyLinkDoubleData
{
btQuaternionDoubleData m_zeroRotParentToThis;
- btVector3DoubleData m_parentComToThisComOffset;
+ btVector3DoubleData m_parentComToThisPivotOffset;
btVector3DoubleData m_thisPivotToThisComOffset;
btVector3DoubleData m_jointAxisTop[6];
btVector3DoubleData m_jointAxisBottom[6];
btVector3DoubleData m_linkInertia; // inertia of the base (in local frame; diagonal)
+ btVector3DoubleData m_absFrameTotVelocityTop;
+ btVector3DoubleData m_absFrameTotVelocityBottom;
+ btVector3DoubleData m_absFrameLocVelocityTop;
+ btVector3DoubleData m_absFrameLocVelocityBottom;
+
double m_linkMass;
int m_parentIndex;
int m_jointType;
@@ -751,11 +759,16 @@ struct btMultiBodyLinkDoubleData
struct btMultiBodyLinkFloatData
{
btQuaternionFloatData m_zeroRotParentToThis;
- btVector3FloatData m_parentComToThisComOffset;
+ btVector3FloatData m_parentComToThisPivotOffset;
btVector3FloatData m_thisPivotToThisComOffset;
btVector3FloatData m_jointAxisTop[6];
btVector3FloatData m_jointAxisBottom[6];
- btVector3FloatData m_linkInertia; // inertia of the base (in local frame; diagonal)
+ btVector3FloatData m_linkInertia; // inertia of the base (in local frame; diagonal)
+ btVector3FloatData m_absFrameTotVelocityTop;
+ btVector3FloatData m_absFrameTotVelocityBottom;
+ btVector3FloatData m_absFrameLocVelocityTop;
+ btVector3FloatData m_absFrameLocVelocityBottom;
+
int m_dofCount;
float m_linkMass;
int m_parentIndex;
@@ -784,29 +797,38 @@ struct btMultiBodyLinkFloatData
///do not change those serialization structures, it requires an updated sBulletDNAstr/sBulletDNAstr64
struct btMultiBodyDoubleData
{
- btTransformDoubleData m_baseWorldTransform;
+ btVector3DoubleData m_baseWorldPosition;
+ btQuaternionDoubleData m_baseWorldOrientation;
+ btVector3DoubleData m_baseLinearVelocity;
+ btVector3DoubleData m_baseAngularVelocity;
btVector3DoubleData m_baseInertia; // inertia of the base (in local frame; diagonal)
double m_baseMass;
+ int m_numLinks;
+ char m_padding[4];
char *m_baseName;
btMultiBodyLinkDoubleData *m_links;
btCollisionObjectDoubleData *m_baseCollider;
- char *m_paddingPtr;
- int m_numLinks;
- char m_padding[4];
+
+
};
///do not change those serialization structures, it requires an updated sBulletDNAstr/sBulletDNAstr64
struct btMultiBodyFloatData
{
- char *m_baseName;
- btMultiBodyLinkFloatData *m_links;
- btCollisionObjectFloatData *m_baseCollider;
- btTransformFloatData m_baseWorldTransform;
+ btVector3FloatData m_baseWorldPosition;
+ btQuaternionFloatData m_baseWorldOrientation;
+ btVector3FloatData m_baseLinearVelocity;
+ btVector3FloatData m_baseAngularVelocity;
+
btVector3FloatData m_baseInertia; // inertia of the base (in local frame; diagonal)
-
float m_baseMass;
int m_numLinks;
+
+ char *m_baseName;
+ btMultiBodyLinkFloatData *m_links;
+ btCollisionObjectFloatData *m_baseCollider;
+
};
diff --git a/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyConstraint.cpp b/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyConstraint.cpp
index d52852dd8e..9f61874b83 100644
--- a/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyConstraint.cpp
+++ b/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyConstraint.cpp
@@ -253,7 +253,7 @@ btScalar btMultiBodyConstraint::fillMultiBodyConstraint( btMultiBodySolverConstr
{
vec = ( solverConstraint.m_angularComponentA).cross(rel_pos1);
if (angConstraint) {
- denom0 = rb0->getInvMass() + constraintNormalAng.dot(vec);
+ denom0 = constraintNormalAng.dot(solverConstraint.m_angularComponentA);
}
else {
denom0 = rb0->getInvMass() + constraintNormalLin.dot(vec);
@@ -277,7 +277,7 @@ btScalar btMultiBodyConstraint::fillMultiBodyConstraint( btMultiBodySolverConstr
{
vec = ( -solverConstraint.m_angularComponentB).cross(rel_pos2);
if (angConstraint) {
- denom1 = rb1->getInvMass() + constraintNormalAng.dot(vec);
+ denom1 = constraintNormalAng.dot(-solverConstraint.m_angularComponentB);
}
else {
denom1 = rb1->getInvMass() + constraintNormalLin.dot(vec);
@@ -315,7 +315,8 @@ btScalar btMultiBodyConstraint::fillMultiBodyConstraint( btMultiBodySolverConstr
}
else if(rb0)
{
- rel_vel += rb0->getVelocityInLocalPoint(rel_pos1).dot(solverConstraint.m_contactNormal1);
+ rel_vel += rb0->getLinearVelocity().dot(solverConstraint.m_contactNormal1);
+ rel_vel += rb0->getAngularVelocity().dot(solverConstraint.m_relpos1CrossNormal);
}
if (multiBodyB)
{
@@ -327,7 +328,8 @@ btScalar btMultiBodyConstraint::fillMultiBodyConstraint( btMultiBodySolverConstr
}
else if(rb1)
{
- rel_vel += rb1->getVelocityInLocalPoint(rel_pos2).dot(solverConstraint.m_contactNormal2);
+ rel_vel += rb1->getLinearVelocity().dot(solverConstraint.m_contactNormal2);
+ rel_vel += rb1->getAngularVelocity().dot(solverConstraint.m_relpos2CrossNormal);
}
solverConstraint.m_friction = 0.f;//cp.m_combinedFriction;
diff --git a/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyConstraint.h b/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyConstraint.h
index 83521b9501..a2ae571273 100644
--- a/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyConstraint.h
+++ b/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyConstraint.h
@@ -119,6 +119,14 @@ public:
return m_bodyB;
}
+ int getLinkA() const
+ {
+ return m_linkA;
+ }
+ int getLinkB() const
+ {
+ return m_linkB;
+ }
void internalSetAppliedImpulse(int dof, btScalar appliedImpulse)
{
btAssert(dof>=0);
diff --git a/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyConstraintSolver.cpp b/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyConstraintSolver.cpp
index 1e2d074096..cd84826e1a 100644
--- a/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyConstraintSolver.cpp
+++ b/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyConstraintSolver.cpp
@@ -39,7 +39,7 @@ btScalar btMultiBodyConstraintSolver::solveSingleIteration(int iteration, btColl
btMultiBodySolverConstraint& constraint = m_multiBodyNonContactConstraints[index];
btScalar residual = resolveSingleConstraintRowGeneric(constraint);
- leastSquaredResidual += residual*residual;
+ leastSquaredResidual = btMax(leastSquaredResidual,residual*residual);
if(constraint.m_multiBodyA)
constraint.m_multiBodyA->setPosUpdated(false);
@@ -60,36 +60,101 @@ btScalar btMultiBodyConstraintSolver::solveSingleIteration(int iteration, btColl
residual = resolveSingleConstraintRowGeneric(constraint);
}
- leastSquaredResidual += residual*residual;
+ leastSquaredResidual = btMax(leastSquaredResidual,residual*residual);
if(constraint.m_multiBodyA)
constraint.m_multiBodyA->setPosUpdated(false);
if(constraint.m_multiBodyB)
constraint.m_multiBodyB->setPosUpdated(false);
}
-
- //solve featherstone frictional contact
- for (int j1=0;j1<this->m_multiBodyFrictionContactConstraints.size();j1++)
+ //solve featherstone frictional contact
+ if (infoGlobal.m_solverMode & SOLVER_USE_2_FRICTION_DIRECTIONS && ((infoGlobal.m_solverMode&SOLVER_DISABLE_IMPLICIT_CONE_FRICTION) == 0))
{
- if (iteration < infoGlobal.m_numIterations)
+ for (int j1 = 0; j1<this->m_multiBodyTorsionalFrictionContactConstraints.size(); j1++)
+ {
+ if (iteration < infoGlobal.m_numIterations)
+ {
+ int index = j1;//iteration&1? j1 : m_multiBodyTorsionalFrictionContactConstraints.size()-1-j1;
+
+ btMultiBodySolverConstraint& frictionConstraint = m_multiBodyTorsionalFrictionContactConstraints[index];
+ btScalar totalImpulse = m_multiBodyNormalContactConstraints[frictionConstraint.m_frictionIndex].m_appliedImpulse;
+ //adjust friction limits here
+ if (totalImpulse>btScalar(0))
+ {
+ frictionConstraint.m_lowerLimit = -(frictionConstraint.m_friction*totalImpulse);
+ frictionConstraint.m_upperLimit = frictionConstraint.m_friction*totalImpulse;
+ btScalar residual = resolveSingleConstraintRowGeneric(frictionConstraint);
+ leastSquaredResidual = btMax(leastSquaredResidual , residual*residual);
+
+ if (frictionConstraint.m_multiBodyA)
+ frictionConstraint.m_multiBodyA->setPosUpdated(false);
+ if (frictionConstraint.m_multiBodyB)
+ frictionConstraint.m_multiBodyB->setPosUpdated(false);
+ }
+ }
+ }
+
+ for (int j1 = 0; j1 < this->m_multiBodyFrictionContactConstraints.size(); j1++)
{
- int index = j1;//iteration&1? j1 : m_multiBodyFrictionContactConstraints.size()-1-j1;
+ if (iteration < infoGlobal.m_numIterations)
+ {
+ int index = j1;//iteration&1? j1 : m_multiBodyFrictionContactConstraints.size()-1-j1;
+ btMultiBodySolverConstraint& frictionConstraint = m_multiBodyFrictionContactConstraints[index];
+
+ btScalar totalImpulse = m_multiBodyNormalContactConstraints[frictionConstraint.m_frictionIndex].m_appliedImpulse;
+ j1++;
+ int index2 = j1;//iteration&1? j1 : m_multiBodyFrictionContactConstraints.size()-1-j1;
+ btMultiBodySolverConstraint& frictionConstraintB = m_multiBodyFrictionContactConstraints[index2];
+ btAssert(frictionConstraint.m_frictionIndex == frictionConstraintB.m_frictionIndex);
+
+ if (frictionConstraint.m_frictionIndex == frictionConstraintB.m_frictionIndex)
+ {
+ frictionConstraint.m_lowerLimit = -(frictionConstraint.m_friction*totalImpulse);
+ frictionConstraint.m_upperLimit = frictionConstraint.m_friction*totalImpulse;
+ frictionConstraintB.m_lowerLimit = -(frictionConstraintB.m_friction*totalImpulse);
+ frictionConstraintB.m_upperLimit = frictionConstraintB.m_friction*totalImpulse;
+ btScalar residual = resolveConeFrictionConstraintRows(frictionConstraint, frictionConstraintB);
+ leastSquaredResidual = btMax(leastSquaredResidual, residual*residual);
+
+ if (frictionConstraintB.m_multiBodyA)
+ frictionConstraintB.m_multiBodyA->setPosUpdated(false);
+ if (frictionConstraintB.m_multiBodyB)
+ frictionConstraintB.m_multiBodyB->setPosUpdated(false);
+
+ if (frictionConstraint.m_multiBodyA)
+ frictionConstraint.m_multiBodyA->setPosUpdated(false);
+ if (frictionConstraint.m_multiBodyB)
+ frictionConstraint.m_multiBodyB->setPosUpdated(false);
+ }
+ }
+ }
- btMultiBodySolverConstraint& frictionConstraint = m_multiBodyFrictionContactConstraints[index];
- btScalar totalImpulse = m_multiBodyNormalContactConstraints[frictionConstraint.m_frictionIndex].m_appliedImpulse;
- //adjust friction limits here
- if (totalImpulse>btScalar(0))
+
+ }
+ else
+ {
+ for (int j1 = 0; j1<this->m_multiBodyFrictionContactConstraints.size(); j1++)
+ {
+ if (iteration < infoGlobal.m_numIterations)
{
- frictionConstraint.m_lowerLimit = -(frictionConstraint.m_friction*totalImpulse);
- frictionConstraint.m_upperLimit = frictionConstraint.m_friction*totalImpulse;
- btScalar residual = resolveSingleConstraintRowGeneric(frictionConstraint);
- leastSquaredResidual += residual*residual;
-
- if(frictionConstraint.m_multiBodyA)
- frictionConstraint.m_multiBodyA->setPosUpdated(false);
- if(frictionConstraint.m_multiBodyB)
- frictionConstraint.m_multiBodyB->setPosUpdated(false);
+ int index = j1;//iteration&1? j1 : m_multiBodyFrictionContactConstraints.size()-1-j1;
+
+ btMultiBodySolverConstraint& frictionConstraint = m_multiBodyFrictionContactConstraints[index];
+ btScalar totalImpulse = m_multiBodyNormalContactConstraints[frictionConstraint.m_frictionIndex].m_appliedImpulse;
+ //adjust friction limits here
+ if (totalImpulse>btScalar(0))
+ {
+ frictionConstraint.m_lowerLimit = -(frictionConstraint.m_friction*totalImpulse);
+ frictionConstraint.m_upperLimit = frictionConstraint.m_friction*totalImpulse;
+ btScalar residual = resolveSingleConstraintRowGeneric(frictionConstraint);
+ leastSquaredResidual = btMax(leastSquaredResidual, residual*residual);
+
+ if (frictionConstraint.m_multiBodyA)
+ frictionConstraint.m_multiBodyA->setPosUpdated(false);
+ if (frictionConstraint.m_multiBodyB)
+ frictionConstraint.m_multiBodyB->setPosUpdated(false);
+ }
}
}
}
@@ -101,6 +166,8 @@ btScalar btMultiBodyConstraintSolver::solveGroupCacheFriendlySetup(btCollisionOb
m_multiBodyNonContactConstraints.resize(0);
m_multiBodyNormalContactConstraints.resize(0);
m_multiBodyFrictionContactConstraints.resize(0);
+ m_multiBodyTorsionalFrictionContactConstraints.resize(0);
+
m_data.m_jacobians.resize(0);
m_data.m_deltaVelocitiesUnitImpulse.resize(0);
m_data.m_deltaVelocities.resize(0);
@@ -128,82 +195,267 @@ void btMultiBodyConstraintSolver::applyDeltaVee(btScalar* delta_vee, btScalar im
btScalar btMultiBodyConstraintSolver::resolveSingleConstraintRowGeneric(const btMultiBodySolverConstraint& c)
{
- btScalar deltaImpulse = c.m_rhs-btScalar(c.m_appliedImpulse)*c.m_cfm;
- btScalar deltaVelADotn=0;
- btScalar deltaVelBDotn=0;
+ btScalar deltaImpulse = c.m_rhs - btScalar(c.m_appliedImpulse)*c.m_cfm;
+ btScalar deltaVelADotn = 0;
+ btScalar deltaVelBDotn = 0;
btSolverBody* bodyA = 0;
btSolverBody* bodyB = 0;
- int ndofA=0;
- int ndofB=0;
+ int ndofA = 0;
+ int ndofB = 0;
if (c.m_multiBodyA)
{
- ndofA = c.m_multiBodyA->getNumDofs() + 6;
- for (int i = 0; i < ndofA; ++i)
- deltaVelADotn += m_data.m_jacobians[c.m_jacAindex+i] * m_data.m_deltaVelocities[c.m_deltaVelAindex+i];
- } else if(c.m_solverBodyIdA >= 0)
+ ndofA = c.m_multiBodyA->getNumDofs() + 6;
+ for (int i = 0; i < ndofA; ++i)
+ deltaVelADotn += m_data.m_jacobians[c.m_jacAindex + i] * m_data.m_deltaVelocities[c.m_deltaVelAindex + i];
+ }
+ else if (c.m_solverBodyIdA >= 0)
{
bodyA = &m_tmpSolverBodyPool[c.m_solverBodyIdA];
- deltaVelADotn += c.m_contactNormal1.dot(bodyA->internalGetDeltaLinearVelocity()) + c.m_relpos1CrossNormal.dot(bodyA->internalGetDeltaAngularVelocity());
+ deltaVelADotn += c.m_contactNormal1.dot(bodyA->internalGetDeltaLinearVelocity()) + c.m_relpos1CrossNormal.dot(bodyA->internalGetDeltaAngularVelocity());
}
if (c.m_multiBodyB)
{
- ndofB = c.m_multiBodyB->getNumDofs() + 6;
- for (int i = 0; i < ndofB; ++i)
- deltaVelBDotn += m_data.m_jacobians[c.m_jacBindex+i] * m_data.m_deltaVelocities[c.m_deltaVelBindex+i];
- } else if(c.m_solverBodyIdB >= 0)
+ ndofB = c.m_multiBodyB->getNumDofs() + 6;
+ for (int i = 0; i < ndofB; ++i)
+ deltaVelBDotn += m_data.m_jacobians[c.m_jacBindex + i] * m_data.m_deltaVelocities[c.m_deltaVelBindex + i];
+ }
+ else if (c.m_solverBodyIdB >= 0)
{
bodyB = &m_tmpSolverBodyPool[c.m_solverBodyIdB];
- deltaVelBDotn += c.m_contactNormal2.dot(bodyB->internalGetDeltaLinearVelocity()) + c.m_relpos2CrossNormal.dot(bodyB->internalGetDeltaAngularVelocity());
+ deltaVelBDotn += c.m_contactNormal2.dot(bodyB->internalGetDeltaLinearVelocity()) + c.m_relpos2CrossNormal.dot(bodyB->internalGetDeltaAngularVelocity());
}
-
- deltaImpulse -= deltaVelADotn*c.m_jacDiagABInv;//m_jacDiagABInv = 1./denom
- deltaImpulse -= deltaVelBDotn*c.m_jacDiagABInv;
+
+ deltaImpulse -= deltaVelADotn*c.m_jacDiagABInv;//m_jacDiagABInv = 1./denom
+ deltaImpulse -= deltaVelBDotn*c.m_jacDiagABInv;
const btScalar sum = btScalar(c.m_appliedImpulse) + deltaImpulse;
-
+
if (sum < c.m_lowerLimit)
{
- deltaImpulse = c.m_lowerLimit-c.m_appliedImpulse;
+ deltaImpulse = c.m_lowerLimit - c.m_appliedImpulse;
c.m_appliedImpulse = c.m_lowerLimit;
}
- else if (sum > c.m_upperLimit)
+ else if (sum > c.m_upperLimit)
{
- deltaImpulse = c.m_upperLimit-c.m_appliedImpulse;
+ deltaImpulse = c.m_upperLimit - c.m_appliedImpulse;
c.m_appliedImpulse = c.m_upperLimit;
}
else
{
c.m_appliedImpulse = sum;
}
-
+
if (c.m_multiBodyA)
{
- applyDeltaVee(&m_data.m_deltaVelocitiesUnitImpulse[c.m_jacAindex],deltaImpulse,c.m_deltaVelAindex,ndofA);
+ applyDeltaVee(&m_data.m_deltaVelocitiesUnitImpulse[c.m_jacAindex], deltaImpulse, c.m_deltaVelAindex, ndofA);
#ifdef DIRECTLY_UPDATE_VELOCITY_DURING_SOLVER_ITERATIONS
//note: update of the actual velocities (below) in the multibody does not have to happen now since m_deltaVelocities can be applied after all iterations
//it would make the multibody solver more like the regular one with m_deltaVelocities being equivalent to btSolverBody::m_deltaLinearVelocity/m_deltaAngularVelocity
- c.m_multiBodyA->applyDeltaVeeMultiDof2(&m_data.m_deltaVelocitiesUnitImpulse[c.m_jacAindex],deltaImpulse);
+ c.m_multiBodyA->applyDeltaVeeMultiDof2(&m_data.m_deltaVelocitiesUnitImpulse[c.m_jacAindex], deltaImpulse);
#endif //DIRECTLY_UPDATE_VELOCITY_DURING_SOLVER_ITERATIONS
- } else if(c.m_solverBodyIdA >= 0)
+ }
+ else if (c.m_solverBodyIdA >= 0)
{
- bodyA->internalApplyImpulse(c.m_contactNormal1*bodyA->internalGetInvMass(),c.m_angularComponentA,deltaImpulse);
+ bodyA->internalApplyImpulse(c.m_contactNormal1*bodyA->internalGetInvMass(), c.m_angularComponentA, deltaImpulse);
}
if (c.m_multiBodyB)
{
- applyDeltaVee(&m_data.m_deltaVelocitiesUnitImpulse[c.m_jacBindex],deltaImpulse,c.m_deltaVelBindex,ndofB);
+ applyDeltaVee(&m_data.m_deltaVelocitiesUnitImpulse[c.m_jacBindex], deltaImpulse, c.m_deltaVelBindex, ndofB);
#ifdef DIRECTLY_UPDATE_VELOCITY_DURING_SOLVER_ITERATIONS
//note: update of the actual velocities (below) in the multibody does not have to happen now since m_deltaVelocities can be applied after all iterations
//it would make the multibody solver more like the regular one with m_deltaVelocities being equivalent to btSolverBody::m_deltaLinearVelocity/m_deltaAngularVelocity
- c.m_multiBodyB->applyDeltaVeeMultiDof2(&m_data.m_deltaVelocitiesUnitImpulse[c.m_jacBindex],deltaImpulse);
+ c.m_multiBodyB->applyDeltaVeeMultiDof2(&m_data.m_deltaVelocitiesUnitImpulse[c.m_jacBindex], deltaImpulse);
#endif //DIRECTLY_UPDATE_VELOCITY_DURING_SOLVER_ITERATIONS
- } else if(c.m_solverBodyIdB >= 0)
+ }
+ else if (c.m_solverBodyIdB >= 0)
{
- bodyB->internalApplyImpulse(c.m_contactNormal2*bodyB->internalGetInvMass(),c.m_angularComponentB,deltaImpulse);
+ bodyB->internalApplyImpulse(c.m_contactNormal2*bodyB->internalGetInvMass(), c.m_angularComponentB, deltaImpulse);
}
- return deltaImpulse;
+ btScalar deltaVel =deltaImpulse/c.m_jacDiagABInv;
+ return deltaVel;
+}
+
+
+btScalar btMultiBodyConstraintSolver::resolveConeFrictionConstraintRows(const btMultiBodySolverConstraint& cA1,const btMultiBodySolverConstraint& cB)
+{
+ int ndofA=0;
+ int ndofB=0;
+ btSolverBody* bodyA = 0;
+ btSolverBody* bodyB = 0;
+ btScalar deltaImpulseB = 0.f;
+ btScalar sumB = 0.f;
+ {
+ deltaImpulseB = cB.m_rhs-btScalar(cB.m_appliedImpulse)*cB.m_cfm;
+ btScalar deltaVelADotn=0;
+ btScalar deltaVelBDotn=0;
+ if (cB.m_multiBodyA)
+ {
+ ndofA = cB.m_multiBodyA->getNumDofs() + 6;
+ for (int i = 0; i < ndofA; ++i)
+ deltaVelADotn += m_data.m_jacobians[cB.m_jacAindex+i] * m_data.m_deltaVelocities[cB.m_deltaVelAindex+i];
+ } else if(cB.m_solverBodyIdA >= 0)
+ {
+ bodyA = &m_tmpSolverBodyPool[cB.m_solverBodyIdA];
+ deltaVelADotn += cB.m_contactNormal1.dot(bodyA->internalGetDeltaLinearVelocity()) + cB.m_relpos1CrossNormal.dot(bodyA->internalGetDeltaAngularVelocity());
+ }
+
+ if (cB.m_multiBodyB)
+ {
+ ndofB = cB.m_multiBodyB->getNumDofs() + 6;
+ for (int i = 0; i < ndofB; ++i)
+ deltaVelBDotn += m_data.m_jacobians[cB.m_jacBindex+i] * m_data.m_deltaVelocities[cB.m_deltaVelBindex+i];
+ } else if(cB.m_solverBodyIdB >= 0)
+ {
+ bodyB = &m_tmpSolverBodyPool[cB.m_solverBodyIdB];
+ deltaVelBDotn += cB.m_contactNormal2.dot(bodyB->internalGetDeltaLinearVelocity()) + cB.m_relpos2CrossNormal.dot(bodyB->internalGetDeltaAngularVelocity());
+ }
+
+
+ deltaImpulseB -= deltaVelADotn*cB.m_jacDiagABInv;//m_jacDiagABInv = 1./denom
+ deltaImpulseB -= deltaVelBDotn*cB.m_jacDiagABInv;
+ sumB = btScalar(cB.m_appliedImpulse) + deltaImpulseB;
+ }
+
+ btScalar deltaImpulseA = 0.f;
+ btScalar sumA = 0.f;
+ const btMultiBodySolverConstraint& cA = cA1;
+ {
+ {
+ deltaImpulseA = cA.m_rhs-btScalar(cA.m_appliedImpulse)*cA.m_cfm;
+ btScalar deltaVelADotn=0;
+ btScalar deltaVelBDotn=0;
+ if (cA.m_multiBodyA)
+ {
+ ndofA = cA.m_multiBodyA->getNumDofs() + 6;
+ for (int i = 0; i < ndofA; ++i)
+ deltaVelADotn += m_data.m_jacobians[cA.m_jacAindex+i] * m_data.m_deltaVelocities[cA.m_deltaVelAindex+i];
+ } else if(cA.m_solverBodyIdA >= 0)
+ {
+ bodyA = &m_tmpSolverBodyPool[cA.m_solverBodyIdA];
+ deltaVelADotn += cA.m_contactNormal1.dot(bodyA->internalGetDeltaLinearVelocity()) + cA.m_relpos1CrossNormal.dot(bodyA->internalGetDeltaAngularVelocity());
+ }
+
+ if (cA.m_multiBodyB)
+ {
+ ndofB = cA.m_multiBodyB->getNumDofs() + 6;
+ for (int i = 0; i < ndofB; ++i)
+ deltaVelBDotn += m_data.m_jacobians[cA.m_jacBindex+i] * m_data.m_deltaVelocities[cA.m_deltaVelBindex+i];
+ } else if(cA.m_solverBodyIdB >= 0)
+ {
+ bodyB = &m_tmpSolverBodyPool[cA.m_solverBodyIdB];
+ deltaVelBDotn += cA.m_contactNormal2.dot(bodyB->internalGetDeltaLinearVelocity()) + cA.m_relpos2CrossNormal.dot(bodyB->internalGetDeltaAngularVelocity());
+ }
+
+
+ deltaImpulseA -= deltaVelADotn*cA.m_jacDiagABInv;//m_jacDiagABInv = 1./denom
+ deltaImpulseA -= deltaVelBDotn*cA.m_jacDiagABInv;
+ sumA = btScalar(cA.m_appliedImpulse) + deltaImpulseA;
+ }
+ }
+
+ if (sumA*sumA+sumB*sumB>=cA.m_lowerLimit*cB.m_lowerLimit)
+ {
+ btScalar angle = btAtan2(sumA,sumB);
+ btScalar sumAclipped = btFabs(cA.m_lowerLimit*btSin(angle));
+ btScalar sumBclipped = btFabs(cB.m_lowerLimit*btCos(angle));
+
+
+ if (sumA < -sumAclipped)
+ {
+ deltaImpulseA = -sumAclipped - cA.m_appliedImpulse;
+ cA.m_appliedImpulse = -sumAclipped;
+ }
+ else if (sumA > sumAclipped)
+ {
+ deltaImpulseA = sumAclipped - cA.m_appliedImpulse;
+ cA.m_appliedImpulse = sumAclipped;
+ }
+ else
+ {
+ cA.m_appliedImpulse = sumA;
+ }
+
+ if (sumB < -sumBclipped)
+ {
+ deltaImpulseB = -sumBclipped - cB.m_appliedImpulse;
+ cB.m_appliedImpulse = -sumBclipped;
+ }
+ else if (sumB > sumBclipped)
+ {
+ deltaImpulseB = sumBclipped - cB.m_appliedImpulse;
+ cB.m_appliedImpulse = sumBclipped;
+ }
+ else
+ {
+ cB.m_appliedImpulse = sumB;
+ }
+ //deltaImpulseA = sumAclipped-cA.m_appliedImpulse;
+ //cA.m_appliedImpulse = sumAclipped;
+ //deltaImpulseB = sumBclipped-cB.m_appliedImpulse;
+ //cB.m_appliedImpulse = sumBclipped;
+ }
+ else
+ {
+ cA.m_appliedImpulse = sumA;
+ cB.m_appliedImpulse = sumB;
+ }
+
+ if (cA.m_multiBodyA)
+ {
+ applyDeltaVee(&m_data.m_deltaVelocitiesUnitImpulse[cA.m_jacAindex],deltaImpulseA,cA.m_deltaVelAindex,ndofA);
+#ifdef DIRECTLY_UPDATE_VELOCITY_DURING_SOLVER_ITERATIONS
+ //note: update of the actual velocities (below) in the multibody does not have to happen now since m_deltaVelocities can be applied after all iterations
+ //it would make the multibody solver more like the regular one with m_deltaVelocities being equivalent to btSolverBody::m_deltaLinearVelocity/m_deltaAngularVelocity
+ cA.m_multiBodyA->applyDeltaVeeMultiDof2(&m_data.m_deltaVelocitiesUnitImpulse[cA.m_jacAindex],deltaImpulseA);
+#endif //DIRECTLY_UPDATE_VELOCITY_DURING_SOLVER_ITERATIONS
+ } else if(cA.m_solverBodyIdA >= 0)
+ {
+ bodyA->internalApplyImpulse(cA.m_contactNormal1*bodyA->internalGetInvMass(),cA.m_angularComponentA,deltaImpulseA);
+
+ }
+ if (cA.m_multiBodyB)
+ {
+ applyDeltaVee(&m_data.m_deltaVelocitiesUnitImpulse[cA.m_jacBindex],deltaImpulseA,cA.m_deltaVelBindex,ndofB);
+#ifdef DIRECTLY_UPDATE_VELOCITY_DURING_SOLVER_ITERATIONS
+ //note: update of the actual velocities (below) in the multibody does not have to happen now since m_deltaVelocities can be applied after all iterations
+ //it would make the multibody solver more like the regular one with m_deltaVelocities being equivalent to btSolverBody::m_deltaLinearVelocity/m_deltaAngularVelocity
+ cA.m_multiBodyB->applyDeltaVeeMultiDof2(&m_data.m_deltaVelocitiesUnitImpulse[cA.m_jacBindex],deltaImpulseA);
+#endif //DIRECTLY_UPDATE_VELOCITY_DURING_SOLVER_ITERATIONS
+ } else if(cA.m_solverBodyIdB >= 0)
+ {
+ bodyB->internalApplyImpulse(cA.m_contactNormal2*bodyB->internalGetInvMass(),cA.m_angularComponentB,deltaImpulseA);
+ }
+
+ if (cB.m_multiBodyA)
+ {
+ applyDeltaVee(&m_data.m_deltaVelocitiesUnitImpulse[cB.m_jacAindex],deltaImpulseB,cB.m_deltaVelAindex,ndofA);
+#ifdef DIRECTLY_UPDATE_VELOCITY_DURING_SOLVER_ITERATIONS
+ //note: update of the actual velocities (below) in the multibody does not have to happen now since m_deltaVelocities can be applied after all iterations
+ //it would make the multibody solver more like the regular one with m_deltaVelocities being equivalent to btSolverBody::m_deltaLinearVelocity/m_deltaAngularVelocity
+ cB.m_multiBodyA->applyDeltaVeeMultiDof2(&m_data.m_deltaVelocitiesUnitImpulse[cB.m_jacAindex],deltaImpulseB);
+#endif //DIRECTLY_UPDATE_VELOCITY_DURING_SOLVER_ITERATIONS
+ } else if(cB.m_solverBodyIdA >= 0)
+ {
+ bodyA->internalApplyImpulse(cB.m_contactNormal1*bodyA->internalGetInvMass(),cB.m_angularComponentA,deltaImpulseB);
+ }
+ if (cB.m_multiBodyB)
+ {
+ applyDeltaVee(&m_data.m_deltaVelocitiesUnitImpulse[cB.m_jacBindex],deltaImpulseB,cB.m_deltaVelBindex,ndofB);
+#ifdef DIRECTLY_UPDATE_VELOCITY_DURING_SOLVER_ITERATIONS
+ //note: update of the actual velocities (below) in the multibody does not have to happen now since m_deltaVelocities can be applied after all iterations
+ //it would make the multibody solver more like the regular one with m_deltaVelocities being equivalent to btSolverBody::m_deltaLinearVelocity/m_deltaAngularVelocity
+ cB.m_multiBodyB->applyDeltaVeeMultiDof2(&m_data.m_deltaVelocitiesUnitImpulse[cB.m_jacBindex],deltaImpulseB);
+#endif //DIRECTLY_UPDATE_VELOCITY_DURING_SOLVER_ITERATIONS
+ } else if(cB.m_solverBodyIdB >= 0)
+ {
+ bodyB->internalApplyImpulse(cB.m_contactNormal2*bodyB->internalGetInvMass(),cB.m_angularComponentB,deltaImpulseB);
+ }
+
+ btScalar deltaVel =deltaImpulseA/cA.m_jacDiagABInv+deltaImpulseB/cB.m_jacDiagABInv;
+ return deltaVel;
}
@@ -908,7 +1160,10 @@ btMultiBodySolverConstraint& btMultiBodyConstraintSolver::addMultiBodyTorsionalF
btCollisionObject* colObj0,btCollisionObject* colObj1, btScalar relaxation, const btContactSolverInfo& infoGlobal, btScalar desiredVelocity, btScalar cfmSlip)
{
BT_PROFILE("addMultiBodyRollingFrictionConstraint");
- btMultiBodySolverConstraint& solverConstraint = m_multiBodyFrictionContactConstraints.expandNonInitializing();
+
+ bool useTorsionalAndConeFriction = (infoGlobal.m_solverMode & SOLVER_USE_2_FRICTION_DIRECTIONS && ((infoGlobal.m_solverMode&SOLVER_DISABLE_IMPLICIT_CONE_FRICTION) == 0));
+
+ btMultiBodySolverConstraint& solverConstraint = useTorsionalAndConeFriction? m_multiBodyTorsionalFrictionContactConstraints.expandNonInitializing() : m_multiBodyFrictionContactConstraints.expandNonInitializing();
solverConstraint.m_orgConstraint = 0;
solverConstraint.m_orgDofIndex = -1;
@@ -1151,6 +1406,7 @@ void btMultiBodyConstraintSolver::convertContacts(btPersistentManifold** manifol
btScalar btMultiBodyConstraintSolver::solveGroup(btCollisionObject** bodies,int numBodies,btPersistentManifold** manifold,int numManifolds,btTypedConstraint** constraints,int numConstraints,const btContactSolverInfo& info, btIDebugDraw* debugDrawer,btDispatcher* dispatcher)
{
+ //printf("btMultiBodyConstraintSolver::solveGroup: numBodies=%d, numConstraints=%d\n", numBodies, numConstraints);
return btSequentialImpulseConstraintSolver::solveGroup(bodies,numBodies,manifold,numManifolds,constraints,numConstraints,info,debugDrawer,dispatcher);
}
@@ -1234,27 +1490,12 @@ void btMultiBodyConstraintSolver::writeBackSolverBodyToMultiBody(btMultiBodySolv
if (c.m_multiBodyA)
{
-
- if(c.m_multiBodyA->isMultiDof())
- {
- c.m_multiBodyA->applyDeltaVeeMultiDof(&m_data.m_deltaVelocitiesUnitImpulse[c.m_jacAindex],c.m_appliedImpulse);
- }
- else
- {
- c.m_multiBodyA->applyDeltaVee(&m_data.m_deltaVelocitiesUnitImpulse[c.m_jacAindex],c.m_appliedImpulse);
- }
+ c.m_multiBodyA->applyDeltaVeeMultiDof(&m_data.m_deltaVelocitiesUnitImpulse[c.m_jacAindex],c.m_appliedImpulse);
}
if (c.m_multiBodyB)
{
- if(c.m_multiBodyB->isMultiDof())
- {
- c.m_multiBodyB->applyDeltaVeeMultiDof(&m_data.m_deltaVelocitiesUnitImpulse[c.m_jacBindex],c.m_appliedImpulse);
- }
- else
- {
- c.m_multiBodyB->applyDeltaVee(&m_data.m_deltaVelocitiesUnitImpulse[c.m_jacBindex],c.m_appliedImpulse);
- }
+ c.m_multiBodyB->applyDeltaVeeMultiDof(&m_data.m_deltaVelocitiesUnitImpulse[c.m_jacBindex],c.m_appliedImpulse);
}
#endif
@@ -1416,6 +1657,8 @@ btScalar btMultiBodyConstraintSolver::solveGroupCacheFriendlyFinish(btCollisionO
void btMultiBodyConstraintSolver::solveMultiBodyGroup(btCollisionObject** bodies,int numBodies,btPersistentManifold** manifold,int numManifolds,btTypedConstraint** constraints,int numConstraints,btMultiBodyConstraint** multiBodyConstraints, int numMultiBodyConstraints, const btContactSolverInfo& info, btIDebugDraw* debugDrawer,btDispatcher* dispatcher)
{
+ //printf("solveMultiBodyGroup: numBodies=%d, numConstraints=%d, numManifolds=%d, numMultiBodyConstraints=%d\n", numBodies, numConstraints, numManifolds, numMultiBodyConstraints);
+
//printf("solveMultiBodyGroup start\n");
m_tmpMultiBodyConstraints = multiBodyConstraints;
m_tmpNumMultiBodyConstraints = numMultiBodyConstraints;
diff --git a/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyConstraintSolver.h b/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyConstraintSolver.h
index 489347d874..29f484e1d8 100644
--- a/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyConstraintSolver.h
+++ b/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyConstraintSolver.h
@@ -36,6 +36,7 @@ protected:
btMultiBodyConstraintArray m_multiBodyNormalContactConstraints;
btMultiBodyConstraintArray m_multiBodyFrictionContactConstraints;
+ btMultiBodyConstraintArray m_multiBodyTorsionalFrictionContactConstraints;
btMultiBodyJacobianData m_data;
@@ -45,6 +46,9 @@ protected:
btScalar resolveSingleConstraintRowGeneric(const btMultiBodySolverConstraint& c);
+ //solve 2 friction directions and clamp against the implicit friction cone
+ btScalar resolveConeFrictionConstraintRows(const btMultiBodySolverConstraint& cA1, const btMultiBodySolverConstraint& cB);
+
void convertContacts(btPersistentManifold** manifoldPtr,int numManifolds, const btContactSolverInfo& infoGlobal);
diff --git a/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyDynamicsWorld.cpp b/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyDynamicsWorld.cpp
index 9eacc22647..9c5f3ad8a9 100644
--- a/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyDynamicsWorld.cpp
+++ b/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyDynamicsWorld.cpp
@@ -277,7 +277,11 @@ struct MultiBodyInplaceSolverIslandCallback : public btSimulationIslandManager::
m_multiBodyConstraints.resize(0);
}
-
+ void setMultiBodyConstraintSolver(btMultiBodyConstraintSolver* solver)
+ {
+ m_solver = solver;
+ }
+
virtual void processIsland(btCollisionObject** bodies,int numBodies,btPersistentManifold** manifolds,int numManifolds, int islandId)
{
if (islandId<0)
@@ -348,7 +352,7 @@ struct MultiBodyInplaceSolverIslandCallback : public btSimulationIslandManager::
for (i=0;i<numCurMultiBodyConstraints;i++)
m_multiBodyConstraints.push_back(startMultiBodyConstraint[i]);
- if ((m_constraints.size()+m_manifolds.size())>m_solverInfo->m_minimumSolverBatchSize)
+ if ((m_multiBodyConstraints.size()+m_constraints.size()+m_manifolds.size())>m_solverInfo->m_minimumSolverBatchSize)
{
processConstraints();
} else
@@ -394,6 +398,22 @@ btMultiBodyDynamicsWorld::~btMultiBodyDynamicsWorld ()
delete m_solverMultiBodyIslandCallback;
}
+void btMultiBodyDynamicsWorld::setMultiBodyConstraintSolver(btMultiBodyConstraintSolver* solver)
+{
+ m_multiBodyConstraintSolver = solver;
+ m_solverMultiBodyIslandCallback->setMultiBodyConstraintSolver(solver);
+ btDiscreteDynamicsWorld::setConstraintSolver(solver);
+}
+
+void btMultiBodyDynamicsWorld::setConstraintSolver(btConstraintSolver* solver)
+{
+ if (solver->getSolverType()==BT_MULTIBODY_SOLVER)
+ {
+ m_multiBodyConstraintSolver = (btMultiBodyConstraintSolver*)solver;
+ }
+ btDiscreteDynamicsWorld::setConstraintSolver(solver);
+}
+
void btMultiBodyDynamicsWorld::forwardKinematics()
{
@@ -411,6 +431,8 @@ void btMultiBodyDynamicsWorld::solveConstraints(btContactSolverInfo& solverInfo)
BT_PROFILE("solveConstraints");
+ clearMultiBodyConstraintForces();
+
m_sortedConstraints.resize( m_constraints.size());
int i;
for (i=0;i<getNumConstraints();i++)
@@ -433,8 +455,6 @@ void btMultiBodyDynamicsWorld::solveConstraints(btContactSolverInfo& solverInfo)
m_solverMultiBodyIslandCallback->setup(&solverInfo,constraintsPtr,m_sortedConstraints.size(),sortedMultiBodyConstraints,m_sortedMultiBodyConstraints.size(), getDebugDrawer());
m_constraintSolver->prepareSolve(getCollisionWorld()->getNumCollisionObjects(), getCollisionWorld()->getDispatcher()->getNumManifolds());
- /// solve all the constraints for this island
- m_islandManager->buildAndProcessIslands(getCollisionWorld()->getDispatcher(),getCollisionWorld(),m_solverMultiBodyIslandCallback);
#ifndef BT_USE_VIRTUAL_CLEARFORCES_AND_GRAVITY
{
@@ -669,7 +689,9 @@ void btMultiBodyDynamicsWorld::solveConstraints(btContactSolverInfo& solverInfo)
}
}
- clearMultiBodyConstraintForces();
+ /// solve all the constraints for this island
+ m_islandManager->buildAndProcessIslands(getCollisionWorld()->getDispatcher(), getCollisionWorld(), m_solverMultiBodyIslandCallback);
+
m_solverMultiBodyIslandCallback->processConstraints();
@@ -824,21 +846,24 @@ void btMultiBodyDynamicsWorld::debugDrawWorld()
{
btMultiBody* bod = m_multiBodies[b];
bod->forwardKinematics(m_scratch_world_to_local1,m_scratch_local_origin1);
-
- getDebugDrawer()->drawTransform(bod->getBaseWorldTransform(), 0.1);
-
+
+ if (mode & btIDebugDraw::DBG_DrawFrames)
+ {
+ getDebugDrawer()->drawTransform(bod->getBaseWorldTransform(), 0.1);
+ }
for (int m = 0; m<bod->getNumLinks(); m++)
{
const btTransform& tr = bod->getLink(m).m_cachedWorldTransform;
-
- getDebugDrawer()->drawTransform(tr, 0.1);
-
+ if (mode & btIDebugDraw::DBG_DrawFrames)
+ {
+ getDebugDrawer()->drawTransform(tr, 0.1);
+ }
//draw the joint axis
if (bod->getLink(m).m_jointType==btMultibodyLink::eRevolute)
{
- btVector3 vec = quatRotate(tr.getRotation(),bod->getLink(m).m_axes[0].m_topVec);
+ btVector3 vec = quatRotate(tr.getRotation(),bod->getLink(m).m_axes[0].m_topVec)*0.1;
btVector4 color(0,0,0,1);//1,1,1);
btVector3 from = vec+tr.getOrigin()-quatRotate(tr.getRotation(),bod->getLink(m).m_dVector);
@@ -847,7 +872,7 @@ void btMultiBodyDynamicsWorld::debugDrawWorld()
}
if (bod->getLink(m).m_jointType==btMultibodyLink::eFixed)
{
- btVector3 vec = quatRotate(tr.getRotation(),bod->getLink(m).m_axes[0].m_bottomVec);
+ btVector3 vec = quatRotate(tr.getRotation(),bod->getLink(m).m_axes[0].m_bottomVec)*0.1;
btVector4 color(0,0,0,1);//1,1,1);
btVector3 from = vec+tr.getOrigin()-quatRotate(tr.getRotation(),bod->getLink(m).m_dVector);
@@ -856,7 +881,7 @@ void btMultiBodyDynamicsWorld::debugDrawWorld()
}
if (bod->getLink(m).m_jointType==btMultibodyLink::ePrismatic)
{
- btVector3 vec = quatRotate(tr.getRotation(),bod->getLink(m).m_axes[0].m_bottomVec);
+ btVector3 vec = quatRotate(tr.getRotation(),bod->getLink(m).m_axes[0].m_bottomVec)*0.1;
btVector4 color(0,0,0,1);//1,1,1);
btVector3 from = vec+tr.getOrigin()-quatRotate(tr.getRotation(),bod->getLink(m).m_dVector);
@@ -970,6 +995,8 @@ void btMultiBodyDynamicsWorld::serialize(btSerializer* serializer)
serializeCollisionObjects(serializer);
+ serializeContactManifolds(serializer);
+
serializer->finishSerialization();
}
@@ -988,4 +1015,17 @@ void btMultiBodyDynamicsWorld::serializeMultiBodies(btSerializer* serializer)
}
}
-} \ No newline at end of file
+ //serialize all multibody links (collision objects)
+ for (i=0;i<m_collisionObjects.size();i++)
+ {
+ btCollisionObject* colObj = m_collisionObjects[i];
+ if (colObj->getInternalType() == btCollisionObject::CO_FEATHERSTONE_LINK)
+ {
+ int len = colObj->calculateSerializeBufferSize();
+ btChunk* chunk = serializer->allocate(len,1);
+ const char* structType = colObj->serialize(chunk->m_oldPtr, serializer);
+ serializer->finalizeChunk(chunk,structType,BT_MB_LINKCOLLIDER_CODE,colObj);
+ }
+ }
+
+}
diff --git a/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyDynamicsWorld.h b/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyDynamicsWorld.h
index c0c132bbba..2fbf089d81 100644
--- a/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyDynamicsWorld.h
+++ b/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyDynamicsWorld.h
@@ -109,6 +109,8 @@ public:
virtual void applyGravity();
virtual void serialize(btSerializer* serializer);
+ virtual void setMultiBodyConstraintSolver(btMultiBodyConstraintSolver* solver);
+ virtual void setConstraintSolver(btConstraintSolver* solver);
};
#endif //BT_MULTIBODY_DYNAMICS_WORLD_H
diff --git a/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyFixedConstraint.cpp b/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyFixedConstraint.cpp
index 1f94117aa9..af48e94a83 100644
--- a/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyFixedConstraint.cpp
+++ b/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyFixedConstraint.cpp
@@ -65,13 +65,16 @@ int btMultiBodyFixedConstraint::getIslandIdA() const
if (m_bodyA)
{
- btMultiBodyLinkCollider* col = m_bodyA->getBaseCollider();
- if (col)
- return col->getIslandTag();
- for (int i=0;i<m_bodyA->getNumLinks();i++)
+ if (m_linkA < 0)
{
- if (m_bodyA->getLink(i).m_collider)
- return m_bodyA->getLink(i).m_collider->getIslandTag();
+ btMultiBodyLinkCollider* col = m_bodyA->getBaseCollider();
+ if (col)
+ return col->getIslandTag();
+ }
+ else
+ {
+ if (m_bodyA->getLink(m_linkA).m_collider)
+ return m_bodyA->getLink(m_linkA).m_collider->getIslandTag();
}
}
return -1;
@@ -83,16 +86,17 @@ int btMultiBodyFixedConstraint::getIslandIdB() const
return m_rigidBodyB->getIslandTag();
if (m_bodyB)
{
- btMultiBodyLinkCollider* col = m_bodyB->getBaseCollider();
- if (col)
- return col->getIslandTag();
-
- for (int i=0;i<m_bodyB->getNumLinks();i++)
+ if (m_linkB < 0)
{
- col = m_bodyB->getLink(i).m_collider;
+ btMultiBodyLinkCollider* col = m_bodyB->getBaseCollider();
if (col)
return col->getIslandTag();
}
+ else
+ {
+ if (m_bodyB->getLink(m_linkB).m_collider)
+ return m_bodyB->getLink(m_linkB).m_collider->getIslandTag();
+ }
}
return -1;
}
diff --git a/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyGearConstraint.cpp b/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyGearConstraint.cpp
index 5fdb7007d8..09ddd65cd8 100644
--- a/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyGearConstraint.cpp
+++ b/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyGearConstraint.cpp
@@ -45,16 +45,18 @@ btMultiBodyGearConstraint::~btMultiBodyGearConstraint()
int btMultiBodyGearConstraint::getIslandIdA() const
{
-
if (m_bodyA)
{
- btMultiBodyLinkCollider* col = m_bodyA->getBaseCollider();
- if (col)
- return col->getIslandTag();
- for (int i=0;i<m_bodyA->getNumLinks();i++)
+ if (m_linkA < 0)
+ {
+ btMultiBodyLinkCollider* col = m_bodyA->getBaseCollider();
+ if (col)
+ return col->getIslandTag();
+ }
+ else
{
- if (m_bodyA->getLink(i).m_collider)
- return m_bodyA->getLink(i).m_collider->getIslandTag();
+ if (m_bodyA->getLink(m_linkA).m_collider)
+ return m_bodyA->getLink(m_linkA).m_collider->getIslandTag();
}
}
return -1;
@@ -64,16 +66,17 @@ int btMultiBodyGearConstraint::getIslandIdB() const
{
if (m_bodyB)
{
- btMultiBodyLinkCollider* col = m_bodyB->getBaseCollider();
- if (col)
- return col->getIslandTag();
-
- for (int i=0;i<m_bodyB->getNumLinks();i++)
+ if (m_linkB < 0)
{
- col = m_bodyB->getLink(i).m_collider;
+ btMultiBodyLinkCollider* col = m_bodyB->getBaseCollider();
if (col)
return col->getIslandTag();
}
+ else
+ {
+ if (m_bodyB->getLink(m_linkB).m_collider)
+ return m_bodyB->getLink(m_linkB).m_collider->getIslandTag();
+ }
}
return -1;
}
@@ -134,6 +137,10 @@ void btMultiBodyGearConstraint::createConstraintRows(btMultiBodyConstraintArray&
if (m_erp!=0)
{
btScalar currentPositionA = m_bodyA->getJointPosMultiDof(m_linkA)[dof];
+ if (m_gearAuxLink >= 0)
+ {
+ currentPositionA -= m_bodyA->getJointPosMultiDof(m_gearAuxLink)[dof];
+ }
btScalar currentPositionB = m_gearRatio*m_bodyA->getJointPosMultiDof(m_linkB)[dof];
btScalar diff = currentPositionB+currentPositionA;
btScalar desiredPositionDiff = this->m_relativePositionTarget;
diff --git a/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyJointLimitConstraint.cpp b/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyJointLimitConstraint.cpp
index 6d173b66a1..35c929f7ce 100644
--- a/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyJointLimitConstraint.cpp
+++ b/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyJointLimitConstraint.cpp
@@ -53,17 +53,22 @@ btMultiBodyJointLimitConstraint::~btMultiBodyJointLimitConstraint()
{
}
+
int btMultiBodyJointLimitConstraint::getIslandIdA() const
{
- if(m_bodyA)
+
+ if (m_bodyA)
{
- btMultiBodyLinkCollider* col = m_bodyA->getBaseCollider();
- if (col)
- return col->getIslandTag();
- for (int i=0;i<m_bodyA->getNumLinks();i++)
+ if (m_linkA < 0)
{
- if (m_bodyA->getLink(i).m_collider)
- return m_bodyA->getLink(i).m_collider->getIslandTag();
+ btMultiBodyLinkCollider* col = m_bodyA->getBaseCollider();
+ if (col)
+ return col->getIslandTag();
+ }
+ else
+ {
+ if (m_bodyA->getLink(m_linkA).m_collider)
+ return m_bodyA->getLink(m_linkA).m_collider->getIslandTag();
}
}
return -1;
@@ -71,18 +76,19 @@ int btMultiBodyJointLimitConstraint::getIslandIdA() const
int btMultiBodyJointLimitConstraint::getIslandIdB() const
{
- if(m_bodyB)
+ if (m_bodyB)
{
- btMultiBodyLinkCollider* col = m_bodyB->getBaseCollider();
- if (col)
- return col->getIslandTag();
-
- for (int i=0;i<m_bodyB->getNumLinks();i++)
+ if (m_linkB < 0)
{
- col = m_bodyB->getLink(i).m_collider;
+ btMultiBodyLinkCollider* col = m_bodyB->getBaseCollider();
if (col)
return col->getIslandTag();
}
+ else
+ {
+ if (m_bodyB->getLink(m_linkB).m_collider)
+ return m_bodyB->getLink(m_linkB).m_collider->getIslandTag();
+ }
}
return -1;
}
diff --git a/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyJointMotor.cpp b/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyJointMotor.cpp
index e0921178e9..2a70ea97e5 100644
--- a/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyJointMotor.cpp
+++ b/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyJointMotor.cpp
@@ -74,29 +74,37 @@ btMultiBodyJointMotor::~btMultiBodyJointMotor()
int btMultiBodyJointMotor::getIslandIdA() const
{
- btMultiBodyLinkCollider* col = m_bodyA->getBaseCollider();
- if (col)
- return col->getIslandTag();
- for (int i=0;i<m_bodyA->getNumLinks();i++)
+ if (this->m_linkA < 0)
{
- if (m_bodyA->getLink(i).m_collider)
- return m_bodyA->getLink(i).m_collider->getIslandTag();
+ btMultiBodyLinkCollider* col = m_bodyA->getBaseCollider();
+ if (col)
+ return col->getIslandTag();
+ }
+ else
+ {
+ if (m_bodyA->getLink(m_linkA).m_collider)
+ {
+ return m_bodyA->getLink(m_linkA).m_collider->getIslandTag();
+ }
}
return -1;
}
int btMultiBodyJointMotor::getIslandIdB() const
{
- btMultiBodyLinkCollider* col = m_bodyB->getBaseCollider();
- if (col)
- return col->getIslandTag();
-
- for (int i=0;i<m_bodyB->getNumLinks();i++)
+ if (m_linkB < 0)
{
- col = m_bodyB->getLink(i).m_collider;
+ btMultiBodyLinkCollider* col = m_bodyB->getBaseCollider();
if (col)
return col->getIslandTag();
}
+ else
+ {
+ if (m_bodyB->getLink(m_linkB).m_collider)
+ {
+ return m_bodyB->getLink(m_linkB).m_collider->getIslandTag();
+ }
+ }
return -1;
}
diff --git a/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyLink.h b/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyLink.h
index 01828e5843..21c9e7a557 100644
--- a/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyLink.h
+++ b/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyLink.h
@@ -182,6 +182,8 @@ btVector3 m_appliedConstraintForce; // In WORLD frame
m_cachedRVector.setValue(0, 0, 0);
m_appliedForce.setValue( 0, 0, 0);
m_appliedTorque.setValue(0, 0, 0);
+ m_appliedConstraintForce.setValue(0,0,0);
+ m_appliedConstraintTorque.setValue(0,0,0);
//
m_jointPos[0] = m_jointPos[1] = m_jointPos[2] = m_jointPos[4] = m_jointPos[5] = m_jointPos[6] = 0.f;
m_jointPos[3] = 1.f; //"quat.w"
diff --git a/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyLinkCollider.h b/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyLinkCollider.h
index 671e15d314..7092e62b5a 100644
--- a/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyLinkCollider.h
+++ b/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyLinkCollider.h
@@ -19,6 +19,16 @@ subject to the following restrictions:
#include "BulletCollision/CollisionDispatch/btCollisionObject.h"
#include "btMultiBody.h"
+#include "LinearMath/btSerializer.h"
+
+#ifdef BT_USE_DOUBLE_PRECISION
+#define btMultiBodyLinkColliderData btMultiBodyLinkColliderDoubleData
+#define btMultiBodyLinkColliderDataName "btMultiBodyLinkColliderDoubleData"
+#else
+#define btMultiBodyLinkColliderData btMultiBodyLinkColliderFloatData
+#define btMultiBodyLinkColliderDataName "btMultiBodyLinkColliderFloatData"
+#endif
+
class btMultiBodyLinkCollider : public btCollisionObject
{
@@ -119,7 +129,49 @@ public:
}
return true;
}
+
+ virtual int calculateSerializeBufferSize() const;
+
+ ///fills the dataBuffer and returns the struct name (and 0 on failure)
+ virtual const char* serialize(void* dataBuffer, class btSerializer* serializer) const;
+
+};
+
+
+struct btMultiBodyLinkColliderFloatData
+{
+ btCollisionObjectFloatData m_colObjData;
+ btMultiBodyFloatData *m_multiBody;
+ int m_link;
+ char m_padding[4];
};
+struct btMultiBodyLinkColliderDoubleData
+{
+ btCollisionObjectDoubleData m_colObjData;
+ btMultiBodyDoubleData *m_multiBody;
+ int m_link;
+ char m_padding[4];
+};
+
+SIMD_FORCE_INLINE int btMultiBodyLinkCollider::calculateSerializeBufferSize() const
+{
+ return sizeof(btMultiBodyLinkColliderData);
+}
+
+SIMD_FORCE_INLINE const char* btMultiBodyLinkCollider::serialize(void* dataBuffer, class btSerializer* serializer) const
+{
+ btMultiBodyLinkColliderData* dataOut = (btMultiBodyLinkColliderData*)dataBuffer;
+ btCollisionObject::serialize(&dataOut->m_colObjData,serializer);
+
+ dataOut->m_link = this->m_link;
+ dataOut->m_multiBody = (btMultiBodyData*)serializer->getUniquePointer(m_multiBody);
+
+ // Fill padding with zeros to appease msan.
+ memset(dataOut->m_padding, 0, sizeof(dataOut->m_padding));
+
+ return btMultiBodyLinkColliderDataName;
+}
+
#endif //BT_FEATHERSTONE_LINK_COLLIDER_H
diff --git a/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyMLCPConstraintSolver.cpp b/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyMLCPConstraintSolver.cpp
new file mode 100644
index 0000000000..338e8af0ab
--- /dev/null
+++ b/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyMLCPConstraintSolver.cpp
@@ -0,0 +1,966 @@
+/*
+Bullet Continuous Collision Detection and Physics Library
+Copyright (c) 2018 Google 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.
+*/
+
+#include "BulletDynamics/Featherstone/btMultiBodyMLCPConstraintSolver.h"
+
+#include "BulletCollision/NarrowPhaseCollision/btPersistentManifold.h"
+#include "BulletDynamics/Featherstone/btMultiBodyLinkCollider.h"
+#include "BulletDynamics/Featherstone/btMultiBodyConstraint.h"
+#include "BulletDynamics/MLCPSolvers/btMLCPSolverInterface.h"
+
+#define DIRECTLY_UPDATE_VELOCITY_DURING_SOLVER_ITERATIONS
+
+static bool interleaveContactAndFriction = false;
+
+struct btJointNode
+{
+ int jointIndex; // pointer to enclosing dxJoint object
+ int otherBodyIndex; // *other* body this joint is connected to
+ int nextJointNodeIndex; //-1 for null
+ int constraintRowIndex;
+};
+
+// Helper function to compute a delta velocity in the constraint space.
+static btScalar computeDeltaVelocityInConstraintSpace(
+ const btVector3& angularDeltaVelocity,
+ const btVector3& contactNormal,
+ btScalar invMass,
+ const btVector3& angularJacobian,
+ const btVector3& linearJacobian)
+{
+ return angularDeltaVelocity.dot(angularJacobian) + contactNormal.dot(linearJacobian) * invMass;
+}
+
+// Faster version of computeDeltaVelocityInConstraintSpace that can be used when contactNormal and linearJacobian are
+// identical.
+static btScalar computeDeltaVelocityInConstraintSpace(
+ const btVector3& angularDeltaVelocity,
+ btScalar invMass,
+ const btVector3& angularJacobian)
+{
+ return angularDeltaVelocity.dot(angularJacobian) + invMass;
+}
+
+// Helper function to compute a delta velocity in the constraint space.
+static btScalar computeDeltaVelocityInConstraintSpace(const btScalar* deltaVelocity, const btScalar* jacobian, int size)
+{
+ btScalar result = 0;
+ for (int i = 0; i < size; ++i)
+ result += deltaVelocity[i] * jacobian[i];
+
+ return result;
+}
+
+static btScalar computeConstraintMatrixDiagElementMultiBody(
+ const btAlignedObjectArray<btSolverBody>& solverBodyPool,
+ const btMultiBodyJacobianData& data,
+ const btMultiBodySolverConstraint& constraint)
+{
+ btScalar ret = 0;
+
+ const btMultiBody* multiBodyA = constraint.m_multiBodyA;
+ const btMultiBody* multiBodyB = constraint.m_multiBodyB;
+
+ if (multiBodyA)
+ {
+ const btScalar* jacA = &data.m_jacobians[constraint.m_jacAindex];
+ const btScalar* deltaA = &data.m_deltaVelocitiesUnitImpulse[constraint.m_jacAindex];
+ const int ndofA = multiBodyA->getNumDofs() + 6;
+ ret += computeDeltaVelocityInConstraintSpace(deltaA, jacA, ndofA);
+ }
+ else
+ {
+ const int solverBodyIdA = constraint.m_solverBodyIdA;
+ btAssert(solverBodyIdA != -1);
+ const btSolverBody* solverBodyA = &solverBodyPool[solverBodyIdA];
+ const btScalar invMassA = solverBodyA->m_originalBody ? solverBodyA->m_originalBody->getInvMass() : 0.0;
+ ret += computeDeltaVelocityInConstraintSpace(
+ constraint.m_relpos1CrossNormal,
+ invMassA,
+ constraint.m_angularComponentA);
+ }
+
+ if (multiBodyB)
+ {
+ const btScalar* jacB = &data.m_jacobians[constraint.m_jacBindex];
+ const btScalar* deltaB = &data.m_deltaVelocitiesUnitImpulse[constraint.m_jacBindex];
+ const int ndofB = multiBodyB->getNumDofs() + 6;
+ ret += computeDeltaVelocityInConstraintSpace(deltaB, jacB, ndofB);
+ }
+ else
+ {
+ const int solverBodyIdB = constraint.m_solverBodyIdB;
+ btAssert(solverBodyIdB != -1);
+ const btSolverBody* solverBodyB = &solverBodyPool[solverBodyIdB];
+ const btScalar invMassB = solverBodyB->m_originalBody ? solverBodyB->m_originalBody->getInvMass() : 0.0;
+ ret += computeDeltaVelocityInConstraintSpace(
+ constraint.m_relpos2CrossNormal,
+ invMassB,
+ constraint.m_angularComponentB);
+ }
+
+ return ret;
+}
+
+static btScalar computeConstraintMatrixOffDiagElementMultiBody(
+ const btAlignedObjectArray<btSolverBody>& solverBodyPool,
+ const btMultiBodyJacobianData& data,
+ const btMultiBodySolverConstraint& constraint,
+ const btMultiBodySolverConstraint& offDiagConstraint)
+{
+ btScalar offDiagA = btScalar(0);
+
+ const btMultiBody* multiBodyA = constraint.m_multiBodyA;
+ const btMultiBody* multiBodyB = constraint.m_multiBodyB;
+ const btMultiBody* offDiagMultiBodyA = offDiagConstraint.m_multiBodyA;
+ const btMultiBody* offDiagMultiBodyB = offDiagConstraint.m_multiBodyB;
+
+ // Assumed at least one system is multibody
+ btAssert(multiBodyA || multiBodyB);
+ btAssert(offDiagMultiBodyA || offDiagMultiBodyB);
+
+ if (offDiagMultiBodyA)
+ {
+ const btScalar* offDiagJacA = &data.m_jacobians[offDiagConstraint.m_jacAindex];
+
+ if (offDiagMultiBodyA == multiBodyA)
+ {
+ const int ndofA = multiBodyA->getNumDofs() + 6;
+ const btScalar* deltaA = &data.m_deltaVelocitiesUnitImpulse[constraint.m_jacAindex];
+ offDiagA += computeDeltaVelocityInConstraintSpace(deltaA, offDiagJacA, ndofA);
+ }
+ else if (offDiagMultiBodyA == multiBodyB)
+ {
+ const int ndofB = multiBodyB->getNumDofs() + 6;
+ const btScalar* deltaB = &data.m_deltaVelocitiesUnitImpulse[constraint.m_jacBindex];
+ offDiagA += computeDeltaVelocityInConstraintSpace(deltaB, offDiagJacA, ndofB);
+ }
+ }
+ else
+ {
+ const int solverBodyIdA = constraint.m_solverBodyIdA;
+ const int solverBodyIdB = constraint.m_solverBodyIdB;
+
+ const int offDiagSolverBodyIdA = offDiagConstraint.m_solverBodyIdA;
+ btAssert(offDiagSolverBodyIdA != -1);
+
+ if (offDiagSolverBodyIdA == solverBodyIdA)
+ {
+ btAssert(solverBodyIdA != -1);
+ const btSolverBody* solverBodyA = &solverBodyPool[solverBodyIdA];
+ const btScalar invMassA = solverBodyA->m_originalBody ? solverBodyA->m_originalBody->getInvMass() : 0.0;
+ offDiagA += computeDeltaVelocityInConstraintSpace(
+ offDiagConstraint.m_relpos1CrossNormal,
+ offDiagConstraint.m_contactNormal1,
+ invMassA, constraint.m_angularComponentA,
+ constraint.m_contactNormal1);
+ }
+ else if (offDiagSolverBodyIdA == solverBodyIdB)
+ {
+ btAssert(solverBodyIdB != -1);
+ const btSolverBody* solverBodyB = &solverBodyPool[solverBodyIdB];
+ const btScalar invMassB = solverBodyB->m_originalBody ? solverBodyB->m_originalBody->getInvMass() : 0.0;
+ offDiagA += computeDeltaVelocityInConstraintSpace(
+ offDiagConstraint.m_relpos1CrossNormal,
+ offDiagConstraint.m_contactNormal1,
+ invMassB,
+ constraint.m_angularComponentB,
+ constraint.m_contactNormal2);
+ }
+ }
+
+ if (offDiagMultiBodyB)
+ {
+ const btScalar* offDiagJacB = &data.m_jacobians[offDiagConstraint.m_jacBindex];
+
+ if (offDiagMultiBodyB == multiBodyA)
+ {
+ const int ndofA = multiBodyA->getNumDofs() + 6;
+ const btScalar* deltaA = &data.m_deltaVelocitiesUnitImpulse[constraint.m_jacAindex];
+ offDiagA += computeDeltaVelocityInConstraintSpace(deltaA, offDiagJacB, ndofA);
+ }
+ else if (offDiagMultiBodyB == multiBodyB)
+ {
+ const int ndofB = multiBodyB->getNumDofs() + 6;
+ const btScalar* deltaB = &data.m_deltaVelocitiesUnitImpulse[constraint.m_jacBindex];
+ offDiagA += computeDeltaVelocityInConstraintSpace(deltaB, offDiagJacB, ndofB);
+ }
+ }
+ else
+ {
+ const int solverBodyIdA = constraint.m_solverBodyIdA;
+ const int solverBodyIdB = constraint.m_solverBodyIdB;
+
+ const int offDiagSolverBodyIdB = offDiagConstraint.m_solverBodyIdB;
+ btAssert(offDiagSolverBodyIdB != -1);
+
+ if (offDiagSolverBodyIdB == solverBodyIdA)
+ {
+ btAssert(solverBodyIdA != -1);
+ const btSolverBody* solverBodyA = &solverBodyPool[solverBodyIdA];
+ const btScalar invMassA = solverBodyA->m_originalBody ? solverBodyA->m_originalBody->getInvMass() : 0.0;
+ offDiagA += computeDeltaVelocityInConstraintSpace(
+ offDiagConstraint.m_relpos2CrossNormal,
+ offDiagConstraint.m_contactNormal2,
+ invMassA, constraint.m_angularComponentA,
+ constraint.m_contactNormal1);
+ }
+ else if (offDiagSolverBodyIdB == solverBodyIdB)
+ {
+ btAssert(solverBodyIdB != -1);
+ const btSolverBody* solverBodyB = &solverBodyPool[solverBodyIdB];
+ const btScalar invMassB = solverBodyB->m_originalBody ? solverBodyB->m_originalBody->getInvMass() : 0.0;
+ offDiagA += computeDeltaVelocityInConstraintSpace(
+ offDiagConstraint.m_relpos2CrossNormal,
+ offDiagConstraint.m_contactNormal2,
+ invMassB, constraint.m_angularComponentB,
+ constraint.m_contactNormal2);
+ }
+ }
+
+ return offDiagA;
+}
+
+void btMultiBodyMLCPConstraintSolver::createMLCPFast(const btContactSolverInfo& infoGlobal)
+{
+ createMLCPFastRigidBody(infoGlobal);
+ createMLCPFastMultiBody(infoGlobal);
+}
+
+void btMultiBodyMLCPConstraintSolver::createMLCPFastRigidBody(const btContactSolverInfo& infoGlobal)
+{
+ int numContactRows = interleaveContactAndFriction ? 3 : 1;
+
+ int numConstraintRows = m_allConstraintPtrArray.size();
+
+ if (numConstraintRows == 0)
+ return;
+
+ int n = numConstraintRows;
+ {
+ BT_PROFILE("init b (rhs)");
+ m_b.resize(numConstraintRows);
+ m_bSplit.resize(numConstraintRows);
+ m_b.setZero();
+ m_bSplit.setZero();
+ for (int i = 0; i < numConstraintRows; i++)
+ {
+ btScalar jacDiag = m_allConstraintPtrArray[i]->m_jacDiagABInv;
+ if (!btFuzzyZero(jacDiag))
+ {
+ btScalar rhs = m_allConstraintPtrArray[i]->m_rhs;
+ btScalar rhsPenetration = m_allConstraintPtrArray[i]->m_rhsPenetration;
+ m_b[i] = rhs / jacDiag;
+ m_bSplit[i] = rhsPenetration / jacDiag;
+ }
+ }
+ }
+
+ // btScalar* w = 0;
+ // int nub = 0;
+
+ m_lo.resize(numConstraintRows);
+ m_hi.resize(numConstraintRows);
+
+ {
+ BT_PROFILE("init lo/ho");
+
+ for (int i = 0; i < numConstraintRows; i++)
+ {
+ if (0) //m_limitDependencies[i]>=0)
+ {
+ m_lo[i] = -BT_INFINITY;
+ m_hi[i] = BT_INFINITY;
+ }
+ else
+ {
+ m_lo[i] = m_allConstraintPtrArray[i]->m_lowerLimit;
+ m_hi[i] = m_allConstraintPtrArray[i]->m_upperLimit;
+ }
+ }
+ }
+
+ //
+ int m = m_allConstraintPtrArray.size();
+
+ int numBodies = m_tmpSolverBodyPool.size();
+ btAlignedObjectArray<int> bodyJointNodeArray;
+ {
+ BT_PROFILE("bodyJointNodeArray.resize");
+ bodyJointNodeArray.resize(numBodies, -1);
+ }
+ btAlignedObjectArray<btJointNode> jointNodeArray;
+ {
+ BT_PROFILE("jointNodeArray.reserve");
+ jointNodeArray.reserve(2 * m_allConstraintPtrArray.size());
+ }
+
+ btMatrixXu& J3 = m_scratchJ3;
+ {
+ BT_PROFILE("J3.resize");
+ J3.resize(2 * m, 8);
+ }
+ btMatrixXu& JinvM3 = m_scratchJInvM3;
+ {
+ BT_PROFILE("JinvM3.resize/setZero");
+
+ JinvM3.resize(2 * m, 8);
+ JinvM3.setZero();
+ J3.setZero();
+ }
+ int cur = 0;
+ int rowOffset = 0;
+ btAlignedObjectArray<int>& ofs = m_scratchOfs;
+ {
+ BT_PROFILE("ofs resize");
+ ofs.resize(0);
+ ofs.resizeNoInitialize(m_allConstraintPtrArray.size());
+ }
+ {
+ BT_PROFILE("Compute J and JinvM");
+ int c = 0;
+
+ int numRows = 0;
+
+ for (int i = 0; i < m_allConstraintPtrArray.size(); i += numRows, c++)
+ {
+ ofs[c] = rowOffset;
+ int sbA = m_allConstraintPtrArray[i]->m_solverBodyIdA;
+ int sbB = m_allConstraintPtrArray[i]->m_solverBodyIdB;
+ btRigidBody* orgBodyA = m_tmpSolverBodyPool[sbA].m_originalBody;
+ btRigidBody* orgBodyB = m_tmpSolverBodyPool[sbB].m_originalBody;
+
+ numRows = i < m_tmpSolverNonContactConstraintPool.size() ? m_tmpConstraintSizesPool[c].m_numConstraintRows : numContactRows;
+ if (orgBodyA)
+ {
+ {
+ int slotA = -1;
+ //find free jointNode slot for sbA
+ slotA = jointNodeArray.size();
+ jointNodeArray.expand(); //NonInitializing();
+ int prevSlot = bodyJointNodeArray[sbA];
+ bodyJointNodeArray[sbA] = slotA;
+ jointNodeArray[slotA].nextJointNodeIndex = prevSlot;
+ jointNodeArray[slotA].jointIndex = c;
+ jointNodeArray[slotA].constraintRowIndex = i;
+ jointNodeArray[slotA].otherBodyIndex = orgBodyB ? sbB : -1;
+ }
+ for (int row = 0; row < numRows; row++, cur++)
+ {
+ btVector3 normalInvMass = m_allConstraintPtrArray[i + row]->m_contactNormal1 * orgBodyA->getInvMass();
+ btVector3 relPosCrossNormalInvInertia = m_allConstraintPtrArray[i + row]->m_relpos1CrossNormal * orgBodyA->getInvInertiaTensorWorld();
+
+ for (int r = 0; r < 3; r++)
+ {
+ J3.setElem(cur, r, m_allConstraintPtrArray[i + row]->m_contactNormal1[r]);
+ J3.setElem(cur, r + 4, m_allConstraintPtrArray[i + row]->m_relpos1CrossNormal[r]);
+ JinvM3.setElem(cur, r, normalInvMass[r]);
+ JinvM3.setElem(cur, r + 4, relPosCrossNormalInvInertia[r]);
+ }
+ J3.setElem(cur, 3, 0);
+ JinvM3.setElem(cur, 3, 0);
+ J3.setElem(cur, 7, 0);
+ JinvM3.setElem(cur, 7, 0);
+ }
+ }
+ else
+ {
+ cur += numRows;
+ }
+ if (orgBodyB)
+ {
+ {
+ int slotB = -1;
+ //find free jointNode slot for sbA
+ slotB = jointNodeArray.size();
+ jointNodeArray.expand(); //NonInitializing();
+ int prevSlot = bodyJointNodeArray[sbB];
+ bodyJointNodeArray[sbB] = slotB;
+ jointNodeArray[slotB].nextJointNodeIndex = prevSlot;
+ jointNodeArray[slotB].jointIndex = c;
+ jointNodeArray[slotB].otherBodyIndex = orgBodyA ? sbA : -1;
+ jointNodeArray[slotB].constraintRowIndex = i;
+ }
+
+ for (int row = 0; row < numRows; row++, cur++)
+ {
+ btVector3 normalInvMassB = m_allConstraintPtrArray[i + row]->m_contactNormal2 * orgBodyB->getInvMass();
+ btVector3 relPosInvInertiaB = m_allConstraintPtrArray[i + row]->m_relpos2CrossNormal * orgBodyB->getInvInertiaTensorWorld();
+
+ for (int r = 0; r < 3; r++)
+ {
+ J3.setElem(cur, r, m_allConstraintPtrArray[i + row]->m_contactNormal2[r]);
+ J3.setElem(cur, r + 4, m_allConstraintPtrArray[i + row]->m_relpos2CrossNormal[r]);
+ JinvM3.setElem(cur, r, normalInvMassB[r]);
+ JinvM3.setElem(cur, r + 4, relPosInvInertiaB[r]);
+ }
+ J3.setElem(cur, 3, 0);
+ JinvM3.setElem(cur, 3, 0);
+ J3.setElem(cur, 7, 0);
+ JinvM3.setElem(cur, 7, 0);
+ }
+ }
+ else
+ {
+ cur += numRows;
+ }
+ rowOffset += numRows;
+ }
+ }
+
+ //compute JinvM = J*invM.
+ const btScalar* JinvM = JinvM3.getBufferPointer();
+
+ const btScalar* Jptr = J3.getBufferPointer();
+ {
+ BT_PROFILE("m_A.resize");
+ m_A.resize(n, n);
+ }
+
+ {
+ BT_PROFILE("m_A.setZero");
+ m_A.setZero();
+ }
+ int c = 0;
+ {
+ int numRows = 0;
+ BT_PROFILE("Compute A");
+ for (int i = 0; i < m_allConstraintPtrArray.size(); i += numRows, c++)
+ {
+ int row__ = ofs[c];
+ int sbA = m_allConstraintPtrArray[i]->m_solverBodyIdA;
+ int sbB = m_allConstraintPtrArray[i]->m_solverBodyIdB;
+ // btRigidBody* orgBodyA = m_tmpSolverBodyPool[sbA].m_originalBody;
+ // btRigidBody* orgBodyB = m_tmpSolverBodyPool[sbB].m_originalBody;
+
+ numRows = i < m_tmpSolverNonContactConstraintPool.size() ? m_tmpConstraintSizesPool[c].m_numConstraintRows : numContactRows;
+
+ const btScalar* JinvMrow = JinvM + 2 * 8 * (size_t)row__;
+
+ {
+ int startJointNodeA = bodyJointNodeArray[sbA];
+ while (startJointNodeA >= 0)
+ {
+ int j0 = jointNodeArray[startJointNodeA].jointIndex;
+ int cr0 = jointNodeArray[startJointNodeA].constraintRowIndex;
+ if (j0 < c)
+ {
+ int numRowsOther = cr0 < m_tmpSolverNonContactConstraintPool.size() ? m_tmpConstraintSizesPool[j0].m_numConstraintRows : numContactRows;
+ size_t ofsother = (m_allConstraintPtrArray[cr0]->m_solverBodyIdB == sbA) ? 8 * numRowsOther : 0;
+ //printf("%d joint i %d and j0: %d: ",count++,i,j0);
+ m_A.multiplyAdd2_p8r(JinvMrow,
+ Jptr + 2 * 8 * (size_t)ofs[j0] + ofsother, numRows, numRowsOther, row__, ofs[j0]);
+ }
+ startJointNodeA = jointNodeArray[startJointNodeA].nextJointNodeIndex;
+ }
+ }
+
+ {
+ int startJointNodeB = bodyJointNodeArray[sbB];
+ while (startJointNodeB >= 0)
+ {
+ int j1 = jointNodeArray[startJointNodeB].jointIndex;
+ int cj1 = jointNodeArray[startJointNodeB].constraintRowIndex;
+
+ if (j1 < c)
+ {
+ int numRowsOther = cj1 < m_tmpSolverNonContactConstraintPool.size() ? m_tmpConstraintSizesPool[j1].m_numConstraintRows : numContactRows;
+ size_t ofsother = (m_allConstraintPtrArray[cj1]->m_solverBodyIdB == sbB) ? 8 * numRowsOther : 0;
+ m_A.multiplyAdd2_p8r(JinvMrow + 8 * (size_t)numRows,
+ Jptr + 2 * 8 * (size_t)ofs[j1] + ofsother, numRows, numRowsOther, row__, ofs[j1]);
+ }
+ startJointNodeB = jointNodeArray[startJointNodeB].nextJointNodeIndex;
+ }
+ }
+ }
+
+ {
+ BT_PROFILE("compute diagonal");
+ // compute diagonal blocks of m_A
+
+ int row__ = 0;
+ int numJointRows = m_allConstraintPtrArray.size();
+
+ int jj = 0;
+ for (; row__ < numJointRows;)
+ {
+ //int sbA = m_allConstraintPtrArray[row__]->m_solverBodyIdA;
+ int sbB = m_allConstraintPtrArray[row__]->m_solverBodyIdB;
+ // btRigidBody* orgBodyA = m_tmpSolverBodyPool[sbA].m_originalBody;
+ btRigidBody* orgBodyB = m_tmpSolverBodyPool[sbB].m_originalBody;
+
+ const unsigned int infom = row__ < m_tmpSolverNonContactConstraintPool.size() ? m_tmpConstraintSizesPool[jj].m_numConstraintRows : numContactRows;
+
+ const btScalar* JinvMrow = JinvM + 2 * 8 * (size_t)row__;
+ const btScalar* Jrow = Jptr + 2 * 8 * (size_t)row__;
+ m_A.multiply2_p8r(JinvMrow, Jrow, infom, infom, row__, row__);
+ if (orgBodyB)
+ {
+ m_A.multiplyAdd2_p8r(JinvMrow + 8 * (size_t)infom, Jrow + 8 * (size_t)infom, infom, infom, row__, row__);
+ }
+ row__ += infom;
+ jj++;
+ }
+ }
+ }
+
+ if (1)
+ {
+ // add cfm to the diagonal of m_A
+ for (int i = 0; i < m_A.rows(); ++i)
+ {
+ m_A.setElem(i, i, m_A(i, i) + infoGlobal.m_globalCfm / infoGlobal.m_timeStep);
+ }
+ }
+
+ ///fill the upper triangle of the matrix, to make it symmetric
+ {
+ BT_PROFILE("fill the upper triangle ");
+ m_A.copyLowerToUpperTriangle();
+ }
+
+ {
+ BT_PROFILE("resize/init x");
+ m_x.resize(numConstraintRows);
+ m_xSplit.resize(numConstraintRows);
+
+ if (infoGlobal.m_solverMode & SOLVER_USE_WARMSTARTING)
+ {
+ for (int i = 0; i < m_allConstraintPtrArray.size(); i++)
+ {
+ const btSolverConstraint& c = *m_allConstraintPtrArray[i];
+ m_x[i] = c.m_appliedImpulse;
+ m_xSplit[i] = c.m_appliedPushImpulse;
+ }
+ }
+ else
+ {
+ m_x.setZero();
+ m_xSplit.setZero();
+ }
+ }
+}
+
+void btMultiBodyMLCPConstraintSolver::createMLCPFastMultiBody(const btContactSolverInfo& infoGlobal)
+{
+ const int multiBodyNumConstraints = m_multiBodyAllConstraintPtrArray.size();
+
+ if (multiBodyNumConstraints == 0)
+ return;
+
+ // 1. Compute b
+ {
+ BT_PROFILE("init b (rhs)");
+
+ m_multiBodyB.resize(multiBodyNumConstraints);
+ m_multiBodyB.setZero();
+
+ for (int i = 0; i < multiBodyNumConstraints; ++i)
+ {
+ const btMultiBodySolverConstraint& constraint = *m_multiBodyAllConstraintPtrArray[i];
+ const btScalar jacDiag = constraint.m_jacDiagABInv;
+
+ if (!btFuzzyZero(jacDiag))
+ {
+ // Note that rhsPenetration is currently always zero because the split impulse hasn't been implemented for multibody yet.
+ const btScalar rhs = constraint.m_rhs;
+ m_multiBodyB[i] = rhs / jacDiag;
+ }
+ }
+ }
+
+ // 2. Compute lo and hi
+ {
+ BT_PROFILE("init lo/ho");
+
+ m_multiBodyLo.resize(multiBodyNumConstraints);
+ m_multiBodyHi.resize(multiBodyNumConstraints);
+
+ for (int i = 0; i < multiBodyNumConstraints; ++i)
+ {
+ const btMultiBodySolverConstraint& constraint = *m_multiBodyAllConstraintPtrArray[i];
+ m_multiBodyLo[i] = constraint.m_lowerLimit;
+ m_multiBodyHi[i] = constraint.m_upperLimit;
+ }
+ }
+
+ // 3. Construct A matrix by using the impulse testing
+ {
+ BT_PROFILE("Compute A");
+
+ {
+ BT_PROFILE("m_A.resize");
+ m_multiBodyA.resize(multiBodyNumConstraints, multiBodyNumConstraints);
+ }
+
+ for (int i = 0; i < multiBodyNumConstraints; ++i)
+ {
+ // Compute the diagonal of A, which is A(i, i)
+ const btMultiBodySolverConstraint& constraint = *m_multiBodyAllConstraintPtrArray[i];
+ const btScalar diagA = computeConstraintMatrixDiagElementMultiBody(m_tmpSolverBodyPool, m_data, constraint);
+ m_multiBodyA.setElem(i, i, diagA);
+
+ // Computes the off-diagonals of A:
+ // a. The rest of i-th row of A, from A(i, i+1) to A(i, n)
+ // b. The rest of i-th column of A, from A(i+1, i) to A(n, i)
+ for (int j = i + 1; j < multiBodyNumConstraints; ++j)
+ {
+ const btMultiBodySolverConstraint& offDiagConstraint = *m_multiBodyAllConstraintPtrArray[j];
+ const btScalar offDiagA = computeConstraintMatrixOffDiagElementMultiBody(m_tmpSolverBodyPool, m_data, constraint, offDiagConstraint);
+
+ // Set the off-diagonal values of A. Note that A is symmetric.
+ m_multiBodyA.setElem(i, j, offDiagA);
+ m_multiBodyA.setElem(j, i, offDiagA);
+ }
+ }
+ }
+
+ // Add CFM to the diagonal of m_A
+ for (int i = 0; i < m_multiBodyA.rows(); ++i)
+ {
+ m_multiBodyA.setElem(i, i, m_multiBodyA(i, i) + infoGlobal.m_globalCfm / infoGlobal.m_timeStep);
+ }
+
+ // 4. Initialize x
+ {
+ BT_PROFILE("resize/init x");
+
+ m_multiBodyX.resize(multiBodyNumConstraints);
+
+ if (infoGlobal.m_solverMode & SOLVER_USE_WARMSTARTING)
+ {
+ for (int i = 0; i < multiBodyNumConstraints; ++i)
+ {
+ const btMultiBodySolverConstraint& constraint = *m_multiBodyAllConstraintPtrArray[i];
+ m_multiBodyX[i] = constraint.m_appliedImpulse;
+ }
+ }
+ else
+ {
+ m_multiBodyX.setZero();
+ }
+ }
+}
+
+bool btMultiBodyMLCPConstraintSolver::solveMLCP(const btContactSolverInfo& infoGlobal)
+{
+ bool result = true;
+
+ if (m_A.rows() != 0)
+ {
+ // If using split impulse, we solve 2 separate (M)LCPs
+ if (infoGlobal.m_splitImpulse)
+ {
+ const btMatrixXu Acopy = m_A;
+ const btAlignedObjectArray<int> limitDependenciesCopy = m_limitDependencies;
+ // TODO(JS): Do we really need these copies when solveMLCP takes them as const?
+
+ result = m_solver->solveMLCP(m_A, m_b, m_x, m_lo, m_hi, m_limitDependencies, infoGlobal.m_numIterations);
+ if (result)
+ result = m_solver->solveMLCP(Acopy, m_bSplit, m_xSplit, m_lo, m_hi, limitDependenciesCopy, infoGlobal.m_numIterations);
+ }
+ else
+ {
+ result = m_solver->solveMLCP(m_A, m_b, m_x, m_lo, m_hi, m_limitDependencies, infoGlobal.m_numIterations);
+ }
+ }
+
+ if (!result)
+ return false;
+
+ if (m_multiBodyA.rows() != 0)
+ {
+ result = m_solver->solveMLCP(m_multiBodyA, m_multiBodyB, m_multiBodyX, m_multiBodyLo, m_multiBodyHi, m_multiBodyLimitDependencies, infoGlobal.m_numIterations);
+ }
+
+ return result;
+}
+
+btScalar btMultiBodyMLCPConstraintSolver::solveGroupCacheFriendlySetup(
+ btCollisionObject** bodies,
+ int numBodies,
+ btPersistentManifold** manifoldPtr,
+ int numManifolds,
+ btTypedConstraint** constraints,
+ int numConstraints,
+ const btContactSolverInfo& infoGlobal,
+ btIDebugDraw* debugDrawer)
+{
+ // 1. Setup for rigid-bodies
+ btMultiBodyConstraintSolver::solveGroupCacheFriendlySetup(
+ bodies, numBodies, manifoldPtr, numManifolds, constraints, numConstraints, infoGlobal, debugDrawer);
+
+ // 2. Setup for multi-bodies
+ // a. Collect all different kinds of constraint as pointers into one array, m_allConstraintPtrArray
+ // b. Set the index array for frictional contact constraints, m_limitDependencies
+ {
+ BT_PROFILE("gather constraint data");
+
+ int dindex = 0;
+
+ const int numRigidBodyConstraints = m_tmpSolverNonContactConstraintPool.size() + m_tmpSolverContactConstraintPool.size() + m_tmpSolverContactFrictionConstraintPool.size();
+ const int numMultiBodyConstraints = m_multiBodyNonContactConstraints.size() + m_multiBodyNormalContactConstraints.size() + m_multiBodyFrictionContactConstraints.size();
+
+ m_allConstraintPtrArray.resize(0);
+ m_multiBodyAllConstraintPtrArray.resize(0);
+
+ // i. Setup for rigid bodies
+
+ m_limitDependencies.resize(numRigidBodyConstraints);
+
+ for (int i = 0; i < m_tmpSolverNonContactConstraintPool.size(); ++i)
+ {
+ m_allConstraintPtrArray.push_back(&m_tmpSolverNonContactConstraintPool[i]);
+ m_limitDependencies[dindex++] = -1;
+ }
+
+ int firstContactConstraintOffset = dindex;
+
+ // The btSequentialImpulseConstraintSolver moves all friction constraints at the very end, we can also interleave them instead
+ if (interleaveContactAndFriction)
+ {
+ for (int i = 0; i < m_tmpSolverContactConstraintPool.size(); i++)
+ {
+ const int numFrictionPerContact = m_tmpSolverContactConstraintPool.size() == m_tmpSolverContactFrictionConstraintPool.size() ? 1 : 2;
+
+ m_allConstraintPtrArray.push_back(&m_tmpSolverContactConstraintPool[i]);
+ m_limitDependencies[dindex++] = -1;
+ m_allConstraintPtrArray.push_back(&m_tmpSolverContactFrictionConstraintPool[i * numFrictionPerContact]);
+ int findex = (m_tmpSolverContactFrictionConstraintPool[i * numFrictionPerContact].m_frictionIndex * (1 + numFrictionPerContact));
+ m_limitDependencies[dindex++] = findex + firstContactConstraintOffset;
+ if (numFrictionPerContact == 2)
+ {
+ m_allConstraintPtrArray.push_back(&m_tmpSolverContactFrictionConstraintPool[i * numFrictionPerContact + 1]);
+ m_limitDependencies[dindex++] = findex + firstContactConstraintOffset;
+ }
+ }
+ }
+ else
+ {
+ for (int i = 0; i < m_tmpSolverContactConstraintPool.size(); i++)
+ {
+ m_allConstraintPtrArray.push_back(&m_tmpSolverContactConstraintPool[i]);
+ m_limitDependencies[dindex++] = -1;
+ }
+ for (int i = 0; i < m_tmpSolverContactFrictionConstraintPool.size(); i++)
+ {
+ m_allConstraintPtrArray.push_back(&m_tmpSolverContactFrictionConstraintPool[i]);
+ m_limitDependencies[dindex++] = m_tmpSolverContactFrictionConstraintPool[i].m_frictionIndex + firstContactConstraintOffset;
+ }
+ }
+
+ if (!m_allConstraintPtrArray.size())
+ {
+ m_A.resize(0, 0);
+ m_b.resize(0);
+ m_x.resize(0);
+ m_lo.resize(0);
+ m_hi.resize(0);
+ }
+
+ // ii. Setup for multibodies
+
+ dindex = 0;
+
+ m_multiBodyLimitDependencies.resize(numMultiBodyConstraints);
+
+ for (int i = 0; i < m_multiBodyNonContactConstraints.size(); ++i)
+ {
+ m_multiBodyAllConstraintPtrArray.push_back(&m_multiBodyNonContactConstraints[i]);
+ m_multiBodyLimitDependencies[dindex++] = -1;
+ }
+
+ firstContactConstraintOffset = dindex;
+
+ // The btSequentialImpulseConstraintSolver moves all friction constraints at the very end, we can also interleave them instead
+ if (interleaveContactAndFriction)
+ {
+ for (int i = 0; i < m_multiBodyNormalContactConstraints.size(); ++i)
+ {
+ const int numtiBodyNumFrictionPerContact = m_multiBodyNormalContactConstraints.size() == m_multiBodyFrictionContactConstraints.size() ? 1 : 2;
+
+ m_multiBodyAllConstraintPtrArray.push_back(&m_multiBodyNormalContactConstraints[i]);
+ m_multiBodyLimitDependencies[dindex++] = -1;
+
+ btMultiBodySolverConstraint& frictionContactConstraint1 = m_multiBodyFrictionContactConstraints[i * numtiBodyNumFrictionPerContact];
+ m_multiBodyAllConstraintPtrArray.push_back(&frictionContactConstraint1);
+
+ const int findex = (frictionContactConstraint1.m_frictionIndex * (1 + numtiBodyNumFrictionPerContact)) + firstContactConstraintOffset;
+
+ m_multiBodyLimitDependencies[dindex++] = findex;
+
+ if (numtiBodyNumFrictionPerContact == 2)
+ {
+ btMultiBodySolverConstraint& frictionContactConstraint2 = m_multiBodyFrictionContactConstraints[i * numtiBodyNumFrictionPerContact + 1];
+ m_multiBodyAllConstraintPtrArray.push_back(&frictionContactConstraint2);
+
+ m_multiBodyLimitDependencies[dindex++] = findex;
+ }
+ }
+ }
+ else
+ {
+ for (int i = 0; i < m_multiBodyNormalContactConstraints.size(); ++i)
+ {
+ m_multiBodyAllConstraintPtrArray.push_back(&m_multiBodyNormalContactConstraints[i]);
+ m_multiBodyLimitDependencies[dindex++] = -1;
+ }
+ for (int i = 0; i < m_multiBodyFrictionContactConstraints.size(); ++i)
+ {
+ m_multiBodyAllConstraintPtrArray.push_back(&m_multiBodyFrictionContactConstraints[i]);
+ m_multiBodyLimitDependencies[dindex++] = m_multiBodyFrictionContactConstraints[i].m_frictionIndex + firstContactConstraintOffset;
+ }
+ }
+
+ if (!m_multiBodyAllConstraintPtrArray.size())
+ {
+ m_multiBodyA.resize(0, 0);
+ m_multiBodyB.resize(0);
+ m_multiBodyX.resize(0);
+ m_multiBodyLo.resize(0);
+ m_multiBodyHi.resize(0);
+ }
+ }
+
+ // Construct MLCP terms
+ {
+ BT_PROFILE("createMLCPFast");
+ createMLCPFast(infoGlobal);
+ }
+
+ return btScalar(0);
+}
+
+btScalar btMultiBodyMLCPConstraintSolver::solveGroupCacheFriendlyIterations(btCollisionObject** bodies, int numBodies, btPersistentManifold** manifoldPtr, int numManifolds, btTypedConstraint** constraints, int numConstraints, const btContactSolverInfo& infoGlobal, btIDebugDraw* debugDrawer)
+{
+ bool result = true;
+ {
+ BT_PROFILE("solveMLCP");
+ result = solveMLCP(infoGlobal);
+ }
+
+ // Fallback to btSequentialImpulseConstraintSolver::solveGroupCacheFriendlyIterations if the solution isn't valid.
+ if (!result)
+ {
+ m_fallback++;
+ return btMultiBodyConstraintSolver::solveGroupCacheFriendlyIterations(bodies, numBodies, manifoldPtr, numManifolds, constraints, numConstraints, infoGlobal, debugDrawer);
+ }
+
+ {
+ BT_PROFILE("process MLCP results");
+
+ for (int i = 0; i < m_allConstraintPtrArray.size(); ++i)
+ {
+ const btSolverConstraint& c = *m_allConstraintPtrArray[i];
+
+ const btScalar deltaImpulse = m_x[i] - c.m_appliedImpulse;
+ c.m_appliedImpulse = m_x[i];
+
+ int sbA = c.m_solverBodyIdA;
+ int sbB = c.m_solverBodyIdB;
+
+ btSolverBody& solverBodyA = m_tmpSolverBodyPool[sbA];
+ btSolverBody& solverBodyB = m_tmpSolverBodyPool[sbB];
+
+ solverBodyA.internalApplyImpulse(c.m_contactNormal1 * solverBodyA.internalGetInvMass(), c.m_angularComponentA, deltaImpulse);
+ solverBodyB.internalApplyImpulse(c.m_contactNormal2 * solverBodyB.internalGetInvMass(), c.m_angularComponentB, deltaImpulse);
+
+ if (infoGlobal.m_splitImpulse)
+ {
+ const btScalar deltaPushImpulse = m_xSplit[i] - c.m_appliedPushImpulse;
+ solverBodyA.internalApplyPushImpulse(c.m_contactNormal1 * solverBodyA.internalGetInvMass(), c.m_angularComponentA, deltaPushImpulse);
+ solverBodyB.internalApplyPushImpulse(c.m_contactNormal2 * solverBodyB.internalGetInvMass(), c.m_angularComponentB, deltaPushImpulse);
+ c.m_appliedPushImpulse = m_xSplit[i];
+ }
+ }
+
+ for (int i = 0; i < m_multiBodyAllConstraintPtrArray.size(); ++i)
+ {
+ btMultiBodySolverConstraint& c = *m_multiBodyAllConstraintPtrArray[i];
+
+ const btScalar deltaImpulse = m_multiBodyX[i] - c.m_appliedImpulse;
+ c.m_appliedImpulse = m_multiBodyX[i];
+
+ btMultiBody* multiBodyA = c.m_multiBodyA;
+ if (multiBodyA)
+ {
+ const int ndofA = multiBodyA->getNumDofs() + 6;
+ applyDeltaVee(&m_data.m_deltaVelocitiesUnitImpulse[c.m_jacAindex], deltaImpulse, c.m_deltaVelAindex, ndofA);
+#ifdef DIRECTLY_UPDATE_VELOCITY_DURING_SOLVER_ITERATIONS
+ //note: update of the actual velocities (below) in the multibody does not have to happen now since m_deltaVelocities can be applied after all iterations
+ //it would make the multibody solver more like the regular one with m_deltaVelocities being equivalent to btSolverBody::m_deltaLinearVelocity/m_deltaAngularVelocity
+ multiBodyA->applyDeltaVeeMultiDof2(&m_data.m_deltaVelocitiesUnitImpulse[c.m_jacAindex], deltaImpulse);
+#endif // DIRECTLY_UPDATE_VELOCITY_DURING_SOLVER_ITERATIONS
+ }
+ else
+ {
+ const int sbA = c.m_solverBodyIdA;
+ btSolverBody& solverBodyA = m_tmpSolverBodyPool[sbA];
+ solverBodyA.internalApplyImpulse(c.m_contactNormal1 * solverBodyA.internalGetInvMass(), c.m_angularComponentA, deltaImpulse);
+ }
+
+ btMultiBody* multiBodyB = c.m_multiBodyB;
+ if (multiBodyB)
+ {
+ const int ndofB = multiBodyB->getNumDofs() + 6;
+ applyDeltaVee(&m_data.m_deltaVelocitiesUnitImpulse[c.m_jacBindex], deltaImpulse, c.m_deltaVelBindex, ndofB);
+#ifdef DIRECTLY_UPDATE_VELOCITY_DURING_SOLVER_ITERATIONS
+ //note: update of the actual velocities (below) in the multibody does not have to happen now since m_deltaVelocities can be applied after all iterations
+ //it would make the multibody solver more like the regular one with m_deltaVelocities being equivalent to btSolverBody::m_deltaLinearVelocity/m_deltaAngularVelocity
+ multiBodyB->applyDeltaVeeMultiDof2(&m_data.m_deltaVelocitiesUnitImpulse[c.m_jacBindex], deltaImpulse);
+#endif // DIRECTLY_UPDATE_VELOCITY_DURING_SOLVER_ITERATIONS
+ }
+ else
+ {
+ const int sbB = c.m_solverBodyIdB;
+ btSolverBody& solverBodyB = m_tmpSolverBodyPool[sbB];
+ solverBodyB.internalApplyImpulse(c.m_contactNormal2 * solverBodyB.internalGetInvMass(), c.m_angularComponentB, deltaImpulse);
+ }
+ }
+ }
+
+ return btScalar(0);
+}
+
+btMultiBodyMLCPConstraintSolver::btMultiBodyMLCPConstraintSolver(btMLCPSolverInterface* solver)
+ : m_solver(solver), m_fallback(0)
+{
+ // Do nothing
+}
+
+btMultiBodyMLCPConstraintSolver::~btMultiBodyMLCPConstraintSolver()
+{
+ // Do nothing
+}
+
+void btMultiBodyMLCPConstraintSolver::setMLCPSolver(btMLCPSolverInterface* solver)
+{
+ m_solver = solver;
+}
+
+int btMultiBodyMLCPConstraintSolver::getNumFallbacks() const
+{
+ return m_fallback;
+}
+
+void btMultiBodyMLCPConstraintSolver::setNumFallbacks(int num)
+{
+ m_fallback = num;
+}
+
+btConstraintSolverType btMultiBodyMLCPConstraintSolver::getSolverType() const
+{
+ return BT_MLCP_SOLVER;
+}
diff --git a/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyMLCPConstraintSolver.h b/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyMLCPConstraintSolver.h
new file mode 100644
index 0000000000..6be36ba142
--- /dev/null
+++ b/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyMLCPConstraintSolver.h
@@ -0,0 +1,187 @@
+/*
+Bullet Continuous Collision Detection and Physics Library
+Copyright (c) 2018 Google 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.
+*/
+
+#ifndef BT_MULTIBODY_MLCP_CONSTRAINT_SOLVER_H
+#define BT_MULTIBODY_MLCP_CONSTRAINT_SOLVER_H
+
+#include "LinearMath/btMatrixX.h"
+#include "LinearMath/btThreads.h"
+#include "BulletDynamics/Featherstone/btMultiBodyConstraintSolver.h"
+
+class btMLCPSolverInterface;
+class btMultiBody;
+
+class btMultiBodyMLCPConstraintSolver : public btMultiBodyConstraintSolver
+{
+protected:
+ /// \name MLCP Formulation for Rigid Bodies
+ /// \{
+
+ /// A matrix in the MLCP formulation
+ btMatrixXu m_A;
+
+ /// b vector in the MLCP formulation.
+ btVectorXu m_b;
+
+ /// Constraint impulse, which is an output of MLCP solving.
+ btVectorXu m_x;
+
+ /// Lower bound of constraint impulse, \c m_x.
+ btVectorXu m_lo;
+
+ /// Upper bound of constraint impulse, \c m_x.
+ btVectorXu m_hi;
+
+ /// \}
+
+ /// \name Cache Variables for Split Impulse for Rigid Bodies
+ /// When using 'split impulse' we solve two separate (M)LCPs
+ /// \{
+
+ /// Split impulse Cache vector corresponding to \c m_b.
+ btVectorXu m_bSplit;
+
+ /// Split impulse cache vector corresponding to \c m_x.
+ btVectorXu m_xSplit;
+
+ /// \}
+
+ /// \name MLCP Formulation for Multibodies
+ /// \{
+
+ /// A matrix in the MLCP formulation
+ btMatrixXu m_multiBodyA;
+
+ /// b vector in the MLCP formulation.
+ btVectorXu m_multiBodyB;
+
+ /// Constraint impulse, which is an output of MLCP solving.
+ btVectorXu m_multiBodyX;
+
+ /// Lower bound of constraint impulse, \c m_x.
+ btVectorXu m_multiBodyLo;
+
+ /// Upper bound of constraint impulse, \c m_x.
+ btVectorXu m_multiBodyHi;
+
+ /// \}
+
+ /// Indices of normal contact constraint associated with frictional contact constraint for rigid bodies.
+ ///
+ /// This is used by the MLCP solver to update the upper bounds of frictional contact impulse given intermediate
+ /// normal contact impulse. For example, i-th element represents the index of a normal constraint that is
+ /// accosiated with i-th frictional contact constraint if i-th constraint is a frictional contact constraint.
+ /// Otherwise, -1.
+ btAlignedObjectArray<int> m_limitDependencies;
+
+ /// Indices of normal contact constraint associated with frictional contact constraint for multibodies.
+ ///
+ /// This is used by the MLCP solver to update the upper bounds of frictional contact impulse given intermediate
+ /// normal contact impulse. For example, i-th element represents the index of a normal constraint that is
+ /// accosiated with i-th frictional contact constraint if i-th constraint is a frictional contact constraint.
+ /// Otherwise, -1.
+ btAlignedObjectArray<int> m_multiBodyLimitDependencies;
+
+ /// Array of all the rigid body constraints
+ btAlignedObjectArray<btSolverConstraint*> m_allConstraintPtrArray;
+
+ /// Array of all the multibody constraints
+ btAlignedObjectArray<btMultiBodySolverConstraint*> m_multiBodyAllConstraintPtrArray;
+
+ /// MLCP solver
+ btMLCPSolverInterface* m_solver;
+
+ /// Count of fallbacks of using btSequentialImpulseConstraintSolver, which happens when the MLCP solver fails.
+ int m_fallback;
+
+ /// \name MLCP Scratch Variables
+ /// The following scratch variables are not stateful -- contents are cleared prior to each use.
+ /// They are only cached here to avoid extra memory allocations and deallocations and to ensure
+ /// that multiple instances of the solver can be run in parallel.
+ ///
+ /// \{
+
+ /// Cache variable for constraint Jacobian matrix.
+ btMatrixXu m_scratchJ3;
+
+ /// Cache variable for constraint Jacobian times inverse mass matrix.
+ btMatrixXu m_scratchJInvM3;
+
+ /// Cache variable for offsets.
+ btAlignedObjectArray<int> m_scratchOfs;
+
+ /// \}
+
+ /// Constructs MLCP terms, which are \c m_A, \c m_b, \c m_lo, and \c m_hi.
+ virtual void createMLCPFast(const btContactSolverInfo& infoGlobal);
+
+ /// Constructs MLCP terms for constraints of two rigid bodies
+ void createMLCPFastRigidBody(const btContactSolverInfo& infoGlobal);
+
+ /// Constructs MLCP terms for constraints of two multi-bodies or one rigid body and one multibody
+ void createMLCPFastMultiBody(const btContactSolverInfo& infoGlobal);
+
+ /// Solves MLCP and returns the success
+ virtual bool solveMLCP(const btContactSolverInfo& infoGlobal);
+
+ // Documentation inherited
+ btScalar solveGroupCacheFriendlySetup(
+ btCollisionObject** bodies,
+ int numBodies,
+ btPersistentManifold** manifoldPtr,
+ int numManifolds,
+ btTypedConstraint** constraints,
+ int numConstraints,
+ const btContactSolverInfo& infoGlobal,
+ btIDebugDraw* debugDrawer) BT_OVERRIDE;
+
+ // Documentation inherited
+ btScalar solveGroupCacheFriendlyIterations(
+ btCollisionObject** bodies,
+ int numBodies,
+ btPersistentManifold** manifoldPtr,
+ int numManifolds,
+ btTypedConstraint** constraints,
+ int numConstraints,
+ const btContactSolverInfo& infoGlobal,
+ btIDebugDraw* debugDrawer) BT_OVERRIDE;
+
+public:
+ BT_DECLARE_ALIGNED_ALLOCATOR()
+
+ /// Constructor
+ ///
+ /// \param[in] solver MLCP solver. Assumed it's not null.
+ /// \param[in] maxLCPSize Maximum size of LCP to solve using MLCP solver. If the MLCP size exceeds this number, sequaltial impulse method will be used.
+ explicit btMultiBodyMLCPConstraintSolver(btMLCPSolverInterface* solver);
+
+ /// Destructor
+ virtual ~btMultiBodyMLCPConstraintSolver();
+
+ /// Sets MLCP solver. Assumed it's not null.
+ void setMLCPSolver(btMLCPSolverInterface* solver);
+
+ /// Returns the number of fallbacks of using btSequentialImpulseConstraintSolver, which happens when the MLCP
+ /// solver fails.
+ int getNumFallbacks() const;
+
+ /// Sets the number of fallbacks. This function may be used to reset the number to zero.
+ void setNumFallbacks(int num);
+
+ /// Returns the constraint solver type.
+ virtual btConstraintSolverType getSolverType() const;
+};
+
+#endif // BT_MULTIBODY_MLCP_CONSTRAINT_SOLVER_H
diff --git a/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyPoint2Point.cpp b/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyPoint2Point.cpp
index 125d52ad0b..2b59f0b7a6 100644
--- a/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyPoint2Point.cpp
+++ b/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyPoint2Point.cpp
@@ -64,13 +64,16 @@ int btMultiBodyPoint2Point::getIslandIdA() const
if (m_bodyA)
{
- btMultiBodyLinkCollider* col = m_bodyA->getBaseCollider();
- if (col)
- return col->getIslandTag();
- for (int i=0;i<m_bodyA->getNumLinks();i++)
+ if (m_linkA < 0)
{
- if (m_bodyA->getLink(i).m_collider)
- return m_bodyA->getLink(i).m_collider->getIslandTag();
+ btMultiBodyLinkCollider* col = m_bodyA->getBaseCollider();
+ if (col)
+ return col->getIslandTag();
+ }
+ else
+ {
+ if (m_bodyA->getLink(m_linkA).m_collider)
+ return m_bodyA->getLink(m_linkA).m_collider->getIslandTag();
}
}
return -1;
@@ -82,16 +85,17 @@ int btMultiBodyPoint2Point::getIslandIdB() const
return m_rigidBodyB->getIslandTag();
if (m_bodyB)
{
- btMultiBodyLinkCollider* col = m_bodyB->getBaseCollider();
- if (col)
- return col->getIslandTag();
-
- for (int i=0;i<m_bodyB->getNumLinks();i++)
+ if (m_linkB < 0)
{
- col = m_bodyB->getLink(i).m_collider;
+ btMultiBodyLinkCollider* col = m_bodyB->getBaseCollider();
if (col)
return col->getIslandTag();
}
+ else
+ {
+ if (m_bodyB->getLink(m_linkB).m_collider)
+ return m_bodyB->getLink(m_linkB).m_collider->getIslandTag();
+ }
}
return -1;
}
diff --git a/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodySliderConstraint.cpp b/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodySliderConstraint.cpp
index 3b64b8183f..43f26f9833 100644
--- a/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodySliderConstraint.cpp
+++ b/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodySliderConstraint.cpp
@@ -68,13 +68,16 @@ int btMultiBodySliderConstraint::getIslandIdA() const
if (m_bodyA)
{
- btMultiBodyLinkCollider* col = m_bodyA->getBaseCollider();
- if (col)
- return col->getIslandTag();
- for (int i=0;i<m_bodyA->getNumLinks();i++)
+ if (m_linkA < 0)
{
- if (m_bodyA->getLink(i).m_collider)
- return m_bodyA->getLink(i).m_collider->getIslandTag();
+ btMultiBodyLinkCollider* col = m_bodyA->getBaseCollider();
+ if (col)
+ return col->getIslandTag();
+ }
+ else
+ {
+ if (m_bodyA->getLink(m_linkA).m_collider)
+ return m_bodyA->getLink(m_linkA).m_collider->getIslandTag();
}
}
return -1;
@@ -86,20 +89,20 @@ int btMultiBodySliderConstraint::getIslandIdB() const
return m_rigidBodyB->getIslandTag();
if (m_bodyB)
{
- btMultiBodyLinkCollider* col = m_bodyB->getBaseCollider();
- if (col)
- return col->getIslandTag();
-
- for (int i=0;i<m_bodyB->getNumLinks();i++)
+ if (m_linkB < 0)
{
- col = m_bodyB->getLink(i).m_collider;
+ btMultiBodyLinkCollider* col = m_bodyB->getBaseCollider();
if (col)
return col->getIslandTag();
}
+ else
+ {
+ if (m_bodyB->getLink(m_linkB).m_collider)
+ return m_bodyB->getLink(m_linkB).m_collider->getIslandTag();
+ }
}
return -1;
}
-
void btMultiBodySliderConstraint::createConstraintRows(btMultiBodyConstraintArray& constraintRows, btMultiBodyJacobianData& data, const btContactSolverInfo& infoGlobal)
{
// Convert local points back to world
diff --git a/thirdparty/bullet/BulletDynamics/Vehicle/btRaycastVehicle.cpp b/thirdparty/bullet/BulletDynamics/Vehicle/btRaycastVehicle.cpp
index a7b1688469..f299aa34e8 100644
--- a/thirdparty/bullet/BulletDynamics/Vehicle/btRaycastVehicle.cpp
+++ b/thirdparty/bullet/BulletDynamics/Vehicle/btRaycastVehicle.cpp
@@ -121,12 +121,19 @@ void btRaycastVehicle::updateWheelTransform( int wheelIndex , bool interpolatedT
btQuaternion rotatingOrn(right,-wheel.m_rotation);
btMatrix3x3 rotatingMat(rotatingOrn);
- btMatrix3x3 basis2(
- right[0],fwd[0],up[0],
- right[1],fwd[1],up[1],
- right[2],fwd[2],up[2]
- );
-
+ btMatrix3x3 basis2;
+ basis2[0][m_indexRightAxis] = -right[0];
+ basis2[1][m_indexRightAxis] = -right[1];
+ basis2[2][m_indexRightAxis] = -right[2];
+
+ basis2[0][m_indexUpAxis] = up[0];
+ basis2[1][m_indexUpAxis] = up[1];
+ basis2[2][m_indexUpAxis] = up[2];
+
+ basis2[0][m_indexForwardAxis] = fwd[0];
+ basis2[1][m_indexForwardAxis] = fwd[1];
+ basis2[2][m_indexForwardAxis] = fwd[2];
+
wheel.m_worldTransform.setBasis(steeringMat * rotatingMat * basis2);
wheel.m_worldTransform.setOrigin(
wheel.m_raycastInfo.m_hardPointWS + wheel.m_raycastInfo.m_wheelDirectionWS * wheel.m_raycastInfo.m_suspensionLength
@@ -493,8 +500,8 @@ struct btWheelContactPoint
};
-btScalar calcRollingFriction(btWheelContactPoint& contactPoint);
-btScalar calcRollingFriction(btWheelContactPoint& contactPoint)
+btScalar calcRollingFriction(btWheelContactPoint& contactPoint, int numWheelsOnGround);
+btScalar calcRollingFriction(btWheelContactPoint& contactPoint, int numWheelsOnGround)
{
btScalar j1=0.f;
@@ -513,7 +520,7 @@ btScalar calcRollingFriction(btWheelContactPoint& contactPoint)
btScalar vrel = contactPoint.m_frictionDirectionWorld.dot(vel);
// calculate j that moves us to zero relative velocity
- j1 = -vrel * contactPoint.m_jacDiagABInv;
+ j1 = -vrel * contactPoint.m_jacDiagABInv/btScalar(numWheelsOnGround);
btSetMin(j1, maxImpulse);
btSetMax(j1, -maxImpulse);
@@ -567,7 +574,7 @@ void btRaycastVehicle::updateFriction(btScalar timeStep)
const btTransform& wheelTrans = getWheelTransformWS( i );
btMatrix3x3 wheelBasis0 = wheelTrans.getBasis();
- m_axle[i] = btVector3(
+ m_axle[i] = -btVector3(
wheelBasis0[0][m_indexRightAxis],
wheelBasis0[1][m_indexRightAxis],
wheelBasis0[2][m_indexRightAxis]);
@@ -615,7 +622,8 @@ void btRaycastVehicle::updateFriction(btScalar timeStep)
btScalar defaultRollingFrictionImpulse = 0.f;
btScalar maxImpulse = wheelInfo.m_brake ? wheelInfo.m_brake : defaultRollingFrictionImpulse;
btWheelContactPoint contactPt(m_chassisBody,groundObject,wheelInfo.m_raycastInfo.m_contactPointWS,m_forwardWS[wheel],maxImpulse);
- rollingFriction = calcRollingFriction(contactPt);
+ btAssert(numWheelsOnGround > 0);
+ rollingFriction = calcRollingFriction(contactPt, numWheelsOnGround);
}
}
diff --git a/thirdparty/bullet/BulletInverseDynamics/IDErrorMessages.hpp b/thirdparty/bullet/BulletInverseDynamics/IDErrorMessages.hpp
index 1dc22f860a..1b3fd268a0 100644
--- a/thirdparty/bullet/BulletInverseDynamics/IDErrorMessages.hpp
+++ b/thirdparty/bullet/BulletInverseDynamics/IDErrorMessages.hpp
@@ -7,19 +7,19 @@
#if !defined(BT_ID_WO_BULLET) && !defined(BT_USE_INVERSE_DYNAMICS_WITH_BULLET2)
#include "Bullet3Common/b3Logging.h"
-#define error_message(...) b3Error(__VA_ARGS__)
-#define warning_message(...) b3Warning(__VA_ARGS__)
+#define bt_id_error_message(...) b3Error(__VA_ARGS__)
+#define bt_id_warning_message(...) b3Warning(__VA_ARGS__)
#define id_printf(...) b3Printf(__VA_ARGS__)
#else // BT_ID_WO_BULLET
#include <cstdio>
/// print error message with file/line information
-#define error_message(...) \
+#define bt_id_error_message(...) \
do { \
fprintf(stderr, "[Error:%s:%d] ", __INVDYN_FILE_WO_DIR__, __LINE__); \
fprintf(stderr, __VA_ARGS__); \
} while (0)
/// print warning message with file/line information
-#define warning_message(...) \
+#define bt_id_warning_message(...) \
do { \
fprintf(stderr, "[Warning:%s:%d] ", __INVDYN_FILE_WO_DIR__, __LINE__); \
fprintf(stderr, __VA_ARGS__); \
diff --git a/thirdparty/bullet/BulletInverseDynamics/IDMath.cpp b/thirdparty/bullet/BulletInverseDynamics/IDMath.cpp
index 99fe20e492..d279d3435c 100644
--- a/thirdparty/bullet/BulletInverseDynamics/IDMath.cpp
+++ b/thirdparty/bullet/BulletInverseDynamics/IDMath.cpp
@@ -81,7 +81,7 @@ idScalar maxAbsMat3x(const mat3x &m) {
void mul(const mat33 &a, const mat3x &b, mat3x *result) {
if (b.cols() != result->cols()) {
- error_message("size missmatch. b.cols()= %d, result->cols()= %d\n",
+ bt_id_error_message("size missmatch. b.cols()= %d, result->cols()= %d\n",
static_cast<int>(b.cols()), static_cast<int>(result->cols()));
abort();
}
@@ -97,7 +97,7 @@ void mul(const mat33 &a, const mat3x &b, mat3x *result) {
}
void add(const mat3x &a, const mat3x &b, mat3x *result) {
if (a.cols() != b.cols()) {
- error_message("size missmatch. a.cols()= %d, b.cols()= %d\n",
+ bt_id_error_message("size missmatch. a.cols()= %d, b.cols()= %d\n",
static_cast<int>(a.cols()), static_cast<int>(b.cols()));
abort();
}
@@ -109,7 +109,7 @@ void add(const mat3x &a, const mat3x &b, mat3x *result) {
}
void sub(const mat3x &a, const mat3x &b, mat3x *result) {
if (a.cols() != b.cols()) {
- error_message("size missmatch. a.cols()= %d, b.cols()= %d\n",
+ bt_id_error_message("size missmatch. a.cols()= %d, b.cols()= %d\n",
static_cast<int>(a.cols()), static_cast<int>(b.cols()));
abort();
}
@@ -305,10 +305,10 @@ bool isValidInertiaMatrix(const mat33 &I, const int index, bool has_fixed_joint)
// the determinant of the inertia tensor about the joint axis is almost
// zero and can have a very small negative value.
if (!isPositiveSemiDefiniteFuzzy(I)) {
- error_message("invalid inertia matrix for body %d, not positive definite "
+ bt_id_error_message("invalid inertia matrix for body %d, not positive definite "
"(fixed joint)\n",
index);
- error_message("matrix is:\n"
+ bt_id_error_message("matrix is:\n"
"[%.20e %.20e %.20e;\n"
"%.20e %.20e %.20e;\n"
"%.20e %.20e %.20e]\n",
@@ -321,8 +321,8 @@ bool isValidInertiaMatrix(const mat33 &I, const int index, bool has_fixed_joint)
// check triangle inequality, must have I(i,i)+I(j,j)>=I(k,k)
if (!has_fixed_joint) {
if (I(0, 0) + I(1, 1) < I(2, 2)) {
- error_message("invalid inertia tensor for body %d, I(0,0) + I(1,1) < I(2,2)\n", index);
- error_message("matrix is:\n"
+ bt_id_error_message("invalid inertia tensor for body %d, I(0,0) + I(1,1) < I(2,2)\n", index);
+ bt_id_error_message("matrix is:\n"
"[%.20e %.20e %.20e;\n"
"%.20e %.20e %.20e;\n"
"%.20e %.20e %.20e]\n",
@@ -331,8 +331,8 @@ bool isValidInertiaMatrix(const mat33 &I, const int index, bool has_fixed_joint)
return false;
}
if (I(0, 0) + I(1, 1) < I(2, 2)) {
- error_message("invalid inertia tensor for body %d, I(0,0) + I(1,1) < I(2,2)\n", index);
- error_message("matrix is:\n"
+ bt_id_error_message("invalid inertia tensor for body %d, I(0,0) + I(1,1) < I(2,2)\n", index);
+ bt_id_error_message("matrix is:\n"
"[%.20e %.20e %.20e;\n"
"%.20e %.20e %.20e;\n"
"%.20e %.20e %.20e]\n",
@@ -341,8 +341,8 @@ bool isValidInertiaMatrix(const mat33 &I, const int index, bool has_fixed_joint)
return false;
}
if (I(1, 1) + I(2, 2) < I(0, 0)) {
- error_message("invalid inertia tensor for body %d, I(1,1) + I(2,2) < I(0,0)\n", index);
- error_message("matrix is:\n"
+ bt_id_error_message("invalid inertia tensor for body %d, I(1,1) + I(2,2) < I(0,0)\n", index);
+ bt_id_error_message("matrix is:\n"
"[%.20e %.20e %.20e;\n"
"%.20e %.20e %.20e;\n"
"%.20e %.20e %.20e]\n",
@@ -354,25 +354,25 @@ bool isValidInertiaMatrix(const mat33 &I, const int index, bool has_fixed_joint)
// check positive/zero diagonal elements
for (int i = 0; i < 3; i++) {
if (I(i, i) < 0) { // accept zero
- error_message("invalid inertia tensor, I(%d,%d)= %e <0\n", i, i, I(i, i));
+ bt_id_error_message("invalid inertia tensor, I(%d,%d)= %e <0\n", i, i, I(i, i));
return false;
}
}
// check symmetry
if (BT_ID_FABS(I(1, 0) - I(0, 1)) > kIsZero) {
- error_message("invalid inertia tensor for body %d I(1,0)!=I(0,1). I(1,0)-I(0,1)= "
+ bt_id_error_message("invalid inertia tensor for body %d I(1,0)!=I(0,1). I(1,0)-I(0,1)= "
"%e\n",
index, I(1, 0) - I(0, 1));
return false;
}
if (BT_ID_FABS(I(2, 0) - I(0, 2)) > kIsZero) {
- error_message("invalid inertia tensor for body %d I(2,0)!=I(0,2). I(2,0)-I(0,2)= "
+ bt_id_error_message("invalid inertia tensor for body %d I(2,0)!=I(0,2). I(2,0)-I(0,2)= "
"%e\n",
index, I(2, 0) - I(0, 2));
return false;
}
if (BT_ID_FABS(I(1, 2) - I(2, 1)) > kIsZero) {
- error_message("invalid inertia tensor body %d I(1,2)!=I(2,1). I(1,2)-I(2,1)= %e\n", index,
+ bt_id_error_message("invalid inertia tensor body %d I(1,2)!=I(2,1). I(1,2)-I(2,1)= %e\n", index,
I(1, 2) - I(2, 1));
return false;
}
@@ -381,7 +381,7 @@ bool isValidInertiaMatrix(const mat33 &I, const int index, bool has_fixed_joint)
bool isValidTransformMatrix(const mat33 &m) {
#define print_mat(x) \
- error_message("matrix is [%e, %e, %e; %e, %e, %e; %e, %e, %e]\n", x(0, 0), x(0, 1), x(0, 2), \
+ bt_id_error_message("matrix is [%e, %e, %e; %e, %e, %e; %e, %e, %e]\n", x(0, 0), x(0, 1), x(0, 2), \
x(1, 0), x(1, 1), x(1, 2), x(2, 0), x(2, 1), x(2, 2))
// check for unit length column vectors
@@ -389,7 +389,7 @@ bool isValidTransformMatrix(const mat33 &m) {
const idScalar length_minus_1 =
BT_ID_FABS(m(0, i) * m(0, i) + m(1, i) * m(1, i) + m(2, i) * m(2, i) - 1.0);
if (length_minus_1 > kAxisLengthEpsilon) {
- error_message("Not a valid rotation matrix (column %d not unit length)\n"
+ bt_id_error_message("Not a valid rotation matrix (column %d not unit length)\n"
"column = [%.18e %.18e %.18e]\n"
"length-1.0= %.18e\n",
i, m(0, i), m(1, i), m(2, i), length_minus_1);
@@ -399,23 +399,23 @@ bool isValidTransformMatrix(const mat33 &m) {
}
// check for orthogonal column vectors
if (BT_ID_FABS(m(0, 0) * m(0, 1) + m(1, 0) * m(1, 1) + m(2, 0) * m(2, 1)) > kAxisLengthEpsilon) {
- error_message("Not a valid rotation matrix (columns 0 and 1 not orthogonal)\n");
+ bt_id_error_message("Not a valid rotation matrix (columns 0 and 1 not orthogonal)\n");
print_mat(m);
return false;
}
if (BT_ID_FABS(m(0, 0) * m(0, 2) + m(1, 0) * m(1, 2) + m(2, 0) * m(2, 2)) > kAxisLengthEpsilon) {
- error_message("Not a valid rotation matrix (columns 0 and 2 not orthogonal)\n");
+ bt_id_error_message("Not a valid rotation matrix (columns 0 and 2 not orthogonal)\n");
print_mat(m);
return false;
}
if (BT_ID_FABS(m(0, 1) * m(0, 2) + m(1, 1) * m(1, 2) + m(2, 1) * m(2, 2)) > kAxisLengthEpsilon) {
- error_message("Not a valid rotation matrix (columns 0 and 2 not orthogonal)\n");
+ bt_id_error_message("Not a valid rotation matrix (columns 0 and 2 not orthogonal)\n");
print_mat(m);
return false;
}
// check determinant (rotation not reflection)
if (determinant(m) <= 0) {
- error_message("Not a valid rotation matrix (determinant <=0)\n");
+ bt_id_error_message("Not a valid rotation matrix (determinant <=0)\n");
print_mat(m);
return false;
}
diff --git a/thirdparty/bullet/BulletInverseDynamics/MultiBodyTree.cpp b/thirdparty/bullet/BulletInverseDynamics/MultiBodyTree.cpp
index c67588d49f..becfe0f4a2 100644
--- a/thirdparty/bullet/BulletInverseDynamics/MultiBodyTree.cpp
+++ b/thirdparty/bullet/BulletInverseDynamics/MultiBodyTree.cpp
@@ -83,11 +83,11 @@ int MultiBodyTree::numDoFs() const { return m_impl->m_num_dofs; }
int MultiBodyTree::calculateInverseDynamics(const vecx &q, const vecx &u, const vecx &dot_u,
vecx *joint_forces) {
if (false == m_is_finalized) {
- error_message("system has not been initialized\n");
+ bt_id_error_message("system has not been initialized\n");
return -1;
}
if (-1 == m_impl->calculateInverseDynamics(q, u, dot_u, joint_forces)) {
- error_message("error in inverse dynamics calculation\n");
+ bt_id_error_message("error in inverse dynamics calculation\n");
return -1;
}
return 0;
@@ -97,13 +97,13 @@ int MultiBodyTree::calculateMassMatrix(const vecx &q, const bool update_kinemati
const bool initialize_matrix,
const bool set_lower_triangular_matrix, matxx *mass_matrix) {
if (false == m_is_finalized) {
- error_message("system has not been initialized\n");
+ bt_id_error_message("system has not been initialized\n");
return -1;
}
if (-1 ==
m_impl->calculateMassMatrix(q, update_kinematics, initialize_matrix,
set_lower_triangular_matrix, mass_matrix)) {
- error_message("error in mass matrix calculation\n");
+ bt_id_error_message("error in mass matrix calculation\n");
return -1;
}
return 0;
@@ -121,12 +121,12 @@ int MultiBodyTree::calculateKinematics(const vecx& q, const vecx& u, const vecx&
setZero(m_impl->m_world_gravity);
if (false == m_is_finalized) {
- error_message("system has not been initialized\n");
+ bt_id_error_message("system has not been initialized\n");
return -1;
}
if (-1 == m_impl->calculateKinematics(q, u, dot_u,
MultiBodyTree::MultiBodyImpl::POSITION_VELOCITY_ACCELERATION)) {
- error_message("error in kinematics calculation\n");
+ bt_id_error_message("error in kinematics calculation\n");
return -1;
}
@@ -137,12 +137,12 @@ int MultiBodyTree::calculateKinematics(const vecx& q, const vecx& u, const vecx&
int MultiBodyTree::calculatePositionKinematics(const vecx& q) {
if (false == m_is_finalized) {
- error_message("system has not been initialized\n");
+ bt_id_error_message("system has not been initialized\n");
return -1;
}
if (-1 == m_impl->calculateKinematics(q, q, q,
MultiBodyTree::MultiBodyImpl::POSITION_VELOCITY)) {
- error_message("error in kinematics calculation\n");
+ bt_id_error_message("error in kinematics calculation\n");
return -1;
}
return 0;
@@ -150,12 +150,12 @@ int MultiBodyTree::calculatePositionKinematics(const vecx& q) {
int MultiBodyTree::calculatePositionAndVelocityKinematics(const vecx& q, const vecx& u) {
if (false == m_is_finalized) {
- error_message("system has not been initialized\n");
+ bt_id_error_message("system has not been initialized\n");
return -1;
}
if (-1 == m_impl->calculateKinematics(q, u, u,
MultiBodyTree::MultiBodyImpl::POSITION_VELOCITY)) {
- error_message("error in kinematics calculation\n");
+ bt_id_error_message("error in kinematics calculation\n");
return -1;
}
return 0;
@@ -165,12 +165,12 @@ int MultiBodyTree::calculatePositionAndVelocityKinematics(const vecx& q, const v
#if (defined BT_ID_HAVE_MAT3X) && (defined BT_ID_WITH_JACOBIANS)
int MultiBodyTree::calculateJacobians(const vecx& q, const vecx& u) {
if (false == m_is_finalized) {
- error_message("system has not been initialized\n");
+ bt_id_error_message("system has not been initialized\n");
return -1;
}
if (-1 == m_impl->calculateJacobians(q, u,
MultiBodyTree::MultiBodyImpl::POSITION_VELOCITY)) {
- error_message("error in jacobian calculation\n");
+ bt_id_error_message("error in jacobian calculation\n");
return -1;
}
return 0;
@@ -178,12 +178,12 @@ int MultiBodyTree::calculateJacobians(const vecx& q, const vecx& u) {
int MultiBodyTree::calculateJacobians(const vecx& q){
if (false == m_is_finalized) {
- error_message("system has not been initialized\n");
+ bt_id_error_message("system has not been initialized\n");
return -1;
}
if (-1 == m_impl->calculateJacobians(q, q,
MultiBodyTree::MultiBodyImpl::POSITION_ONLY)) {
- error_message("error in jacobian calculation\n");
+ bt_id_error_message("error in jacobian calculation\n");
return -1;
}
return 0;
@@ -214,7 +214,7 @@ int MultiBodyTree::addBody(int body_index, int parent_index, JointType joint_typ
const vec3 &body_r_body_com, const mat33 &body_I_body,
const int user_int, void *user_ptr) {
if (body_index < 0) {
- error_message("body index must be positive (got %d)\n", body_index);
+ bt_id_error_message("body index must be positive (got %d)\n", body_index);
return -1;
}
vec3 body_axis_of_motion(body_axis_of_motion_);
@@ -223,14 +223,14 @@ int MultiBodyTree::addBody(int body_index, int parent_index, JointType joint_typ
case PRISMATIC:
// check if axis is unit vector
if (!isUnitVector(body_axis_of_motion)) {
- warning_message(
+ bt_id_warning_message(
"axis of motion not a unit axis ([%f %f %f]), will use normalized vector\n",
body_axis_of_motion(0), body_axis_of_motion(1), body_axis_of_motion(2));
idScalar length = BT_ID_SQRT(BT_ID_POW(body_axis_of_motion(0), 2) +
BT_ID_POW(body_axis_of_motion(1), 2) +
BT_ID_POW(body_axis_of_motion(2), 2));
if (length < BT_ID_SQRT(std::numeric_limits<idScalar>::min())) {
- error_message("axis of motion vector too short (%e)\n", length);
+ bt_id_error_message("axis of motion vector too short (%e)\n", length);
return -1;
}
body_axis_of_motion = (1.0 / length) * body_axis_of_motion;
@@ -241,14 +241,14 @@ int MultiBodyTree::addBody(int body_index, int parent_index, JointType joint_typ
case FLOATING:
break;
default:
- error_message("unknown joint type %d\n", joint_type);
+ bt_id_error_message("unknown joint type %d\n", joint_type);
return -1;
}
// sanity check for mass properties. Zero mass is OK.
if (mass < 0) {
m_mass_parameters_are_valid = false;
- error_message("Body %d has invalid mass %e\n", body_index, mass);
+ bt_id_error_message("Body %d has invalid mass %e\n", body_index, mass);
if (!m_accept_invalid_mass_parameters) {
return -1;
}
@@ -296,7 +296,7 @@ int MultiBodyTree::finalize() {
const int &num_dofs = m_init_cache->numDoFs();
if(num_dofs<=0) {
- error_message("Need num_dofs>=1, but num_dofs= %d\n", num_dofs);
+ bt_id_error_message("Need num_dofs>=1, but num_dofs= %d\n", num_dofs);
//return -1;
}
@@ -331,6 +331,22 @@ int MultiBodyTree::finalize() {
rigid_body.m_parent_pos_parent_body_ref = joint.m_parent_pos_parent_child_ref;
rigid_body.m_joint_type = joint.m_type;
+ int user_int;
+ if (-1 == m_init_cache->getUserInt(index, &user_int)) {
+ return -1;
+ }
+ if (-1 == m_impl->setUserInt(index, user_int)) {
+ return -1;
+ }
+
+ void* user_ptr;
+ if (-1 == m_init_cache->getUserPtr(index, &user_ptr)) {
+ return -1;
+ }
+ if (-1 == m_impl->setUserPtr(index, user_ptr)) {
+ return -1;
+ }
+
// Set joint Jacobians. Note that the dimension is always 3x1 here to avoid variable sized
// matrices.
switch (rigid_body.m_joint_type) {
@@ -370,14 +386,14 @@ int MultiBodyTree::finalize() {
rigid_body.m_Jac_JT(2) = 0.0;
break;
default:
- error_message("unsupported joint type %d\n", rigid_body.m_joint_type);
+ bt_id_error_message("unsupported joint type %d\n", rigid_body.m_joint_type);
return -1;
}
}
// 4 assign degree of freedom indices & build per-joint-type index arrays
if (-1 == m_impl->generateIndexSets()) {
- error_message("generating index sets\n");
+ bt_id_error_message("generating index sets\n");
return -1;
}
diff --git a/thirdparty/bullet/BulletInverseDynamics/details/IDLinearMathInterface.hpp b/thirdparty/bullet/BulletInverseDynamics/details/IDLinearMathInterface.hpp
index 5bb4a33bdd..c179daeec6 100644
--- a/thirdparty/bullet/BulletInverseDynamics/details/IDLinearMathInterface.hpp
+++ b/thirdparty/bullet/BulletInverseDynamics/details/IDLinearMathInterface.hpp
@@ -49,9 +49,9 @@ inline mat33 operator*(const idScalar& s, const mat33& a) { return a * s; }
class vecx : public btVectorX<idScalar> {
public:
- vecx(int size) : btVectorX(size) {}
+ vecx(int size) : btVectorX<idScalar>(size) {}
const vecx& operator=(const btVectorX<idScalar>& rhs) {
- *static_cast<btVectorX*>(this) = rhs;
+ *static_cast<btVectorX<idScalar>*>(this) = rhs;
return *this;
}
@@ -78,7 +78,7 @@ inline vecx operator+(const vecx& a, const vecx& b) {
vecx result(a.size());
// TODO: error handling for a.size() != b.size()??
if (a.size() != b.size()) {
- error_message("size missmatch. a.size()= %d, b.size()= %d\n", a.size(), b.size());
+ bt_id_error_message("size missmatch. a.size()= %d, b.size()= %d\n", a.size(), b.size());
abort();
}
for (int i = 0; i < a.size(); i++) {
@@ -92,7 +92,7 @@ inline vecx operator-(const vecx& a, const vecx& b) {
vecx result(a.size());
// TODO: error handling for a.size() != b.size()??
if (a.size() != b.size()) {
- error_message("size missmatch. a.size()= %d, b.size()= %d\n", a.size(), b.size());
+ bt_id_error_message("size missmatch. a.size()= %d, b.size()= %d\n", a.size(), b.size());
abort();
}
for (int i = 0; i < a.size(); i++) {
@@ -121,7 +121,7 @@ public:
}
void operator=(const mat3x& rhs) {
if (m_cols != rhs.m_cols) {
- error_message("size missmatch, cols= %d but rhs.cols= %d\n", cols(), rhs.cols());
+ bt_id_error_message("size missmatch, cols= %d but rhs.cols= %d\n", cols(), rhs.cols());
abort();
}
for(int i=0;i<rows();i++) {
@@ -139,7 +139,7 @@ public:
inline vec3 operator*(const mat3x& a, const vecx& b) {
vec3 result;
if (a.cols() != b.size()) {
- error_message("size missmatch. a.cols()= %d, b.size()= %d\n", a.cols(), b.size());
+ bt_id_error_message("size missmatch. a.cols()= %d, b.size()= %d\n", a.cols(), b.size());
abort();
}
result(0)=0.0;
diff --git a/thirdparty/bullet/BulletInverseDynamics/details/IDMatVec.hpp b/thirdparty/bullet/BulletInverseDynamics/details/IDMatVec.hpp
index 4d3f6c87e9..c89db5e123 100644
--- a/thirdparty/bullet/BulletInverseDynamics/details/IDMatVec.hpp
+++ b/thirdparty/bullet/BulletInverseDynamics/details/IDMatVec.hpp
@@ -123,7 +123,7 @@ public:
};
void operator=(const mat3x& rhs) {
if (m_cols != rhs.m_cols) {
- error_message("size missmatch, cols= %d but rhs.cols= %d\n", cols(), rhs.cols());
+ bt_id_error_message("size missmatch, cols= %d but rhs.cols= %d\n", cols(), rhs.cols());
abort();
}
for(int i=0;i<3*m_cols;i++) {
@@ -336,7 +336,7 @@ inline vec3 operator/(const vec3& a, const idScalar& s) {
inline const vecx& vecx::operator=(const vecx& rhs) {
if (size() != rhs.size()) {
- error_message("size missmatch, size()= %d but rhs.size()= %d\n", size(), rhs.size());
+ bt_id_error_message("size missmatch, size()= %d but rhs.size()= %d\n", size(), rhs.size());
abort();
}
if (&rhs != this) {
@@ -356,7 +356,7 @@ inline vecx operator+(const vecx& a, const vecx& b) {
vecx result(a.size());
// TODO: error handling for a.size() != b.size()??
if (a.size() != b.size()) {
- error_message("size missmatch. a.size()= %d, b.size()= %d\n", a.size(), b.size());
+ bt_id_error_message("size missmatch. a.size()= %d, b.size()= %d\n", a.size(), b.size());
abort();
}
for (int i = 0; i < a.size(); i++) {
@@ -369,7 +369,7 @@ inline vecx operator-(const vecx& a, const vecx& b) {
vecx result(a.size());
// TODO: error handling for a.size() != b.size()??
if (a.size() != b.size()) {
- error_message("size missmatch. a.size()= %d, b.size()= %d\n", a.size(), b.size());
+ bt_id_error_message("size missmatch. a.size()= %d, b.size()= %d\n", a.size(), b.size());
abort();
}
for (int i = 0; i < a.size(); i++) {
@@ -389,7 +389,7 @@ inline vecx operator/(const vecx& a, const idScalar& s) {
inline vec3 operator*(const mat3x& a, const vecx& b) {
vec3 result;
if (a.cols() != b.size()) {
- error_message("size missmatch. a.cols()= %d, b.size()= %d\n", a.cols(), b.size());
+ bt_id_error_message("size missmatch. a.cols()= %d, b.size()= %d\n", a.cols(), b.size());
abort();
}
result(0)=0.0;
diff --git a/thirdparty/bullet/BulletInverseDynamics/details/MultiBodyTreeImpl.cpp b/thirdparty/bullet/BulletInverseDynamics/details/MultiBodyTreeImpl.cpp
index b35c55df61..e8563238c3 100644
--- a/thirdparty/bullet/BulletInverseDynamics/details/MultiBodyTreeImpl.cpp
+++ b/thirdparty/bullet/BulletInverseDynamics/details/MultiBodyTreeImpl.cpp
@@ -80,7 +80,7 @@ int MultiBodyTree::MultiBodyImpl::bodyNumDoFs(const JointType &type) const {
case FLOATING:
return 6;
}
- error_message("unknown joint type %d\n", type);
+ bt_id_error_message("unknown joint type %d\n", type);
return 0;
}
@@ -136,13 +136,13 @@ int MultiBodyTree::MultiBodyImpl::generateIndexSets() {
q_index += 6;
break;
default:
- error_message("unsupported joint type %d\n", body.m_joint_type);
+ bt_id_error_message("unsupported joint type %d\n", body.m_joint_type);
return -1;
}
}
// sanity check
if (q_index != m_num_dofs) {
- error_message("internal error, q_index= %d but num_dofs %d\n", q_index, m_num_dofs);
+ bt_id_error_message("internal error, q_index= %d but num_dofs %d\n", q_index, m_num_dofs);
return -1;
}
@@ -155,10 +155,10 @@ int MultiBodyTree::MultiBodyImpl::generateIndexSets() {
} else {
if (-1 == parent) {
// multiple bodies are directly linked to the environment, ie, not a single root
- error_message("building index sets parent(%zu)= -1 (multiple roots)\n", child);
+ bt_id_error_message("building index sets parent(%zu)= -1 (multiple roots)\n", child);
} else {
// should never happen
- error_message(
+ bt_id_error_message(
"building index sets. parent_index[%zu]= %d, but m_parent_index.size()= %d\n",
child, parent, static_cast<int>(m_parent_index.size()));
}
@@ -234,7 +234,7 @@ int MultiBodyTree::MultiBodyImpl::calculateInverseDynamics(const vecx &q, const
const vecx &dot_u, vecx *joint_forces) {
if (q.size() != m_num_dofs || u.size() != m_num_dofs || dot_u.size() != m_num_dofs ||
joint_forces->size() != m_num_dofs) {
- error_message("wrong vector dimension. system has %d DOFs,\n"
+ bt_id_error_message("wrong vector dimension. system has %d DOFs,\n"
"but dim(q)= %d, dim(u)= %d, dim(dot_u)= %d, dim(joint_forces)= %d\n",
m_num_dofs, static_cast<int>(q.size()), static_cast<int>(u.size()),
static_cast<int>(dot_u.size()), static_cast<int>(joint_forces->size()));
@@ -242,7 +242,7 @@ int MultiBodyTree::MultiBodyImpl::calculateInverseDynamics(const vecx &q, const
}
// 1. relative kinematics
if(-1 == calculateKinematics(q,u,dot_u, POSITION_VELOCITY_ACCELERATION)) {
- error_message("error in calculateKinematics\n");
+ bt_id_error_message("error in calculateKinematics\n");
return -1;
}
// 2. update contributions to equations of motion for every body.
@@ -322,14 +322,14 @@ int MultiBodyTree::MultiBodyImpl::calculateInverseDynamics(const vecx &q, const
int MultiBodyTree::MultiBodyImpl::calculateKinematics(const vecx &q, const vecx &u, const vecx& dot_u,
const KinUpdateType type) {
if (q.size() != m_num_dofs || u.size() != m_num_dofs || dot_u.size() != m_num_dofs ) {
- error_message("wrong vector dimension. system has %d DOFs,\n"
+ bt_id_error_message("wrong vector dimension. system has %d DOFs,\n"
"but dim(q)= %d, dim(u)= %d, dim(dot_u)= %d\n",
m_num_dofs, static_cast<int>(q.size()), static_cast<int>(u.size()),
static_cast<int>(dot_u.size()));
return -1;
}
if(type != POSITION_ONLY && type != POSITION_VELOCITY && type != POSITION_VELOCITY_ACCELERATION) {
- error_message("invalid type %d\n", type);
+ bt_id_error_message("invalid type %d\n", type);
return -1;
}
@@ -516,13 +516,13 @@ void MultiBodyTree::MultiBodyImpl::addRelativeJacobianComponent(RigidBody&body)
int MultiBodyTree::MultiBodyImpl::calculateJacobians(const vecx& q, const vecx& u, const KinUpdateType type) {
if (q.size() != m_num_dofs || u.size() != m_num_dofs) {
- error_message("wrong vector dimension. system has %d DOFs,\n"
+ bt_id_error_message("wrong vector dimension. system has %d DOFs,\n"
"but dim(q)= %d, dim(u)= %d\n",
m_num_dofs, static_cast<int>(q.size()), static_cast<int>(u.size()));
return -1;
}
if(type != POSITION_ONLY && type != POSITION_VELOCITY) {
- error_message("invalid type %d\n", type);
+ bt_id_error_message("invalid type %d\n", type);
return -1;
}
@@ -606,7 +606,7 @@ static inline int jointNumDoFs(const JointType &type) {
return 6;
}
// this should never happen
- error_message("invalid joint type\n");
+ bt_id_error_message("invalid joint type\n");
// TODO add configurable abort/crash function
abort();
return 0;
@@ -626,7 +626,7 @@ int MultiBodyTree::MultiBodyImpl::calculateMassMatrix(const vecx &q, const bool
if (q.size() != m_num_dofs || mass_matrix->rows() != m_num_dofs ||
mass_matrix->cols() != m_num_dofs) {
- error_message("Dimension error. System has %d DOFs,\n"
+ bt_id_error_message("Dimension error. System has %d DOFs,\n"
"but dim(q)= %d, dim(mass_matrix)= %d x %d\n",
m_num_dofs, static_cast<int>(q.size()), static_cast<int>(mass_matrix->rows()),
static_cast<int>(mass_matrix->cols()));
@@ -734,7 +734,7 @@ int MultiBodyTree::MultiBodyImpl::calculateMassMatrix(const vecx &q, const bool
// 1. for multi-dof joints, rest of the dofs of this body
for (int row = col - 1; row >= q_index_min; row--) {
if (FLOATING != body.m_joint_type) {
- error_message("??\n");
+ bt_id_error_message("??\n");
return -1;
}
setSixDoFJacobians(row - q_index_min, Jac_JR, Jac_JT);
@@ -788,7 +788,7 @@ int MultiBodyTree::MultiBodyImpl::calculateMassMatrix(const vecx &q, const bool
#define CHECK_IF_BODY_INDEX_IS_VALID(index) \
do { \
if (index < 0 || index >= m_num_bodies) { \
- error_message("invalid index %d (num_bodies= %d)\n", index, m_num_bodies); \
+ bt_id_error_message("invalid index %d (num_bodies= %d)\n", index, m_num_bodies); \
return -1; \
} \
} while (0)
diff --git a/thirdparty/bullet/BulletInverseDynamics/details/MultiBodyTreeInitCache.cpp b/thirdparty/bullet/BulletInverseDynamics/details/MultiBodyTreeInitCache.cpp
index 47b4ab3890..e9511b7076 100644
--- a/thirdparty/bullet/BulletInverseDynamics/details/MultiBodyTreeInitCache.cpp
+++ b/thirdparty/bullet/BulletInverseDynamics/details/MultiBodyTreeInitCache.cpp
@@ -29,13 +29,13 @@ int MultiBodyTree::InitCache::addBody(const int body_index, const int parent_ind
m_num_dofs += 6;
break;
default:
- error_message("unknown joint type %d\n", joint_type);
+ bt_id_error_message("unknown joint type %d\n", joint_type);
return -1;
}
if(-1 == parent_index) {
if(m_root_index>=0) {
- error_message("trying to add body %d as root, but already added %d as root body\n",
+ bt_id_error_message("trying to add body %d as root, but already added %d as root body\n",
body_index, m_root_index);
return -1;
}
@@ -63,7 +63,7 @@ int MultiBodyTree::InitCache::addBody(const int body_index, const int parent_ind
}
int MultiBodyTree::InitCache::getInertiaData(const int index, InertiaData* inertia) const {
if (index < 0 || index > static_cast<int>(m_inertias.size())) {
- error_message("index out of range\n");
+ bt_id_error_message("index out of range\n");
return -1;
}
@@ -73,7 +73,7 @@ int MultiBodyTree::InitCache::getInertiaData(const int index, InertiaData* inert
int MultiBodyTree::InitCache::getUserInt(const int index, int* user_int) const {
if (index < 0 || index > static_cast<int>(m_user_int.size())) {
- error_message("index out of range\n");
+ bt_id_error_message("index out of range\n");
return -1;
}
*user_int = m_user_int[index];
@@ -82,7 +82,7 @@ int MultiBodyTree::InitCache::getUserInt(const int index, int* user_int) const {
int MultiBodyTree::InitCache::getUserPtr(const int index, void** user_ptr) const {
if (index < 0 || index > static_cast<int>(m_user_ptr.size())) {
- error_message("index out of range\n");
+ bt_id_error_message("index out of range\n");
return -1;
}
*user_ptr = m_user_ptr[index];
@@ -91,7 +91,7 @@ int MultiBodyTree::InitCache::getUserPtr(const int index, void** user_ptr) const
int MultiBodyTree::InitCache::getJointData(const int index, JointData* joint) const {
if (index < 0 || index > static_cast<int>(m_joints.size())) {
- error_message("index out of range\n");
+ bt_id_error_message("index out of range\n");
return -1;
}
*joint = m_joints[index];
diff --git a/thirdparty/bullet/BulletSoftBody/btSoftMultiBodyDynamicsWorld.cpp b/thirdparty/bullet/BulletSoftBody/btSoftMultiBodyDynamicsWorld.cpp
index 4e76dca9db..6facce4e86 100644
--- a/thirdparty/bullet/BulletSoftBody/btSoftMultiBodyDynamicsWorld.cpp
+++ b/thirdparty/bullet/BulletSoftBody/btSoftMultiBodyDynamicsWorld.cpp
@@ -157,7 +157,7 @@ void btSoftMultiBodyDynamicsWorld::removeCollisionObject(btCollisionObject* coll
void btSoftMultiBodyDynamicsWorld::debugDrawWorld()
{
- btDiscreteDynamicsWorld::debugDrawWorld();
+ btMultiBodyDynamicsWorld::debugDrawWorld();
if (getDebugDrawer())
{
@@ -357,10 +357,14 @@ void btSoftMultiBodyDynamicsWorld::serialize(btSerializer* serializer)
serializeSoftBodies(serializer);
+ serializeMultiBodies(serializer);
+
serializeRigidBodies(serializer);
serializeCollisionObjects(serializer);
+ serializeContactManifolds(serializer);
+
serializer->finishSerialization();
}
diff --git a/thirdparty/bullet/LinearMath/TaskScheduler/btTaskScheduler.cpp b/thirdparty/bullet/LinearMath/TaskScheduler/btTaskScheduler.cpp
new file mode 100644
index 0000000000..49510d1660
--- /dev/null
+++ b/thirdparty/bullet/LinearMath/TaskScheduler/btTaskScheduler.cpp
@@ -0,0 +1,802 @@
+
+#include "LinearMath/btMinMax.h"
+#include "LinearMath/btAlignedObjectArray.h"
+#include "LinearMath/btThreads.h"
+#include "LinearMath/btQuickprof.h"
+#include <stdio.h>
+#include <algorithm>
+
+
+
+#if BT_THREADSAFE
+
+#include "btThreadSupportInterface.h"
+
+#if defined( _WIN32 )
+
+#define WIN32_LEAN_AND_MEAN
+
+#include <windows.h>
+
+#endif
+
+
+typedef unsigned long long btU64;
+static const int kCacheLineSize = 64;
+
+void btSpinPause()
+{
+#if defined( _WIN32 )
+ YieldProcessor();
+#endif
+}
+
+
+struct WorkerThreadStatus
+{
+ enum Type
+ {
+ kInvalid,
+ kWaitingForWork,
+ kWorking,
+ kSleeping,
+ };
+};
+
+
+ATTRIBUTE_ALIGNED64(class) WorkerThreadDirectives
+{
+ static const int kMaxThreadCount = BT_MAX_THREAD_COUNT;
+ // directives for all worker threads packed into a single cacheline
+ char m_threadDirs[kMaxThreadCount];
+
+public:
+ enum Type
+ {
+ kInvalid,
+ kGoToSleep, // go to sleep
+ kStayAwakeButIdle, // wait for not checking job queue
+ kScanForJobs, // actively scan job queue for jobs
+ };
+ WorkerThreadDirectives()
+ {
+ for ( int i = 0; i < kMaxThreadCount; ++i )
+ {
+ m_threadDirs[ i ] = 0;
+ }
+ }
+
+ Type getDirective(int threadId)
+ {
+ btAssert(threadId < kMaxThreadCount);
+ return static_cast<Type>(m_threadDirs[threadId]);
+ }
+
+ void setDirectiveByRange(int threadBegin, int threadEnd, Type dir)
+ {
+ btAssert( threadBegin < threadEnd );
+ btAssert( threadEnd <= kMaxThreadCount );
+ char dirChar = static_cast<char>(dir);
+ for ( int i = threadBegin; i < threadEnd; ++i )
+ {
+ m_threadDirs[ i ] = dirChar;
+ }
+ }
+};
+
+class JobQueue;
+
+ATTRIBUTE_ALIGNED64(struct) ThreadLocalStorage
+{
+ int m_threadId;
+ WorkerThreadStatus::Type m_status;
+ int m_numJobsFinished;
+ btSpinMutex m_mutex;
+ btScalar m_sumResult;
+ WorkerThreadDirectives * m_directive;
+ JobQueue* m_queue;
+ btClock* m_clock;
+ unsigned int m_cooldownTime;
+};
+
+
+struct IJob
+{
+ virtual void executeJob(int threadId) = 0;
+};
+
+class ParallelForJob : public IJob
+{
+ const btIParallelForBody* m_body;
+ int m_begin;
+ int m_end;
+
+public:
+ ParallelForJob( int iBegin, int iEnd, const btIParallelForBody& body )
+ {
+ m_body = &body;
+ m_begin = iBegin;
+ m_end = iEnd;
+ }
+ virtual void executeJob(int threadId) BT_OVERRIDE
+ {
+ BT_PROFILE( "executeJob" );
+
+ // call the functor body to do the work
+ m_body->forLoop( m_begin, m_end );
+ }
+};
+
+
+class ParallelSumJob : public IJob
+{
+ const btIParallelSumBody* m_body;
+ ThreadLocalStorage* m_threadLocalStoreArray;
+ int m_begin;
+ int m_end;
+
+public:
+ ParallelSumJob( int iBegin, int iEnd, const btIParallelSumBody& body, ThreadLocalStorage* tls )
+ {
+ m_body = &body;
+ m_threadLocalStoreArray = tls;
+ m_begin = iBegin;
+ m_end = iEnd;
+ }
+ virtual void executeJob( int threadId ) BT_OVERRIDE
+ {
+ BT_PROFILE( "executeJob" );
+
+ // call the functor body to do the work
+ btScalar val = m_body->sumLoop( m_begin, m_end );
+#if BT_PARALLEL_SUM_DETERMINISTISM
+ // by truncating bits of the result, we can make the parallelSum deterministic (at the expense of precision)
+ const float TRUNC_SCALE = float(1<<19);
+ val = floor(val*TRUNC_SCALE+0.5f)/TRUNC_SCALE; // truncate some bits
+#endif
+ m_threadLocalStoreArray[threadId].m_sumResult += val;
+ }
+};
+
+
+ATTRIBUTE_ALIGNED64(class) JobQueue
+{
+ btThreadSupportInterface* m_threadSupport;
+ btCriticalSection* m_queueLock;
+ btSpinMutex m_mutex;
+
+ btAlignedObjectArray<IJob*> m_jobQueue;
+ char* m_jobMem;
+ int m_jobMemSize;
+ bool m_queueIsEmpty;
+ int m_tailIndex;
+ int m_headIndex;
+ int m_allocSize;
+ bool m_useSpinMutex;
+ btAlignedObjectArray<JobQueue*> m_neighborContexts;
+ char m_cachePadding[kCacheLineSize]; // prevent false sharing
+
+ void freeJobMem()
+ {
+ if ( m_jobMem )
+ {
+ // free old
+ btAlignedFree(m_jobMem);
+ m_jobMem = NULL;
+ }
+ }
+ void resizeJobMem(int newSize)
+ {
+ if (newSize > m_jobMemSize)
+ {
+ freeJobMem();
+ m_jobMem = static_cast<char*>(btAlignedAlloc(newSize, kCacheLineSize));
+ m_jobMemSize = newSize;
+ }
+ }
+
+public:
+
+ JobQueue()
+ {
+ m_jobMem = NULL;
+ m_jobMemSize = 0;
+ m_threadSupport = NULL;
+ m_queueLock = NULL;
+ m_headIndex = 0;
+ m_tailIndex = 0;
+ m_useSpinMutex = false;
+ }
+ ~JobQueue()
+ {
+ exit();
+ }
+ void exit()
+ {
+ freeJobMem();
+ if (m_queueLock && m_threadSupport)
+ {
+ m_threadSupport->deleteCriticalSection(m_queueLock);
+ m_queueLock = NULL;
+ m_threadSupport = 0;
+ }
+ }
+
+ void init(btThreadSupportInterface* threadSup, btAlignedObjectArray<JobQueue>* contextArray)
+ {
+ m_threadSupport = threadSup;
+ if (threadSup)
+ {
+ m_queueLock = m_threadSupport->createCriticalSection();
+ }
+ setupJobStealing(contextArray, contextArray->size());
+ }
+ void setupJobStealing(btAlignedObjectArray<JobQueue>* contextArray, int numActiveContexts)
+ {
+ btAlignedObjectArray<JobQueue>& contexts = *contextArray;
+ int selfIndex = 0;
+ for (int i = 0; i < contexts.size(); ++i)
+ {
+ if ( this == &contexts[ i ] )
+ {
+ selfIndex = i;
+ break;
+ }
+ }
+ int numNeighbors = btMin(2, contexts.size() - 1);
+ int neighborOffsets[ ] = {-1, 1, -2, 2, -3, 3};
+ int numOffsets = sizeof(neighborOffsets)/sizeof(neighborOffsets[0]);
+ m_neighborContexts.reserve( numNeighbors );
+ m_neighborContexts.resizeNoInitialize(0);
+ for (int i = 0; i < numOffsets && m_neighborContexts.size() < numNeighbors; i++)
+ {
+ int neighborIndex = selfIndex + neighborOffsets[i];
+ if ( neighborIndex >= 0 && neighborIndex < numActiveContexts)
+ {
+ m_neighborContexts.push_back( &contexts[ neighborIndex ] );
+ }
+ }
+ }
+
+ bool isQueueEmpty() const {return m_queueIsEmpty;}
+ void lockQueue()
+ {
+ if ( m_useSpinMutex )
+ {
+ m_mutex.lock();
+ }
+ else
+ {
+ m_queueLock->lock();
+ }
+ }
+ void unlockQueue()
+ {
+ if ( m_useSpinMutex )
+ {
+ m_mutex.unlock();
+ }
+ else
+ {
+ m_queueLock->unlock();
+ }
+ }
+ void clearQueue(int jobCount, int jobSize)
+ {
+ lockQueue();
+ m_headIndex = 0;
+ m_tailIndex = 0;
+ m_allocSize = 0;
+ m_queueIsEmpty = true;
+ int jobBufSize = jobSize * jobCount;
+ // make sure we have enough memory allocated to store jobs
+ if ( jobBufSize > m_jobMemSize )
+ {
+ resizeJobMem( jobBufSize );
+ }
+ // make sure job queue is big enough
+ if ( jobCount > m_jobQueue.capacity() )
+ {
+ m_jobQueue.reserve( jobCount );
+ }
+ unlockQueue();
+ m_jobQueue.resizeNoInitialize( 0 );
+ }
+ void* allocJobMem(int jobSize)
+ {
+ btAssert(m_jobMemSize >= (m_allocSize + jobSize));
+ void* jobMem = &m_jobMem[m_allocSize];
+ m_allocSize += jobSize;
+ return jobMem;
+ }
+ void submitJob( IJob* job )
+ {
+ btAssert( reinterpret_cast<char*>( job ) >= &m_jobMem[ 0 ] && reinterpret_cast<char*>( job ) < &m_jobMem[ 0 ] + m_allocSize );
+ m_jobQueue.push_back( job );
+ lockQueue();
+ m_tailIndex++;
+ m_queueIsEmpty = false;
+ unlockQueue();
+ }
+ IJob* consumeJobFromOwnQueue()
+ {
+ if ( m_queueIsEmpty )
+ {
+ // lock free path. even if this is taken erroneously it isn't harmful
+ return NULL;
+ }
+ IJob* job = NULL;
+ lockQueue();
+ if ( !m_queueIsEmpty )
+ {
+ job = m_jobQueue[ m_headIndex++ ];
+ btAssert( reinterpret_cast<char*>( job ) >= &m_jobMem[ 0 ] && reinterpret_cast<char*>( job ) < &m_jobMem[ 0 ] + m_allocSize );
+ if ( m_headIndex == m_tailIndex )
+ {
+ m_queueIsEmpty = true;
+ }
+ }
+ unlockQueue();
+ return job;
+ }
+ IJob* consumeJob()
+ {
+ if (IJob* job = consumeJobFromOwnQueue())
+ {
+ return job;
+ }
+ // own queue is empty, try to steal from neighbor
+ for (int i = 0; i < m_neighborContexts.size(); ++i)
+ {
+ JobQueue* otherContext = m_neighborContexts[ i ];
+ if ( IJob* job = otherContext->consumeJobFromOwnQueue() )
+ {
+ return job;
+ }
+ }
+ return NULL;
+ }
+};
+
+
+static void WorkerThreadFunc( void* userPtr )
+{
+ BT_PROFILE( "WorkerThreadFunc" );
+ ThreadLocalStorage* localStorage = (ThreadLocalStorage*) userPtr;
+ JobQueue* jobQueue = localStorage->m_queue;
+
+ bool shouldSleep = false;
+ int threadId = localStorage->m_threadId;
+ while (! shouldSleep)
+ {
+ // do work
+ localStorage->m_mutex.lock();
+ while ( IJob* job = jobQueue->consumeJob() )
+ {
+ localStorage->m_status = WorkerThreadStatus::kWorking;
+ job->executeJob( threadId );
+ localStorage->m_numJobsFinished++;
+ }
+ localStorage->m_status = WorkerThreadStatus::kWaitingForWork;
+ localStorage->m_mutex.unlock();
+ btU64 clockStart = localStorage->m_clock->getTimeMicroseconds();
+ // while queue is empty,
+ while (jobQueue->isQueueEmpty())
+ {
+ // todo: spin wait a bit to avoid hammering the empty queue
+ btSpinPause();
+ if ( localStorage->m_directive->getDirective(threadId) == WorkerThreadDirectives::kGoToSleep )
+ {
+ shouldSleep = true;
+ break;
+ }
+ // if jobs are incoming,
+ if ( localStorage->m_directive->getDirective( threadId ) == WorkerThreadDirectives::kScanForJobs )
+ {
+ clockStart = localStorage->m_clock->getTimeMicroseconds(); // reset clock
+ }
+ else
+ {
+ for ( int i = 0; i < 50; ++i )
+ {
+ btSpinPause();
+ btSpinPause();
+ btSpinPause();
+ btSpinPause();
+ if (localStorage->m_directive->getDirective( threadId ) == WorkerThreadDirectives::kScanForJobs || !jobQueue->isQueueEmpty())
+ {
+ break;
+ }
+ }
+ // if no jobs incoming and queue has been empty for the cooldown time, sleep
+ btU64 timeElapsed = localStorage->m_clock->getTimeMicroseconds() - clockStart;
+ if (timeElapsed > localStorage->m_cooldownTime)
+ {
+ shouldSleep = true;
+ break;
+ }
+ }
+ }
+ }
+ {
+ BT_PROFILE("sleep");
+ // go sleep
+ localStorage->m_mutex.lock();
+ localStorage->m_status = WorkerThreadStatus::kSleeping;
+ localStorage->m_mutex.unlock();
+ }
+}
+
+
+class btTaskSchedulerDefault : public btITaskScheduler
+{
+ btThreadSupportInterface* m_threadSupport;
+ WorkerThreadDirectives* m_workerDirective;
+ btAlignedObjectArray<JobQueue> m_jobQueues;
+ btAlignedObjectArray<JobQueue*> m_perThreadJobQueues;
+ btAlignedObjectArray<ThreadLocalStorage> m_threadLocalStorage;
+ btSpinMutex m_antiNestingLock; // prevent nested parallel-for
+ btClock m_clock;
+ int m_numThreads;
+ int m_numWorkerThreads;
+ int m_numActiveJobQueues;
+ int m_maxNumThreads;
+ int m_numJobs;
+ static const int kFirstWorkerThreadId = 1;
+public:
+
+ btTaskSchedulerDefault() : btITaskScheduler("ThreadSupport")
+ {
+ m_threadSupport = NULL;
+ m_workerDirective = NULL;
+ }
+
+ virtual ~btTaskSchedulerDefault()
+ {
+ waitForWorkersToSleep();
+
+ for ( int i = 0; i < m_jobQueues.size(); ++i )
+ {
+ m_jobQueues[i].exit();
+ }
+
+ if (m_threadSupport)
+ {
+ delete m_threadSupport;
+ m_threadSupport = NULL;
+ }
+ if (m_workerDirective)
+ {
+ btAlignedFree(m_workerDirective);
+ m_workerDirective = NULL;
+ }
+ }
+
+ void init()
+ {
+ btThreadSupportInterface::ConstructionInfo constructionInfo( "TaskScheduler", WorkerThreadFunc );
+ m_threadSupport = btThreadSupportInterface::create( constructionInfo );
+ m_workerDirective = static_cast<WorkerThreadDirectives*>(btAlignedAlloc(sizeof(*m_workerDirective), 64));
+
+ m_numWorkerThreads = m_threadSupport->getNumWorkerThreads();
+ m_maxNumThreads = m_threadSupport->getNumWorkerThreads() + 1;
+ m_numThreads = m_maxNumThreads;
+ // ideal to have one job queue for each physical processor (except for the main thread which needs no queue)
+ int numThreadsPerQueue = m_threadSupport->getLogicalToPhysicalCoreRatio();
+ int numJobQueues = (numThreadsPerQueue == 1) ? (m_maxNumThreads-1) : (m_maxNumThreads / numThreadsPerQueue);
+ m_jobQueues.resize(numJobQueues);
+ m_numActiveJobQueues = numJobQueues;
+ for ( int i = 0; i < m_jobQueues.size(); ++i )
+ {
+ m_jobQueues[i].init( m_threadSupport, &m_jobQueues );
+ }
+ m_perThreadJobQueues.resize(m_numThreads);
+ for ( int i = 0; i < m_numThreads; i++ )
+ {
+ JobQueue* jq = NULL;
+ // only worker threads get a job queue
+ if (i > 0)
+ {
+ if (numThreadsPerQueue == 1)
+ {
+ // one queue per worker thread
+ jq = &m_jobQueues[ i - kFirstWorkerThreadId ];
+ }
+ else
+ {
+ // 2 threads share each queue
+ jq = &m_jobQueues[ i / numThreadsPerQueue ];
+ }
+ }
+ m_perThreadJobQueues[i] = jq;
+ }
+ m_threadLocalStorage.resize(m_numThreads);
+ for ( int i = 0; i < m_numThreads; i++ )
+ {
+ ThreadLocalStorage& storage = m_threadLocalStorage[i];
+ storage.m_threadId = i;
+ storage.m_directive = m_workerDirective;
+ storage.m_status = WorkerThreadStatus::kSleeping;
+ storage.m_cooldownTime = 100; // 100 microseconds, threads go to sleep after this long if they have nothing to do
+ storage.m_clock = &m_clock;
+ storage.m_queue = m_perThreadJobQueues[i];
+ }
+ setWorkerDirectives( WorkerThreadDirectives::kGoToSleep ); // no work for them yet
+ setNumThreads( m_threadSupport->getCacheFriendlyNumThreads() );
+ }
+
+ void setWorkerDirectives(WorkerThreadDirectives::Type dir)
+ {
+ m_workerDirective->setDirectiveByRange(kFirstWorkerThreadId, m_numThreads, dir);
+ }
+
+ virtual int getMaxNumThreads() const BT_OVERRIDE
+ {
+ return m_maxNumThreads;
+ }
+
+ virtual int getNumThreads() const BT_OVERRIDE
+ {
+ return m_numThreads;
+ }
+
+ virtual void setNumThreads( int numThreads ) BT_OVERRIDE
+ {
+ m_numThreads = btMax( btMin(numThreads, int(m_maxNumThreads)), 1 );
+ m_numWorkerThreads = m_numThreads - 1;
+ m_numActiveJobQueues = 0;
+ // if there is at least 1 worker,
+ if ( m_numWorkerThreads > 0 )
+ {
+ // re-setup job stealing between queues to avoid attempting to steal from an inactive job queue
+ JobQueue* lastActiveContext = m_perThreadJobQueues[ m_numThreads - 1 ];
+ int iLastActiveContext = lastActiveContext - &m_jobQueues[0];
+ m_numActiveJobQueues = iLastActiveContext + 1;
+ for ( int i = 0; i < m_jobQueues.size(); ++i )
+ {
+ m_jobQueues[ i ].setupJobStealing( &m_jobQueues, m_numActiveJobQueues );
+ }
+ }
+ m_workerDirective->setDirectiveByRange(m_numThreads, BT_MAX_THREAD_COUNT, WorkerThreadDirectives::kGoToSleep);
+ }
+
+ void waitJobs()
+ {
+ BT_PROFILE( "waitJobs" );
+ // have the main thread work until the job queues are empty
+ int numMainThreadJobsFinished = 0;
+ for ( int i = 0; i < m_numActiveJobQueues; ++i )
+ {
+ while ( IJob* job = m_jobQueues[i].consumeJob() )
+ {
+ job->executeJob( 0 );
+ numMainThreadJobsFinished++;
+ }
+ }
+
+ // done with jobs for now, tell workers to rest (but not sleep)
+ setWorkerDirectives( WorkerThreadDirectives::kStayAwakeButIdle );
+
+ btU64 clockStart = m_clock.getTimeMicroseconds();
+ // wait for workers to finish any jobs in progress
+ while ( true )
+ {
+ int numWorkerJobsFinished = 0;
+ for ( int iThread = kFirstWorkerThreadId; iThread < m_numThreads; ++iThread )
+ {
+ ThreadLocalStorage* storage = &m_threadLocalStorage[iThread];
+ storage->m_mutex.lock();
+ numWorkerJobsFinished += storage->m_numJobsFinished;
+ storage->m_mutex.unlock();
+ }
+ if (numWorkerJobsFinished + numMainThreadJobsFinished == m_numJobs)
+ {
+ break;
+ }
+ btU64 timeElapsed = m_clock.getTimeMicroseconds() - clockStart;
+ btAssert(timeElapsed < 1000);
+ if (timeElapsed > 100000)
+ {
+ break;
+ }
+ btSpinPause();
+ }
+ }
+
+ void wakeWorkers(int numWorkersToWake)
+ {
+ BT_PROFILE( "wakeWorkers" );
+ btAssert( m_workerDirective->getDirective(1) == WorkerThreadDirectives::kScanForJobs );
+ int numDesiredWorkers = btMin(numWorkersToWake, m_numWorkerThreads);
+ int numActiveWorkers = 0;
+ for ( int iWorker = 0; iWorker < m_numWorkerThreads; ++iWorker )
+ {
+ // note this count of active workers is not necessarily totally reliable, because a worker thread could be
+ // just about to put itself to sleep. So we may on occasion fail to wake up all the workers. It should be rare.
+ ThreadLocalStorage& storage = m_threadLocalStorage[ kFirstWorkerThreadId + iWorker ];
+ if (storage.m_status != WorkerThreadStatus::kSleeping)
+ {
+ numActiveWorkers++;
+ }
+ }
+ for ( int iWorker = 0; iWorker < m_numWorkerThreads && numActiveWorkers < numDesiredWorkers; ++iWorker )
+ {
+ ThreadLocalStorage& storage = m_threadLocalStorage[ kFirstWorkerThreadId + iWorker ];
+ if (storage.m_status == WorkerThreadStatus::kSleeping)
+ {
+ m_threadSupport->runTask( iWorker, &storage );
+ numActiveWorkers++;
+ }
+ }
+ }
+
+ void waitForWorkersToSleep()
+ {
+ BT_PROFILE( "waitForWorkersToSleep" );
+ setWorkerDirectives( WorkerThreadDirectives::kGoToSleep );
+ m_threadSupport->waitForAllTasks();
+ for ( int i = kFirstWorkerThreadId; i < m_numThreads; i++ )
+ {
+ ThreadLocalStorage& storage = m_threadLocalStorage[i];
+ btAssert( storage.m_status == WorkerThreadStatus::kSleeping );
+ }
+ }
+
+ virtual void sleepWorkerThreadsHint() BT_OVERRIDE
+ {
+ BT_PROFILE( "sleepWorkerThreadsHint" );
+ // hint the task scheduler that we may not be using these threads for a little while
+ setWorkerDirectives( WorkerThreadDirectives::kGoToSleep );
+ }
+
+ void prepareWorkerThreads()
+ {
+ for ( int i = kFirstWorkerThreadId; i < m_numThreads; ++i )
+ {
+ ThreadLocalStorage& storage = m_threadLocalStorage[i];
+ storage.m_mutex.lock();
+ storage.m_numJobsFinished = 0;
+ storage.m_mutex.unlock();
+ }
+ setWorkerDirectives( WorkerThreadDirectives::kScanForJobs );
+ }
+
+ virtual void parallelFor( int iBegin, int iEnd, int grainSize, const btIParallelForBody& body ) BT_OVERRIDE
+ {
+ BT_PROFILE( "parallelFor_ThreadSupport" );
+ btAssert( iEnd >= iBegin );
+ btAssert( grainSize >= 1 );
+ int iterationCount = iEnd - iBegin;
+ if ( iterationCount > grainSize && m_numWorkerThreads > 0 && m_antiNestingLock.tryLock() )
+ {
+ typedef ParallelForJob JobType;
+ int jobCount = ( iterationCount + grainSize - 1 ) / grainSize;
+ m_numJobs = jobCount;
+ btAssert( jobCount >= 2 ); // need more than one job for multithreading
+ int jobSize = sizeof( JobType );
+
+ for (int i = 0; i < m_numActiveJobQueues; ++i)
+ {
+ m_jobQueues[i].clearQueue( jobCount, jobSize );
+ }
+ // prepare worker threads for incoming work
+ prepareWorkerThreads();
+ // submit all of the jobs
+ int iJob = 0;
+ int iThread = kFirstWorkerThreadId; // first worker thread
+ for ( int i = iBegin; i < iEnd; i += grainSize )
+ {
+ btAssert( iJob < jobCount );
+ int iE = btMin( i + grainSize, iEnd );
+ JobQueue* jq = m_perThreadJobQueues[ iThread ];
+ btAssert(jq);
+ btAssert((jq - &m_jobQueues[0]) < m_numActiveJobQueues);
+ void* jobMem = jq->allocJobMem(jobSize);
+ JobType* job = new ( jobMem ) ParallelForJob( i, iE, body ); // placement new
+ jq->submitJob( job );
+ iJob++;
+ iThread++;
+ if ( iThread >= m_numThreads )
+ {
+ iThread = kFirstWorkerThreadId; // first worker thread
+ }
+ }
+ wakeWorkers( jobCount - 1 );
+
+ // put the main thread to work on emptying the job queue and then wait for all workers to finish
+ waitJobs();
+ m_antiNestingLock.unlock();
+ }
+ else
+ {
+ BT_PROFILE( "parallelFor_mainThread" );
+ // just run on main thread
+ body.forLoop( iBegin, iEnd );
+ }
+ }
+ virtual btScalar parallelSum( int iBegin, int iEnd, int grainSize, const btIParallelSumBody& body ) BT_OVERRIDE
+ {
+ BT_PROFILE( "parallelSum_ThreadSupport" );
+ btAssert( iEnd >= iBegin );
+ btAssert( grainSize >= 1 );
+ int iterationCount = iEnd - iBegin;
+ if ( iterationCount > grainSize && m_numWorkerThreads > 0 && m_antiNestingLock.tryLock() )
+ {
+ typedef ParallelSumJob JobType;
+ int jobCount = ( iterationCount + grainSize - 1 ) / grainSize;
+ m_numJobs = jobCount;
+ btAssert( jobCount >= 2 ); // need more than one job for multithreading
+ int jobSize = sizeof( JobType );
+ for (int i = 0; i < m_numActiveJobQueues; ++i)
+ {
+ m_jobQueues[i].clearQueue( jobCount, jobSize );
+ }
+
+ // initialize summation
+ for ( int iThread = 0; iThread < m_numThreads; ++iThread )
+ {
+ m_threadLocalStorage[iThread].m_sumResult = btScalar(0);
+ }
+
+ // prepare worker threads for incoming work
+ prepareWorkerThreads();
+ // submit all of the jobs
+ int iJob = 0;
+ int iThread = kFirstWorkerThreadId; // first worker thread
+ for ( int i = iBegin; i < iEnd; i += grainSize )
+ {
+ btAssert( iJob < jobCount );
+ int iE = btMin( i + grainSize, iEnd );
+ JobQueue* jq = m_perThreadJobQueues[ iThread ];
+ btAssert(jq);
+ btAssert((jq - &m_jobQueues[0]) < m_numActiveJobQueues);
+ void* jobMem = jq->allocJobMem(jobSize);
+ JobType* job = new ( jobMem ) ParallelSumJob( i, iE, body, &m_threadLocalStorage[0] ); // placement new
+ jq->submitJob( job );
+ iJob++;
+ iThread++;
+ if ( iThread >= m_numThreads )
+ {
+ iThread = kFirstWorkerThreadId; // first worker thread
+ }
+ }
+ wakeWorkers( jobCount - 1 );
+
+ // put the main thread to work on emptying the job queue and then wait for all workers to finish
+ waitJobs();
+
+ // add up all the thread sums
+ btScalar sum = btScalar(0);
+ for ( int iThread = 0; iThread < m_numThreads; ++iThread )
+ {
+ sum += m_threadLocalStorage[ iThread ].m_sumResult;
+ }
+ m_antiNestingLock.unlock();
+ return sum;
+ }
+ else
+ {
+ BT_PROFILE( "parallelSum_mainThread" );
+ // just run on main thread
+ return body.sumLoop( iBegin, iEnd );
+ }
+ }
+};
+
+
+
+btITaskScheduler* btCreateDefaultTaskScheduler()
+{
+ btTaskSchedulerDefault* ts = new btTaskSchedulerDefault();
+ ts->init();
+ return ts;
+}
+
+#else // #if BT_THREADSAFE
+
+btITaskScheduler* btCreateDefaultTaskScheduler()
+{
+ return NULL;
+}
+
+#endif // #else // #if BT_THREADSAFE
diff --git a/thirdparty/bullet/LinearMath/TaskScheduler/btThreadSupportInterface.h b/thirdparty/bullet/LinearMath/TaskScheduler/btThreadSupportInterface.h
new file mode 100644
index 0000000000..a0ad802b1e
--- /dev/null
+++ b/thirdparty/bullet/LinearMath/TaskScheduler/btThreadSupportInterface.h
@@ -0,0 +1,70 @@
+/*
+Bullet Continuous Collision Detection and Physics Library
+Copyright (c) 2003-2018 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.
+*/
+
+#ifndef BT_THREAD_SUPPORT_INTERFACE_H
+#define BT_THREAD_SUPPORT_INTERFACE_H
+
+
+
+class btCriticalSection
+{
+public:
+ btCriticalSection() {}
+ virtual ~btCriticalSection() {}
+
+ virtual void lock() = 0;
+ virtual void unlock() = 0;
+};
+
+
+class btThreadSupportInterface
+{
+public:
+
+ virtual ~btThreadSupportInterface() {}
+
+ virtual int getNumWorkerThreads() const = 0; // number of worker threads (total number of logical processors - 1)
+ virtual int getCacheFriendlyNumThreads() const = 0; // the number of logical processors sharing a single L3 cache
+ virtual int getLogicalToPhysicalCoreRatio() const = 0; // the number of logical processors per physical processor (usually 1 or 2)
+ virtual void runTask( int threadIndex, void* userData ) = 0;
+ virtual void waitForAllTasks() = 0;
+
+ virtual btCriticalSection* createCriticalSection() = 0;
+ virtual void deleteCriticalSection( btCriticalSection* criticalSection ) = 0;
+
+ typedef void( *ThreadFunc )( void* userPtr );
+
+ struct ConstructionInfo
+ {
+ ConstructionInfo( const char* uniqueName,
+ ThreadFunc userThreadFunc,
+ int threadStackSize = 65535
+ )
+ :m_uniqueName( uniqueName ),
+ m_userThreadFunc( userThreadFunc ),
+ m_threadStackSize( threadStackSize )
+ {
+ }
+
+ const char* m_uniqueName;
+ ThreadFunc m_userThreadFunc;
+ int m_threadStackSize;
+ };
+
+ static btThreadSupportInterface* create( const ConstructionInfo& info );
+};
+
+#endif //BT_THREAD_SUPPORT_INTERFACE_H
+
diff --git a/thirdparty/bullet/LinearMath/TaskScheduler/btThreadSupportPosix.cpp b/thirdparty/bullet/LinearMath/TaskScheduler/btThreadSupportPosix.cpp
new file mode 100644
index 0000000000..50ca060dfe
--- /dev/null
+++ b/thirdparty/bullet/LinearMath/TaskScheduler/btThreadSupportPosix.cpp
@@ -0,0 +1,365 @@
+/*
+Bullet Continuous Collision Detection and Physics Library
+Copyright (c) 2003-2018 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.
+*/
+
+
+#if BT_THREADSAFE && !defined( _WIN32 )
+
+
+#include "LinearMath/btScalar.h"
+#include "LinearMath/btAlignedObjectArray.h"
+#include "LinearMath/btThreads.h"
+#include "LinearMath/btMinMax.h"
+#include "btThreadSupportInterface.h"
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+
+
+#ifndef _XOPEN_SOURCE
+#define _XOPEN_SOURCE 600 //for definition of pthread_barrier_t, see http://pages.cs.wisc.edu/~travitch/pthreads_primer.html
+#endif //_XOPEN_SOURCE
+#include <pthread.h>
+#include <semaphore.h>
+#include <unistd.h> //for sysconf
+
+
+///
+/// getNumHardwareThreads()
+///
+///
+/// https://stackoverflow.com/questions/150355/programmatically-find-the-number-of-cores-on-a-machine
+///
+#if __cplusplus >= 201103L
+
+#include <thread>
+
+int btGetNumHardwareThreads()
+{
+ return btMin<int>(BT_MAX_THREAD_COUNT, std::thread::hardware_concurrency());
+}
+
+#else
+
+int btGetNumHardwareThreads()
+{
+ return btMin<int>(BT_MAX_THREAD_COUNT, sysconf( _SC_NPROCESSORS_ONLN ));
+}
+
+#endif
+
+
+// btThreadSupportPosix helps to initialize/shutdown libspe2, start/stop SPU tasks and communication
+class btThreadSupportPosix : public btThreadSupportInterface
+{
+public:
+ struct btThreadStatus
+ {
+ int m_taskId;
+ int m_commandId;
+ int m_status;
+
+ ThreadFunc m_userThreadFunc;
+ void* m_userPtr; //for taskDesc etc
+
+ pthread_t thread;
+ //each tread will wait until this signal to start its work
+ sem_t* startSemaphore;
+
+ // this is a copy of m_mainSemaphore,
+ //each tread will signal once it is finished with its work
+ sem_t* m_mainSemaphore;
+ unsigned long threadUsed;
+ };
+private:
+ typedef unsigned long long UINT64;
+
+ btAlignedObjectArray<btThreadStatus> m_activeThreadStatus;
+ // m_mainSemaphoresemaphore will signal, if and how many threads are finished with their work
+ sem_t* m_mainSemaphore;
+ int m_numThreads;
+ UINT64 m_startedThreadsMask;
+ void startThreads( const ConstructionInfo& threadInfo );
+ void stopThreads();
+ int waitForResponse();
+
+public:
+ btThreadSupportPosix( const ConstructionInfo& threadConstructionInfo );
+ virtual ~btThreadSupportPosix();
+
+ virtual int getNumWorkerThreads() const BT_OVERRIDE { return m_numThreads; }
+ // TODO: return the number of logical processors sharing the first L3 cache
+ virtual int getCacheFriendlyNumThreads() const BT_OVERRIDE { return m_numThreads + 1; }
+ // TODO: detect if CPU has hyperthreading enabled
+ virtual int getLogicalToPhysicalCoreRatio() const BT_OVERRIDE { return 1; }
+
+ virtual void runTask( int threadIndex, void* userData ) BT_OVERRIDE;
+ virtual void waitForAllTasks() BT_OVERRIDE;
+
+ virtual btCriticalSection* createCriticalSection() BT_OVERRIDE;
+ virtual void deleteCriticalSection( btCriticalSection* criticalSection ) BT_OVERRIDE;
+};
+
+
+#define checkPThreadFunction(returnValue) \
+ if(0 != returnValue) { \
+ printf("PThread problem at line %i in file %s: %i %d\n", __LINE__, __FILE__, returnValue, errno); \
+ }
+
+// The number of threads should be equal to the number of available cores
+// Todo: each worker should be linked to a single core, using SetThreadIdealProcessor.
+
+
+btThreadSupportPosix::btThreadSupportPosix( const ConstructionInfo& threadConstructionInfo )
+{
+ startThreads( threadConstructionInfo );
+}
+
+// cleanup/shutdown Libspe2
+btThreadSupportPosix::~btThreadSupportPosix()
+{
+ stopThreads();
+}
+
+#if (defined (__APPLE__))
+#define NAMED_SEMAPHORES
+#endif
+
+
+static sem_t* createSem( const char* baseName )
+{
+ static int semCount = 0;
+#ifdef NAMED_SEMAPHORES
+ /// Named semaphore begin
+ char name[ 32 ];
+ snprintf( name, 32, "/%8.s-%4.d-%4.4d", baseName, getpid(), semCount++ );
+ sem_t* tempSem = sem_open( name, O_CREAT, 0600, 0 );
+
+ if ( tempSem != reinterpret_cast<sem_t *>( SEM_FAILED ) )
+ {
+ // printf("Created \"%s\" Semaphore %p\n", name, tempSem);
+ }
+ else
+ {
+ //printf("Error creating Semaphore %d\n", errno);
+ exit( -1 );
+ }
+ /// Named semaphore end
+#else
+ sem_t* tempSem = new sem_t;
+ checkPThreadFunction( sem_init( tempSem, 0, 0 ) );
+#endif
+ return tempSem;
+}
+
+static void destroySem( sem_t* semaphore )
+{
+#ifdef NAMED_SEMAPHORES
+ checkPThreadFunction( sem_close( semaphore ) );
+#else
+ checkPThreadFunction( sem_destroy( semaphore ) );
+ delete semaphore;
+#endif
+}
+
+static void *threadFunction( void *argument )
+{
+ btThreadSupportPosix::btThreadStatus* status = ( btThreadSupportPosix::btThreadStatus* )argument;
+
+ while ( 1 )
+ {
+ checkPThreadFunction( sem_wait( status->startSemaphore ) );
+ void* userPtr = status->m_userPtr;
+
+ if ( userPtr )
+ {
+ btAssert( status->m_status );
+ status->m_userThreadFunc( userPtr );
+ status->m_status = 2;
+ checkPThreadFunction( sem_post( status->m_mainSemaphore ) );
+ status->threadUsed++;
+ }
+ else
+ {
+ //exit Thread
+ status->m_status = 3;
+ checkPThreadFunction( sem_post( status->m_mainSemaphore ) );
+ printf( "Thread with taskId %i exiting\n", status->m_taskId );
+ break;
+ }
+ }
+
+ printf( "Thread TERMINATED\n" );
+ return 0;
+}
+
+///send messages to SPUs
+void btThreadSupportPosix::runTask( int threadIndex, void* userData )
+{
+ ///we should spawn an SPU task here, and in 'waitForResponse' it should wait for response of the (one of) the first tasks that finished
+ btThreadStatus& threadStatus = m_activeThreadStatus[ threadIndex ];
+ btAssert( threadIndex >= 0 );
+ btAssert( threadIndex < m_activeThreadStatus.size() );
+
+ threadStatus.m_commandId = 1;
+ threadStatus.m_status = 1;
+ threadStatus.m_userPtr = userData;
+ m_startedThreadsMask |= UINT64( 1 ) << threadIndex;
+
+ // fire event to start new task
+ checkPThreadFunction( sem_post( threadStatus.startSemaphore ) );
+}
+
+
+///check for messages from SPUs
+int btThreadSupportPosix::waitForResponse()
+{
+ ///We should wait for (one of) the first tasks to finish (or other SPU messages), and report its response
+ ///A possible response can be 'yes, SPU handled it', or 'no, please do a PPU fallback'
+
+ btAssert( m_activeThreadStatus.size() );
+
+ // wait for any of the threads to finish
+ checkPThreadFunction( sem_wait( m_mainSemaphore ) );
+ // get at least one thread which has finished
+ size_t last = -1;
+
+ for ( size_t t = 0; t < size_t( m_activeThreadStatus.size() ); ++t )
+ {
+ if ( 2 == m_activeThreadStatus[ t ].m_status )
+ {
+ last = t;
+ break;
+ }
+ }
+
+ btThreadStatus& threadStatus = m_activeThreadStatus[ last ];
+
+ btAssert( threadStatus.m_status > 1 );
+ threadStatus.m_status = 0;
+
+ // need to find an active spu
+ btAssert( last >= 0 );
+ m_startedThreadsMask &= ~( UINT64( 1 ) << last );
+
+ return last;
+}
+
+
+void btThreadSupportPosix::waitForAllTasks()
+{
+ while ( m_startedThreadsMask )
+ {
+ waitForResponse();
+ }
+}
+
+
+void btThreadSupportPosix::startThreads( const ConstructionInfo& threadConstructionInfo )
+{
+ m_numThreads = btGetNumHardwareThreads() - 1; // main thread exists already
+ printf( "%s creating %i threads.\n", __FUNCTION__, m_numThreads );
+ m_activeThreadStatus.resize( m_numThreads );
+ m_startedThreadsMask = 0;
+
+ m_mainSemaphore = createSem( "main" );
+ //checkPThreadFunction(sem_wait(mainSemaphore));
+
+ for ( int i = 0; i < m_numThreads; i++ )
+ {
+ printf( "starting thread %d\n", i );
+ btThreadStatus& threadStatus = m_activeThreadStatus[ i ];
+ threadStatus.startSemaphore = createSem( "threadLocal" );
+ checkPThreadFunction( pthread_create( &threadStatus.thread, NULL, &threadFunction, (void*) &threadStatus ) );
+
+ threadStatus.m_userPtr = 0;
+ threadStatus.m_taskId = i;
+ threadStatus.m_commandId = 0;
+ threadStatus.m_status = 0;
+ threadStatus.m_mainSemaphore = m_mainSemaphore;
+ threadStatus.m_userThreadFunc = threadConstructionInfo.m_userThreadFunc;
+ threadStatus.threadUsed = 0;
+
+ printf( "started thread %d \n", i );
+ }
+}
+
+///tell the task scheduler we are done with the SPU tasks
+void btThreadSupportPosix::stopThreads()
+{
+ for ( size_t t = 0; t < size_t( m_activeThreadStatus.size() ); ++t )
+ {
+ btThreadStatus& threadStatus = m_activeThreadStatus[ t ];
+ printf( "%s: Thread %i used: %ld\n", __FUNCTION__, int( t ), threadStatus.threadUsed );
+
+ threadStatus.m_userPtr = 0;
+ checkPThreadFunction( sem_post( threadStatus.startSemaphore ) );
+ checkPThreadFunction( sem_wait( m_mainSemaphore ) );
+
+ printf( "destroy semaphore\n" );
+ destroySem( threadStatus.startSemaphore );
+ printf( "semaphore destroyed\n" );
+ checkPThreadFunction( pthread_join( threadStatus.thread, 0 ) );
+
+ }
+ printf( "destroy main semaphore\n" );
+ destroySem( m_mainSemaphore );
+ printf( "main semaphore destroyed\n" );
+ m_activeThreadStatus.clear();
+}
+
+class btCriticalSectionPosix : public btCriticalSection
+{
+ pthread_mutex_t m_mutex;
+
+public:
+ btCriticalSectionPosix()
+ {
+ pthread_mutex_init( &m_mutex, NULL );
+ }
+ virtual ~btCriticalSectionPosix()
+ {
+ pthread_mutex_destroy( &m_mutex );
+ }
+
+ virtual void lock()
+ {
+ pthread_mutex_lock( &m_mutex );
+ }
+ virtual void unlock()
+ {
+ pthread_mutex_unlock( &m_mutex );
+ }
+};
+
+
+btCriticalSection* btThreadSupportPosix::createCriticalSection()
+{
+ return new btCriticalSectionPosix();
+}
+
+void btThreadSupportPosix::deleteCriticalSection( btCriticalSection* cs )
+{
+ delete cs;
+}
+
+
+btThreadSupportInterface* btThreadSupportInterface::create( const ConstructionInfo& info )
+{
+ return new btThreadSupportPosix( info );
+}
+
+#endif // BT_THREADSAFE && !defined( _WIN32 )
+
diff --git a/thirdparty/bullet/LinearMath/TaskScheduler/btThreadSupportWin32.cpp b/thirdparty/bullet/LinearMath/TaskScheduler/btThreadSupportWin32.cpp
new file mode 100644
index 0000000000..00edac650b
--- /dev/null
+++ b/thirdparty/bullet/LinearMath/TaskScheduler/btThreadSupportWin32.cpp
@@ -0,0 +1,472 @@
+/*
+Bullet Continuous Collision Detection and Physics Library
+Copyright (c) 2003-2018 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.
+*/
+
+#if defined( _WIN32 ) && BT_THREADSAFE
+
+#include "LinearMath/btScalar.h"
+#include "LinearMath/btMinMax.h"
+#include "LinearMath/btAlignedObjectArray.h"
+#include "LinearMath/btThreads.h"
+#include "btThreadSupportInterface.h"
+#include <windows.h>
+#include <stdio.h>
+
+
+struct btProcessorInfo
+{
+ int numLogicalProcessors;
+ int numCores;
+ int numNumaNodes;
+ int numL1Cache;
+ int numL2Cache;
+ int numL3Cache;
+ int numPhysicalPackages;
+ static const int maxNumTeamMasks = 32;
+ int numTeamMasks;
+ UINT64 processorTeamMasks[ maxNumTeamMasks ];
+};
+
+UINT64 getProcessorTeamMask( const btProcessorInfo& procInfo, int procId )
+{
+ UINT64 procMask = UINT64( 1 ) << procId;
+ for ( int i = 0; i < procInfo.numTeamMasks; ++i )
+ {
+ if ( procMask & procInfo.processorTeamMasks[ i ] )
+ {
+ return procInfo.processorTeamMasks[ i ];
+ }
+ }
+ return 0;
+}
+
+int getProcessorTeamIndex( const btProcessorInfo& procInfo, int procId )
+{
+ UINT64 procMask = UINT64( 1 ) << procId;
+ for ( int i = 0; i < procInfo.numTeamMasks; ++i )
+ {
+ if ( procMask & procInfo.processorTeamMasks[ i ] )
+ {
+ return i;
+ }
+ }
+ return -1;
+}
+
+int countSetBits( ULONG64 bits )
+{
+ int count = 0;
+ while ( bits )
+ {
+ if ( bits & 1 )
+ {
+ count++;
+ }
+ bits >>= 1;
+ }
+ return count;
+}
+
+
+typedef BOOL( WINAPI *Pfn_GetLogicalProcessorInformation )( PSYSTEM_LOGICAL_PROCESSOR_INFORMATION, PDWORD );
+
+
+void getProcessorInformation( btProcessorInfo* procInfo )
+{
+ memset( procInfo, 0, sizeof( *procInfo ) );
+ Pfn_GetLogicalProcessorInformation getLogicalProcInfo =
+ (Pfn_GetLogicalProcessorInformation) GetProcAddress( GetModuleHandle( TEXT( "kernel32" ) ), "GetLogicalProcessorInformation" );
+ if ( getLogicalProcInfo == NULL )
+ {
+ // no info
+ return;
+ }
+ PSYSTEM_LOGICAL_PROCESSOR_INFORMATION buf = NULL;
+ DWORD bufSize = 0;
+ while ( true )
+ {
+ if ( getLogicalProcInfo( buf, &bufSize ) )
+ {
+ break;
+ }
+ else
+ {
+ if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER )
+ {
+ if ( buf )
+ {
+ free( buf );
+ }
+ buf = (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION) malloc( bufSize );
+ }
+ }
+ }
+
+ int len = bufSize / sizeof( *buf );
+ for ( int i = 0; i < len; ++i )
+ {
+ PSYSTEM_LOGICAL_PROCESSOR_INFORMATION info = buf + i;
+ switch ( info->Relationship )
+ {
+ case RelationNumaNode:
+ procInfo->numNumaNodes++;
+ break;
+
+ case RelationProcessorCore:
+ procInfo->numCores++;
+ procInfo->numLogicalProcessors += countSetBits( info->ProcessorMask );
+ break;
+
+ case RelationCache:
+ if ( info->Cache.Level == 1 )
+ {
+ procInfo->numL1Cache++;
+ }
+ else if ( info->Cache.Level == 2 )
+ {
+ procInfo->numL2Cache++;
+ }
+ else if ( info->Cache.Level == 3 )
+ {
+ procInfo->numL3Cache++;
+ // processors that share L3 cache are considered to be on the same team
+ // because they can more easily work together on the same data.
+ // Large performance penalties will occur if 2 or more threads from different
+ // teams attempt to frequently read and modify the same cache lines.
+ //
+ // On the AMD Ryzen 7 CPU for example, the 8 cores on the CPU are split into
+ // 2 CCX units of 4 cores each. Each CCX has a separate L3 cache, so if both
+ // CCXs are operating on the same data, many cycles will be spent keeping the
+ // two caches coherent.
+ if ( procInfo->numTeamMasks < btProcessorInfo::maxNumTeamMasks )
+ {
+ procInfo->processorTeamMasks[ procInfo->numTeamMasks ] = info->ProcessorMask;
+ procInfo->numTeamMasks++;
+ }
+ }
+ break;
+
+ case RelationProcessorPackage:
+ procInfo->numPhysicalPackages++;
+ break;
+ }
+ }
+ free( buf );
+}
+
+
+
+///btThreadSupportWin32 helps to initialize/shutdown libspe2, start/stop SPU tasks and communication
+class btThreadSupportWin32 : public btThreadSupportInterface
+{
+public:
+ struct btThreadStatus
+ {
+ int m_taskId;
+ int m_commandId;
+ int m_status;
+
+ ThreadFunc m_userThreadFunc;
+ void* m_userPtr; //for taskDesc etc
+
+ void* m_threadHandle; //this one is calling 'Win32ThreadFunc'
+
+ void* m_eventStartHandle;
+ char m_eventStartHandleName[ 32 ];
+
+ void* m_eventCompleteHandle;
+ char m_eventCompleteHandleName[ 32 ];
+ };
+
+private:
+ btAlignedObjectArray<btThreadStatus> m_activeThreadStatus;
+ btAlignedObjectArray<void*> m_completeHandles;
+ int m_numThreads;
+ DWORD_PTR m_startedThreadMask;
+ btProcessorInfo m_processorInfo;
+
+ void startThreads( const ConstructionInfo& threadInfo );
+ void stopThreads();
+ int waitForResponse();
+
+public:
+
+ btThreadSupportWin32( const ConstructionInfo& threadConstructionInfo );
+ virtual ~btThreadSupportWin32();
+
+ virtual int getNumWorkerThreads() const BT_OVERRIDE { return m_numThreads; }
+ virtual int getCacheFriendlyNumThreads() const BT_OVERRIDE { return countSetBits(m_processorInfo.processorTeamMasks[0]); }
+ virtual int getLogicalToPhysicalCoreRatio() const BT_OVERRIDE { return m_processorInfo.numLogicalProcessors / m_processorInfo.numCores; }
+
+ virtual void runTask( int threadIndex, void* userData ) BT_OVERRIDE;
+ virtual void waitForAllTasks() BT_OVERRIDE;
+
+ virtual btCriticalSection* createCriticalSection() BT_OVERRIDE;
+ virtual void deleteCriticalSection( btCriticalSection* criticalSection ) BT_OVERRIDE;
+};
+
+
+btThreadSupportWin32::btThreadSupportWin32( const ConstructionInfo & threadConstructionInfo )
+{
+ startThreads( threadConstructionInfo );
+}
+
+
+btThreadSupportWin32::~btThreadSupportWin32()
+{
+ stopThreads();
+}
+
+
+DWORD WINAPI win32threadStartFunc( LPVOID lpParam )
+{
+ btThreadSupportWin32::btThreadStatus* status = ( btThreadSupportWin32::btThreadStatus* )lpParam;
+
+ while ( 1 )
+ {
+ WaitForSingleObject( status->m_eventStartHandle, INFINITE );
+ void* userPtr = status->m_userPtr;
+
+ if ( userPtr )
+ {
+ btAssert( status->m_status );
+ status->m_userThreadFunc( userPtr );
+ status->m_status = 2;
+ SetEvent( status->m_eventCompleteHandle );
+ }
+ else
+ {
+ //exit Thread
+ status->m_status = 3;
+ printf( "Thread with taskId %i with handle %p exiting\n", status->m_taskId, status->m_threadHandle );
+ SetEvent( status->m_eventCompleteHandle );
+ break;
+ }
+ }
+ printf( "Thread TERMINATED\n" );
+ return 0;
+}
+
+
+void btThreadSupportWin32::runTask( int threadIndex, void* userData )
+{
+ btThreadStatus& threadStatus = m_activeThreadStatus[ threadIndex ];
+ btAssert( threadIndex >= 0 );
+ btAssert( int( threadIndex ) < m_activeThreadStatus.size() );
+
+ threadStatus.m_commandId = 1;
+ threadStatus.m_status = 1;
+ threadStatus.m_userPtr = userData;
+ m_startedThreadMask |= DWORD_PTR( 1 ) << threadIndex;
+
+ ///fire event to start new task
+ SetEvent( threadStatus.m_eventStartHandle );
+}
+
+
+int btThreadSupportWin32::waitForResponse()
+{
+ btAssert( m_activeThreadStatus.size() );
+
+ int last = -1;
+ DWORD res = WaitForMultipleObjects( m_completeHandles.size(), &m_completeHandles[ 0 ], FALSE, INFINITE );
+ btAssert( res != WAIT_FAILED );
+ last = res - WAIT_OBJECT_0;
+
+ btThreadStatus& threadStatus = m_activeThreadStatus[ last ];
+ btAssert( threadStatus.m_threadHandle );
+ btAssert( threadStatus.m_eventCompleteHandle );
+
+ //WaitForSingleObject(threadStatus.m_eventCompleteHandle, INFINITE);
+ btAssert( threadStatus.m_status > 1 );
+ threadStatus.m_status = 0;
+
+ ///need to find an active spu
+ btAssert( last >= 0 );
+ m_startedThreadMask &= ~( DWORD_PTR( 1 ) << last );
+
+ return last;
+}
+
+
+void btThreadSupportWin32::waitForAllTasks()
+{
+ while ( m_startedThreadMask )
+ {
+ waitForResponse();
+ }
+}
+
+
+void btThreadSupportWin32::startThreads( const ConstructionInfo& threadConstructionInfo )
+{
+ static int uniqueId = 0;
+ uniqueId++;
+ btProcessorInfo& procInfo = m_processorInfo;
+ getProcessorInformation( &procInfo );
+ DWORD_PTR dwProcessAffinityMask = 0;
+ DWORD_PTR dwSystemAffinityMask = 0;
+ if ( !GetProcessAffinityMask( GetCurrentProcess(), &dwProcessAffinityMask, &dwSystemAffinityMask ) )
+ {
+ dwProcessAffinityMask = 0;
+ }
+ ///The number of threads should be equal to the number of available cores - 1
+ m_numThreads = btMin(procInfo.numLogicalProcessors, int(BT_MAX_THREAD_COUNT)) - 1; // cap to max thread count (-1 because main thread already exists)
+
+ m_activeThreadStatus.resize( m_numThreads );
+ m_completeHandles.resize( m_numThreads );
+ m_startedThreadMask = 0;
+
+ // set main thread affinity
+ if ( DWORD_PTR mask = dwProcessAffinityMask & getProcessorTeamMask( procInfo, 0 ))
+ {
+ SetThreadAffinityMask( GetCurrentThread(), mask );
+ SetThreadIdealProcessor( GetCurrentThread(), 0 );
+ }
+
+ for ( int i = 0; i < m_numThreads; i++ )
+ {
+ printf( "starting thread %d\n", i );
+
+ btThreadStatus& threadStatus = m_activeThreadStatus[ i ];
+
+ LPSECURITY_ATTRIBUTES lpThreadAttributes = NULL;
+ SIZE_T dwStackSize = threadConstructionInfo.m_threadStackSize;
+ LPTHREAD_START_ROUTINE lpStartAddress = &win32threadStartFunc;
+ LPVOID lpParameter = &threadStatus;
+ DWORD dwCreationFlags = 0;
+ LPDWORD lpThreadId = 0;
+
+ threadStatus.m_userPtr = 0;
+
+ sprintf( threadStatus.m_eventStartHandleName, "es%.8s%d%d", threadConstructionInfo.m_uniqueName, uniqueId, i );
+ threadStatus.m_eventStartHandle = CreateEventA( 0, false, false, threadStatus.m_eventStartHandleName );
+
+ sprintf( threadStatus.m_eventCompleteHandleName, "ec%.8s%d%d", threadConstructionInfo.m_uniqueName, uniqueId, i );
+ threadStatus.m_eventCompleteHandle = CreateEventA( 0, false, false, threadStatus.m_eventCompleteHandleName );
+
+ m_completeHandles[ i ] = threadStatus.m_eventCompleteHandle;
+
+ HANDLE handle = CreateThread( lpThreadAttributes, dwStackSize, lpStartAddress, lpParameter, dwCreationFlags, lpThreadId );
+ //SetThreadPriority( handle, THREAD_PRIORITY_HIGHEST );
+ // highest priority -- can cause erratic performance when numThreads > numCores
+ // we don't want worker threads to be higher priority than the main thread or the main thread could get
+ // totally shut out and unable to tell the workers to stop
+ //SetThreadPriority( handle, THREAD_PRIORITY_BELOW_NORMAL );
+
+ {
+ int processorId = i + 1; // leave processor 0 for main thread
+ DWORD_PTR teamMask = getProcessorTeamMask( procInfo, processorId );
+ if ( teamMask )
+ {
+ // bind each thread to only execute on processors of it's assigned team
+ // - for single-socket Intel x86 CPUs this has no effect (only a single, shared L3 cache so there is only 1 team)
+ // - for multi-socket Intel this will keep threads from migrating from one socket to another
+ // - for AMD Ryzen this will keep threads from migrating from one CCX to another
+ DWORD_PTR mask = teamMask & dwProcessAffinityMask;
+ if ( mask )
+ {
+ SetThreadAffinityMask( handle, mask );
+ }
+ }
+ SetThreadIdealProcessor( handle, processorId );
+ }
+
+ threadStatus.m_taskId = i;
+ threadStatus.m_commandId = 0;
+ threadStatus.m_status = 0;
+ threadStatus.m_threadHandle = handle;
+ threadStatus.m_userThreadFunc = threadConstructionInfo.m_userThreadFunc;
+
+ printf( "started %s thread %d with threadHandle %p\n", threadConstructionInfo.m_uniqueName, i, handle );
+ }
+}
+
+///tell the task scheduler we are done with the SPU tasks
+void btThreadSupportWin32::stopThreads()
+{
+ for ( int i = 0; i < m_activeThreadStatus.size(); i++ )
+ {
+ btThreadStatus& threadStatus = m_activeThreadStatus[ i ];
+ if ( threadStatus.m_status > 0 )
+ {
+ WaitForSingleObject( threadStatus.m_eventCompleteHandle, INFINITE );
+ }
+
+ threadStatus.m_userPtr = NULL;
+ SetEvent( threadStatus.m_eventStartHandle );
+ WaitForSingleObject( threadStatus.m_eventCompleteHandle, INFINITE );
+
+ CloseHandle( threadStatus.m_eventCompleteHandle );
+ CloseHandle( threadStatus.m_eventStartHandle );
+ CloseHandle( threadStatus.m_threadHandle );
+
+ }
+
+ m_activeThreadStatus.clear();
+ m_completeHandles.clear();
+}
+
+
+class btWin32CriticalSection : public btCriticalSection
+{
+private:
+ CRITICAL_SECTION mCriticalSection;
+
+public:
+ btWin32CriticalSection()
+ {
+ InitializeCriticalSection( &mCriticalSection );
+ }
+
+ ~btWin32CriticalSection()
+ {
+ DeleteCriticalSection( &mCriticalSection );
+ }
+
+ void lock()
+ {
+ EnterCriticalSection( &mCriticalSection );
+ }
+
+ void unlock()
+ {
+ LeaveCriticalSection( &mCriticalSection );
+ }
+};
+
+
+btCriticalSection* btThreadSupportWin32::createCriticalSection()
+{
+ unsigned char* mem = (unsigned char*) btAlignedAlloc( sizeof( btWin32CriticalSection ), 16 );
+ btWin32CriticalSection* cs = new( mem ) btWin32CriticalSection();
+ return cs;
+}
+
+void btThreadSupportWin32::deleteCriticalSection( btCriticalSection* criticalSection )
+{
+ criticalSection->~btCriticalSection();
+ btAlignedFree( criticalSection );
+}
+
+
+btThreadSupportInterface* btThreadSupportInterface::create( const ConstructionInfo& info )
+{
+ return new btThreadSupportWin32( info );
+}
+
+
+
+#endif //defined(_WIN32) && BT_THREADSAFE
+
diff --git a/thirdparty/bullet/LinearMath/btAlignedAllocator.cpp b/thirdparty/bullet/LinearMath/btAlignedAllocator.cpp
index e5f6040c43..0526a42283 100644
--- a/thirdparty/bullet/LinearMath/btAlignedAllocator.cpp
+++ b/thirdparty/bullet/LinearMath/btAlignedAllocator.cpp
@@ -15,9 +15,11 @@ subject to the following restrictions:
#include "btAlignedAllocator.h"
+#ifdef BT_DEBUG_MEMORY_ALLOCATIONS
int gNumAlignedAllocs = 0;
int gNumAlignedFree = 0;
int gTotalBytesAlignedAllocs = 0;//detect memory leaks
+#endif //BT_DEBUG_MEMORY_ALLOCATIONST_DEBUG_ALLOCATIONS
static void *btAllocDefault(size_t size)
{
@@ -246,7 +248,6 @@ void btAlignedFreeInternal (void* ptr,int line,char* filename)
void* btAlignedAllocInternal (size_t size, int alignment)
{
- gNumAlignedAllocs++;
void* ptr;
ptr = sAlignedAllocFunc(size, alignment);
// printf("btAlignedAllocInternal %d, %x\n",size,ptr);
@@ -260,7 +261,6 @@ void btAlignedFreeInternal (void* ptr)
return;
}
- gNumAlignedFree++;
// printf("btAlignedFreeInternal %x\n",ptr);
sAlignedFreeFunc(ptr);
}
diff --git a/thirdparty/bullet/LinearMath/btHashMap.h b/thirdparty/bullet/LinearMath/btHashMap.h
index 5e9cdb6054..180e7b44af 100644
--- a/thirdparty/bullet/LinearMath/btHashMap.h
+++ b/thirdparty/bullet/LinearMath/btHashMap.h
@@ -17,12 +17,13 @@ subject to the following restrictions:
#ifndef BT_HASH_MAP_H
#define BT_HASH_MAP_H
+#include <string>
#include "btAlignedObjectArray.h"
///very basic hashable string implementation, compatible with btHashMap
struct btHashString
{
- const char* m_string;
+ std::string m_string1;
unsigned int m_hash;
SIMD_FORCE_INLINE unsigned int getHash()const
@@ -30,8 +31,13 @@ struct btHashString
return m_hash;
}
+ btHashString()
+ {
+ m_string1="";
+ m_hash=0;
+ }
btHashString(const char* name)
- :m_string(name)
+ :m_string1(name)
{
/* magic numbers from http://www.isthe.com/chongo/tech/comp/fnv/ */
static const unsigned int InitialFNV = 2166136261u;
@@ -40,36 +46,18 @@ struct btHashString
/* Fowler / Noll / Vo (FNV) Hash */
unsigned int hash = InitialFNV;
- for(int i = 0; m_string[i]; i++)
+ for(int i = 0; m_string1.c_str()[i]; i++)
{
- hash = hash ^ (m_string[i]); /* xor the low 8 bits */
+ hash = hash ^ (m_string1.c_str()[i]); /* xor the low 8 bits */
hash = hash * FNVMultiple; /* multiply by the magic number */
}
m_hash = hash;
}
- int portableStringCompare(const char* src, const char* dst) const
- {
- int ret = 0 ;
-
- while( ! (ret = *(const unsigned char *)src - *(const unsigned char *)dst) && *dst)
- ++src, ++dst;
-
- if ( ret < 0 )
- ret = -1 ;
- else if ( ret > 0 )
- ret = 1 ;
-
- return( ret );
- }
-
bool equals(const btHashString& other) const
{
- return (m_string == other.m_string) ||
- (0==portableStringCompare(m_string,other.m_string));
-
+ return (m_string1 == other.m_string1);
}
-
};
const int BT_HASH_NULL=0xffffffff;
diff --git a/thirdparty/bullet/LinearMath/btIDebugDraw.h b/thirdparty/bullet/LinearMath/btIDebugDraw.h
index 936aaa896b..b57282717d 100644
--- a/thirdparty/bullet/LinearMath/btIDebugDraw.h
+++ b/thirdparty/bullet/LinearMath/btIDebugDraw.h
@@ -166,9 +166,9 @@ class btIDebugDraw
virtual void drawTransform(const btTransform& transform, btScalar orthoLen)
{
btVector3 start = transform.getOrigin();
- drawLine(start, start+transform.getBasis() * btVector3(orthoLen, 0, 0), btVector3(1.f,0.3,0.3));
- drawLine(start, start+transform.getBasis() * btVector3(0, orthoLen, 0), btVector3(0.3,1.f, 0.3));
- drawLine(start, start+transform.getBasis() * btVector3(0, 0, orthoLen), btVector3(0.3, 0.3,1.f));
+ drawLine(start, start+transform.getBasis() * btVector3(orthoLen, 0, 0), btVector3(btScalar(1.), btScalar(0.3), btScalar(0.3)));
+ drawLine(start, start+transform.getBasis() * btVector3(0, orthoLen, 0), btVector3(btScalar(0.3), btScalar(1.), btScalar(0.3)));
+ drawLine(start, start+transform.getBasis() * btVector3(0, 0, orthoLen), btVector3(btScalar(0.3), btScalar(0.3), btScalar(1.)));
}
virtual void drawArc(const btVector3& center, const btVector3& normal, const btVector3& axis, btScalar radiusA, btScalar radiusB, btScalar minAngle, btScalar maxAngle,
diff --git a/thirdparty/bullet/LinearMath/btMatrix3x3.h b/thirdparty/bullet/LinearMath/btMatrix3x3.h
index 9f642a1779..6cc4993da5 100644
--- a/thirdparty/bullet/LinearMath/btMatrix3x3.h
+++ b/thirdparty/bullet/LinearMath/btMatrix3x3.h
@@ -289,7 +289,7 @@ public:
/** @brief Set the matrix from euler angles YPR around ZYX axes
* @param eulerX Roll about X axis
* @param eulerY Pitch around Y axis
- * @param eulerZ Yaw aboud Z axis
+ * @param eulerZ Yaw about Z axis
*
* These angles are used to produce a rotation matrix. The euler
* angles are applied in ZYX order. I.e a vector is first rotated
@@ -514,7 +514,7 @@ public:
/**@brief Get the matrix represented as euler angles around ZYX
- * @param yaw Yaw around X axis
+ * @param yaw Yaw around Z axis
* @param pitch Pitch around Y axis
* @param roll around X axis
* @param solution_number Which solution of two possible solutions ( 1 or 2) are possible values*/
@@ -649,6 +649,10 @@ public:
///extractRotation is from "A robust method to extract the rotational part of deformations"
///See http://dl.acm.org/citation.cfm?doid=2994258.2994269
+ ///decomposes a matrix A in a orthogonal matrix R and a
+ ///symmetric matrix S:
+ ///A = R*S.
+ ///note that R can include both rotation and scaling.
SIMD_FORCE_INLINE void extractRotation(btQuaternion &q,btScalar tolerance = 1.0e-9, int maxIter=100)
{
int iter =0;
@@ -673,25 +677,93 @@ public:
- /**@brief diagonalizes this matrix
+
+ /**@brief diagonalizes this matrix by the Jacobi method.
* @param rot stores the rotation from the coordinate system in which the matrix is diagonal to the original
- * coordinate system, i.e., old_this = rot * new_this * rot^T.
+ * coordinate system, i.e., old_this = rot * new_this * rot^T.
* @param threshold See iteration
- * @param maxIter The iteration stops when we hit the given tolerance or when maxIter have been executed.
+ * @param iteration The iteration stops when all off-diagonal elements are less than the threshold multiplied
+ * by the sum of the absolute values of the diagonal, or when maxSteps have been executed.
+ *
+ * Note that this matrix is assumed to be symmetric.
*/
- void diagonalize(btMatrix3x3& rot, btScalar tolerance = 1.0e-9, int maxIter=100)
+ void diagonalize(btMatrix3x3& rot, btScalar threshold, int maxSteps)
{
- btQuaternion r;
- r = btQuaternion::getIdentity();
- extractRotation(r,tolerance,maxIter);
- rot.setRotation(r);
- btMatrix3x3 rotInv = btMatrix3x3(r.inverse());
- btMatrix3x3 old = *this;
- setValue(old.tdotx( rotInv[0]), old.tdoty( rotInv[0]), old.tdotz( rotInv[0]),
- old.tdotx( rotInv[1]), old.tdoty( rotInv[1]), old.tdotz( rotInv[1]),
- old.tdotx( rotInv[2]), old.tdoty( rotInv[2]), old.tdotz( rotInv[2]));
- }
+ rot.setIdentity();
+ for (int step = maxSteps; step > 0; step--)
+ {
+ // find off-diagonal element [p][q] with largest magnitude
+ int p = 0;
+ int q = 1;
+ int r = 2;
+ btScalar max = btFabs(m_el[0][1]);
+ btScalar v = btFabs(m_el[0][2]);
+ if (v > max)
+ {
+ q = 2;
+ r = 1;
+ max = v;
+ }
+ v = btFabs(m_el[1][2]);
+ if (v > max)
+ {
+ p = 1;
+ q = 2;
+ r = 0;
+ max = v;
+ }
+
+ btScalar t = threshold * (btFabs(m_el[0][0]) + btFabs(m_el[1][1]) + btFabs(m_el[2][2]));
+ if (max <= t)
+ {
+ if (max <= SIMD_EPSILON * t)
+ {
+ return;
+ }
+ step = 1;
+ }
+ // compute Jacobi rotation J which leads to a zero for element [p][q]
+ btScalar mpq = m_el[p][q];
+ btScalar theta = (m_el[q][q] - m_el[p][p]) / (2 * mpq);
+ btScalar theta2 = theta * theta;
+ btScalar cos;
+ btScalar sin;
+ if (theta2 * theta2 < btScalar(10 / SIMD_EPSILON))
+ {
+ t = (theta >= 0) ? 1 / (theta + btSqrt(1 + theta2))
+ : 1 / (theta - btSqrt(1 + theta2));
+ cos = 1 / btSqrt(1 + t * t);
+ sin = cos * t;
+ }
+ else
+ {
+ // approximation for large theta-value, i.e., a nearly diagonal matrix
+ t = 1 / (theta * (2 + btScalar(0.5) / theta2));
+ cos = 1 - btScalar(0.5) * t * t;
+ sin = cos * t;
+ }
+
+ // apply rotation to matrix (this = J^T * this * J)
+ m_el[p][q] = m_el[q][p] = 0;
+ m_el[p][p] -= t * mpq;
+ m_el[q][q] += t * mpq;
+ btScalar mrp = m_el[r][p];
+ btScalar mrq = m_el[r][q];
+ m_el[r][p] = m_el[p][r] = cos * mrp - sin * mrq;
+ m_el[r][q] = m_el[q][r] = cos * mrq + sin * mrp;
+
+ // apply rotation to rot (rot = rot * J)
+ for (int i = 0; i < 3; i++)
+ {
+ btVector3& row = rot[i];
+ mrp = row[p];
+ mrq = row[q];
+ row[p] = cos * mrp - sin * mrq;
+ row[q] = cos * mrq + sin * mrp;
+ }
+ }
+ }
diff --git a/thirdparty/bullet/LinearMath/btQuaternion.h b/thirdparty/bullet/LinearMath/btQuaternion.h
index 7bd39e6a33..a98fec7bc4 100644
--- a/thirdparty/bullet/LinearMath/btQuaternion.h
+++ b/thirdparty/bullet/LinearMath/btQuaternion.h
@@ -173,10 +173,28 @@ public:
sqy = m_floats[1] * m_floats[1];
sqz = m_floats[2] * m_floats[2];
squ = m_floats[3] * m_floats[3];
- rollX = btAtan2(2 * (m_floats[1] * m_floats[2] + m_floats[3] * m_floats[0]), squ - sqx - sqy + sqz);
- sarg = btScalar(-2.) * (m_floats[0] * m_floats[2] - m_floats[3] * m_floats[1]);
- pitchY = sarg <= btScalar(-1.0) ? btScalar(-0.5) * SIMD_PI: (sarg >= btScalar(1.0) ? btScalar(0.5) * SIMD_PI : btAsin(sarg));
- yawZ = btAtan2(2 * (m_floats[0] * m_floats[1] + m_floats[3] * m_floats[2]), squ + sqx - sqy - sqz);
+ sarg = btScalar(-2.) * (m_floats[0] * m_floats[2] - m_floats[3] * m_floats[1]);
+
+ // If the pitch angle is PI/2 or -PI/2, we can only compute
+ // the sum roll + yaw. However, any combination that gives
+ // the right sum will produce the correct orientation, so we
+ // set rollX = 0 and compute yawZ.
+ if (sarg <= -btScalar(0.99999))
+ {
+ pitchY = btScalar(-0.5)*SIMD_PI;
+ rollX = 0;
+ yawZ = btScalar(2) * btAtan2(m_floats[0],-m_floats[1]);
+ } else if (sarg >= btScalar(0.99999))
+ {
+ pitchY = btScalar(0.5)*SIMD_PI;
+ rollX = 0;
+ yawZ = btScalar(2) * btAtan2(-m_floats[0], m_floats[1]);
+ } else
+ {
+ pitchY = btAsin(sarg);
+ rollX = btAtan2(2 * (m_floats[1] * m_floats[2] + m_floats[3] * m_floats[0]), squ - sqx - sqy + sqz);
+ yawZ = btAtan2(2 * (m_floats[0] * m_floats[1] + m_floats[3] * m_floats[2]), squ + sqx - sqy - sqz);
+ }
}
/**@brief Add two quaternions
@@ -602,7 +620,9 @@ public:
SIMD_FORCE_INLINE void serialize(struct btQuaternionData& dataOut) const;
- SIMD_FORCE_INLINE void deSerialize(const struct btQuaternionData& dataIn);
+ SIMD_FORCE_INLINE void deSerialize(const struct btQuaternionFloatData& dataIn);
+
+ SIMD_FORCE_INLINE void deSerialize(const struct btQuaternionDoubleData& dataIn);
SIMD_FORCE_INLINE void serializeFloat(struct btQuaternionFloatData& dataOut) const;
@@ -1003,10 +1023,16 @@ SIMD_FORCE_INLINE void btQuaternion::serialize(struct btQuaternionData& dataOut)
dataOut.m_floats[i] = m_floats[i];
}
-SIMD_FORCE_INLINE void btQuaternion::deSerialize(const struct btQuaternionData& dataIn)
+SIMD_FORCE_INLINE void btQuaternion::deSerialize(const struct btQuaternionFloatData& dataIn)
+{
+ for (int i = 0; i<4; i++)
+ m_floats[i] = (btScalar)dataIn.m_floats[i];
+}
+
+SIMD_FORCE_INLINE void btQuaternion::deSerialize(const struct btQuaternionDoubleData& dataIn)
{
for (int i=0;i<4;i++)
- m_floats[i] = dataIn.m_floats[i];
+ m_floats[i] = (btScalar)dataIn.m_floats[i];
}
diff --git a/thirdparty/bullet/LinearMath/btQuickprof.cpp b/thirdparty/bullet/LinearMath/btQuickprof.cpp
index aed3104a6e..1572b96262 100644
--- a/thirdparty/bullet/LinearMath/btQuickprof.cpp
+++ b/thirdparty/bullet/LinearMath/btQuickprof.cpp
@@ -680,56 +680,58 @@ void CProfileManager::dumpAll()
CProfileManager::Release_Iterator(profileIterator);
}
+// clang-format off
+#if defined(_WIN32) && (defined(__MINGW32__) || defined(__MINGW64__))
+ #define BT_HAVE_TLS 1
+#elif __APPLE__ && !TARGET_OS_IPHONE
+ // TODO: Modern versions of iOS support TLS now with updated version checking.
+ #define BT_HAVE_TLS 1
+#elif __linux__
+ #define BT_HAVE_TLS 1
+#endif
+// __thread is broken on Andorid clang until r12b. See
+// https://github.com/android-ndk/ndk/issues/8
+#if defined(__ANDROID__) && defined(__clang__)
+ #if __has_include(<android/ndk-version.h>)
+ #include <android/ndk-version.h>
+ #endif // __has_include(<android/ndk-version.h>)
+ #if defined(__NDK_MAJOR__) && \
+ ((__NDK_MAJOR__ < 12) || ((__NDK_MAJOR__ == 12) && (__NDK_MINOR__ < 1)))
+ #undef BT_HAVE_TLS
+ #endif
+#endif // defined(__ANDROID__) && defined(__clang__)
+// clang-format on
+
+unsigned int btQuickprofGetCurrentThreadIndex2() {
+ const unsigned int kNullIndex = ~0U;
-
-unsigned int btQuickprofGetCurrentThreadIndex2()
-{
#if BT_THREADSAFE
- return btGetCurrentThreadIndex();
-#else // #if BT_THREADSAFE
- const unsigned int kNullIndex = ~0U;
-#ifdef _WIN32
- #if defined(__MINGW32__) || defined(__MINGW64__)
- static __thread unsigned int sThreadIndex = kNullIndex;
- #else
- __declspec( thread ) static unsigned int sThreadIndex = kNullIndex;
- #endif
+ return btGetCurrentThreadIndex();
#else
-#ifdef __APPLE__
- #if TARGET_OS_IPHONE
- unsigned int sThreadIndex = 0;
- return -1;
- #else
- static __thread unsigned int sThreadIndex = kNullIndex;
- #endif
-#else//__APPLE__
-#if __linux__
- static __thread unsigned int sThreadIndex = kNullIndex;
+#if defined(BT_HAVE_TLS)
+ static __thread unsigned int sThreadIndex = kNullIndex;
+#elif defined(_WIN32)
+ __declspec(thread) static unsigned int sThreadIndex = kNullIndex;
#else
- unsigned int sThreadIndex = 0;
- return -1;
+ unsigned int sThreadIndex = 0;
+ return -1;
#endif
-#endif//__APPLE__
-
-#endif
- static int gThreadCounter=0;
- if ( sThreadIndex == kNullIndex )
- {
- sThreadIndex = gThreadCounter++;
- }
- return sThreadIndex;
-#endif // #else // #if BT_THREADSAFE
+ static int gThreadCounter = 0;
+
+ if (sThreadIndex == kNullIndex) {
+ sThreadIndex = gThreadCounter++;
+ }
+ return sThreadIndex;
+#endif //BT_THREADSAFE
}
void btEnterProfileZoneDefault(const char* name)
{
- CProfileManager::Start_Profile( name );
}
void btLeaveProfileZoneDefault()
{
- CProfileManager::Stop_Profile();
}
diff --git a/thirdparty/bullet/LinearMath/btQuickprof.h b/thirdparty/bullet/LinearMath/btQuickprof.h
index 7b38d71b90..98a2675771 100644
--- a/thirdparty/bullet/LinearMath/btQuickprof.h
+++ b/thirdparty/bullet/LinearMath/btQuickprof.h
@@ -70,11 +70,12 @@ void btSetCustomLeaveProfileZoneFunc(btLeaveProfileZoneFunc* leaveFunc);
//#define BT_NO_PROFILE 1
#endif //BT_NO_PROFILE
+const unsigned int BT_QUICKPROF_MAX_THREAD_COUNT = 64;
+
#ifndef BT_NO_PROFILE
//btQuickprofGetCurrentThreadIndex will return -1 if thread index cannot be determined,
//otherwise returns thread index in range [0..maxThreads]
unsigned int btQuickprofGetCurrentThreadIndex2();
-const unsigned int BT_QUICKPROF_MAX_THREAD_COUNT = 64;
#include <stdio.h>//@todo remove this, backwards compatibility
diff --git a/thirdparty/bullet/LinearMath/btScalar.h b/thirdparty/bullet/LinearMath/btScalar.h
index bffb2ce274..24e8454c1f 100644
--- a/thirdparty/bullet/LinearMath/btScalar.h
+++ b/thirdparty/bullet/LinearMath/btScalar.h
@@ -25,7 +25,7 @@ subject to the following restrictions:
#include <float.h>
/* SVN $Revision$ on $Date$ from http://bullet.googlecode.com*/
-#define BT_BULLET_VERSION 287
+#define BT_BULLET_VERSION 288
inline int btGetVersion()
{
diff --git a/thirdparty/bullet/LinearMath/btSerializer.cpp b/thirdparty/bullet/LinearMath/btSerializer.cpp
index fcd2255ad5..4faa8f536b 100644
--- a/thirdparty/bullet/LinearMath/btSerializer.cpp
+++ b/thirdparty/bullet/LinearMath/btSerializer.cpp
@@ -1,5 +1,5 @@
char sBulletDNAstr[]= {
-char(83),char(68),char(78),char(65),char(78),char(65),char(77),char(69),char(-124),char(1),char(0),char(0),char(109),char(95),char(115),char(105),char(122),char(101),char(0),char(109),
+char(83),char(68),char(78),char(65),char(78),char(65),char(77),char(69),char(-76),char(1),char(0),char(0),char(109),char(95),char(115),char(105),char(122),char(101),char(0),char(109),
char(95),char(99),char(97),char(112),char(97),char(99),char(105),char(116),char(121),char(0),char(42),char(109),char(95),char(100),char(97),char(116),char(97),char(0),char(109),char(95),
char(99),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(83),char(104),char(97),char(112),char(101),char(115),char(0),char(109),char(95),char(99),char(111),
char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(79),char(98),char(106),char(101),char(99),char(116),char(115),char(0),char(109),char(95),char(99),char(111),char(110),
@@ -72,528 +72,618 @@ char(105),char(115),char(116),char(97),char(110),char(99),char(101),char(84),cha
char(101),char(114),char(111),char(65),char(114),char(101),char(97),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109),char(95),char(110),
char(101),char(120),char(116),char(83),char(105),char(122),char(101),char(0),char(109),char(95),char(104),char(97),char(115),char(104),char(84),char(97),char(98),char(108),char(101),char(83),
char(105),char(122),char(101),char(0),char(109),char(95),char(110),char(117),char(109),char(86),char(97),char(108),char(117),char(101),char(115),char(0),char(109),char(95),char(110),char(117),
-char(109),char(75),char(101),char(121),char(115),char(0),char(109),char(95),char(103),char(105),char(109),char(112),char(97),char(99),char(116),char(83),char(117),char(98),char(84),char(121),
-char(112),char(101),char(0),char(42),char(109),char(95),char(117),char(110),char(115),char(99),char(97),char(108),char(101),char(100),char(80),char(111),char(105),char(110),char(116),char(115),
-char(70),char(108),char(111),char(97),char(116),char(80),char(116),char(114),char(0),char(42),char(109),char(95),char(117),char(110),char(115),char(99),char(97),char(108),char(101),char(100),
-char(80),char(111),char(105),char(110),char(116),char(115),char(68),char(111),char(117),char(98),char(108),char(101),char(80),char(116),char(114),char(0),char(109),char(95),char(110),char(117),
-char(109),char(85),char(110),char(115),char(99),char(97),char(108),char(101),char(100),char(80),char(111),char(105),char(110),char(116),char(115),char(0),char(109),char(95),char(112),char(97),
-char(100),char(100),char(105),char(110),char(103),char(51),char(91),char(52),char(93),char(0),char(42),char(109),char(95),char(98),char(114),char(111),char(97),char(100),char(112),char(104),
-char(97),char(115),char(101),char(72),char(97),char(110),char(100),char(108),char(101),char(0),char(42),char(109),char(95),char(99),char(111),char(108),char(108),char(105),char(115),char(105),
-char(111),char(110),char(83),char(104),char(97),char(112),char(101),char(0),char(42),char(109),char(95),char(114),char(111),char(111),char(116),char(67),char(111),char(108),char(108),char(105),
-char(115),char(105),char(111),char(110),char(83),char(104),char(97),char(112),char(101),char(0),char(109),char(95),char(119),char(111),char(114),char(108),char(100),char(84),char(114),char(97),
-char(110),char(115),char(102),char(111),char(114),char(109),char(0),char(109),char(95),char(105),char(110),char(116),char(101),char(114),char(112),char(111),char(108),char(97),char(116),char(105),
-char(111),char(110),char(87),char(111),char(114),char(108),char(100),char(84),char(114),char(97),char(110),char(115),char(102),char(111),char(114),char(109),char(0),char(109),char(95),char(105),
-char(110),char(116),char(101),char(114),char(112),char(111),char(108),char(97),char(116),char(105),char(111),char(110),char(76),char(105),char(110),char(101),char(97),char(114),char(86),char(101),
-char(108),char(111),char(99),char(105),char(116),char(121),char(0),char(109),char(95),char(105),char(110),char(116),char(101),char(114),char(112),char(111),char(108),char(97),char(116),char(105),
-char(111),char(110),char(65),char(110),char(103),char(117),char(108),char(97),char(114),char(86),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(0),char(109),char(95),
-char(97),char(110),char(105),char(115),char(111),char(116),char(114),char(111),char(112),char(105),char(99),char(70),char(114),char(105),char(99),char(116),char(105),char(111),char(110),char(0),
-char(109),char(95),char(99),char(111),char(110),char(116),char(97),char(99),char(116),char(80),char(114),char(111),char(99),char(101),char(115),char(115),char(105),char(110),char(103),char(84),
-char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109),char(95),char(100),char(101),char(97),char(99),char(116),char(105),char(118),char(97),char(116),
-char(105),char(111),char(110),char(84),char(105),char(109),char(101),char(0),char(109),char(95),char(102),char(114),char(105),char(99),char(116),char(105),char(111),char(110),char(0),char(109),
-char(95),char(114),char(111),char(108),char(108),char(105),char(110),char(103),char(70),char(114),char(105),char(99),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(99),
-char(111),char(110),char(116),char(97),char(99),char(116),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(0),char(109),char(95),char(99),char(111),char(110),char(116),
-char(97),char(99),char(116),char(83),char(116),char(105),char(102),char(102),char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(114),char(101),char(115),char(116),char(105),
-char(116),char(117),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(104),char(105),char(116),char(70),char(114),char(97),char(99),char(116),char(105),char(111),char(110),
-char(0),char(109),char(95),char(99),char(99),char(100),char(83),char(119),char(101),char(112),char(116),char(83),char(112),char(104),char(101),char(114),char(101),char(82),char(97),char(100),
-char(105),char(117),char(115),char(0),char(109),char(95),char(99),char(99),char(100),char(77),char(111),char(116),char(105),char(111),char(110),char(84),char(104),char(114),char(101),char(115),
-char(104),char(111),char(108),char(100),char(0),char(109),char(95),char(104),char(97),char(115),char(65),char(110),char(105),char(115),char(111),char(116),char(114),char(111),char(112),char(105),
-char(99),char(70),char(114),char(105),char(99),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(99),char(111),char(108),char(108),char(105),char(115),char(105),char(111),
-char(110),char(70),char(108),char(97),char(103),char(115),char(0),char(109),char(95),char(105),char(115),char(108),char(97),char(110),char(100),char(84),char(97),char(103),char(49),char(0),
-char(109),char(95),char(99),char(111),char(109),char(112),char(97),char(110),char(105),char(111),char(110),char(73),char(100),char(0),char(109),char(95),char(97),char(99),char(116),char(105),
-char(118),char(97),char(116),char(105),char(111),char(110),char(83),char(116),char(97),char(116),char(101),char(49),char(0),char(109),char(95),char(105),char(110),char(116),char(101),char(114),
-char(110),char(97),char(108),char(84),char(121),char(112),char(101),char(0),char(109),char(95),char(99),char(104),char(101),char(99),char(107),char(67),char(111),char(108),char(108),char(105),
-char(100),char(101),char(87),char(105),char(116),char(104),char(0),char(109),char(95),char(116),char(97),char(117),char(0),char(109),char(95),char(100),char(97),char(109),char(112),char(105),
-char(110),char(103),char(0),char(109),char(95),char(116),char(105),char(109),char(101),char(83),char(116),char(101),char(112),char(0),char(109),char(95),char(109),char(97),char(120),char(69),
-char(114),char(114),char(111),char(114),char(82),char(101),char(100),char(117),char(99),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(115),char(111),char(114),char(0),
-char(109),char(95),char(101),char(114),char(112),char(0),char(109),char(95),char(101),char(114),char(112),char(50),char(0),char(109),char(95),char(103),char(108),char(111),char(98),char(97),
-char(108),char(67),char(102),char(109),char(0),char(109),char(95),char(115),char(112),char(108),char(105),char(116),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(80),
-char(101),char(110),char(101),char(116),char(114),char(97),char(116),char(105),char(111),char(110),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),
-char(109),char(95),char(115),char(112),char(108),char(105),char(116),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(84),char(117),char(114),char(110),char(69),char(114),
-char(112),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83),char(108),char(111),char(112),char(0),char(109),char(95),char(119),char(97),char(114),
-char(109),char(115),char(116),char(97),char(114),char(116),char(105),char(110),char(103),char(70),char(97),char(99),char(116),char(111),char(114),char(0),char(109),char(95),char(109),char(97),
-char(120),char(71),char(121),char(114),char(111),char(115),char(99),char(111),char(112),char(105),char(99),char(70),char(111),char(114),char(99),char(101),char(0),char(109),char(95),char(115),
-char(105),char(110),char(103),char(108),char(101),char(65),char(120),char(105),char(115),char(82),char(111),char(108),char(108),char(105),char(110),char(103),char(70),char(114),char(105),char(99),
-char(116),char(105),char(111),char(110),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109),char(95),char(110),char(117),char(109),char(73),
-char(116),char(101),char(114),char(97),char(116),char(105),char(111),char(110),char(115),char(0),char(109),char(95),char(115),char(111),char(108),char(118),char(101),char(114),char(77),char(111),
-char(100),char(101),char(0),char(109),char(95),char(114),char(101),char(115),char(116),char(105),char(110),char(103),char(67),char(111),char(110),char(116),char(97),char(99),char(116),char(82),
-char(101),char(115),char(116),char(105),char(116),char(117),char(116),char(105),char(111),char(110),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),
-char(109),char(95),char(109),char(105),char(110),char(105),char(109),char(117),char(109),char(83),char(111),char(108),char(118),char(101),char(114),char(66),char(97),char(116),char(99),char(104),
-char(83),char(105),char(122),char(101),char(0),char(109),char(95),char(115),char(112),char(108),char(105),char(116),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(0),
-char(109),char(95),char(115),char(111),char(108),char(118),char(101),char(114),char(73),char(110),char(102),char(111),char(0),char(109),char(95),char(103),char(114),char(97),char(118),char(105),
-char(116),char(121),char(0),char(109),char(95),char(99),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(79),char(98),char(106),char(101),char(99),char(116),
-char(68),char(97),char(116),char(97),char(0),char(109),char(95),char(105),char(110),char(118),char(73),char(110),char(101),char(114),char(116),char(105),char(97),char(84),char(101),char(110),
-char(115),char(111),char(114),char(87),char(111),char(114),char(108),char(100),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(86),char(101),char(108),
-char(111),char(99),char(105),char(116),char(121),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(86),char(101),char(108),char(111),char(99),
-char(105),char(116),char(121),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(70),char(97),char(99),char(116),char(111),char(114),char(0),
-char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(70),char(97),char(99),char(116),char(111),char(114),char(0),char(109),char(95),char(103),char(114),char(97),
-char(118),char(105),char(116),char(121),char(95),char(97),char(99),char(99),char(101),char(108),char(101),char(114),char(97),char(116),char(105),char(111),char(110),char(0),char(109),char(95),
-char(105),char(110),char(118),char(73),char(110),char(101),char(114),char(116),char(105),char(97),char(76),char(111),char(99),char(97),char(108),char(0),char(109),char(95),char(116),char(111),
-char(116),char(97),char(108),char(70),char(111),char(114),char(99),char(101),char(0),char(109),char(95),char(116),char(111),char(116),char(97),char(108),char(84),char(111),char(114),char(113),
-char(117),char(101),char(0),char(109),char(95),char(105),char(110),char(118),char(101),char(114),char(115),char(101),char(77),char(97),char(115),char(115),char(0),char(109),char(95),char(108),
-char(105),char(110),char(101),char(97),char(114),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),
-char(97),char(114),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(0),char(109),char(95),char(97),char(100),char(100),char(105),char(116),char(105),char(111),char(110),
-char(97),char(108),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(70),char(97),char(99),char(116),char(111),char(114),char(0),char(109),char(95),char(97),char(100),
-char(100),char(105),char(116),char(105),char(111),char(110),char(97),char(108),char(76),char(105),char(110),char(101),char(97),char(114),char(68),char(97),char(109),char(112),char(105),char(110),
-char(103),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(83),char(113),char(114),char(0),char(109),char(95),char(97),char(100),char(100),char(105),
-char(116),char(105),char(111),char(110),char(97),char(108),char(65),char(110),char(103),char(117),char(108),char(97),char(114),char(68),char(97),char(109),char(112),char(105),char(110),char(103),
-char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(83),char(113),char(114),char(0),char(109),char(95),char(97),char(100),char(100),char(105),char(116),
-char(105),char(111),char(110),char(97),char(108),char(65),char(110),char(103),char(117),char(108),char(97),char(114),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(70),
-char(97),char(99),char(116),char(111),char(114),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83),char(108),char(101),char(101),char(112),char(105),
-char(110),char(103),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),
-char(114),char(83),char(108),char(101),char(101),char(112),char(105),char(110),char(103),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109),
-char(95),char(97),char(100),char(100),char(105),char(116),char(105),char(111),char(110),char(97),char(108),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(0),char(109),
-char(95),char(110),char(117),char(109),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(82),char(111),char(119),char(115),char(0),char(110),
-char(117),char(98),char(0),char(42),char(109),char(95),char(114),char(98),char(65),char(0),char(42),char(109),char(95),char(114),char(98),char(66),char(0),char(109),char(95),char(111),
-char(98),char(106),char(101),char(99),char(116),char(84),char(121),char(112),char(101),char(0),char(109),char(95),char(117),char(115),char(101),char(114),char(67),char(111),char(110),char(115),
-char(116),char(114),char(97),char(105),char(110),char(116),char(84),char(121),char(112),char(101),char(0),char(109),char(95),char(117),char(115),char(101),char(114),char(67),char(111),char(110),
-char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(73),char(100),char(0),char(109),char(95),char(110),char(101),char(101),char(100),char(115),char(70),char(101),char(101),
-char(100),char(98),char(97),char(99),char(107),char(0),char(109),char(95),char(97),char(112),char(112),char(108),char(105),char(101),char(100),char(73),char(109),char(112),char(117),char(108),
-char(115),char(101),char(0),char(109),char(95),char(100),char(98),char(103),char(68),char(114),char(97),char(119),char(83),char(105),char(122),char(101),char(0),char(109),char(95),char(100),
-char(105),char(115),char(97),char(98),char(108),char(101),char(67),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(115),char(66),char(101),char(116),char(119),
-char(101),char(101),char(110),char(76),char(105),char(110),char(107),char(101),char(100),char(66),char(111),char(100),char(105),char(101),char(115),char(0),char(109),char(95),char(111),char(118),
-char(101),char(114),char(114),char(105),char(100),char(101),char(78),char(117),char(109),char(83),char(111),char(108),char(118),char(101),char(114),char(73),char(116),char(101),char(114),char(97),
-char(116),char(105),char(111),char(110),char(115),char(0),char(109),char(95),char(98),char(114),char(101),char(97),char(107),char(105),char(110),char(103),char(73),char(109),char(112),char(117),
-char(108),char(115),char(101),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109),char(95),char(105),char(115),char(69),char(110),char(97),
-char(98),char(108),char(101),char(100),char(0),char(112),char(97),char(100),char(100),char(105),char(110),char(103),char(91),char(52),char(93),char(0),char(109),char(95),char(116),char(121),
-char(112),char(101),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(97),char(116),char(97),char(0),char(109),char(95),char(112),
-char(105),char(118),char(111),char(116),char(73),char(110),char(65),char(0),char(109),char(95),char(112),char(105),char(118),char(111),char(116),char(73),char(110),char(66),char(0),char(109),
-char(95),char(114),char(98),char(65),char(70),char(114),char(97),char(109),char(101),char(0),char(109),char(95),char(114),char(98),char(66),char(70),char(114),char(97),char(109),char(101),
-char(0),char(109),char(95),char(117),char(115),char(101),char(82),char(101),char(102),char(101),char(114),char(101),char(110),char(99),char(101),char(70),char(114),char(97),char(109),char(101),
-char(65),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(79),char(110),char(108),char(121),char(0),char(109),char(95),char(101),char(110),
-char(97),char(98),char(108),char(101),char(65),char(110),char(103),char(117),char(108),char(97),char(114),char(77),char(111),char(116),char(111),char(114),char(0),char(109),char(95),char(109),
-char(111),char(116),char(111),char(114),char(84),char(97),char(114),char(103),char(101),char(116),char(86),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(0),char(109),
-char(95),char(109),char(97),char(120),char(77),char(111),char(116),char(111),char(114),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(0),char(109),char(95),char(108),
-char(111),char(119),char(101),char(114),char(76),char(105),char(109),char(105),char(116),char(0),char(109),char(95),char(117),char(112),char(112),char(101),char(114),char(76),char(105),char(109),
-char(105),char(116),char(0),char(109),char(95),char(108),char(105),char(109),char(105),char(116),char(83),char(111),char(102),char(116),char(110),char(101),char(115),char(115),char(0),char(109),
-char(95),char(98),char(105),char(97),char(115),char(70),char(97),char(99),char(116),char(111),char(114),char(0),char(109),char(95),char(114),char(101),char(108),char(97),char(120),char(97),
-char(116),char(105),char(111),char(110),char(70),char(97),char(99),char(116),char(111),char(114),char(0),char(109),char(95),char(112),char(97),char(100),char(100),char(105),char(110),char(103),
-char(49),char(91),char(52),char(93),char(0),char(109),char(95),char(115),char(119),char(105),char(110),char(103),char(83),char(112),char(97),char(110),char(49),char(0),char(109),char(95),
-char(115),char(119),char(105),char(110),char(103),char(83),char(112),char(97),char(110),char(50),char(0),char(109),char(95),char(116),char(119),char(105),char(115),char(116),char(83),char(112),
-char(97),char(110),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(85),char(112),char(112),char(101),char(114),char(76),char(105),char(109),char(105),
-char(116),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(76),char(111),char(119),char(101),char(114),char(76),char(105),char(109),char(105),char(116),
-char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(85),char(112),char(112),char(101),char(114),char(76),char(105),char(109),char(105),char(116),
-char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(76),char(111),char(119),char(101),char(114),char(76),char(105),char(109),char(105),char(116),
-char(0),char(109),char(95),char(117),char(115),char(101),char(76),char(105),char(110),char(101),char(97),char(114),char(82),char(101),char(102),char(101),char(114),char(101),char(110),char(99),
-char(101),char(70),char(114),char(97),char(109),char(101),char(65),char(0),char(109),char(95),char(117),char(115),char(101),char(79),char(102),char(102),char(115),char(101),char(116),char(70),
-char(111),char(114),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(70),char(114),char(97),char(109),char(101),char(0),char(109),char(95),
-char(54),char(100),char(111),char(102),char(68),char(97),char(116),char(97),char(0),char(109),char(95),char(115),char(112),char(114),char(105),char(110),char(103),char(69),char(110),char(97),
-char(98),char(108),char(101),char(100),char(91),char(54),char(93),char(0),char(109),char(95),char(101),char(113),char(117),char(105),char(108),char(105),char(98),char(114),char(105),char(117),
-char(109),char(80),char(111),char(105),char(110),char(116),char(91),char(54),char(93),char(0),char(109),char(95),char(115),char(112),char(114),char(105),char(110),char(103),char(83),char(116),
-char(105),char(102),char(102),char(110),char(101),char(115),char(115),char(91),char(54),char(93),char(0),char(109),char(95),char(115),char(112),char(114),char(105),char(110),char(103),char(68),
-char(97),char(109),char(112),char(105),char(110),char(103),char(91),char(54),char(93),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(66),char(111),
-char(117),char(110),char(99),char(101),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83),char(116),char(111),char(112),char(69),char(82),char(80),
-char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83),char(116),char(111),char(112),char(67),char(70),char(77),char(0),char(109),char(95),char(108),
-char(105),char(110),char(101),char(97),char(114),char(77),char(111),char(116),char(111),char(114),char(69),char(82),char(80),char(0),char(109),char(95),char(108),char(105),char(110),char(101),
-char(97),char(114),char(77),char(111),char(116),char(111),char(114),char(67),char(70),char(77),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(84),
-char(97),char(114),char(103),char(101),char(116),char(86),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(0),char(109),char(95),char(108),char(105),char(110),char(101),
-char(97),char(114),char(77),char(97),char(120),char(77),char(111),char(116),char(111),char(114),char(70),char(111),char(114),char(99),char(101),char(0),char(109),char(95),char(108),char(105),
-char(110),char(101),char(97),char(114),char(83),char(101),char(114),char(118),char(111),char(84),char(97),char(114),char(103),char(101),char(116),char(0),char(109),char(95),char(108),char(105),
-char(110),char(101),char(97),char(114),char(83),char(112),char(114),char(105),char(110),char(103),char(83),char(116),char(105),char(102),char(102),char(110),char(101),char(115),char(115),char(0),
-char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83),char(112),char(114),char(105),char(110),char(103),char(68),char(97),char(109),char(112),char(105),char(110),
-char(103),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(69),char(113),char(117),char(105),char(108),char(105),char(98),char(114),char(105),char(117),
-char(109),char(80),char(111),char(105),char(110),char(116),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(69),char(110),char(97),char(98),char(108),
-char(101),char(77),char(111),char(116),char(111),char(114),char(91),char(52),char(93),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83),char(101),
-char(114),char(118),char(111),char(77),char(111),char(116),char(111),char(114),char(91),char(52),char(93),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),
-char(69),char(110),char(97),char(98),char(108),char(101),char(83),char(112),char(114),char(105),char(110),char(103),char(91),char(52),char(93),char(0),char(109),char(95),char(108),char(105),
-char(110),char(101),char(97),char(114),char(83),char(112),char(114),char(105),char(110),char(103),char(83),char(116),char(105),char(102),char(102),char(110),char(101),char(115),char(115),char(76),
-char(105),char(109),char(105),char(116),char(101),char(100),char(91),char(52),char(93),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83),char(112),
-char(114),char(105),char(110),char(103),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(76),char(105),char(109),char(105),char(116),char(101),char(100),char(91),char(52),
-char(93),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(66),char(111),char(117),char(110),char(99),char(101),char(0),char(109),char(95),
-char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(83),char(116),char(111),char(112),char(69),char(82),char(80),char(0),char(109),char(95),char(97),char(110),char(103),
-char(117),char(108),char(97),char(114),char(83),char(116),char(111),char(112),char(67),char(70),char(77),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),
-char(114),char(77),char(111),char(116),char(111),char(114),char(69),char(82),char(80),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(77),
-char(111),char(116),char(111),char(114),char(67),char(70),char(77),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(84),char(97),char(114),
-char(103),char(101),char(116),char(86),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),
-char(114),char(77),char(97),char(120),char(77),char(111),char(116),char(111),char(114),char(70),char(111),char(114),char(99),char(101),char(0),char(109),char(95),char(97),char(110),char(103),
-char(117),char(108),char(97),char(114),char(83),char(101),char(114),char(118),char(111),char(84),char(97),char(114),char(103),char(101),char(116),char(0),char(109),char(95),char(97),char(110),
-char(103),char(117),char(108),char(97),char(114),char(83),char(112),char(114),char(105),char(110),char(103),char(83),char(116),char(105),char(102),char(102),char(110),char(101),char(115),char(115),
-char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(83),char(112),char(114),char(105),char(110),char(103),char(68),char(97),char(109),char(112),
-char(105),char(110),char(103),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(69),char(113),char(117),char(105),char(108),char(105),char(98),
-char(114),char(105),char(117),char(109),char(80),char(111),char(105),char(110),char(116),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(69),
-char(110),char(97),char(98),char(108),char(101),char(77),char(111),char(116),char(111),char(114),char(91),char(52),char(93),char(0),char(109),char(95),char(97),char(110),char(103),char(117),
-char(108),char(97),char(114),char(83),char(101),char(114),char(118),char(111),char(77),char(111),char(116),char(111),char(114),char(91),char(52),char(93),char(0),char(109),char(95),char(97),
-char(110),char(103),char(117),char(108),char(97),char(114),char(69),char(110),char(97),char(98),char(108),char(101),char(83),char(112),char(114),char(105),char(110),char(103),char(91),char(52),
-char(93),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(83),char(112),char(114),char(105),char(110),char(103),char(83),char(116),char(105),
-char(102),char(102),char(110),char(101),char(115),char(115),char(76),char(105),char(109),char(105),char(116),char(101),char(100),char(91),char(52),char(93),char(0),char(109),char(95),char(97),
-char(110),char(103),char(117),char(108),char(97),char(114),char(83),char(112),char(114),char(105),char(110),char(103),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(76),
-char(105),char(109),char(105),char(116),char(101),char(100),char(91),char(52),char(93),char(0),char(109),char(95),char(114),char(111),char(116),char(97),char(116),char(101),char(79),char(114),
-char(100),char(101),char(114),char(0),char(109),char(95),char(97),char(120),char(105),char(115),char(73),char(110),char(65),char(0),char(109),char(95),char(97),char(120),char(105),char(115),
-char(73),char(110),char(66),char(0),char(109),char(95),char(114),char(97),char(116),char(105),char(111),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),
-char(83),char(116),char(105),char(102),char(102),char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(83),
-char(116),char(105),char(102),char(102),char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(118),char(111),char(108),char(117),char(109),char(101),char(83),char(116),char(105),
-char(102),char(102),char(110),char(101),char(115),char(115),char(0),char(42),char(109),char(95),char(109),char(97),char(116),char(101),char(114),char(105),char(97),char(108),char(0),char(109),
-char(95),char(112),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(112),char(114),char(101),char(118),char(105),char(111),char(117),char(115),
-char(80),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(118),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(0),
-char(109),char(95),char(97),char(99),char(99),char(117),char(109),char(117),char(108),char(97),char(116),char(101),char(100),char(70),char(111),char(114),char(99),char(101),char(0),char(109),
-char(95),char(110),char(111),char(114),char(109),char(97),char(108),char(0),char(109),char(95),char(97),char(114),char(101),char(97),char(0),char(109),char(95),char(97),char(116),char(116),
-char(97),char(99),char(104),char(0),char(109),char(95),char(110),char(111),char(100),char(101),char(73),char(110),char(100),char(105),char(99),char(101),char(115),char(91),char(50),char(93),
-char(0),char(109),char(95),char(114),char(101),char(115),char(116),char(76),char(101),char(110),char(103),char(116),char(104),char(0),char(109),char(95),char(98),char(98),char(101),char(110),
-char(100),char(105),char(110),char(103),char(0),char(109),char(95),char(110),char(111),char(100),char(101),char(73),char(110),char(100),char(105),char(99),char(101),char(115),char(91),char(51),
-char(93),char(0),char(109),char(95),char(114),char(101),char(115),char(116),char(65),char(114),char(101),char(97),char(0),char(109),char(95),char(99),char(48),char(91),char(52),char(93),
-char(0),char(109),char(95),char(110),char(111),char(100),char(101),char(73),char(110),char(100),char(105),char(99),char(101),char(115),char(91),char(52),char(93),char(0),char(109),char(95),
-char(114),char(101),char(115),char(116),char(86),char(111),char(108),char(117),char(109),char(101),char(0),char(109),char(95),char(99),char(49),char(0),char(109),char(95),char(99),char(50),
-char(0),char(109),char(95),char(99),char(48),char(0),char(109),char(95),char(108),char(111),char(99),char(97),char(108),char(70),char(114),char(97),char(109),char(101),char(0),char(42),
-char(109),char(95),char(114),char(105),char(103),char(105),char(100),char(66),char(111),char(100),char(121),char(0),char(109),char(95),char(110),char(111),char(100),char(101),char(73),char(110),
-char(100),char(101),char(120),char(0),char(109),char(95),char(97),char(101),char(114),char(111),char(77),char(111),char(100),char(101),char(108),char(0),char(109),char(95),char(98),char(97),
-char(117),char(109),char(103),char(97),char(114),char(116),char(101),char(0),char(109),char(95),char(100),char(114),char(97),char(103),char(0),char(109),char(95),char(108),char(105),char(102),
-char(116),char(0),char(109),char(95),char(112),char(114),char(101),char(115),char(115),char(117),char(114),char(101),char(0),char(109),char(95),char(118),char(111),char(108),char(117),char(109),
-char(101),char(0),char(109),char(95),char(100),char(121),char(110),char(97),char(109),char(105),char(99),char(70),char(114),char(105),char(99),char(116),char(105),char(111),char(110),char(0),
-char(109),char(95),char(112),char(111),char(115),char(101),char(77),char(97),char(116),char(99),char(104),char(0),char(109),char(95),char(114),char(105),char(103),char(105),char(100),char(67),
-char(111),char(110),char(116),char(97),char(99),char(116),char(72),char(97),char(114),char(100),char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(107),char(105),char(110),
-char(101),char(116),char(105),char(99),char(67),char(111),char(110),char(116),char(97),char(99),char(116),char(72),char(97),char(114),char(100),char(110),char(101),char(115),char(115),char(0),
-char(109),char(95),char(115),char(111),char(102),char(116),char(67),char(111),char(110),char(116),char(97),char(99),char(116),char(72),char(97),char(114),char(100),char(110),char(101),char(115),
-char(115),char(0),char(109),char(95),char(97),char(110),char(99),char(104),char(111),char(114),char(72),char(97),char(114),char(100),char(110),char(101),char(115),char(115),char(0),char(109),
-char(95),char(115),char(111),char(102),char(116),char(82),char(105),char(103),char(105),char(100),char(67),char(108),char(117),char(115),char(116),char(101),char(114),char(72),char(97),char(114),
-char(100),char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(115),char(111),char(102),char(116),char(75),char(105),char(110),char(101),char(116),char(105),char(99),char(67),
-char(108),char(117),char(115),char(116),char(101),char(114),char(72),char(97),char(114),char(100),char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(115),char(111),char(102),
-char(116),char(83),char(111),char(102),char(116),char(67),char(108),char(117),char(115),char(116),char(101),char(114),char(72),char(97),char(114),char(100),char(110),char(101),char(115),char(115),
-char(0),char(109),char(95),char(115),char(111),char(102),char(116),char(82),char(105),char(103),char(105),char(100),char(67),char(108),char(117),char(115),char(116),char(101),char(114),char(73),
-char(109),char(112),char(117),char(108),char(115),char(101),char(83),char(112),char(108),char(105),char(116),char(0),char(109),char(95),char(115),char(111),char(102),char(116),char(75),char(105),
-char(110),char(101),char(116),char(105),char(99),char(67),char(108),char(117),char(115),char(116),char(101),char(114),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(83),
-char(112),char(108),char(105),char(116),char(0),char(109),char(95),char(115),char(111),char(102),char(116),char(83),char(111),char(102),char(116),char(67),char(108),char(117),char(115),char(116),
-char(101),char(114),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(83),char(112),char(108),char(105),char(116),char(0),char(109),char(95),char(109),char(97),char(120),
-char(86),char(111),char(108),char(117),char(109),char(101),char(0),char(109),char(95),char(116),char(105),char(109),char(101),char(83),char(99),char(97),char(108),char(101),char(0),char(109),
-char(95),char(118),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(73),char(116),char(101),char(114),char(97),char(116),char(105),char(111),char(110),char(115),char(0),
-char(109),char(95),char(112),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(73),char(116),char(101),char(114),char(97),char(116),char(105),char(111),char(110),char(115),
-char(0),char(109),char(95),char(100),char(114),char(105),char(102),char(116),char(73),char(116),char(101),char(114),char(97),char(116),char(105),char(111),char(110),char(115),char(0),char(109),
-char(95),char(99),char(108),char(117),char(115),char(116),char(101),char(114),char(73),char(116),char(101),char(114),char(97),char(116),char(105),char(111),char(110),char(115),char(0),char(109),
-char(95),char(114),char(111),char(116),char(0),char(109),char(95),char(115),char(99),char(97),char(108),char(101),char(0),char(109),char(95),char(97),char(113),char(113),char(0),char(109),
-char(95),char(99),char(111),char(109),char(0),char(42),char(109),char(95),char(112),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(115),char(0),char(42),char(109),
-char(95),char(119),char(101),char(105),char(103),char(104),char(116),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(80),char(111),char(115),char(105),char(116),char(105),
-char(111),char(110),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(87),char(101),char(105),char(103),char(116),char(115),char(0),char(109),char(95),char(98),char(118),
-char(111),char(108),char(117),char(109),char(101),char(0),char(109),char(95),char(98),char(102),char(114),char(97),char(109),char(101),char(0),char(109),char(95),char(102),char(114),char(97),
-char(109),char(101),char(120),char(102),char(111),char(114),char(109),char(0),char(109),char(95),char(108),char(111),char(99),char(105),char(105),char(0),char(109),char(95),char(105),char(110),
-char(118),char(119),char(105),char(0),char(109),char(95),char(118),char(105),char(109),char(112),char(117),char(108),char(115),char(101),char(115),char(91),char(50),char(93),char(0),char(109),
-char(95),char(100),char(105),char(109),char(112),char(117),char(108),char(115),char(101),char(115),char(91),char(50),char(93),char(0),char(109),char(95),char(108),char(118),char(0),char(109),
-char(95),char(97),char(118),char(0),char(42),char(109),char(95),char(102),char(114),char(97),char(109),char(101),char(114),char(101),char(102),char(115),char(0),char(42),char(109),char(95),
-char(110),char(111),char(100),char(101),char(73),char(110),char(100),char(105),char(99),char(101),char(115),char(0),char(42),char(109),char(95),char(109),char(97),char(115),char(115),char(101),
-char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(70),char(114),char(97),char(109),char(101),char(82),char(101),char(102),char(115),char(0),char(109),char(95),char(110),
-char(117),char(109),char(78),char(111),char(100),char(101),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(77),char(97),char(115),char(115),char(101),char(115),char(0),
-char(109),char(95),char(105),char(100),char(109),char(97),char(115),char(115),char(0),char(109),char(95),char(105),char(109),char(97),char(115),char(115),char(0),char(109),char(95),char(110),
-char(118),char(105),char(109),char(112),char(117),char(108),char(115),char(101),char(115),char(0),char(109),char(95),char(110),char(100),char(105),char(109),char(112),char(117),char(108),char(115),
-char(101),char(115),char(0),char(109),char(95),char(110),char(100),char(97),char(109),char(112),char(105),char(110),char(103),char(0),char(109),char(95),char(108),char(100),char(97),char(109),
-char(112),char(105),char(110),char(103),char(0),char(109),char(95),char(97),char(100),char(97),char(109),char(112),char(105),char(110),char(103),char(0),char(109),char(95),char(109),char(97),
-char(116),char(99),char(104),char(105),char(110),char(103),char(0),char(109),char(95),char(109),char(97),char(120),char(83),char(101),char(108),char(102),char(67),char(111),char(108),char(108),
-char(105),char(115),char(105),char(111),char(110),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(0),char(109),char(95),char(115),char(101),char(108),char(102),char(67),
-char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(70),char(97),char(99),char(116),char(111),
-char(114),char(0),char(109),char(95),char(99),char(111),char(110),char(116),char(97),char(105),char(110),char(115),char(65),char(110),char(99),char(104),char(111),char(114),char(0),char(109),
-char(95),char(99),char(111),char(108),char(108),char(105),char(100),char(101),char(0),char(109),char(95),char(99),char(108),char(117),char(115),char(116),char(101),char(114),char(73),char(110),
-char(100),char(101),char(120),char(0),char(42),char(109),char(95),char(98),char(111),char(100),char(121),char(65),char(0),char(42),char(109),char(95),char(98),char(111),char(100),char(121),
-char(66),char(0),char(109),char(95),char(114),char(101),char(102),char(115),char(91),char(50),char(93),char(0),char(109),char(95),char(99),char(102),char(109),char(0),char(109),char(95),
-char(115),char(112),char(108),char(105),char(116),char(0),char(109),char(95),char(100),char(101),char(108),char(101),char(116),char(101),char(0),char(109),char(95),char(114),char(101),char(108),
-char(80),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(91),char(50),char(93),char(0),char(109),char(95),char(98),char(111),char(100),char(121),char(65),char(116),
-char(121),char(112),char(101),char(0),char(109),char(95),char(98),char(111),char(100),char(121),char(66),char(116),char(121),char(112),char(101),char(0),char(109),char(95),char(106),char(111),
-char(105),char(110),char(116),char(84),char(121),char(112),char(101),char(0),char(42),char(109),char(95),char(112),char(111),char(115),char(101),char(0),char(42),char(42),char(109),char(95),
-char(109),char(97),char(116),char(101),char(114),char(105),char(97),char(108),char(115),char(0),char(42),char(109),char(95),char(110),char(111),char(100),char(101),char(115),char(0),char(42),
-char(109),char(95),char(108),char(105),char(110),char(107),char(115),char(0),char(42),char(109),char(95),char(102),char(97),char(99),char(101),char(115),char(0),char(42),char(109),char(95),
-char(116),char(101),char(116),char(114),char(97),char(104),char(101),char(100),char(114),char(97),char(0),char(42),char(109),char(95),char(97),char(110),char(99),char(104),char(111),char(114),
-char(115),char(0),char(42),char(109),char(95),char(99),char(108),char(117),char(115),char(116),char(101),char(114),char(115),char(0),char(42),char(109),char(95),char(106),char(111),char(105),
-char(110),char(116),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(77),char(97),char(116),char(101),char(114),char(105),char(97),char(108),char(115),char(0),char(109),
-char(95),char(110),char(117),char(109),char(76),char(105),char(110),char(107),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(70),char(97),char(99),char(101),char(115),
-char(0),char(109),char(95),char(110),char(117),char(109),char(84),char(101),char(116),char(114),char(97),char(104),char(101),char(100),char(114),char(97),char(0),char(109),char(95),char(110),
-char(117),char(109),char(65),char(110),char(99),char(104),char(111),char(114),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(67),char(108),char(117),char(115),char(116),
-char(101),char(114),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(74),char(111),char(105),char(110),char(116),char(115),char(0),char(109),char(95),char(99),char(111),
-char(110),char(102),char(105),char(103),char(0),char(109),char(95),char(122),char(101),char(114),char(111),char(82),char(111),char(116),char(80),char(97),char(114),char(101),char(110),char(116),
-char(84),char(111),char(84),char(104),char(105),char(115),char(0),char(109),char(95),char(112),char(97),char(114),char(101),char(110),char(116),char(67),char(111),char(109),char(84),char(111),
-char(84),char(104),char(105),char(115),char(67),char(111),char(109),char(79),char(102),char(102),char(115),char(101),char(116),char(0),char(109),char(95),char(116),char(104),char(105),char(115),
-char(80),char(105),char(118),char(111),char(116),char(84),char(111),char(84),char(104),char(105),char(115),char(67),char(111),char(109),char(79),char(102),char(102),char(115),char(101),char(116),
-char(0),char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(65),char(120),char(105),char(115),char(84),char(111),char(112),char(91),char(54),char(93),char(0),char(109),
-char(95),char(106),char(111),char(105),char(110),char(116),char(65),char(120),char(105),char(115),char(66),char(111),char(116),char(116),char(111),char(109),char(91),char(54),char(93),char(0),
-char(109),char(95),char(108),char(105),char(110),char(107),char(73),char(110),char(101),char(114),char(116),char(105),char(97),char(0),char(109),char(95),char(108),char(105),char(110),char(107),
-char(77),char(97),char(115),char(115),char(0),char(109),char(95),char(112),char(97),char(114),char(101),char(110),char(116),char(73),char(110),char(100),char(101),char(120),char(0),char(109),
-char(95),char(100),char(111),char(102),char(67),char(111),char(117),char(110),char(116),char(0),char(109),char(95),char(112),char(111),char(115),char(86),char(97),char(114),char(67),char(111),
-char(117),char(110),char(116),char(0),char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(80),char(111),char(115),char(91),char(55),char(93),char(0),char(109),char(95),
-char(106),char(111),char(105),char(110),char(116),char(86),char(101),char(108),char(91),char(54),char(93),char(0),char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(84),
-char(111),char(114),char(113),char(117),char(101),char(91),char(54),char(93),char(0),char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(68),char(97),char(109),char(112),
-char(105),char(110),char(103),char(0),char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(70),char(114),char(105),char(99),char(116),char(105),char(111),char(110),char(0),
-char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(76),char(111),char(119),char(101),char(114),char(76),char(105),char(109),char(105),char(116),char(0),char(109),char(95),
-char(106),char(111),char(105),char(110),char(116),char(85),char(112),char(112),char(101),char(114),char(76),char(105),char(109),char(105),char(116),char(0),char(109),char(95),char(106),char(111),
-char(105),char(110),char(116),char(77),char(97),char(120),char(70),char(111),char(114),char(99),char(101),char(0),char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(77),
-char(97),char(120),char(86),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(0),char(42),char(109),char(95),char(108),char(105),char(110),char(107),char(78),char(97),
-char(109),char(101),char(0),char(42),char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(78),char(97),char(109),char(101),char(0),char(42),char(109),char(95),char(108),
-char(105),char(110),char(107),char(67),char(111),char(108),char(108),char(105),char(100),char(101),char(114),char(0),char(42),char(109),char(95),char(112),char(97),char(100),char(100),char(105),
-char(110),char(103),char(80),char(116),char(114),char(0),char(109),char(95),char(98),char(97),char(115),char(101),char(87),char(111),char(114),char(108),char(100),char(84),char(114),char(97),
-char(110),char(115),char(102),char(111),char(114),char(109),char(0),char(109),char(95),char(98),char(97),char(115),char(101),char(73),char(110),char(101),char(114),char(116),char(105),char(97),
-char(0),char(109),char(95),char(98),char(97),char(115),char(101),char(77),char(97),char(115),char(115),char(0),char(42),char(109),char(95),char(98),char(97),char(115),char(101),char(78),
-char(97),char(109),char(101),char(0),char(42),char(109),char(95),char(98),char(97),char(115),char(101),char(67),char(111),char(108),char(108),char(105),char(100),char(101),char(114),char(0),
-char(84),char(89),char(80),char(69),char(95),char(0),char(0),char(0),char(99),char(104),char(97),char(114),char(0),char(117),char(99),char(104),char(97),char(114),char(0),char(115),
-char(104),char(111),char(114),char(116),char(0),char(117),char(115),char(104),char(111),char(114),char(116),char(0),char(105),char(110),char(116),char(0),char(108),char(111),char(110),char(103),
-char(0),char(117),char(108),char(111),char(110),char(103),char(0),char(102),char(108),char(111),char(97),char(116),char(0),char(100),char(111),char(117),char(98),char(108),char(101),char(0),
-char(118),char(111),char(105),char(100),char(0),char(80),char(111),char(105),char(110),char(116),char(101),char(114),char(65),char(114),char(114),char(97),char(121),char(0),char(98),char(116),
-char(80),char(104),char(121),char(115),char(105),char(99),char(115),char(83),char(121),char(115),char(116),char(101),char(109),char(0),char(76),char(105),char(115),char(116),char(66),char(97),
-char(115),char(101),char(0),char(98),char(116),char(86),char(101),char(99),char(116),char(111),char(114),char(51),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),
-char(97),char(0),char(98),char(116),char(86),char(101),char(99),char(116),char(111),char(114),char(51),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),
-char(97),char(0),char(98),char(116),char(81),char(117),char(97),char(116),char(101),char(114),char(110),char(105),char(111),char(110),char(70),char(108),char(111),char(97),char(116),char(68),
-char(97),char(116),char(97),char(0),char(98),char(116),char(81),char(117),char(97),char(116),char(101),char(114),char(110),char(105),char(111),char(110),char(68),char(111),char(117),char(98),
-char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(77),char(97),char(116),char(114),char(105),char(120),char(51),char(120),char(51),char(70),char(108),
-char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(77),char(97),char(116),char(114),char(105),char(120),char(51),char(120),char(51),char(68),
-char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(84),char(114),char(97),char(110),char(115),char(102),char(111),char(114),
-char(109),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(84),char(114),char(97),char(110),char(115),char(102),char(111),
-char(114),char(109),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(66),char(118),char(104),char(83),char(117),
-char(98),char(116),char(114),char(101),char(101),char(73),char(110),char(102),char(111),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(79),char(112),char(116),char(105),
-char(109),char(105),char(122),char(101),char(100),char(66),char(118),char(104),char(78),char(111),char(100),char(101),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),
+char(109),char(75),char(101),char(121),char(115),char(0),char(109),char(95),char(112),char(111),char(105),char(110),char(116),char(67),char(97),char(99),char(104),char(101),char(76),char(111),
+char(99),char(97),char(108),char(80),char(111),char(105),char(110),char(116),char(65),char(91),char(52),char(93),char(0),char(109),char(95),char(112),char(111),char(105),char(110),char(116),
+char(67),char(97),char(99),char(104),char(101),char(76),char(111),char(99),char(97),char(108),char(80),char(111),char(105),char(110),char(116),char(66),char(91),char(52),char(93),char(0),
+char(109),char(95),char(112),char(111),char(105),char(110),char(116),char(67),char(97),char(99),char(104),char(101),char(80),char(111),char(115),char(105),char(116),char(105),char(111),char(110),
+char(87),char(111),char(114),char(108),char(100),char(79),char(110),char(65),char(91),char(52),char(93),char(0),char(109),char(95),char(112),char(111),char(105),char(110),char(116),char(67),
+char(97),char(99),char(104),char(101),char(80),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(87),char(111),char(114),char(108),char(100),char(79),char(110),char(66),
+char(91),char(52),char(93),char(0),char(109),char(95),char(112),char(111),char(105),char(110),char(116),char(67),char(97),char(99),char(104),char(101),char(78),char(111),char(114),char(109),
+char(97),char(108),char(87),char(111),char(114),char(108),char(100),char(79),char(110),char(66),char(91),char(52),char(93),char(0),char(109),char(95),char(112),char(111),char(105),char(110),
+char(116),char(67),char(97),char(99),char(104),char(101),char(76),char(97),char(116),char(101),char(114),char(97),char(108),char(70),char(114),char(105),char(99),char(116),char(105),char(111),
+char(110),char(68),char(105),char(114),char(49),char(91),char(52),char(93),char(0),char(109),char(95),char(112),char(111),char(105),char(110),char(116),char(67),char(97),char(99),char(104),
+char(101),char(76),char(97),char(116),char(101),char(114),char(97),char(108),char(70),char(114),char(105),char(99),char(116),char(105),char(111),char(110),char(68),char(105),char(114),char(50),
+char(91),char(52),char(93),char(0),char(109),char(95),char(112),char(111),char(105),char(110),char(116),char(67),char(97),char(99),char(104),char(101),char(68),char(105),char(115),char(116),
+char(97),char(110),char(99),char(101),char(91),char(52),char(93),char(0),char(109),char(95),char(112),char(111),char(105),char(110),char(116),char(67),char(97),char(99),char(104),char(101),
+char(65),char(112),char(112),char(108),char(105),char(101),char(100),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(91),char(52),char(93),char(0),char(109),char(95),
+char(112),char(111),char(105),char(110),char(116),char(67),char(97),char(99),char(104),char(101),char(67),char(111),char(109),char(98),char(105),char(110),char(101),char(100),char(70),char(114),
+char(105),char(99),char(116),char(105),char(111),char(110),char(91),char(52),char(93),char(0),char(109),char(95),char(112),char(111),char(105),char(110),char(116),char(67),char(97),char(99),
+char(104),char(101),char(67),char(111),char(109),char(98),char(105),char(110),char(101),char(100),char(82),char(111),char(108),char(108),char(105),char(110),char(103),char(70),char(114),char(105),
+char(99),char(116),char(105),char(111),char(110),char(91),char(52),char(93),char(0),char(109),char(95),char(112),char(111),char(105),char(110),char(116),char(67),char(97),char(99),char(104),
+char(101),char(67),char(111),char(109),char(98),char(105),char(110),char(101),char(100),char(83),char(112),char(105),char(110),char(110),char(105),char(110),char(103),char(70),char(114),char(105),
+char(99),char(116),char(105),char(111),char(110),char(91),char(52),char(93),char(0),char(109),char(95),char(112),char(111),char(105),char(110),char(116),char(67),char(97),char(99),char(104),
+char(101),char(67),char(111),char(109),char(98),char(105),char(110),char(101),char(100),char(82),char(101),char(115),char(116),char(105),char(116),char(117),char(116),char(105),char(111),char(110),
+char(91),char(52),char(93),char(0),char(109),char(95),char(112),char(111),char(105),char(110),char(116),char(67),char(97),char(99),char(104),char(101),char(80),char(97),char(114),char(116),
+char(73),char(100),char(48),char(91),char(52),char(93),char(0),char(109),char(95),char(112),char(111),char(105),char(110),char(116),char(67),char(97),char(99),char(104),char(101),char(80),
+char(97),char(114),char(116),char(73),char(100),char(49),char(91),char(52),char(93),char(0),char(109),char(95),char(112),char(111),char(105),char(110),char(116),char(67),char(97),char(99),
+char(104),char(101),char(73),char(110),char(100),char(101),char(120),char(48),char(91),char(52),char(93),char(0),char(109),char(95),char(112),char(111),char(105),char(110),char(116),char(67),
+char(97),char(99),char(104),char(101),char(73),char(110),char(100),char(101),char(120),char(49),char(91),char(52),char(93),char(0),char(109),char(95),char(112),char(111),char(105),char(110),
+char(116),char(67),char(97),char(99),char(104),char(101),char(67),char(111),char(110),char(116),char(97),char(99),char(116),char(80),char(111),char(105),char(110),char(116),char(70),char(108),
+char(97),char(103),char(115),char(91),char(52),char(93),char(0),char(109),char(95),char(112),char(111),char(105),char(110),char(116),char(67),char(97),char(99),char(104),char(101),char(65),
+char(112),char(112),char(108),char(105),char(101),char(100),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(76),char(97),char(116),char(101),char(114),char(97),char(108),
+char(49),char(91),char(52),char(93),char(0),char(109),char(95),char(112),char(111),char(105),char(110),char(116),char(67),char(97),char(99),char(104),char(101),char(65),char(112),char(112),
+char(108),char(105),char(101),char(100),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(76),char(97),char(116),char(101),char(114),char(97),char(108),char(50),char(91),
+char(52),char(93),char(0),char(109),char(95),char(112),char(111),char(105),char(110),char(116),char(67),char(97),char(99),char(104),char(101),char(67),char(111),char(110),char(116),char(97),
+char(99),char(116),char(77),char(111),char(116),char(105),char(111),char(110),char(49),char(91),char(52),char(93),char(0),char(109),char(95),char(112),char(111),char(105),char(110),char(116),
+char(67),char(97),char(99),char(104),char(101),char(67),char(111),char(110),char(116),char(97),char(99),char(116),char(77),char(111),char(116),char(105),char(111),char(110),char(50),char(91),
+char(52),char(93),char(0),char(109),char(95),char(112),char(111),char(105),char(110),char(116),char(67),char(97),char(99),char(104),char(101),char(67),char(111),char(110),char(116),char(97),
+char(99),char(116),char(67),char(70),char(77),char(91),char(52),char(93),char(0),char(109),char(95),char(112),char(111),char(105),char(110),char(116),char(67),char(97),char(99),char(104),
+char(101),char(67),char(111),char(109),char(98),char(105),char(110),char(101),char(100),char(67),char(111),char(110),char(116),char(97),char(99),char(116),char(83),char(116),char(105),char(102),
+char(102),char(110),char(101),char(115),char(115),char(49),char(91),char(52),char(93),char(0),char(109),char(95),char(112),char(111),char(105),char(110),char(116),char(67),char(97),char(99),
+char(104),char(101),char(67),char(111),char(110),char(116),char(97),char(99),char(116),char(69),char(82),char(80),char(91),char(52),char(93),char(0),char(109),char(95),char(112),char(111),
+char(105),char(110),char(116),char(67),char(97),char(99),char(104),char(101),char(67),char(111),char(109),char(98),char(105),char(110),char(101),char(100),char(67),char(111),char(110),char(116),
+char(97),char(99),char(116),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(49),char(91),char(52),char(93),char(0),char(109),char(95),char(112),char(111),char(105),
+char(110),char(116),char(67),char(97),char(99),char(104),char(101),char(70),char(114),char(105),char(99),char(116),char(105),char(111),char(110),char(67),char(70),char(77),char(91),char(52),
+char(93),char(0),char(109),char(95),char(112),char(111),char(105),char(110),char(116),char(67),char(97),char(99),char(104),char(101),char(76),char(105),char(102),char(101),char(84),char(105),
+char(109),char(101),char(91),char(52),char(93),char(0),char(109),char(95),char(110),char(117),char(109),char(67),char(97),char(99),char(104),char(101),char(100),char(80),char(111),char(105),
+char(110),char(116),char(115),char(0),char(109),char(95),char(99),char(111),char(109),char(112),char(97),char(110),char(105),char(111),char(110),char(73),char(100),char(65),char(0),char(109),
+char(95),char(99),char(111),char(109),char(112),char(97),char(110),char(105),char(111),char(110),char(73),char(100),char(66),char(0),char(109),char(95),char(105),char(110),char(100),char(101),
+char(120),char(49),char(97),char(0),char(109),char(95),char(111),char(98),char(106),char(101),char(99),char(116),char(84),char(121),char(112),char(101),char(0),char(109),char(95),char(99),
+char(111),char(110),char(116),char(97),char(99),char(116),char(66),char(114),char(101),char(97),char(107),char(105),char(110),char(103),char(84),char(104),char(114),char(101),char(115),char(104),
+char(111),char(108),char(100),char(0),char(109),char(95),char(99),char(111),char(110),char(116),char(97),char(99),char(116),char(80),char(114),char(111),char(99),char(101),char(115),char(115),
+char(105),char(110),char(103),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(42),char(109),char(95),char(98),char(111),char(100),char(121),
+char(48),char(0),char(42),char(109),char(95),char(98),char(111),char(100),char(121),char(49),char(0),char(109),char(95),char(103),char(105),char(109),char(112),char(97),char(99),char(116),
+char(83),char(117),char(98),char(84),char(121),char(112),char(101),char(0),char(42),char(109),char(95),char(117),char(110),char(115),char(99),char(97),char(108),char(101),char(100),char(80),
+char(111),char(105),char(110),char(116),char(115),char(70),char(108),char(111),char(97),char(116),char(80),char(116),char(114),char(0),char(42),char(109),char(95),char(117),char(110),char(115),
+char(99),char(97),char(108),char(101),char(100),char(80),char(111),char(105),char(110),char(116),char(115),char(68),char(111),char(117),char(98),char(108),char(101),char(80),char(116),char(114),
+char(0),char(109),char(95),char(110),char(117),char(109),char(85),char(110),char(115),char(99),char(97),char(108),char(101),char(100),char(80),char(111),char(105),char(110),char(116),char(115),
+char(0),char(109),char(95),char(112),char(97),char(100),char(100),char(105),char(110),char(103),char(51),char(91),char(52),char(93),char(0),char(42),char(109),char(95),char(98),char(114),
+char(111),char(97),char(100),char(112),char(104),char(97),char(115),char(101),char(72),char(97),char(110),char(100),char(108),char(101),char(0),char(42),char(109),char(95),char(99),char(111),
+char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(83),char(104),char(97),char(112),char(101),char(0),char(42),char(109),char(95),char(114),char(111),char(111),char(116),
+char(67),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(83),char(104),char(97),char(112),char(101),char(0),char(109),char(95),char(119),char(111),char(114),
+char(108),char(100),char(84),char(114),char(97),char(110),char(115),char(102),char(111),char(114),char(109),char(0),char(109),char(95),char(105),char(110),char(116),char(101),char(114),char(112),
+char(111),char(108),char(97),char(116),char(105),char(111),char(110),char(87),char(111),char(114),char(108),char(100),char(84),char(114),char(97),char(110),char(115),char(102),char(111),char(114),
+char(109),char(0),char(109),char(95),char(105),char(110),char(116),char(101),char(114),char(112),char(111),char(108),char(97),char(116),char(105),char(111),char(110),char(76),char(105),char(110),
+char(101),char(97),char(114),char(86),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(0),char(109),char(95),char(105),char(110),char(116),char(101),char(114),char(112),
+char(111),char(108),char(97),char(116),char(105),char(111),char(110),char(65),char(110),char(103),char(117),char(108),char(97),char(114),char(86),char(101),char(108),char(111),char(99),char(105),
+char(116),char(121),char(0),char(109),char(95),char(97),char(110),char(105),char(115),char(111),char(116),char(114),char(111),char(112),char(105),char(99),char(70),char(114),char(105),char(99),
+char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(100),char(101),char(97),char(99),char(116),char(105),char(118),char(97),char(116),char(105),char(111),char(110),char(84),
+char(105),char(109),char(101),char(0),char(109),char(95),char(102),char(114),char(105),char(99),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(114),char(111),char(108),
+char(108),char(105),char(110),char(103),char(70),char(114),char(105),char(99),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(99),char(111),char(110),char(116),char(97),
+char(99),char(116),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(0),char(109),char(95),char(99),char(111),char(110),char(116),char(97),char(99),char(116),char(83),
+char(116),char(105),char(102),char(102),char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(114),char(101),char(115),char(116),char(105),char(116),char(117),char(116),char(105),
+char(111),char(110),char(0),char(109),char(95),char(104),char(105),char(116),char(70),char(114),char(97),char(99),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(99),
+char(99),char(100),char(83),char(119),char(101),char(112),char(116),char(83),char(112),char(104),char(101),char(114),char(101),char(82),char(97),char(100),char(105),char(117),char(115),char(0),
+char(109),char(95),char(99),char(99),char(100),char(77),char(111),char(116),char(105),char(111),char(110),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),
+char(0),char(109),char(95),char(104),char(97),char(115),char(65),char(110),char(105),char(115),char(111),char(116),char(114),char(111),char(112),char(105),char(99),char(70),char(114),char(105),
+char(99),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(99),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(70),char(108),char(97),
+char(103),char(115),char(0),char(109),char(95),char(105),char(115),char(108),char(97),char(110),char(100),char(84),char(97),char(103),char(49),char(0),char(109),char(95),char(99),char(111),
+char(109),char(112),char(97),char(110),char(105),char(111),char(110),char(73),char(100),char(0),char(109),char(95),char(97),char(99),char(116),char(105),char(118),char(97),char(116),char(105),
+char(111),char(110),char(83),char(116),char(97),char(116),char(101),char(49),char(0),char(109),char(95),char(105),char(110),char(116),char(101),char(114),char(110),char(97),char(108),char(84),
+char(121),char(112),char(101),char(0),char(109),char(95),char(99),char(104),char(101),char(99),char(107),char(67),char(111),char(108),char(108),char(105),char(100),char(101),char(87),char(105),
+char(116),char(104),char(0),char(109),char(95),char(99),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(70),char(105),char(108),char(116),char(101),char(114),
+char(71),char(114),char(111),char(117),char(112),char(0),char(109),char(95),char(99),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(70),char(105),char(108),
+char(116),char(101),char(114),char(77),char(97),char(115),char(107),char(0),char(109),char(95),char(117),char(110),char(105),char(113),char(117),char(101),char(73),char(100),char(0),char(109),
+char(95),char(116),char(97),char(117),char(0),char(109),char(95),char(100),char(97),char(109),char(112),char(105),char(110),char(103),char(0),char(109),char(95),char(116),char(105),char(109),
+char(101),char(83),char(116),char(101),char(112),char(0),char(109),char(95),char(109),char(97),char(120),char(69),char(114),char(114),char(111),char(114),char(82),char(101),char(100),char(117),
+char(99),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(115),char(111),char(114),char(0),char(109),char(95),char(101),char(114),char(112),char(0),char(109),char(95),
+char(101),char(114),char(112),char(50),char(0),char(109),char(95),char(103),char(108),char(111),char(98),char(97),char(108),char(67),char(102),char(109),char(0),char(109),char(95),char(115),
+char(112),char(108),char(105),char(116),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(80),char(101),char(110),char(101),char(116),char(114),char(97),char(116),char(105),
+char(111),char(110),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109),char(95),char(115),char(112),char(108),char(105),char(116),char(73),
+char(109),char(112),char(117),char(108),char(115),char(101),char(84),char(117),char(114),char(110),char(69),char(114),char(112),char(0),char(109),char(95),char(108),char(105),char(110),char(101),
+char(97),char(114),char(83),char(108),char(111),char(112),char(0),char(109),char(95),char(119),char(97),char(114),char(109),char(115),char(116),char(97),char(114),char(116),char(105),char(110),
+char(103),char(70),char(97),char(99),char(116),char(111),char(114),char(0),char(109),char(95),char(109),char(97),char(120),char(71),char(121),char(114),char(111),char(115),char(99),char(111),
+char(112),char(105),char(99),char(70),char(111),char(114),char(99),char(101),char(0),char(109),char(95),char(115),char(105),char(110),char(103),char(108),char(101),char(65),char(120),char(105),
+char(115),char(82),char(111),char(108),char(108),char(105),char(110),char(103),char(70),char(114),char(105),char(99),char(116),char(105),char(111),char(110),char(84),char(104),char(114),char(101),
+char(115),char(104),char(111),char(108),char(100),char(0),char(109),char(95),char(110),char(117),char(109),char(73),char(116),char(101),char(114),char(97),char(116),char(105),char(111),char(110),
+char(115),char(0),char(109),char(95),char(115),char(111),char(108),char(118),char(101),char(114),char(77),char(111),char(100),char(101),char(0),char(109),char(95),char(114),char(101),char(115),
+char(116),char(105),char(110),char(103),char(67),char(111),char(110),char(116),char(97),char(99),char(116),char(82),char(101),char(115),char(116),char(105),char(116),char(117),char(116),char(105),
+char(111),char(110),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109),char(95),char(109),char(105),char(110),char(105),char(109),char(117),
+char(109),char(83),char(111),char(108),char(118),char(101),char(114),char(66),char(97),char(116),char(99),char(104),char(83),char(105),char(122),char(101),char(0),char(109),char(95),char(115),
+char(112),char(108),char(105),char(116),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(0),char(109),char(95),char(115),char(111),char(108),char(118),char(101),char(114),
+char(73),char(110),char(102),char(111),char(0),char(109),char(95),char(103),char(114),char(97),char(118),char(105),char(116),char(121),char(0),char(109),char(95),char(99),char(111),char(108),
+char(108),char(105),char(115),char(105),char(111),char(110),char(79),char(98),char(106),char(101),char(99),char(116),char(68),char(97),char(116),char(97),char(0),char(109),char(95),char(105),
+char(110),char(118),char(73),char(110),char(101),char(114),char(116),char(105),char(97),char(84),char(101),char(110),char(115),char(111),char(114),char(87),char(111),char(114),char(108),char(100),
+char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(86),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(0),char(109),char(95),
+char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(86),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(0),char(109),char(95),char(97),char(110),
+char(103),char(117),char(108),char(97),char(114),char(70),char(97),char(99),char(116),char(111),char(114),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),
+char(70),char(97),char(99),char(116),char(111),char(114),char(0),char(109),char(95),char(103),char(114),char(97),char(118),char(105),char(116),char(121),char(95),char(97),char(99),char(99),
+char(101),char(108),char(101),char(114),char(97),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(105),char(110),char(118),char(73),char(110),char(101),char(114),char(116),
+char(105),char(97),char(76),char(111),char(99),char(97),char(108),char(0),char(109),char(95),char(116),char(111),char(116),char(97),char(108),char(70),char(111),char(114),char(99),char(101),
+char(0),char(109),char(95),char(116),char(111),char(116),char(97),char(108),char(84),char(111),char(114),char(113),char(117),char(101),char(0),char(109),char(95),char(105),char(110),char(118),
+char(101),char(114),char(115),char(101),char(77),char(97),char(115),char(115),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(68),char(97),char(109),
+char(112),char(105),char(110),char(103),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(68),char(97),char(109),char(112),char(105),char(110),
+char(103),char(0),char(109),char(95),char(97),char(100),char(100),char(105),char(116),char(105),char(111),char(110),char(97),char(108),char(68),char(97),char(109),char(112),char(105),char(110),
+char(103),char(70),char(97),char(99),char(116),char(111),char(114),char(0),char(109),char(95),char(97),char(100),char(100),char(105),char(116),char(105),char(111),char(110),char(97),char(108),
+char(76),char(105),char(110),char(101),char(97),char(114),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(84),char(104),char(114),char(101),char(115),char(104),char(111),
+char(108),char(100),char(83),char(113),char(114),char(0),char(109),char(95),char(97),char(100),char(100),char(105),char(116),char(105),char(111),char(110),char(97),char(108),char(65),char(110),
+char(103),char(117),char(108),char(97),char(114),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),
+char(100),char(83),char(113),char(114),char(0),char(109),char(95),char(97),char(100),char(100),char(105),char(116),char(105),char(111),char(110),char(97),char(108),char(65),char(110),char(103),
+char(117),char(108),char(97),char(114),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(70),char(97),char(99),char(116),char(111),char(114),char(0),char(109),char(95),
+char(108),char(105),char(110),char(101),char(97),char(114),char(83),char(108),char(101),char(101),char(112),char(105),char(110),char(103),char(84),char(104),char(114),char(101),char(115),char(104),
+char(111),char(108),char(100),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(83),char(108),char(101),char(101),char(112),char(105),char(110),
+char(103),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109),char(95),char(97),char(100),char(100),char(105),char(116),char(105),char(111),
+char(110),char(97),char(108),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(0),char(109),char(95),char(110),char(117),char(109),char(67),char(111),char(110),char(115),
+char(116),char(114),char(97),char(105),char(110),char(116),char(82),char(111),char(119),char(115),char(0),char(110),char(117),char(98),char(0),char(42),char(109),char(95),char(114),char(98),
+char(65),char(0),char(42),char(109),char(95),char(114),char(98),char(66),char(0),char(109),char(95),char(117),char(115),char(101),char(114),char(67),char(111),char(110),char(115),char(116),
+char(114),char(97),char(105),char(110),char(116),char(84),char(121),char(112),char(101),char(0),char(109),char(95),char(117),char(115),char(101),char(114),char(67),char(111),char(110),char(115),
+char(116),char(114),char(97),char(105),char(110),char(116),char(73),char(100),char(0),char(109),char(95),char(110),char(101),char(101),char(100),char(115),char(70),char(101),char(101),char(100),
+char(98),char(97),char(99),char(107),char(0),char(109),char(95),char(97),char(112),char(112),char(108),char(105),char(101),char(100),char(73),char(109),char(112),char(117),char(108),char(115),
+char(101),char(0),char(109),char(95),char(100),char(98),char(103),char(68),char(114),char(97),char(119),char(83),char(105),char(122),char(101),char(0),char(109),char(95),char(100),char(105),
+char(115),char(97),char(98),char(108),char(101),char(67),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(115),char(66),char(101),char(116),char(119),char(101),
+char(101),char(110),char(76),char(105),char(110),char(107),char(101),char(100),char(66),char(111),char(100),char(105),char(101),char(115),char(0),char(109),char(95),char(111),char(118),char(101),
+char(114),char(114),char(105),char(100),char(101),char(78),char(117),char(109),char(83),char(111),char(108),char(118),char(101),char(114),char(73),char(116),char(101),char(114),char(97),char(116),
+char(105),char(111),char(110),char(115),char(0),char(109),char(95),char(98),char(114),char(101),char(97),char(107),char(105),char(110),char(103),char(73),char(109),char(112),char(117),char(108),
+char(115),char(101),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109),char(95),char(105),char(115),char(69),char(110),char(97),char(98),
+char(108),char(101),char(100),char(0),char(112),char(97),char(100),char(100),char(105),char(110),char(103),char(91),char(52),char(93),char(0),char(109),char(95),char(116),char(121),char(112),
+char(101),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(97),char(116),char(97),char(0),char(109),char(95),char(112),char(105),
+char(118),char(111),char(116),char(73),char(110),char(65),char(0),char(109),char(95),char(112),char(105),char(118),char(111),char(116),char(73),char(110),char(66),char(0),char(109),char(95),
+char(114),char(98),char(65),char(70),char(114),char(97),char(109),char(101),char(0),char(109),char(95),char(114),char(98),char(66),char(70),char(114),char(97),char(109),char(101),char(0),
+char(109),char(95),char(117),char(115),char(101),char(82),char(101),char(102),char(101),char(114),char(101),char(110),char(99),char(101),char(70),char(114),char(97),char(109),char(101),char(65),
+char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(79),char(110),char(108),char(121),char(0),char(109),char(95),char(101),char(110),char(97),
+char(98),char(108),char(101),char(65),char(110),char(103),char(117),char(108),char(97),char(114),char(77),char(111),char(116),char(111),char(114),char(0),char(109),char(95),char(109),char(111),
+char(116),char(111),char(114),char(84),char(97),char(114),char(103),char(101),char(116),char(86),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(0),char(109),char(95),
+char(109),char(97),char(120),char(77),char(111),char(116),char(111),char(114),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(0),char(109),char(95),char(108),char(111),
+char(119),char(101),char(114),char(76),char(105),char(109),char(105),char(116),char(0),char(109),char(95),char(117),char(112),char(112),char(101),char(114),char(76),char(105),char(109),char(105),
+char(116),char(0),char(109),char(95),char(108),char(105),char(109),char(105),char(116),char(83),char(111),char(102),char(116),char(110),char(101),char(115),char(115),char(0),char(109),char(95),
+char(98),char(105),char(97),char(115),char(70),char(97),char(99),char(116),char(111),char(114),char(0),char(109),char(95),char(114),char(101),char(108),char(97),char(120),char(97),char(116),
+char(105),char(111),char(110),char(70),char(97),char(99),char(116),char(111),char(114),char(0),char(109),char(95),char(112),char(97),char(100),char(100),char(105),char(110),char(103),char(49),
+char(91),char(52),char(93),char(0),char(109),char(95),char(115),char(119),char(105),char(110),char(103),char(83),char(112),char(97),char(110),char(49),char(0),char(109),char(95),char(115),
+char(119),char(105),char(110),char(103),char(83),char(112),char(97),char(110),char(50),char(0),char(109),char(95),char(116),char(119),char(105),char(115),char(116),char(83),char(112),char(97),
+char(110),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(85),char(112),char(112),char(101),char(114),char(76),char(105),char(109),char(105),char(116),
+char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(76),char(111),char(119),char(101),char(114),char(76),char(105),char(109),char(105),char(116),char(0),
+char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(85),char(112),char(112),char(101),char(114),char(76),char(105),char(109),char(105),char(116),char(0),
+char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(76),char(111),char(119),char(101),char(114),char(76),char(105),char(109),char(105),char(116),char(0),
+char(109),char(95),char(117),char(115),char(101),char(76),char(105),char(110),char(101),char(97),char(114),char(82),char(101),char(102),char(101),char(114),char(101),char(110),char(99),char(101),
+char(70),char(114),char(97),char(109),char(101),char(65),char(0),char(109),char(95),char(117),char(115),char(101),char(79),char(102),char(102),char(115),char(101),char(116),char(70),char(111),
+char(114),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(70),char(114),char(97),char(109),char(101),char(0),char(109),char(95),char(54),
+char(100),char(111),char(102),char(68),char(97),char(116),char(97),char(0),char(109),char(95),char(115),char(112),char(114),char(105),char(110),char(103),char(69),char(110),char(97),char(98),
+char(108),char(101),char(100),char(91),char(54),char(93),char(0),char(109),char(95),char(101),char(113),char(117),char(105),char(108),char(105),char(98),char(114),char(105),char(117),char(109),
+char(80),char(111),char(105),char(110),char(116),char(91),char(54),char(93),char(0),char(109),char(95),char(115),char(112),char(114),char(105),char(110),char(103),char(83),char(116),char(105),
+char(102),char(102),char(110),char(101),char(115),char(115),char(91),char(54),char(93),char(0),char(109),char(95),char(115),char(112),char(114),char(105),char(110),char(103),char(68),char(97),
+char(109),char(112),char(105),char(110),char(103),char(91),char(54),char(93),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(66),char(111),char(117),
+char(110),char(99),char(101),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83),char(116),char(111),char(112),char(69),char(82),char(80),char(0),
+char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83),char(116),char(111),char(112),char(67),char(70),char(77),char(0),char(109),char(95),char(108),char(105),
+char(110),char(101),char(97),char(114),char(77),char(111),char(116),char(111),char(114),char(69),char(82),char(80),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),
+char(114),char(77),char(111),char(116),char(111),char(114),char(67),char(70),char(77),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(84),char(97),
+char(114),char(103),char(101),char(116),char(86),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),
+char(114),char(77),char(97),char(120),char(77),char(111),char(116),char(111),char(114),char(70),char(111),char(114),char(99),char(101),char(0),char(109),char(95),char(108),char(105),char(110),
+char(101),char(97),char(114),char(83),char(101),char(114),char(118),char(111),char(84),char(97),char(114),char(103),char(101),char(116),char(0),char(109),char(95),char(108),char(105),char(110),
+char(101),char(97),char(114),char(83),char(112),char(114),char(105),char(110),char(103),char(83),char(116),char(105),char(102),char(102),char(110),char(101),char(115),char(115),char(0),char(109),
+char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83),char(112),char(114),char(105),char(110),char(103),char(68),char(97),char(109),char(112),char(105),char(110),char(103),
+char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(69),char(113),char(117),char(105),char(108),char(105),char(98),char(114),char(105),char(117),char(109),
+char(80),char(111),char(105),char(110),char(116),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(69),char(110),char(97),char(98),char(108),char(101),
+char(77),char(111),char(116),char(111),char(114),char(91),char(52),char(93),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83),char(101),char(114),
+char(118),char(111),char(77),char(111),char(116),char(111),char(114),char(91),char(52),char(93),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(69),
+char(110),char(97),char(98),char(108),char(101),char(83),char(112),char(114),char(105),char(110),char(103),char(91),char(52),char(93),char(0),char(109),char(95),char(108),char(105),char(110),
+char(101),char(97),char(114),char(83),char(112),char(114),char(105),char(110),char(103),char(83),char(116),char(105),char(102),char(102),char(110),char(101),char(115),char(115),char(76),char(105),
+char(109),char(105),char(116),char(101),char(100),char(91),char(52),char(93),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83),char(112),char(114),
+char(105),char(110),char(103),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(76),char(105),char(109),char(105),char(116),char(101),char(100),char(91),char(52),char(93),
+char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(66),char(111),char(117),char(110),char(99),char(101),char(0),char(109),char(95),char(97),
+char(110),char(103),char(117),char(108),char(97),char(114),char(83),char(116),char(111),char(112),char(69),char(82),char(80),char(0),char(109),char(95),char(97),char(110),char(103),char(117),
+char(108),char(97),char(114),char(83),char(116),char(111),char(112),char(67),char(70),char(77),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),
+char(77),char(111),char(116),char(111),char(114),char(69),char(82),char(80),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(77),char(111),
+char(116),char(111),char(114),char(67),char(70),char(77),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(84),char(97),char(114),char(103),
+char(101),char(116),char(86),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),
+char(77),char(97),char(120),char(77),char(111),char(116),char(111),char(114),char(70),char(111),char(114),char(99),char(101),char(0),char(109),char(95),char(97),char(110),char(103),char(117),
+char(108),char(97),char(114),char(83),char(101),char(114),char(118),char(111),char(84),char(97),char(114),char(103),char(101),char(116),char(0),char(109),char(95),char(97),char(110),char(103),
+char(117),char(108),char(97),char(114),char(83),char(112),char(114),char(105),char(110),char(103),char(83),char(116),char(105),char(102),char(102),char(110),char(101),char(115),char(115),char(0),
+char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(83),char(112),char(114),char(105),char(110),char(103),char(68),char(97),char(109),char(112),char(105),
+char(110),char(103),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(69),char(113),char(117),char(105),char(108),char(105),char(98),char(114),
+char(105),char(117),char(109),char(80),char(111),char(105),char(110),char(116),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(69),char(110),
+char(97),char(98),char(108),char(101),char(77),char(111),char(116),char(111),char(114),char(91),char(52),char(93),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),
+char(97),char(114),char(83),char(101),char(114),char(118),char(111),char(77),char(111),char(116),char(111),char(114),char(91),char(52),char(93),char(0),char(109),char(95),char(97),char(110),
+char(103),char(117),char(108),char(97),char(114),char(69),char(110),char(97),char(98),char(108),char(101),char(83),char(112),char(114),char(105),char(110),char(103),char(91),char(52),char(93),
+char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(83),char(112),char(114),char(105),char(110),char(103),char(83),char(116),char(105),char(102),
+char(102),char(110),char(101),char(115),char(115),char(76),char(105),char(109),char(105),char(116),char(101),char(100),char(91),char(52),char(93),char(0),char(109),char(95),char(97),char(110),
+char(103),char(117),char(108),char(97),char(114),char(83),char(112),char(114),char(105),char(110),char(103),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(76),char(105),
+char(109),char(105),char(116),char(101),char(100),char(91),char(52),char(93),char(0),char(109),char(95),char(114),char(111),char(116),char(97),char(116),char(101),char(79),char(114),char(100),
+char(101),char(114),char(0),char(109),char(95),char(97),char(120),char(105),char(115),char(73),char(110),char(65),char(0),char(109),char(95),char(97),char(120),char(105),char(115),char(73),
+char(110),char(66),char(0),char(109),char(95),char(114),char(97),char(116),char(105),char(111),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83),
+char(116),char(105),char(102),char(102),char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(83),char(116),
+char(105),char(102),char(102),char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(118),char(111),char(108),char(117),char(109),char(101),char(83),char(116),char(105),char(102),
+char(102),char(110),char(101),char(115),char(115),char(0),char(42),char(109),char(95),char(109),char(97),char(116),char(101),char(114),char(105),char(97),char(108),char(0),char(109),char(95),
+char(112),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(112),char(114),char(101),char(118),char(105),char(111),char(117),char(115),char(80),
+char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(118),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(0),char(109),
+char(95),char(97),char(99),char(99),char(117),char(109),char(117),char(108),char(97),char(116),char(101),char(100),char(70),char(111),char(114),char(99),char(101),char(0),char(109),char(95),
+char(110),char(111),char(114),char(109),char(97),char(108),char(0),char(109),char(95),char(97),char(114),char(101),char(97),char(0),char(109),char(95),char(97),char(116),char(116),char(97),
+char(99),char(104),char(0),char(109),char(95),char(110),char(111),char(100),char(101),char(73),char(110),char(100),char(105),char(99),char(101),char(115),char(91),char(50),char(93),char(0),
+char(109),char(95),char(114),char(101),char(115),char(116),char(76),char(101),char(110),char(103),char(116),char(104),char(0),char(109),char(95),char(98),char(98),char(101),char(110),char(100),
+char(105),char(110),char(103),char(0),char(109),char(95),char(110),char(111),char(100),char(101),char(73),char(110),char(100),char(105),char(99),char(101),char(115),char(91),char(51),char(93),
+char(0),char(109),char(95),char(114),char(101),char(115),char(116),char(65),char(114),char(101),char(97),char(0),char(109),char(95),char(99),char(48),char(91),char(52),char(93),char(0),
+char(109),char(95),char(110),char(111),char(100),char(101),char(73),char(110),char(100),char(105),char(99),char(101),char(115),char(91),char(52),char(93),char(0),char(109),char(95),char(114),
+char(101),char(115),char(116),char(86),char(111),char(108),char(117),char(109),char(101),char(0),char(109),char(95),char(99),char(49),char(0),char(109),char(95),char(99),char(50),char(0),
+char(109),char(95),char(99),char(48),char(0),char(109),char(95),char(108),char(111),char(99),char(97),char(108),char(70),char(114),char(97),char(109),char(101),char(0),char(42),char(109),
+char(95),char(114),char(105),char(103),char(105),char(100),char(66),char(111),char(100),char(121),char(0),char(109),char(95),char(110),char(111),char(100),char(101),char(73),char(110),char(100),
+char(101),char(120),char(0),char(109),char(95),char(97),char(101),char(114),char(111),char(77),char(111),char(100),char(101),char(108),char(0),char(109),char(95),char(98),char(97),char(117),
+char(109),char(103),char(97),char(114),char(116),char(101),char(0),char(109),char(95),char(100),char(114),char(97),char(103),char(0),char(109),char(95),char(108),char(105),char(102),char(116),
+char(0),char(109),char(95),char(112),char(114),char(101),char(115),char(115),char(117),char(114),char(101),char(0),char(109),char(95),char(118),char(111),char(108),char(117),char(109),char(101),
+char(0),char(109),char(95),char(100),char(121),char(110),char(97),char(109),char(105),char(99),char(70),char(114),char(105),char(99),char(116),char(105),char(111),char(110),char(0),char(109),
+char(95),char(112),char(111),char(115),char(101),char(77),char(97),char(116),char(99),char(104),char(0),char(109),char(95),char(114),char(105),char(103),char(105),char(100),char(67),char(111),
+char(110),char(116),char(97),char(99),char(116),char(72),char(97),char(114),char(100),char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(107),char(105),char(110),char(101),
+char(116),char(105),char(99),char(67),char(111),char(110),char(116),char(97),char(99),char(116),char(72),char(97),char(114),char(100),char(110),char(101),char(115),char(115),char(0),char(109),
+char(95),char(115),char(111),char(102),char(116),char(67),char(111),char(110),char(116),char(97),char(99),char(116),char(72),char(97),char(114),char(100),char(110),char(101),char(115),char(115),
+char(0),char(109),char(95),char(97),char(110),char(99),char(104),char(111),char(114),char(72),char(97),char(114),char(100),char(110),char(101),char(115),char(115),char(0),char(109),char(95),
+char(115),char(111),char(102),char(116),char(82),char(105),char(103),char(105),char(100),char(67),char(108),char(117),char(115),char(116),char(101),char(114),char(72),char(97),char(114),char(100),
+char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(115),char(111),char(102),char(116),char(75),char(105),char(110),char(101),char(116),char(105),char(99),char(67),char(108),
+char(117),char(115),char(116),char(101),char(114),char(72),char(97),char(114),char(100),char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(115),char(111),char(102),char(116),
+char(83),char(111),char(102),char(116),char(67),char(108),char(117),char(115),char(116),char(101),char(114),char(72),char(97),char(114),char(100),char(110),char(101),char(115),char(115),char(0),
+char(109),char(95),char(115),char(111),char(102),char(116),char(82),char(105),char(103),char(105),char(100),char(67),char(108),char(117),char(115),char(116),char(101),char(114),char(73),char(109),
+char(112),char(117),char(108),char(115),char(101),char(83),char(112),char(108),char(105),char(116),char(0),char(109),char(95),char(115),char(111),char(102),char(116),char(75),char(105),char(110),
+char(101),char(116),char(105),char(99),char(67),char(108),char(117),char(115),char(116),char(101),char(114),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(83),char(112),
+char(108),char(105),char(116),char(0),char(109),char(95),char(115),char(111),char(102),char(116),char(83),char(111),char(102),char(116),char(67),char(108),char(117),char(115),char(116),char(101),
+char(114),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(83),char(112),char(108),char(105),char(116),char(0),char(109),char(95),char(109),char(97),char(120),char(86),
+char(111),char(108),char(117),char(109),char(101),char(0),char(109),char(95),char(116),char(105),char(109),char(101),char(83),char(99),char(97),char(108),char(101),char(0),char(109),char(95),
+char(118),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(73),char(116),char(101),char(114),char(97),char(116),char(105),char(111),char(110),char(115),char(0),char(109),
+char(95),char(112),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(73),char(116),char(101),char(114),char(97),char(116),char(105),char(111),char(110),char(115),char(0),
+char(109),char(95),char(100),char(114),char(105),char(102),char(116),char(73),char(116),char(101),char(114),char(97),char(116),char(105),char(111),char(110),char(115),char(0),char(109),char(95),
+char(99),char(108),char(117),char(115),char(116),char(101),char(114),char(73),char(116),char(101),char(114),char(97),char(116),char(105),char(111),char(110),char(115),char(0),char(109),char(95),
+char(114),char(111),char(116),char(0),char(109),char(95),char(115),char(99),char(97),char(108),char(101),char(0),char(109),char(95),char(97),char(113),char(113),char(0),char(109),char(95),
+char(99),char(111),char(109),char(0),char(42),char(109),char(95),char(112),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(115),char(0),char(42),char(109),char(95),
+char(119),char(101),char(105),char(103),char(104),char(116),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(80),char(111),char(115),char(105),char(116),char(105),char(111),
+char(110),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(87),char(101),char(105),char(103),char(116),char(115),char(0),char(109),char(95),char(98),char(118),char(111),
+char(108),char(117),char(109),char(101),char(0),char(109),char(95),char(98),char(102),char(114),char(97),char(109),char(101),char(0),char(109),char(95),char(102),char(114),char(97),char(109),
+char(101),char(120),char(102),char(111),char(114),char(109),char(0),char(109),char(95),char(108),char(111),char(99),char(105),char(105),char(0),char(109),char(95),char(105),char(110),char(118),
+char(119),char(105),char(0),char(109),char(95),char(118),char(105),char(109),char(112),char(117),char(108),char(115),char(101),char(115),char(91),char(50),char(93),char(0),char(109),char(95),
+char(100),char(105),char(109),char(112),char(117),char(108),char(115),char(101),char(115),char(91),char(50),char(93),char(0),char(109),char(95),char(108),char(118),char(0),char(109),char(95),
+char(97),char(118),char(0),char(42),char(109),char(95),char(102),char(114),char(97),char(109),char(101),char(114),char(101),char(102),char(115),char(0),char(42),char(109),char(95),char(110),
+char(111),char(100),char(101),char(73),char(110),char(100),char(105),char(99),char(101),char(115),char(0),char(42),char(109),char(95),char(109),char(97),char(115),char(115),char(101),char(115),
+char(0),char(109),char(95),char(110),char(117),char(109),char(70),char(114),char(97),char(109),char(101),char(82),char(101),char(102),char(115),char(0),char(109),char(95),char(110),char(117),
+char(109),char(78),char(111),char(100),char(101),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(77),char(97),char(115),char(115),char(101),char(115),char(0),char(109),
+char(95),char(105),char(100),char(109),char(97),char(115),char(115),char(0),char(109),char(95),char(105),char(109),char(97),char(115),char(115),char(0),char(109),char(95),char(110),char(118),
+char(105),char(109),char(112),char(117),char(108),char(115),char(101),char(115),char(0),char(109),char(95),char(110),char(100),char(105),char(109),char(112),char(117),char(108),char(115),char(101),
+char(115),char(0),char(109),char(95),char(110),char(100),char(97),char(109),char(112),char(105),char(110),char(103),char(0),char(109),char(95),char(108),char(100),char(97),char(109),char(112),
+char(105),char(110),char(103),char(0),char(109),char(95),char(97),char(100),char(97),char(109),char(112),char(105),char(110),char(103),char(0),char(109),char(95),char(109),char(97),char(116),
+char(99),char(104),char(105),char(110),char(103),char(0),char(109),char(95),char(109),char(97),char(120),char(83),char(101),char(108),char(102),char(67),char(111),char(108),char(108),char(105),
+char(115),char(105),char(111),char(110),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(0),char(109),char(95),char(115),char(101),char(108),char(102),char(67),char(111),
+char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(70),char(97),char(99),char(116),char(111),char(114),
+char(0),char(109),char(95),char(99),char(111),char(110),char(116),char(97),char(105),char(110),char(115),char(65),char(110),char(99),char(104),char(111),char(114),char(0),char(109),char(95),
+char(99),char(111),char(108),char(108),char(105),char(100),char(101),char(0),char(109),char(95),char(99),char(108),char(117),char(115),char(116),char(101),char(114),char(73),char(110),char(100),
+char(101),char(120),char(0),char(42),char(109),char(95),char(98),char(111),char(100),char(121),char(65),char(0),char(42),char(109),char(95),char(98),char(111),char(100),char(121),char(66),
+char(0),char(109),char(95),char(114),char(101),char(102),char(115),char(91),char(50),char(93),char(0),char(109),char(95),char(99),char(102),char(109),char(0),char(109),char(95),char(115),
+char(112),char(108),char(105),char(116),char(0),char(109),char(95),char(100),char(101),char(108),char(101),char(116),char(101),char(0),char(109),char(95),char(114),char(101),char(108),char(80),
+char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(91),char(50),char(93),char(0),char(109),char(95),char(98),char(111),char(100),char(121),char(65),char(116),char(121),
+char(112),char(101),char(0),char(109),char(95),char(98),char(111),char(100),char(121),char(66),char(116),char(121),char(112),char(101),char(0),char(109),char(95),char(106),char(111),char(105),
+char(110),char(116),char(84),char(121),char(112),char(101),char(0),char(42),char(109),char(95),char(112),char(111),char(115),char(101),char(0),char(42),char(42),char(109),char(95),char(109),
+char(97),char(116),char(101),char(114),char(105),char(97),char(108),char(115),char(0),char(42),char(109),char(95),char(110),char(111),char(100),char(101),char(115),char(0),char(42),char(109),
+char(95),char(108),char(105),char(110),char(107),char(115),char(0),char(42),char(109),char(95),char(102),char(97),char(99),char(101),char(115),char(0),char(42),char(109),char(95),char(116),
+char(101),char(116),char(114),char(97),char(104),char(101),char(100),char(114),char(97),char(0),char(42),char(109),char(95),char(97),char(110),char(99),char(104),char(111),char(114),char(115),
+char(0),char(42),char(109),char(95),char(99),char(108),char(117),char(115),char(116),char(101),char(114),char(115),char(0),char(42),char(109),char(95),char(106),char(111),char(105),char(110),
+char(116),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(77),char(97),char(116),char(101),char(114),char(105),char(97),char(108),char(115),char(0),char(109),char(95),
+char(110),char(117),char(109),char(76),char(105),char(110),char(107),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(70),char(97),char(99),char(101),char(115),char(0),
+char(109),char(95),char(110),char(117),char(109),char(84),char(101),char(116),char(114),char(97),char(104),char(101),char(100),char(114),char(97),char(0),char(109),char(95),char(110),char(117),
+char(109),char(65),char(110),char(99),char(104),char(111),char(114),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(67),char(108),char(117),char(115),char(116),char(101),
+char(114),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(74),char(111),char(105),char(110),char(116),char(115),char(0),char(109),char(95),char(99),char(111),char(110),
+char(102),char(105),char(103),char(0),char(109),char(95),char(122),char(101),char(114),char(111),char(82),char(111),char(116),char(80),char(97),char(114),char(101),char(110),char(116),char(84),
+char(111),char(84),char(104),char(105),char(115),char(0),char(109),char(95),char(112),char(97),char(114),char(101),char(110),char(116),char(67),char(111),char(109),char(84),char(111),char(84),
+char(104),char(105),char(115),char(80),char(105),char(118),char(111),char(116),char(79),char(102),char(102),char(115),char(101),char(116),char(0),char(109),char(95),char(116),char(104),char(105),
+char(115),char(80),char(105),char(118),char(111),char(116),char(84),char(111),char(84),char(104),char(105),char(115),char(67),char(111),char(109),char(79),char(102),char(102),char(115),char(101),
+char(116),char(0),char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(65),char(120),char(105),char(115),char(84),char(111),char(112),char(91),char(54),char(93),char(0),
+char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(65),char(120),char(105),char(115),char(66),char(111),char(116),char(116),char(111),char(109),char(91),char(54),char(93),
+char(0),char(109),char(95),char(108),char(105),char(110),char(107),char(73),char(110),char(101),char(114),char(116),char(105),char(97),char(0),char(109),char(95),char(97),char(98),char(115),
+char(70),char(114),char(97),char(109),char(101),char(84),char(111),char(116),char(86),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(84),char(111),char(112),char(0),
+char(109),char(95),char(97),char(98),char(115),char(70),char(114),char(97),char(109),char(101),char(84),char(111),char(116),char(86),char(101),char(108),char(111),char(99),char(105),char(116),
+char(121),char(66),char(111),char(116),char(116),char(111),char(109),char(0),char(109),char(95),char(97),char(98),char(115),char(70),char(114),char(97),char(109),char(101),char(76),char(111),
+char(99),char(86),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(84),char(111),char(112),char(0),char(109),char(95),char(97),char(98),char(115),char(70),char(114),
+char(97),char(109),char(101),char(76),char(111),char(99),char(86),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(66),char(111),char(116),char(116),char(111),char(109),
+char(0),char(109),char(95),char(108),char(105),char(110),char(107),char(77),char(97),char(115),char(115),char(0),char(109),char(95),char(112),char(97),char(114),char(101),char(110),char(116),
+char(73),char(110),char(100),char(101),char(120),char(0),char(109),char(95),char(100),char(111),char(102),char(67),char(111),char(117),char(110),char(116),char(0),char(109),char(95),char(112),
+char(111),char(115),char(86),char(97),char(114),char(67),char(111),char(117),char(110),char(116),char(0),char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(80),char(111),
+char(115),char(91),char(55),char(93),char(0),char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(86),char(101),char(108),char(91),char(54),char(93),char(0),char(109),
+char(95),char(106),char(111),char(105),char(110),char(116),char(84),char(111),char(114),char(113),char(117),char(101),char(91),char(54),char(93),char(0),char(109),char(95),char(106),char(111),
+char(105),char(110),char(116),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(0),char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(70),char(114),
+char(105),char(99),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(76),char(111),char(119),char(101),char(114),char(76),
+char(105),char(109),char(105),char(116),char(0),char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(85),char(112),char(112),char(101),char(114),char(76),char(105),char(109),
+char(105),char(116),char(0),char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(77),char(97),char(120),char(70),char(111),char(114),char(99),char(101),char(0),char(109),
+char(95),char(106),char(111),char(105),char(110),char(116),char(77),char(97),char(120),char(86),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(0),char(42),char(109),
+char(95),char(108),char(105),char(110),char(107),char(78),char(97),char(109),char(101),char(0),char(42),char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(78),char(97),
+char(109),char(101),char(0),char(42),char(109),char(95),char(108),char(105),char(110),char(107),char(67),char(111),char(108),char(108),char(105),char(100),char(101),char(114),char(0),char(42),
+char(109),char(95),char(112),char(97),char(100),char(100),char(105),char(110),char(103),char(80),char(116),char(114),char(0),char(109),char(95),char(98),char(97),char(115),char(101),char(87),
+char(111),char(114),char(108),char(100),char(80),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(98),char(97),char(115),char(101),char(87),
+char(111),char(114),char(108),char(100),char(79),char(114),char(105),char(101),char(110),char(116),char(97),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(98),char(97),
+char(115),char(101),char(76),char(105),char(110),char(101),char(97),char(114),char(86),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(0),char(109),char(95),char(98),
+char(97),char(115),char(101),char(65),char(110),char(103),char(117),char(108),char(97),char(114),char(86),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(0),char(109),
+char(95),char(98),char(97),char(115),char(101),char(73),char(110),char(101),char(114),char(116),char(105),char(97),char(0),char(109),char(95),char(98),char(97),char(115),char(101),char(77),
+char(97),char(115),char(115),char(0),char(42),char(109),char(95),char(98),char(97),char(115),char(101),char(78),char(97),char(109),char(101),char(0),char(42),char(109),char(95),char(98),
+char(97),char(115),char(101),char(67),char(111),char(108),char(108),char(105),char(100),char(101),char(114),char(0),char(109),char(95),char(99),char(111),char(108),char(79),char(98),char(106),
+char(68),char(97),char(116),char(97),char(0),char(42),char(109),char(95),char(109),char(117),char(108),char(116),char(105),char(66),char(111),char(100),char(121),char(0),char(109),char(95),
+char(108),char(105),char(110),char(107),char(0),char(0),char(0),char(0),char(84),char(89),char(80),char(69),char(99),char(0),char(0),char(0),char(99),char(104),char(97),char(114),
+char(0),char(117),char(99),char(104),char(97),char(114),char(0),char(115),char(104),char(111),char(114),char(116),char(0),char(117),char(115),char(104),char(111),char(114),char(116),char(0),
+char(105),char(110),char(116),char(0),char(108),char(111),char(110),char(103),char(0),char(117),char(108),char(111),char(110),char(103),char(0),char(102),char(108),char(111),char(97),char(116),
+char(0),char(100),char(111),char(117),char(98),char(108),char(101),char(0),char(118),char(111),char(105),char(100),char(0),char(80),char(111),char(105),char(110),char(116),char(101),char(114),
+char(65),char(114),char(114),char(97),char(121),char(0),char(98),char(116),char(80),char(104),char(121),char(115),char(105),char(99),char(115),char(83),char(121),char(115),char(116),char(101),
+char(109),char(0),char(76),char(105),char(115),char(116),char(66),char(97),char(115),char(101),char(0),char(98),char(116),char(86),char(101),char(99),char(116),char(111),char(114),char(51),
+char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(86),char(101),char(99),char(116),char(111),char(114),char(51),char(68),
+char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(81),char(117),char(97),char(116),char(101),char(114),char(110),char(105),
+char(111),char(110),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(81),char(117),char(97),char(116),char(101),char(114),
+char(110),char(105),char(111),char(110),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(77),char(97),char(116),
+char(114),char(105),char(120),char(51),char(120),char(51),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(77),char(97),
+char(116),char(114),char(105),char(120),char(51),char(120),char(51),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),
+char(84),char(114),char(97),char(110),char(115),char(102),char(111),char(114),char(109),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),
+char(116),char(84),char(114),char(97),char(110),char(115),char(102),char(111),char(114),char(109),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),
+char(0),char(98),char(116),char(66),char(118),char(104),char(83),char(117),char(98),char(116),char(114),char(101),char(101),char(73),char(110),char(102),char(111),char(68),char(97),char(116),
char(97),char(0),char(98),char(116),char(79),char(112),char(116),char(105),char(109),char(105),char(122),char(101),char(100),char(66),char(118),char(104),char(78),char(111),char(100),char(101),
-char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(81),char(117),char(97),char(110),char(116),char(105),char(122),
-char(101),char(100),char(66),char(118),char(104),char(78),char(111),char(100),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(81),char(117),char(97),char(110),
-char(116),char(105),char(122),char(101),char(100),char(66),char(118),char(104),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),
-char(81),char(117),char(97),char(110),char(116),char(105),char(122),char(101),char(100),char(66),char(118),char(104),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),
-char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(83),char(104),char(97),char(112),char(101),char(68),
-char(97),char(116),char(97),char(0),char(98),char(116),char(83),char(116),char(97),char(116),char(105),char(99),char(80),char(108),char(97),char(110),char(101),char(83),char(104),char(97),
-char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(110),char(118),char(101),char(120),char(73),char(110),char(116),char(101),char(114),
-char(110),char(97),char(108),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(80),char(111),char(115),char(105),char(116),
-char(105),char(111),char(110),char(65),char(110),char(100),char(82),char(97),char(100),char(105),char(117),char(115),char(0),char(98),char(116),char(77),char(117),char(108),char(116),char(105),
-char(83),char(112),char(104),char(101),char(114),char(101),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(73),char(110),
-char(116),char(73),char(110),char(100),char(101),char(120),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(83),char(104),char(111),char(114),char(116),char(73),char(110),
-char(116),char(73),char(110),char(100),char(101),char(120),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(83),char(104),char(111),char(114),char(116),char(73),char(110),
-char(116),char(73),char(110),char(100),char(101),char(120),char(84),char(114),char(105),char(112),char(108),char(101),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),
-char(67),char(104),char(97),char(114),char(73),char(110),char(100),char(101),char(120),char(84),char(114),char(105),char(112),char(108),char(101),char(116),char(68),char(97),char(116),char(97),
-char(0),char(98),char(116),char(77),char(101),char(115),char(104),char(80),char(97),char(114),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(83),char(116),
-char(114),char(105),char(100),char(105),char(110),char(103),char(77),char(101),char(115),char(104),char(73),char(110),char(116),char(101),char(114),char(102),char(97),char(99),char(101),char(68),
-char(97),char(116),char(97),char(0),char(98),char(116),char(84),char(114),char(105),char(97),char(110),char(103),char(108),char(101),char(77),char(101),char(115),char(104),char(83),char(104),
+char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(79),char(112),char(116),char(105),char(109),char(105),char(122),char(101),
+char(100),char(66),char(118),char(104),char(78),char(111),char(100),char(101),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),
+char(116),char(81),char(117),char(97),char(110),char(116),char(105),char(122),char(101),char(100),char(66),char(118),char(104),char(78),char(111),char(100),char(101),char(68),char(97),char(116),
+char(97),char(0),char(98),char(116),char(81),char(117),char(97),char(110),char(116),char(105),char(122),char(101),char(100),char(66),char(118),char(104),char(70),char(108),char(111),char(97),
+char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(81),char(117),char(97),char(110),char(116),char(105),char(122),char(101),char(100),char(66),char(118),char(104),
+char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(108),char(108),char(105),char(115),char(105),
+char(111),char(110),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(83),char(116),char(97),char(116),char(105),char(99),
+char(80),char(108),char(97),char(110),char(101),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(110),
+char(118),char(101),char(120),char(73),char(110),char(116),char(101),char(114),char(110),char(97),char(108),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),
+char(0),char(98),char(116),char(80),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(65),char(110),char(100),char(82),char(97),char(100),char(105),char(117),char(115),
+char(0),char(98),char(116),char(77),char(117),char(108),char(116),char(105),char(83),char(112),char(104),char(101),char(114),char(101),char(83),char(104),char(97),char(112),char(101),char(68),
+char(97),char(116),char(97),char(0),char(98),char(116),char(73),char(110),char(116),char(73),char(110),char(100),char(101),char(120),char(68),char(97),char(116),char(97),char(0),char(98),
+char(116),char(83),char(104),char(111),char(114),char(116),char(73),char(110),char(116),char(73),char(110),char(100),char(101),char(120),char(68),char(97),char(116),char(97),char(0),char(98),
+char(116),char(83),char(104),char(111),char(114),char(116),char(73),char(110),char(116),char(73),char(110),char(100),char(101),char(120),char(84),char(114),char(105),char(112),char(108),char(101),
+char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(104),char(97),char(114),char(73),char(110),char(100),char(101),char(120),char(84),char(114),char(105),
+char(112),char(108),char(101),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(77),char(101),char(115),char(104),char(80),char(97),char(114),char(116),char(68),
+char(97),char(116),char(97),char(0),char(98),char(116),char(83),char(116),char(114),char(105),char(100),char(105),char(110),char(103),char(77),char(101),char(115),char(104),char(73),char(110),
+char(116),char(101),char(114),char(102),char(97),char(99),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(84),char(114),char(105),char(97),char(110),char(103),
+char(108),char(101),char(77),char(101),char(115),char(104),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(84),char(114),
+char(105),char(97),char(110),char(103),char(108),char(101),char(73),char(110),char(102),char(111),char(77),char(97),char(112),char(68),char(97),char(116),char(97),char(0),char(98),char(116),
+char(83),char(99),char(97),char(108),char(101),char(100),char(84),char(114),char(105),char(97),char(110),char(103),char(108),char(101),char(77),char(101),char(115),char(104),char(83),char(104),
+char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(109),char(112),char(111),char(117),char(110),char(100),char(83),char(104),
+char(97),char(112),char(101),char(67),char(104),char(105),char(108),char(100),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(109),char(112),char(111),
+char(117),char(110),char(100),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(121),char(108),char(105),char(110),
+char(100),char(101),char(114),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(110),char(101),char(83),
+char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(97),char(112),char(115),char(117),char(108),char(101),char(83),char(104),
char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(84),char(114),char(105),char(97),char(110),char(103),char(108),char(101),char(73),char(110),
-char(102),char(111),char(77),char(97),char(112),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(83),char(99),char(97),char(108),char(101),char(100),char(84),char(114),
-char(105),char(97),char(110),char(103),char(108),char(101),char(77),char(101),char(115),char(104),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),
-char(98),char(116),char(67),char(111),char(109),char(112),char(111),char(117),char(110),char(100),char(83),char(104),char(97),char(112),char(101),char(67),char(104),char(105),char(108),char(100),
-char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(109),char(112),char(111),char(117),char(110),char(100),char(83),char(104),char(97),char(112),char(101),
-char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(121),char(108),char(105),char(110),char(100),char(101),char(114),char(83),char(104),char(97),char(112),char(101),
-char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(110),char(101),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),
-char(0),char(98),char(116),char(67),char(97),char(112),char(115),char(117),char(108),char(101),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),
-char(98),char(116),char(84),char(114),char(105),char(97),char(110),char(103),char(108),char(101),char(73),char(110),char(102),char(111),char(68),char(97),char(116),char(97),char(0),char(98),
-char(116),char(71),char(73),char(109),char(112),char(97),char(99),char(116),char(77),char(101),char(115),char(104),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),
-char(97),char(0),char(98),char(116),char(67),char(111),char(110),char(118),char(101),char(120),char(72),char(117),char(108),char(108),char(83),char(104),char(97),char(112),char(101),char(68),
-char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(79),char(98),char(106),char(101),char(99),
-char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(108),char(108),char(105),char(115),
-char(105),char(111),char(110),char(79),char(98),char(106),char(101),char(99),char(116),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),
-char(116),char(67),char(111),char(110),char(116),char(97),char(99),char(116),char(83),char(111),char(108),char(118),char(101),char(114),char(73),char(110),char(102),char(111),char(68),char(111),
-char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(110),char(116),char(97),char(99),char(116),char(83),char(111),
-char(108),char(118),char(101),char(114),char(73),char(110),char(102),char(111),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),
-char(68),char(121),char(110),char(97),char(109),char(105),char(99),char(115),char(87),char(111),char(114),char(108),char(100),char(68),char(111),char(117),char(98),char(108),char(101),char(68),
-char(97),char(116),char(97),char(0),char(98),char(116),char(68),char(121),char(110),char(97),char(109),char(105),char(99),char(115),char(87),char(111),char(114),char(108),char(100),char(70),
-char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(82),char(105),char(103),char(105),char(100),char(66),char(111),char(100),char(121),
-char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(82),char(105),char(103),char(105),char(100),char(66),char(111),char(100),
-char(121),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(110),char(115),char(116),char(114),
-char(97),char(105),char(110),char(116),char(73),char(110),char(102),char(111),char(49),char(0),char(98),char(116),char(84),char(121),char(112),char(101),char(100),char(67),char(111),char(110),
-char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(84),
-char(121),char(112),char(101),char(100),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(97),char(116),char(97),char(0),char(98),
-char(116),char(82),char(105),char(103),char(105),char(100),char(66),char(111),char(100),char(121),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(84),char(121),char(112),
-char(101),char(100),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),
-char(116),char(97),char(0),char(98),char(116),char(80),char(111),char(105),char(110),char(116),char(50),char(80),char(111),char(105),char(110),char(116),char(67),char(111),char(110),char(115),
-char(116),char(114),char(97),char(105),char(110),char(116),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(80),char(111),
-char(105),char(110),char(116),char(50),char(80),char(111),char(105),char(110),char(116),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),
-char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(50),char(0),char(98),char(116),char(80),char(111),char(105),char(110),char(116),char(50),char(80),
-char(111),char(105),char(110),char(116),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),
-char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(72),char(105),char(110),char(103),char(101),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),
-char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(72),char(105),char(110),char(103),char(101),
-char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),
-char(98),char(116),char(72),char(105),char(110),char(103),char(101),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111),char(117),
-char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(50),char(0),char(98),char(116),char(67),char(111),char(110),char(101),char(84),char(119),char(105),char(115),char(116),
-char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),
-char(0),char(98),char(116),char(67),char(111),char(110),char(101),char(84),char(119),char(105),char(115),char(116),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),
-char(110),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(71),char(101),char(110),char(101),char(114),char(105),char(99),char(54),char(68),char(111),char(102),
-char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(71),char(101),char(110),
-char(101),char(114),char(105),char(99),char(54),char(68),char(111),char(102),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111),
-char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(50),char(0),char(98),char(116),char(71),char(101),char(110),char(101),char(114),char(105),char(99),char(54),
-char(68),char(111),char(102),char(83),char(112),char(114),char(105),char(110),char(103),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),
-char(97),char(116),char(97),char(0),char(98),char(116),char(71),char(101),char(110),char(101),char(114),char(105),char(99),char(54),char(68),char(111),char(102),char(83),char(112),char(114),
-char(105),char(110),char(103),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),
-char(97),char(116),char(97),char(50),char(0),char(98),char(116),char(71),char(101),char(110),char(101),char(114),char(105),char(99),char(54),char(68),char(111),char(102),char(83),char(112),
-char(114),char(105),char(110),char(103),char(50),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(97),char(116),char(97),char(0),
-char(98),char(116),char(71),char(101),char(110),char(101),char(114),char(105),char(99),char(54),char(68),char(111),char(102),char(83),char(112),char(114),char(105),char(110),char(103),char(50),
-char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),
-char(50),char(0),char(98),char(116),char(83),char(108),char(105),char(100),char(101),char(114),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),
-char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(83),char(108),char(105),char(100),char(101),char(114),char(67),char(111),char(110),char(115),char(116),char(114),char(97),
-char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(71),char(101),char(97),char(114),
-char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),
-char(98),char(116),char(71),char(101),char(97),char(114),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111),char(117),char(98),
-char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(77),char(97),char(116),char(101),char(114),
-char(105),char(97),char(108),char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(78),char(111),char(100),char(101),
-char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(76),char(105),char(110),char(107),char(68),char(97),char(116),
-char(97),char(0),char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(70),char(97),char(99),char(101),char(68),char(97),char(116),char(97),char(0),char(83),
-char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(84),char(101),char(116),char(114),char(97),char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102),
-char(116),char(82),char(105),char(103),char(105),char(100),char(65),char(110),char(99),char(104),char(111),char(114),char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102),
-char(116),char(66),char(111),char(100),char(121),char(67),char(111),char(110),char(102),char(105),char(103),char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102),char(116),
-char(66),char(111),char(100),char(121),char(80),char(111),char(115),char(101),char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102),char(116),char(66),char(111),char(100),
-char(121),char(67),char(108),char(117),char(115),char(116),char(101),char(114),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(83),char(111),char(102),char(116),char(66),
-char(111),char(100),char(121),char(74),char(111),char(105),char(110),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(83),char(111),char(102),char(116),char(66),
-char(111),char(100),char(121),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(77),char(117),char(108),char(116),char(105),
-char(66),char(111),char(100),char(121),char(76),char(105),char(110),char(107),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),
-char(116),char(77),char(117),char(108),char(116),char(105),char(66),char(111),char(100),char(121),char(76),char(105),char(110),char(107),char(70),char(108),char(111),char(97),char(116),char(68),
-char(97),char(116),char(97),char(0),char(98),char(116),char(77),char(117),char(108),char(116),char(105),char(66),char(111),char(100),char(121),char(68),char(111),char(117),char(98),char(108),
-char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(77),char(117),char(108),char(116),char(105),char(66),char(111),char(100),char(121),char(70),char(108),char(111),
-char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(0),char(84),char(76),char(69),char(78),char(1),char(0),char(1),char(0),char(2),char(0),char(2),char(0),
-char(4),char(0),char(4),char(0),char(4),char(0),char(4),char(0),char(8),char(0),char(0),char(0),char(12),char(0),char(36),char(0),char(8),char(0),char(16),char(0),
-char(32),char(0),char(16),char(0),char(32),char(0),char(48),char(0),char(96),char(0),char(64),char(0),char(-128),char(0),char(20),char(0),char(48),char(0),char(80),char(0),
-char(16),char(0),char(84),char(0),char(-124),char(0),char(12),char(0),char(52),char(0),char(52),char(0),char(20),char(0),char(64),char(0),char(4),char(0),char(4),char(0),
-char(8),char(0),char(4),char(0),char(32),char(0),char(28),char(0),char(60),char(0),char(56),char(0),char(76),char(0),char(76),char(0),char(24),char(0),char(60),char(0),
-char(60),char(0),char(60),char(0),char(16),char(0),char(64),char(0),char(68),char(0),char(-32),char(1),char(8),char(1),char(-104),char(0),char(88),char(0),char(-72),char(0),
-char(104),char(0),char(-16),char(1),char(-80),char(3),char(8),char(0),char(52),char(0),char(52),char(0),char(0),char(0),char(68),char(0),char(84),char(0),char(-124),char(0),
+char(102),char(111),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(80),char(101),char(114),char(115),char(105),char(115),char(116),char(101),char(110),char(116),char(77),
+char(97),char(110),char(105),char(102),char(111),char(108),char(100),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),
+char(67),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(79),char(98),char(106),char(101),char(99),char(116),char(68),char(111),char(117),char(98),char(108),
+char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(80),char(101),char(114),char(115),char(105),char(115),char(116),char(101),char(110),char(116),char(77),char(97),
+char(110),char(105),char(102),char(111),char(108),char(100),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),
+char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(79),char(98),char(106),char(101),char(99),char(116),char(70),char(108),char(111),char(97),char(116),char(68),char(97),
+char(116),char(97),char(0),char(98),char(116),char(71),char(73),char(109),char(112),char(97),char(99),char(116),char(77),char(101),char(115),char(104),char(83),char(104),char(97),char(112),
+char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(110),char(118),char(101),char(120),char(72),char(117),char(108),char(108),char(83),char(104),
+char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(110),char(116),char(97),char(99),char(116),char(83),char(111),char(108),
+char(118),char(101),char(114),char(73),char(110),char(102),char(111),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),
+char(67),char(111),char(110),char(116),char(97),char(99),char(116),char(83),char(111),char(108),char(118),char(101),char(114),char(73),char(110),char(102),char(111),char(70),char(108),char(111),
+char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(68),char(121),char(110),char(97),char(109),char(105),char(99),char(115),char(87),char(111),char(114),
+char(108),char(100),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(68),char(121),char(110),char(97),char(109),
+char(105),char(99),char(115),char(87),char(111),char(114),char(108),char(100),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),
+char(82),char(105),char(103),char(105),char(100),char(66),char(111),char(100),char(121),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),
+char(116),char(82),char(105),char(103),char(105),char(100),char(66),char(111),char(100),char(121),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),
+char(0),char(98),char(116),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(73),char(110),char(102),char(111),char(49),char(0),char(98),
+char(116),char(84),char(121),char(112),char(101),char(100),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(70),char(108),char(111),char(97),
+char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(84),char(121),char(112),char(101),char(100),char(67),char(111),char(110),char(115),char(116),char(114),char(97),
+char(105),char(110),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(82),char(105),char(103),char(105),char(100),char(66),char(111),char(100),char(121),char(68),
+char(97),char(116),char(97),char(0),char(98),char(116),char(84),char(121),char(112),char(101),char(100),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),
+char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(80),char(111),char(105),char(110),char(116),char(50),
+char(80),char(111),char(105),char(110),char(116),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(70),char(108),char(111),char(97),char(116),
+char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(80),char(111),char(105),char(110),char(116),char(50),char(80),char(111),char(105),char(110),char(116),char(67),char(111),
+char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(50),char(0),
+char(98),char(116),char(80),char(111),char(105),char(110),char(116),char(50),char(80),char(111),char(105),char(110),char(116),char(67),char(111),char(110),char(115),char(116),char(114),char(97),
+char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(72),char(105),char(110),char(103),
+char(101),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),
+char(97),char(0),char(98),char(116),char(72),char(105),char(110),char(103),char(101),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(70),
+char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(72),char(105),char(110),char(103),char(101),char(67),char(111),char(110),char(115),
+char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(50),char(0),char(98),char(116),
+char(67),char(111),char(110),char(101),char(84),char(119),char(105),char(115),char(116),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),
+char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(110),char(101),char(84),char(119),char(105),char(115),
+char(116),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(71),char(101),
+char(110),char(101),char(114),char(105),char(99),char(54),char(68),char(111),char(102),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),
+char(97),char(116),char(97),char(0),char(98),char(116),char(71),char(101),char(110),char(101),char(114),char(105),char(99),char(54),char(68),char(111),char(102),char(67),char(111),char(110),
+char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(50),char(0),char(98),
+char(116),char(71),char(101),char(110),char(101),char(114),char(105),char(99),char(54),char(68),char(111),char(102),char(83),char(112),char(114),char(105),char(110),char(103),char(67),char(111),
+char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(71),char(101),char(110),char(101),char(114),
+char(105),char(99),char(54),char(68),char(111),char(102),char(83),char(112),char(114),char(105),char(110),char(103),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),
+char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(50),char(0),char(98),char(116),char(71),char(101),char(110),char(101),
+char(114),char(105),char(99),char(54),char(68),char(111),char(102),char(83),char(112),char(114),char(105),char(110),char(103),char(50),char(67),char(111),char(110),char(115),char(116),char(114),
+char(97),char(105),char(110),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(71),char(101),char(110),char(101),char(114),char(105),char(99),char(54),char(68),
+char(111),char(102),char(83),char(112),char(114),char(105),char(110),char(103),char(50),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),
+char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(50),char(0),char(98),char(116),char(83),char(108),char(105),char(100),char(101),char(114),char(67),
+char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(83),char(108),char(105),char(100),
+char(101),char(114),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),
+char(116),char(97),char(0),char(98),char(116),char(71),char(101),char(97),char(114),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(70),
+char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(71),char(101),char(97),char(114),char(67),char(111),char(110),char(115),char(116),
+char(114),char(97),char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102),char(116),
+char(66),char(111),char(100),char(121),char(77),char(97),char(116),char(101),char(114),char(105),char(97),char(108),char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102),
+char(116),char(66),char(111),char(100),char(121),char(78),char(111),char(100),char(101),char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102),char(116),char(66),char(111),
+char(100),char(121),char(76),char(105),char(110),char(107),char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(70),
+char(97),char(99),char(101),char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(84),char(101),char(116),char(114),
+char(97),char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102),char(116),char(82),char(105),char(103),char(105),char(100),char(65),char(110),char(99),char(104),char(111),
+char(114),char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(67),char(111),char(110),char(102),char(105),char(103),
+char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(80),char(111),char(115),char(101),char(68),char(97),char(116),
+char(97),char(0),char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(67),char(108),char(117),char(115),char(116),char(101),char(114),char(68),char(97),char(116),
+char(97),char(0),char(98),char(116),char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(74),char(111),char(105),char(110),char(116),char(68),char(97),char(116),
+char(97),char(0),char(98),char(116),char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),
+char(97),char(0),char(98),char(116),char(77),char(117),char(108),char(116),char(105),char(66),char(111),char(100),char(121),char(76),char(105),char(110),char(107),char(68),char(111),char(117),
+char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(77),char(117),char(108),char(116),char(105),char(66),char(111),char(100),char(121),char(76),
+char(105),char(110),char(107),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(77),char(117),char(108),char(116),char(105),
+char(66),char(111),char(100),char(121),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(77),char(117),char(108),
+char(116),char(105),char(66),char(111),char(100),char(121),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(77),char(117),
+char(108),char(116),char(105),char(66),char(111),char(100),char(121),char(76),char(105),char(110),char(107),char(67),char(111),char(108),char(108),char(105),char(100),char(101),char(114),char(70),
+char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(77),char(117),char(108),char(116),char(105),char(66),char(111),char(100),char(121),
+char(76),char(105),char(110),char(107),char(67),char(111),char(108),char(108),char(105),char(100),char(101),char(114),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),
+char(116),char(97),char(0),char(0),char(84),char(76),char(69),char(78),char(1),char(0),char(1),char(0),char(2),char(0),char(2),char(0),char(4),char(0),char(4),char(0),
+char(4),char(0),char(4),char(0),char(8),char(0),char(0),char(0),char(12),char(0),char(36),char(0),char(8),char(0),char(16),char(0),char(32),char(0),char(16),char(0),
+char(32),char(0),char(48),char(0),char(96),char(0),char(64),char(0),char(-128),char(0),char(20),char(0),char(48),char(0),char(80),char(0),char(16),char(0),char(84),char(0),
+char(-124),char(0),char(12),char(0),char(52),char(0),char(52),char(0),char(20),char(0),char(64),char(0),char(4),char(0),char(4),char(0),char(8),char(0),char(4),char(0),
+char(32),char(0),char(28),char(0),char(60),char(0),char(56),char(0),char(76),char(0),char(76),char(0),char(24),char(0),char(60),char(0),char(60),char(0),char(60),char(0),
+char(16),char(0),char(-16),char(5),char(-24),char(1),char(56),char(3),char(16),char(1),char(64),char(0),char(68),char(0),char(-104),char(0),char(88),char(0),char(-72),char(0),
+char(104),char(0),char(-8),char(1),char(-72),char(3),char(8),char(0),char(52),char(0),char(52),char(0),char(0),char(0),char(68),char(0),char(84),char(0),char(-124),char(0),
char(116),char(0),char(92),char(1),char(-36),char(0),char(-116),char(1),char(124),char(1),char(-44),char(0),char(-4),char(0),char(-52),char(1),char(92),char(1),char(116),char(2),
char(-124),char(2),char(-76),char(4),char(-52),char(0),char(108),char(1),char(92),char(0),char(-116),char(0),char(16),char(0),char(100),char(0),char(20),char(0),char(36),char(0),
-char(100),char(0),char(92),char(0),char(104),char(0),char(-64),char(0),char(92),char(1),char(104),char(0),char(-76),char(1),char(-16),char(2),char(-120),char(1),char(-64),char(0),
-char(100),char(0),char(0),char(0),char(83),char(84),char(82),char(67),char(84),char(0),char(0),char(0),char(10),char(0),char(3),char(0),char(4),char(0),char(0),char(0),
-char(4),char(0),char(1),char(0),char(9),char(0),char(2),char(0),char(11),char(0),char(3),char(0),char(10),char(0),char(3),char(0),char(10),char(0),char(4),char(0),
-char(10),char(0),char(5),char(0),char(12),char(0),char(2),char(0),char(9),char(0),char(6),char(0),char(9),char(0),char(7),char(0),char(13),char(0),char(1),char(0),
-char(7),char(0),char(8),char(0),char(14),char(0),char(1),char(0),char(8),char(0),char(8),char(0),char(15),char(0),char(1),char(0),char(7),char(0),char(8),char(0),
-char(16),char(0),char(1),char(0),char(8),char(0),char(8),char(0),char(17),char(0),char(1),char(0),char(13),char(0),char(9),char(0),char(18),char(0),char(1),char(0),
-char(14),char(0),char(9),char(0),char(19),char(0),char(2),char(0),char(17),char(0),char(10),char(0),char(13),char(0),char(11),char(0),char(20),char(0),char(2),char(0),
-char(18),char(0),char(10),char(0),char(14),char(0),char(11),char(0),char(21),char(0),char(4),char(0),char(4),char(0),char(12),char(0),char(4),char(0),char(13),char(0),
-char(2),char(0),char(14),char(0),char(2),char(0),char(15),char(0),char(22),char(0),char(6),char(0),char(13),char(0),char(16),char(0),char(13),char(0),char(17),char(0),
-char(4),char(0),char(18),char(0),char(4),char(0),char(19),char(0),char(4),char(0),char(20),char(0),char(0),char(0),char(21),char(0),char(23),char(0),char(6),char(0),
-char(14),char(0),char(16),char(0),char(14),char(0),char(17),char(0),char(4),char(0),char(18),char(0),char(4),char(0),char(19),char(0),char(4),char(0),char(20),char(0),
-char(0),char(0),char(21),char(0),char(24),char(0),char(3),char(0),char(2),char(0),char(14),char(0),char(2),char(0),char(15),char(0),char(4),char(0),char(22),char(0),
-char(25),char(0),char(12),char(0),char(13),char(0),char(23),char(0),char(13),char(0),char(24),char(0),char(13),char(0),char(25),char(0),char(4),char(0),char(26),char(0),
-char(4),char(0),char(27),char(0),char(4),char(0),char(28),char(0),char(4),char(0),char(29),char(0),char(22),char(0),char(30),char(0),char(24),char(0),char(31),char(0),
-char(21),char(0),char(32),char(0),char(4),char(0),char(33),char(0),char(4),char(0),char(34),char(0),char(26),char(0),char(12),char(0),char(14),char(0),char(23),char(0),
-char(14),char(0),char(24),char(0),char(14),char(0),char(25),char(0),char(4),char(0),char(26),char(0),char(4),char(0),char(27),char(0),char(4),char(0),char(28),char(0),
-char(4),char(0),char(29),char(0),char(23),char(0),char(30),char(0),char(24),char(0),char(31),char(0),char(4),char(0),char(33),char(0),char(4),char(0),char(34),char(0),
-char(21),char(0),char(32),char(0),char(27),char(0),char(3),char(0),char(0),char(0),char(35),char(0),char(4),char(0),char(36),char(0),char(0),char(0),char(37),char(0),
-char(28),char(0),char(5),char(0),char(27),char(0),char(38),char(0),char(13),char(0),char(39),char(0),char(13),char(0),char(40),char(0),char(7),char(0),char(41),char(0),
-char(0),char(0),char(21),char(0),char(29),char(0),char(5),char(0),char(27),char(0),char(38),char(0),char(13),char(0),char(39),char(0),char(13),char(0),char(42),char(0),
-char(7),char(0),char(43),char(0),char(4),char(0),char(44),char(0),char(30),char(0),char(2),char(0),char(13),char(0),char(45),char(0),char(7),char(0),char(46),char(0),
-char(31),char(0),char(4),char(0),char(29),char(0),char(47),char(0),char(30),char(0),char(48),char(0),char(4),char(0),char(49),char(0),char(0),char(0),char(37),char(0),
-char(32),char(0),char(1),char(0),char(4),char(0),char(50),char(0),char(33),char(0),char(2),char(0),char(2),char(0),char(50),char(0),char(0),char(0),char(51),char(0),
-char(34),char(0),char(2),char(0),char(2),char(0),char(52),char(0),char(0),char(0),char(51),char(0),char(35),char(0),char(2),char(0),char(0),char(0),char(52),char(0),
-char(0),char(0),char(53),char(0),char(36),char(0),char(8),char(0),char(13),char(0),char(54),char(0),char(14),char(0),char(55),char(0),char(32),char(0),char(56),char(0),
-char(34),char(0),char(57),char(0),char(35),char(0),char(58),char(0),char(33),char(0),char(59),char(0),char(4),char(0),char(60),char(0),char(4),char(0),char(61),char(0),
-char(37),char(0),char(4),char(0),char(36),char(0),char(62),char(0),char(13),char(0),char(63),char(0),char(4),char(0),char(64),char(0),char(0),char(0),char(37),char(0),
-char(38),char(0),char(7),char(0),char(27),char(0),char(38),char(0),char(37),char(0),char(65),char(0),char(25),char(0),char(66),char(0),char(26),char(0),char(67),char(0),
-char(39),char(0),char(68),char(0),char(7),char(0),char(43),char(0),char(0),char(0),char(69),char(0),char(40),char(0),char(2),char(0),char(38),char(0),char(70),char(0),
-char(13),char(0),char(39),char(0),char(41),char(0),char(4),char(0),char(19),char(0),char(71),char(0),char(27),char(0),char(72),char(0),char(4),char(0),char(73),char(0),
-char(7),char(0),char(74),char(0),char(42),char(0),char(4),char(0),char(27),char(0),char(38),char(0),char(41),char(0),char(75),char(0),char(4),char(0),char(76),char(0),
-char(7),char(0),char(43),char(0),char(43),char(0),char(3),char(0),char(29),char(0),char(47),char(0),char(4),char(0),char(77),char(0),char(0),char(0),char(37),char(0),
-char(44),char(0),char(3),char(0),char(29),char(0),char(47),char(0),char(4),char(0),char(78),char(0),char(0),char(0),char(37),char(0),char(45),char(0),char(3),char(0),
-char(29),char(0),char(47),char(0),char(4),char(0),char(77),char(0),char(0),char(0),char(37),char(0),char(46),char(0),char(4),char(0),char(4),char(0),char(79),char(0),
-char(7),char(0),char(80),char(0),char(7),char(0),char(81),char(0),char(7),char(0),char(82),char(0),char(39),char(0),char(14),char(0),char(4),char(0),char(83),char(0),
-char(4),char(0),char(84),char(0),char(46),char(0),char(85),char(0),char(4),char(0),char(86),char(0),char(7),char(0),char(87),char(0),char(7),char(0),char(88),char(0),
-char(7),char(0),char(89),char(0),char(7),char(0),char(90),char(0),char(7),char(0),char(91),char(0),char(4),char(0),char(92),char(0),char(4),char(0),char(93),char(0),
-char(4),char(0),char(94),char(0),char(4),char(0),char(95),char(0),char(0),char(0),char(37),char(0),char(47),char(0),char(5),char(0),char(27),char(0),char(38),char(0),
-char(37),char(0),char(65),char(0),char(13),char(0),char(39),char(0),char(7),char(0),char(43),char(0),char(4),char(0),char(96),char(0),char(48),char(0),char(5),char(0),
-char(29),char(0),char(47),char(0),char(13),char(0),char(97),char(0),char(14),char(0),char(98),char(0),char(4),char(0),char(99),char(0),char(0),char(0),char(100),char(0),
-char(49),char(0),char(27),char(0),char(9),char(0),char(101),char(0),char(9),char(0),char(102),char(0),char(27),char(0),char(103),char(0),char(0),char(0),char(35),char(0),
-char(20),char(0),char(104),char(0),char(20),char(0),char(105),char(0),char(14),char(0),char(106),char(0),char(14),char(0),char(107),char(0),char(14),char(0),char(108),char(0),
-char(8),char(0),char(109),char(0),char(8),char(0),char(110),char(0),char(8),char(0),char(111),char(0),char(8),char(0),char(112),char(0),char(8),char(0),char(113),char(0),
-char(8),char(0),char(114),char(0),char(8),char(0),char(115),char(0),char(8),char(0),char(116),char(0),char(8),char(0),char(117),char(0),char(8),char(0),char(118),char(0),
-char(4),char(0),char(119),char(0),char(4),char(0),char(120),char(0),char(4),char(0),char(121),char(0),char(4),char(0),char(122),char(0),char(4),char(0),char(123),char(0),
-char(4),char(0),char(124),char(0),char(4),char(0),char(125),char(0),char(0),char(0),char(37),char(0),char(50),char(0),char(27),char(0),char(9),char(0),char(101),char(0),
-char(9),char(0),char(102),char(0),char(27),char(0),char(103),char(0),char(0),char(0),char(35),char(0),char(19),char(0),char(104),char(0),char(19),char(0),char(105),char(0),
-char(13),char(0),char(106),char(0),char(13),char(0),char(107),char(0),char(13),char(0),char(108),char(0),char(7),char(0),char(109),char(0),char(7),char(0),char(110),char(0),
-char(7),char(0),char(111),char(0),char(7),char(0),char(112),char(0),char(7),char(0),char(113),char(0),char(7),char(0),char(114),char(0),char(7),char(0),char(115),char(0),
-char(7),char(0),char(116),char(0),char(7),char(0),char(117),char(0),char(7),char(0),char(118),char(0),char(4),char(0),char(119),char(0),char(4),char(0),char(120),char(0),
-char(4),char(0),char(121),char(0),char(4),char(0),char(122),char(0),char(4),char(0),char(123),char(0),char(4),char(0),char(124),char(0),char(4),char(0),char(125),char(0),
-char(0),char(0),char(37),char(0),char(51),char(0),char(22),char(0),char(8),char(0),char(126),char(0),char(8),char(0),char(127),char(0),char(8),char(0),char(111),char(0),
-char(8),char(0),char(-128),char(0),char(8),char(0),char(115),char(0),char(8),char(0),char(-127),char(0),char(8),char(0),char(-126),char(0),char(8),char(0),char(-125),char(0),
-char(8),char(0),char(-124),char(0),char(8),char(0),char(-123),char(0),char(8),char(0),char(-122),char(0),char(8),char(0),char(-121),char(0),char(8),char(0),char(-120),char(0),
-char(8),char(0),char(-119),char(0),char(8),char(0),char(-118),char(0),char(8),char(0),char(-117),char(0),char(4),char(0),char(-116),char(0),char(4),char(0),char(-115),char(0),
-char(4),char(0),char(-114),char(0),char(4),char(0),char(-113),char(0),char(4),char(0),char(-112),char(0),char(0),char(0),char(37),char(0),char(52),char(0),char(22),char(0),
-char(7),char(0),char(126),char(0),char(7),char(0),char(127),char(0),char(7),char(0),char(111),char(0),char(7),char(0),char(-128),char(0),char(7),char(0),char(115),char(0),
-char(7),char(0),char(-127),char(0),char(7),char(0),char(-126),char(0),char(7),char(0),char(-125),char(0),char(7),char(0),char(-124),char(0),char(7),char(0),char(-123),char(0),
-char(7),char(0),char(-122),char(0),char(7),char(0),char(-121),char(0),char(7),char(0),char(-120),char(0),char(7),char(0),char(-119),char(0),char(7),char(0),char(-118),char(0),
-char(7),char(0),char(-117),char(0),char(4),char(0),char(-116),char(0),char(4),char(0),char(-115),char(0),char(4),char(0),char(-114),char(0),char(4),char(0),char(-113),char(0),
-char(4),char(0),char(-112),char(0),char(0),char(0),char(37),char(0),char(53),char(0),char(2),char(0),char(51),char(0),char(-111),char(0),char(14),char(0),char(-110),char(0),
-char(54),char(0),char(2),char(0),char(52),char(0),char(-111),char(0),char(13),char(0),char(-110),char(0),char(55),char(0),char(21),char(0),char(50),char(0),char(-109),char(0),
-char(17),char(0),char(-108),char(0),char(13),char(0),char(-107),char(0),char(13),char(0),char(-106),char(0),char(13),char(0),char(-105),char(0),char(13),char(0),char(-104),char(0),
-char(13),char(0),char(-110),char(0),char(13),char(0),char(-103),char(0),char(13),char(0),char(-102),char(0),char(13),char(0),char(-101),char(0),char(13),char(0),char(-100),char(0),
-char(7),char(0),char(-99),char(0),char(7),char(0),char(-98),char(0),char(7),char(0),char(-97),char(0),char(7),char(0),char(-96),char(0),char(7),char(0),char(-95),char(0),
-char(7),char(0),char(-94),char(0),char(7),char(0),char(-93),char(0),char(7),char(0),char(-92),char(0),char(7),char(0),char(-91),char(0),char(4),char(0),char(-90),char(0),
-char(56),char(0),char(22),char(0),char(49),char(0),char(-109),char(0),char(18),char(0),char(-108),char(0),char(14),char(0),char(-107),char(0),char(14),char(0),char(-106),char(0),
-char(14),char(0),char(-105),char(0),char(14),char(0),char(-104),char(0),char(14),char(0),char(-110),char(0),char(14),char(0),char(-103),char(0),char(14),char(0),char(-102),char(0),
-char(14),char(0),char(-101),char(0),char(14),char(0),char(-100),char(0),char(8),char(0),char(-99),char(0),char(8),char(0),char(-98),char(0),char(8),char(0),char(-97),char(0),
-char(8),char(0),char(-96),char(0),char(8),char(0),char(-95),char(0),char(8),char(0),char(-94),char(0),char(8),char(0),char(-93),char(0),char(8),char(0),char(-92),char(0),
-char(8),char(0),char(-91),char(0),char(4),char(0),char(-90),char(0),char(0),char(0),char(37),char(0),char(57),char(0),char(2),char(0),char(4),char(0),char(-89),char(0),
-char(4),char(0),char(-88),char(0),char(58),char(0),char(13),char(0),char(55),char(0),char(-87),char(0),char(55),char(0),char(-86),char(0),char(0),char(0),char(35),char(0),
-char(4),char(0),char(-85),char(0),char(4),char(0),char(-84),char(0),char(4),char(0),char(-83),char(0),char(4),char(0),char(-82),char(0),char(7),char(0),char(-81),char(0),
-char(7),char(0),char(-80),char(0),char(4),char(0),char(-79),char(0),char(4),char(0),char(-78),char(0),char(7),char(0),char(-77),char(0),char(4),char(0),char(-76),char(0),
-char(59),char(0),char(13),char(0),char(60),char(0),char(-87),char(0),char(60),char(0),char(-86),char(0),char(0),char(0),char(35),char(0),char(4),char(0),char(-85),char(0),
-char(4),char(0),char(-84),char(0),char(4),char(0),char(-83),char(0),char(4),char(0),char(-82),char(0),char(7),char(0),char(-81),char(0),char(7),char(0),char(-80),char(0),
-char(4),char(0),char(-79),char(0),char(4),char(0),char(-78),char(0),char(7),char(0),char(-77),char(0),char(4),char(0),char(-76),char(0),char(61),char(0),char(14),char(0),
-char(56),char(0),char(-87),char(0),char(56),char(0),char(-86),char(0),char(0),char(0),char(35),char(0),char(4),char(0),char(-85),char(0),char(4),char(0),char(-84),char(0),
-char(4),char(0),char(-83),char(0),char(4),char(0),char(-82),char(0),char(8),char(0),char(-81),char(0),char(8),char(0),char(-80),char(0),char(4),char(0),char(-79),char(0),
-char(4),char(0),char(-78),char(0),char(8),char(0),char(-77),char(0),char(4),char(0),char(-76),char(0),char(0),char(0),char(-75),char(0),char(62),char(0),char(3),char(0),
-char(59),char(0),char(-74),char(0),char(13),char(0),char(-73),char(0),char(13),char(0),char(-72),char(0),char(63),char(0),char(3),char(0),char(61),char(0),char(-74),char(0),
-char(14),char(0),char(-73),char(0),char(14),char(0),char(-72),char(0),char(64),char(0),char(3),char(0),char(59),char(0),char(-74),char(0),char(14),char(0),char(-73),char(0),
-char(14),char(0),char(-72),char(0),char(65),char(0),char(13),char(0),char(59),char(0),char(-74),char(0),char(20),char(0),char(-71),char(0),char(20),char(0),char(-70),char(0),
-char(4),char(0),char(-69),char(0),char(4),char(0),char(-68),char(0),char(4),char(0),char(-67),char(0),char(7),char(0),char(-66),char(0),char(7),char(0),char(-65),char(0),
-char(7),char(0),char(-64),char(0),char(7),char(0),char(-63),char(0),char(7),char(0),char(-62),char(0),char(7),char(0),char(-61),char(0),char(7),char(0),char(-60),char(0),
-char(66),char(0),char(13),char(0),char(59),char(0),char(-74),char(0),char(19),char(0),char(-71),char(0),char(19),char(0),char(-70),char(0),char(4),char(0),char(-69),char(0),
-char(4),char(0),char(-68),char(0),char(4),char(0),char(-67),char(0),char(7),char(0),char(-66),char(0),char(7),char(0),char(-65),char(0),char(7),char(0),char(-64),char(0),
-char(7),char(0),char(-63),char(0),char(7),char(0),char(-62),char(0),char(7),char(0),char(-61),char(0),char(7),char(0),char(-60),char(0),char(67),char(0),char(14),char(0),
-char(61),char(0),char(-74),char(0),char(20),char(0),char(-71),char(0),char(20),char(0),char(-70),char(0),char(4),char(0),char(-69),char(0),char(4),char(0),char(-68),char(0),
-char(4),char(0),char(-67),char(0),char(8),char(0),char(-66),char(0),char(8),char(0),char(-65),char(0),char(8),char(0),char(-64),char(0),char(8),char(0),char(-63),char(0),
-char(8),char(0),char(-62),char(0),char(8),char(0),char(-61),char(0),char(8),char(0),char(-60),char(0),char(0),char(0),char(-59),char(0),char(68),char(0),char(10),char(0),
-char(61),char(0),char(-74),char(0),char(20),char(0),char(-71),char(0),char(20),char(0),char(-70),char(0),char(8),char(0),char(-58),char(0),char(8),char(0),char(-57),char(0),
-char(8),char(0),char(-56),char(0),char(8),char(0),char(-62),char(0),char(8),char(0),char(-61),char(0),char(8),char(0),char(-60),char(0),char(8),char(0),char(127),char(0),
-char(69),char(0),char(11),char(0),char(59),char(0),char(-74),char(0),char(19),char(0),char(-71),char(0),char(19),char(0),char(-70),char(0),char(7),char(0),char(-58),char(0),
-char(7),char(0),char(-57),char(0),char(7),char(0),char(-56),char(0),char(7),char(0),char(-62),char(0),char(7),char(0),char(-61),char(0),char(7),char(0),char(-60),char(0),
-char(7),char(0),char(127),char(0),char(0),char(0),char(21),char(0),char(70),char(0),char(9),char(0),char(59),char(0),char(-74),char(0),char(19),char(0),char(-71),char(0),
-char(19),char(0),char(-70),char(0),char(13),char(0),char(-55),char(0),char(13),char(0),char(-54),char(0),char(13),char(0),char(-53),char(0),char(13),char(0),char(-52),char(0),
-char(4),char(0),char(-51),char(0),char(4),char(0),char(-50),char(0),char(71),char(0),char(9),char(0),char(61),char(0),char(-74),char(0),char(20),char(0),char(-71),char(0),
-char(20),char(0),char(-70),char(0),char(14),char(0),char(-55),char(0),char(14),char(0),char(-54),char(0),char(14),char(0),char(-53),char(0),char(14),char(0),char(-52),char(0),
-char(4),char(0),char(-51),char(0),char(4),char(0),char(-50),char(0),char(72),char(0),char(5),char(0),char(70),char(0),char(-49),char(0),char(4),char(0),char(-48),char(0),
-char(7),char(0),char(-47),char(0),char(7),char(0),char(-46),char(0),char(7),char(0),char(-45),char(0),char(73),char(0),char(5),char(0),char(71),char(0),char(-49),char(0),
-char(4),char(0),char(-48),char(0),char(8),char(0),char(-47),char(0),char(8),char(0),char(-46),char(0),char(8),char(0),char(-45),char(0),char(74),char(0),char(41),char(0),
-char(59),char(0),char(-74),char(0),char(19),char(0),char(-71),char(0),char(19),char(0),char(-70),char(0),char(13),char(0),char(-55),char(0),char(13),char(0),char(-54),char(0),
-char(13),char(0),char(-44),char(0),char(13),char(0),char(-43),char(0),char(13),char(0),char(-42),char(0),char(13),char(0),char(-41),char(0),char(13),char(0),char(-40),char(0),
-char(13),char(0),char(-39),char(0),char(13),char(0),char(-38),char(0),char(13),char(0),char(-37),char(0),char(13),char(0),char(-36),char(0),char(13),char(0),char(-35),char(0),
-char(13),char(0),char(-34),char(0),char(0),char(0),char(-33),char(0),char(0),char(0),char(-32),char(0),char(0),char(0),char(-31),char(0),char(0),char(0),char(-30),char(0),
-char(0),char(0),char(-29),char(0),char(0),char(0),char(-59),char(0),char(13),char(0),char(-53),char(0),char(13),char(0),char(-52),char(0),char(13),char(0),char(-28),char(0),
-char(13),char(0),char(-27),char(0),char(13),char(0),char(-26),char(0),char(13),char(0),char(-25),char(0),char(13),char(0),char(-24),char(0),char(13),char(0),char(-23),char(0),
-char(13),char(0),char(-22),char(0),char(13),char(0),char(-21),char(0),char(13),char(0),char(-20),char(0),char(13),char(0),char(-19),char(0),char(13),char(0),char(-18),char(0),
-char(0),char(0),char(-17),char(0),char(0),char(0),char(-16),char(0),char(0),char(0),char(-15),char(0),char(0),char(0),char(-14),char(0),char(0),char(0),char(-13),char(0),
-char(4),char(0),char(-12),char(0),char(75),char(0),char(41),char(0),char(61),char(0),char(-74),char(0),char(20),char(0),char(-71),char(0),char(20),char(0),char(-70),char(0),
-char(14),char(0),char(-55),char(0),char(14),char(0),char(-54),char(0),char(14),char(0),char(-44),char(0),char(14),char(0),char(-43),char(0),char(14),char(0),char(-42),char(0),
-char(14),char(0),char(-41),char(0),char(14),char(0),char(-40),char(0),char(14),char(0),char(-39),char(0),char(14),char(0),char(-38),char(0),char(14),char(0),char(-37),char(0),
-char(14),char(0),char(-36),char(0),char(14),char(0),char(-35),char(0),char(14),char(0),char(-34),char(0),char(0),char(0),char(-33),char(0),char(0),char(0),char(-32),char(0),
-char(0),char(0),char(-31),char(0),char(0),char(0),char(-30),char(0),char(0),char(0),char(-29),char(0),char(0),char(0),char(-59),char(0),char(14),char(0),char(-53),char(0),
-char(14),char(0),char(-52),char(0),char(14),char(0),char(-28),char(0),char(14),char(0),char(-27),char(0),char(14),char(0),char(-26),char(0),char(14),char(0),char(-25),char(0),
-char(14),char(0),char(-24),char(0),char(14),char(0),char(-23),char(0),char(14),char(0),char(-22),char(0),char(14),char(0),char(-21),char(0),char(14),char(0),char(-20),char(0),
-char(14),char(0),char(-19),char(0),char(14),char(0),char(-18),char(0),char(0),char(0),char(-17),char(0),char(0),char(0),char(-16),char(0),char(0),char(0),char(-15),char(0),
-char(0),char(0),char(-14),char(0),char(0),char(0),char(-13),char(0),char(4),char(0),char(-12),char(0),char(76),char(0),char(9),char(0),char(59),char(0),char(-74),char(0),
-char(19),char(0),char(-71),char(0),char(19),char(0),char(-70),char(0),char(7),char(0),char(-55),char(0),char(7),char(0),char(-54),char(0),char(7),char(0),char(-53),char(0),
-char(7),char(0),char(-52),char(0),char(4),char(0),char(-51),char(0),char(4),char(0),char(-50),char(0),char(77),char(0),char(9),char(0),char(61),char(0),char(-74),char(0),
-char(20),char(0),char(-71),char(0),char(20),char(0),char(-70),char(0),char(8),char(0),char(-55),char(0),char(8),char(0),char(-54),char(0),char(8),char(0),char(-53),char(0),
-char(8),char(0),char(-52),char(0),char(4),char(0),char(-51),char(0),char(4),char(0),char(-50),char(0),char(78),char(0),char(5),char(0),char(58),char(0),char(-74),char(0),
-char(13),char(0),char(-11),char(0),char(13),char(0),char(-10),char(0),char(7),char(0),char(-9),char(0),char(0),char(0),char(37),char(0),char(79),char(0),char(4),char(0),
-char(61),char(0),char(-74),char(0),char(14),char(0),char(-11),char(0),char(14),char(0),char(-10),char(0),char(8),char(0),char(-9),char(0),char(80),char(0),char(4),char(0),
-char(7),char(0),char(-8),char(0),char(7),char(0),char(-7),char(0),char(7),char(0),char(-6),char(0),char(4),char(0),char(79),char(0),char(81),char(0),char(10),char(0),
-char(80),char(0),char(-5),char(0),char(13),char(0),char(-4),char(0),char(13),char(0),char(-3),char(0),char(13),char(0),char(-2),char(0),char(13),char(0),char(-1),char(0),
-char(13),char(0),char(0),char(1),char(7),char(0),char(-99),char(0),char(7),char(0),char(1),char(1),char(4),char(0),char(2),char(1),char(4),char(0),char(53),char(0),
-char(82),char(0),char(4),char(0),char(80),char(0),char(-5),char(0),char(4),char(0),char(3),char(1),char(7),char(0),char(4),char(1),char(4),char(0),char(5),char(1),
-char(83),char(0),char(4),char(0),char(13),char(0),char(0),char(1),char(80),char(0),char(-5),char(0),char(4),char(0),char(6),char(1),char(7),char(0),char(7),char(1),
-char(84),char(0),char(7),char(0),char(13),char(0),char(8),char(1),char(80),char(0),char(-5),char(0),char(4),char(0),char(9),char(1),char(7),char(0),char(10),char(1),
-char(7),char(0),char(11),char(1),char(7),char(0),char(12),char(1),char(4),char(0),char(53),char(0),char(85),char(0),char(6),char(0),char(17),char(0),char(13),char(1),
-char(13),char(0),char(11),char(1),char(13),char(0),char(14),char(1),char(60),char(0),char(15),char(1),char(4),char(0),char(16),char(1),char(7),char(0),char(12),char(1),
-char(86),char(0),char(26),char(0),char(4),char(0),char(17),char(1),char(7),char(0),char(18),char(1),char(7),char(0),char(127),char(0),char(7),char(0),char(19),char(1),
-char(7),char(0),char(20),char(1),char(7),char(0),char(21),char(1),char(7),char(0),char(22),char(1),char(7),char(0),char(23),char(1),char(7),char(0),char(24),char(1),
-char(7),char(0),char(25),char(1),char(7),char(0),char(26),char(1),char(7),char(0),char(27),char(1),char(7),char(0),char(28),char(1),char(7),char(0),char(29),char(1),
-char(7),char(0),char(30),char(1),char(7),char(0),char(31),char(1),char(7),char(0),char(32),char(1),char(7),char(0),char(33),char(1),char(7),char(0),char(34),char(1),
-char(7),char(0),char(35),char(1),char(7),char(0),char(36),char(1),char(4),char(0),char(37),char(1),char(4),char(0),char(38),char(1),char(4),char(0),char(39),char(1),
-char(4),char(0),char(40),char(1),char(4),char(0),char(120),char(0),char(87),char(0),char(12),char(0),char(17),char(0),char(41),char(1),char(17),char(0),char(42),char(1),
-char(17),char(0),char(43),char(1),char(13),char(0),char(44),char(1),char(13),char(0),char(45),char(1),char(7),char(0),char(46),char(1),char(4),char(0),char(47),char(1),
-char(4),char(0),char(48),char(1),char(4),char(0),char(49),char(1),char(4),char(0),char(50),char(1),char(7),char(0),char(10),char(1),char(4),char(0),char(53),char(0),
-char(88),char(0),char(27),char(0),char(19),char(0),char(51),char(1),char(17),char(0),char(52),char(1),char(17),char(0),char(53),char(1),char(13),char(0),char(44),char(1),
-char(13),char(0),char(54),char(1),char(13),char(0),char(55),char(1),char(13),char(0),char(56),char(1),char(13),char(0),char(57),char(1),char(13),char(0),char(58),char(1),
-char(4),char(0),char(59),char(1),char(7),char(0),char(60),char(1),char(4),char(0),char(61),char(1),char(4),char(0),char(62),char(1),char(4),char(0),char(63),char(1),
-char(7),char(0),char(64),char(1),char(7),char(0),char(65),char(1),char(4),char(0),char(66),char(1),char(4),char(0),char(67),char(1),char(7),char(0),char(68),char(1),
-char(7),char(0),char(69),char(1),char(7),char(0),char(70),char(1),char(7),char(0),char(71),char(1),char(7),char(0),char(72),char(1),char(7),char(0),char(73),char(1),
-char(4),char(0),char(74),char(1),char(4),char(0),char(75),char(1),char(4),char(0),char(76),char(1),char(89),char(0),char(12),char(0),char(9),char(0),char(77),char(1),
-char(9),char(0),char(78),char(1),char(13),char(0),char(79),char(1),char(7),char(0),char(80),char(1),char(7),char(0),char(-125),char(0),char(7),char(0),char(81),char(1),
-char(4),char(0),char(82),char(1),char(13),char(0),char(83),char(1),char(4),char(0),char(84),char(1),char(4),char(0),char(85),char(1),char(4),char(0),char(86),char(1),
-char(4),char(0),char(53),char(0),char(90),char(0),char(19),char(0),char(50),char(0),char(-109),char(0),char(87),char(0),char(87),char(1),char(80),char(0),char(88),char(1),
-char(81),char(0),char(89),char(1),char(82),char(0),char(90),char(1),char(83),char(0),char(91),char(1),char(84),char(0),char(92),char(1),char(85),char(0),char(93),char(1),
-char(88),char(0),char(94),char(1),char(89),char(0),char(95),char(1),char(4),char(0),char(96),char(1),char(4),char(0),char(62),char(1),char(4),char(0),char(97),char(1),
-char(4),char(0),char(98),char(1),char(4),char(0),char(99),char(1),char(4),char(0),char(100),char(1),char(4),char(0),char(101),char(1),char(4),char(0),char(102),char(1),
-char(86),char(0),char(103),char(1),char(91),char(0),char(24),char(0),char(16),char(0),char(104),char(1),char(14),char(0),char(105),char(1),char(14),char(0),char(106),char(1),
-char(14),char(0),char(107),char(1),char(14),char(0),char(108),char(1),char(14),char(0),char(109),char(1),char(8),char(0),char(110),char(1),char(4),char(0),char(111),char(1),
-char(4),char(0),char(86),char(1),char(4),char(0),char(112),char(1),char(4),char(0),char(113),char(1),char(8),char(0),char(114),char(1),char(8),char(0),char(115),char(1),
-char(8),char(0),char(116),char(1),char(8),char(0),char(117),char(1),char(8),char(0),char(118),char(1),char(8),char(0),char(119),char(1),char(8),char(0),char(120),char(1),
-char(8),char(0),char(121),char(1),char(8),char(0),char(122),char(1),char(0),char(0),char(123),char(1),char(0),char(0),char(124),char(1),char(49),char(0),char(125),char(1),
-char(0),char(0),char(126),char(1),char(92),char(0),char(24),char(0),char(15),char(0),char(104),char(1),char(13),char(0),char(105),char(1),char(13),char(0),char(106),char(1),
-char(13),char(0),char(107),char(1),char(13),char(0),char(108),char(1),char(13),char(0),char(109),char(1),char(4),char(0),char(112),char(1),char(7),char(0),char(110),char(1),
-char(4),char(0),char(111),char(1),char(4),char(0),char(86),char(1),char(7),char(0),char(114),char(1),char(7),char(0),char(115),char(1),char(7),char(0),char(116),char(1),
-char(4),char(0),char(113),char(1),char(7),char(0),char(117),char(1),char(7),char(0),char(118),char(1),char(7),char(0),char(119),char(1),char(7),char(0),char(120),char(1),
-char(7),char(0),char(121),char(1),char(7),char(0),char(122),char(1),char(0),char(0),char(123),char(1),char(0),char(0),char(124),char(1),char(50),char(0),char(125),char(1),
-char(0),char(0),char(126),char(1),char(93),char(0),char(9),char(0),char(20),char(0),char(127),char(1),char(14),char(0),char(-128),char(1),char(8),char(0),char(-127),char(1),
-char(0),char(0),char(-126),char(1),char(91),char(0),char(90),char(1),char(49),char(0),char(-125),char(1),char(0),char(0),char(126),char(1),char(4),char(0),char(97),char(1),
-char(0),char(0),char(37),char(0),char(94),char(0),char(7),char(0),char(0),char(0),char(-126),char(1),char(92),char(0),char(90),char(1),char(50),char(0),char(-125),char(1),
-char(19),char(0),char(127),char(1),char(13),char(0),char(-128),char(1),char(7),char(0),char(-127),char(1),char(4),char(0),char(97),char(1),};
+char(100),char(0),char(92),char(0),char(104),char(0),char(-64),char(0),char(92),char(1),char(104),char(0),char(-68),char(1),char(112),char(3),char(-56),char(1),char(-68),char(0),
+char(100),char(0),char(28),char(1),char(-12),char(1),char(0),char(0),char(83),char(84),char(82),char(67),char(88),char(0),char(0),char(0),char(10),char(0),char(3),char(0),
+char(4),char(0),char(0),char(0),char(4),char(0),char(1),char(0),char(9),char(0),char(2),char(0),char(11),char(0),char(3),char(0),char(10),char(0),char(3),char(0),
+char(10),char(0),char(4),char(0),char(10),char(0),char(5),char(0),char(12),char(0),char(2),char(0),char(9),char(0),char(6),char(0),char(9),char(0),char(7),char(0),
+char(13),char(0),char(1),char(0),char(7),char(0),char(8),char(0),char(14),char(0),char(1),char(0),char(8),char(0),char(8),char(0),char(15),char(0),char(1),char(0),
+char(7),char(0),char(8),char(0),char(16),char(0),char(1),char(0),char(8),char(0),char(8),char(0),char(17),char(0),char(1),char(0),char(13),char(0),char(9),char(0),
+char(18),char(0),char(1),char(0),char(14),char(0),char(9),char(0),char(19),char(0),char(2),char(0),char(17),char(0),char(10),char(0),char(13),char(0),char(11),char(0),
+char(20),char(0),char(2),char(0),char(18),char(0),char(10),char(0),char(14),char(0),char(11),char(0),char(21),char(0),char(4),char(0),char(4),char(0),char(12),char(0),
+char(4),char(0),char(13),char(0),char(2),char(0),char(14),char(0),char(2),char(0),char(15),char(0),char(22),char(0),char(6),char(0),char(13),char(0),char(16),char(0),
+char(13),char(0),char(17),char(0),char(4),char(0),char(18),char(0),char(4),char(0),char(19),char(0),char(4),char(0),char(20),char(0),char(0),char(0),char(21),char(0),
+char(23),char(0),char(6),char(0),char(14),char(0),char(16),char(0),char(14),char(0),char(17),char(0),char(4),char(0),char(18),char(0),char(4),char(0),char(19),char(0),
+char(4),char(0),char(20),char(0),char(0),char(0),char(21),char(0),char(24),char(0),char(3),char(0),char(2),char(0),char(14),char(0),char(2),char(0),char(15),char(0),
+char(4),char(0),char(22),char(0),char(25),char(0),char(12),char(0),char(13),char(0),char(23),char(0),char(13),char(0),char(24),char(0),char(13),char(0),char(25),char(0),
+char(4),char(0),char(26),char(0),char(4),char(0),char(27),char(0),char(4),char(0),char(28),char(0),char(4),char(0),char(29),char(0),char(22),char(0),char(30),char(0),
+char(24),char(0),char(31),char(0),char(21),char(0),char(32),char(0),char(4),char(0),char(33),char(0),char(4),char(0),char(34),char(0),char(26),char(0),char(12),char(0),
+char(14),char(0),char(23),char(0),char(14),char(0),char(24),char(0),char(14),char(0),char(25),char(0),char(4),char(0),char(26),char(0),char(4),char(0),char(27),char(0),
+char(4),char(0),char(28),char(0),char(4),char(0),char(29),char(0),char(23),char(0),char(30),char(0),char(24),char(0),char(31),char(0),char(4),char(0),char(33),char(0),
+char(4),char(0),char(34),char(0),char(21),char(0),char(32),char(0),char(27),char(0),char(3),char(0),char(0),char(0),char(35),char(0),char(4),char(0),char(36),char(0),
+char(0),char(0),char(37),char(0),char(28),char(0),char(5),char(0),char(27),char(0),char(38),char(0),char(13),char(0),char(39),char(0),char(13),char(0),char(40),char(0),
+char(7),char(0),char(41),char(0),char(0),char(0),char(21),char(0),char(29),char(0),char(5),char(0),char(27),char(0),char(38),char(0),char(13),char(0),char(39),char(0),
+char(13),char(0),char(42),char(0),char(7),char(0),char(43),char(0),char(4),char(0),char(44),char(0),char(30),char(0),char(2),char(0),char(13),char(0),char(45),char(0),
+char(7),char(0),char(46),char(0),char(31),char(0),char(4),char(0),char(29),char(0),char(47),char(0),char(30),char(0),char(48),char(0),char(4),char(0),char(49),char(0),
+char(0),char(0),char(37),char(0),char(32),char(0),char(1),char(0),char(4),char(0),char(50),char(0),char(33),char(0),char(2),char(0),char(2),char(0),char(50),char(0),
+char(0),char(0),char(51),char(0),char(34),char(0),char(2),char(0),char(2),char(0),char(52),char(0),char(0),char(0),char(51),char(0),char(35),char(0),char(2),char(0),
+char(0),char(0),char(52),char(0),char(0),char(0),char(53),char(0),char(36),char(0),char(8),char(0),char(13),char(0),char(54),char(0),char(14),char(0),char(55),char(0),
+char(32),char(0),char(56),char(0),char(34),char(0),char(57),char(0),char(35),char(0),char(58),char(0),char(33),char(0),char(59),char(0),char(4),char(0),char(60),char(0),
+char(4),char(0),char(61),char(0),char(37),char(0),char(4),char(0),char(36),char(0),char(62),char(0),char(13),char(0),char(63),char(0),char(4),char(0),char(64),char(0),
+char(0),char(0),char(37),char(0),char(38),char(0),char(7),char(0),char(27),char(0),char(38),char(0),char(37),char(0),char(65),char(0),char(25),char(0),char(66),char(0),
+char(26),char(0),char(67),char(0),char(39),char(0),char(68),char(0),char(7),char(0),char(43),char(0),char(0),char(0),char(69),char(0),char(40),char(0),char(2),char(0),
+char(38),char(0),char(70),char(0),char(13),char(0),char(39),char(0),char(41),char(0),char(4),char(0),char(19),char(0),char(71),char(0),char(27),char(0),char(72),char(0),
+char(4),char(0),char(73),char(0),char(7),char(0),char(74),char(0),char(42),char(0),char(4),char(0),char(27),char(0),char(38),char(0),char(41),char(0),char(75),char(0),
+char(4),char(0),char(76),char(0),char(7),char(0),char(43),char(0),char(43),char(0),char(3),char(0),char(29),char(0),char(47),char(0),char(4),char(0),char(77),char(0),
+char(0),char(0),char(37),char(0),char(44),char(0),char(3),char(0),char(29),char(0),char(47),char(0),char(4),char(0),char(78),char(0),char(0),char(0),char(37),char(0),
+char(45),char(0),char(3),char(0),char(29),char(0),char(47),char(0),char(4),char(0),char(77),char(0),char(0),char(0),char(37),char(0),char(46),char(0),char(4),char(0),
+char(4),char(0),char(79),char(0),char(7),char(0),char(80),char(0),char(7),char(0),char(81),char(0),char(7),char(0),char(82),char(0),char(39),char(0),char(14),char(0),
+char(4),char(0),char(83),char(0),char(4),char(0),char(84),char(0),char(46),char(0),char(85),char(0),char(4),char(0),char(86),char(0),char(7),char(0),char(87),char(0),
+char(7),char(0),char(88),char(0),char(7),char(0),char(89),char(0),char(7),char(0),char(90),char(0),char(7),char(0),char(91),char(0),char(4),char(0),char(92),char(0),
+char(4),char(0),char(93),char(0),char(4),char(0),char(94),char(0),char(4),char(0),char(95),char(0),char(0),char(0),char(37),char(0),char(47),char(0),char(38),char(0),
+char(14),char(0),char(96),char(0),char(14),char(0),char(97),char(0),char(14),char(0),char(98),char(0),char(14),char(0),char(99),char(0),char(14),char(0),char(100),char(0),
+char(14),char(0),char(101),char(0),char(14),char(0),char(102),char(0),char(8),char(0),char(103),char(0),char(8),char(0),char(104),char(0),char(8),char(0),char(105),char(0),
+char(8),char(0),char(106),char(0),char(8),char(0),char(107),char(0),char(8),char(0),char(108),char(0),char(4),char(0),char(109),char(0),char(4),char(0),char(110),char(0),
+char(4),char(0),char(111),char(0),char(4),char(0),char(112),char(0),char(4),char(0),char(113),char(0),char(8),char(0),char(114),char(0),char(8),char(0),char(115),char(0),
+char(8),char(0),char(116),char(0),char(8),char(0),char(117),char(0),char(8),char(0),char(118),char(0),char(8),char(0),char(119),char(0),char(8),char(0),char(120),char(0),
+char(8),char(0),char(121),char(0),char(8),char(0),char(122),char(0),char(4),char(0),char(123),char(0),char(4),char(0),char(124),char(0),char(4),char(0),char(125),char(0),
+char(4),char(0),char(126),char(0),char(4),char(0),char(127),char(0),char(4),char(0),char(-128),char(0),char(8),char(0),char(-127),char(0),char(8),char(0),char(-126),char(0),
+char(4),char(0),char(44),char(0),char(48),char(0),char(-125),char(0),char(48),char(0),char(-124),char(0),char(49),char(0),char(38),char(0),char(13),char(0),char(96),char(0),
+char(13),char(0),char(97),char(0),char(13),char(0),char(98),char(0),char(13),char(0),char(99),char(0),char(13),char(0),char(100),char(0),char(13),char(0),char(101),char(0),
+char(13),char(0),char(102),char(0),char(7),char(0),char(103),char(0),char(7),char(0),char(104),char(0),char(7),char(0),char(105),char(0),char(7),char(0),char(106),char(0),
+char(7),char(0),char(107),char(0),char(7),char(0),char(108),char(0),char(4),char(0),char(109),char(0),char(4),char(0),char(110),char(0),char(4),char(0),char(111),char(0),
+char(4),char(0),char(112),char(0),char(4),char(0),char(113),char(0),char(7),char(0),char(114),char(0),char(7),char(0),char(115),char(0),char(7),char(0),char(116),char(0),
+char(7),char(0),char(117),char(0),char(7),char(0),char(118),char(0),char(7),char(0),char(119),char(0),char(7),char(0),char(120),char(0),char(7),char(0),char(121),char(0),
+char(7),char(0),char(122),char(0),char(4),char(0),char(123),char(0),char(4),char(0),char(124),char(0),char(4),char(0),char(125),char(0),char(4),char(0),char(126),char(0),
+char(4),char(0),char(127),char(0),char(4),char(0),char(-128),char(0),char(7),char(0),char(-127),char(0),char(7),char(0),char(-126),char(0),char(4),char(0),char(44),char(0),
+char(50),char(0),char(-125),char(0),char(50),char(0),char(-124),char(0),char(51),char(0),char(5),char(0),char(27),char(0),char(38),char(0),char(37),char(0),char(65),char(0),
+char(13),char(0),char(39),char(0),char(7),char(0),char(43),char(0),char(4),char(0),char(-123),char(0),char(52),char(0),char(5),char(0),char(29),char(0),char(47),char(0),
+char(13),char(0),char(-122),char(0),char(14),char(0),char(-121),char(0),char(4),char(0),char(-120),char(0),char(0),char(0),char(-119),char(0),char(48),char(0),char(29),char(0),
+char(9),char(0),char(-118),char(0),char(9),char(0),char(-117),char(0),char(27),char(0),char(-116),char(0),char(0),char(0),char(35),char(0),char(20),char(0),char(-115),char(0),
+char(20),char(0),char(-114),char(0),char(14),char(0),char(-113),char(0),char(14),char(0),char(-112),char(0),char(14),char(0),char(-111),char(0),char(8),char(0),char(-126),char(0),
+char(8),char(0),char(-110),char(0),char(8),char(0),char(-109),char(0),char(8),char(0),char(-108),char(0),char(8),char(0),char(-107),char(0),char(8),char(0),char(-106),char(0),
+char(8),char(0),char(-105),char(0),char(8),char(0),char(-104),char(0),char(8),char(0),char(-103),char(0),char(8),char(0),char(-102),char(0),char(4),char(0),char(-101),char(0),
+char(4),char(0),char(-100),char(0),char(4),char(0),char(-99),char(0),char(4),char(0),char(-98),char(0),char(4),char(0),char(-97),char(0),char(4),char(0),char(-96),char(0),
+char(4),char(0),char(-95),char(0),char(4),char(0),char(-94),char(0),char(4),char(0),char(-93),char(0),char(4),char(0),char(-92),char(0),char(50),char(0),char(29),char(0),
+char(9),char(0),char(-118),char(0),char(9),char(0),char(-117),char(0),char(27),char(0),char(-116),char(0),char(0),char(0),char(35),char(0),char(19),char(0),char(-115),char(0),
+char(19),char(0),char(-114),char(0),char(13),char(0),char(-113),char(0),char(13),char(0),char(-112),char(0),char(13),char(0),char(-111),char(0),char(7),char(0),char(-126),char(0),
+char(7),char(0),char(-110),char(0),char(7),char(0),char(-109),char(0),char(7),char(0),char(-108),char(0),char(7),char(0),char(-107),char(0),char(7),char(0),char(-106),char(0),
+char(7),char(0),char(-105),char(0),char(7),char(0),char(-104),char(0),char(7),char(0),char(-103),char(0),char(7),char(0),char(-102),char(0),char(4),char(0),char(-101),char(0),
+char(4),char(0),char(-100),char(0),char(4),char(0),char(-99),char(0),char(4),char(0),char(-98),char(0),char(4),char(0),char(-97),char(0),char(4),char(0),char(-96),char(0),
+char(4),char(0),char(-95),char(0),char(4),char(0),char(-94),char(0),char(4),char(0),char(-93),char(0),char(4),char(0),char(-92),char(0),char(53),char(0),char(22),char(0),
+char(8),char(0),char(-91),char(0),char(8),char(0),char(-90),char(0),char(8),char(0),char(-109),char(0),char(8),char(0),char(-89),char(0),char(8),char(0),char(-105),char(0),
+char(8),char(0),char(-88),char(0),char(8),char(0),char(-87),char(0),char(8),char(0),char(-86),char(0),char(8),char(0),char(-85),char(0),char(8),char(0),char(-84),char(0),
+char(8),char(0),char(-83),char(0),char(8),char(0),char(-82),char(0),char(8),char(0),char(-81),char(0),char(8),char(0),char(-80),char(0),char(8),char(0),char(-79),char(0),
+char(8),char(0),char(-78),char(0),char(4),char(0),char(-77),char(0),char(4),char(0),char(-76),char(0),char(4),char(0),char(-75),char(0),char(4),char(0),char(-74),char(0),
+char(4),char(0),char(-73),char(0),char(0),char(0),char(37),char(0),char(54),char(0),char(22),char(0),char(7),char(0),char(-91),char(0),char(7),char(0),char(-90),char(0),
+char(7),char(0),char(-109),char(0),char(7),char(0),char(-89),char(0),char(7),char(0),char(-105),char(0),char(7),char(0),char(-88),char(0),char(7),char(0),char(-87),char(0),
+char(7),char(0),char(-86),char(0),char(7),char(0),char(-85),char(0),char(7),char(0),char(-84),char(0),char(7),char(0),char(-83),char(0),char(7),char(0),char(-82),char(0),
+char(7),char(0),char(-81),char(0),char(7),char(0),char(-80),char(0),char(7),char(0),char(-79),char(0),char(7),char(0),char(-78),char(0),char(4),char(0),char(-77),char(0),
+char(4),char(0),char(-76),char(0),char(4),char(0),char(-75),char(0),char(4),char(0),char(-74),char(0),char(4),char(0),char(-73),char(0),char(0),char(0),char(37),char(0),
+char(55),char(0),char(2),char(0),char(53),char(0),char(-72),char(0),char(14),char(0),char(-71),char(0),char(56),char(0),char(2),char(0),char(54),char(0),char(-72),char(0),
+char(13),char(0),char(-71),char(0),char(57),char(0),char(21),char(0),char(50),char(0),char(-70),char(0),char(17),char(0),char(-69),char(0),char(13),char(0),char(-68),char(0),
+char(13),char(0),char(-67),char(0),char(13),char(0),char(-66),char(0),char(13),char(0),char(-65),char(0),char(13),char(0),char(-71),char(0),char(13),char(0),char(-64),char(0),
+char(13),char(0),char(-63),char(0),char(13),char(0),char(-62),char(0),char(13),char(0),char(-61),char(0),char(7),char(0),char(-60),char(0),char(7),char(0),char(-59),char(0),
+char(7),char(0),char(-58),char(0),char(7),char(0),char(-57),char(0),char(7),char(0),char(-56),char(0),char(7),char(0),char(-55),char(0),char(7),char(0),char(-54),char(0),
+char(7),char(0),char(-53),char(0),char(7),char(0),char(-52),char(0),char(4),char(0),char(-51),char(0),char(58),char(0),char(22),char(0),char(48),char(0),char(-70),char(0),
+char(18),char(0),char(-69),char(0),char(14),char(0),char(-68),char(0),char(14),char(0),char(-67),char(0),char(14),char(0),char(-66),char(0),char(14),char(0),char(-65),char(0),
+char(14),char(0),char(-71),char(0),char(14),char(0),char(-64),char(0),char(14),char(0),char(-63),char(0),char(14),char(0),char(-62),char(0),char(14),char(0),char(-61),char(0),
+char(8),char(0),char(-60),char(0),char(8),char(0),char(-59),char(0),char(8),char(0),char(-58),char(0),char(8),char(0),char(-57),char(0),char(8),char(0),char(-56),char(0),
+char(8),char(0),char(-55),char(0),char(8),char(0),char(-54),char(0),char(8),char(0),char(-53),char(0),char(8),char(0),char(-52),char(0),char(4),char(0),char(-51),char(0),
+char(0),char(0),char(37),char(0),char(59),char(0),char(2),char(0),char(4),char(0),char(-50),char(0),char(4),char(0),char(-49),char(0),char(60),char(0),char(13),char(0),
+char(57),char(0),char(-48),char(0),char(57),char(0),char(-47),char(0),char(0),char(0),char(35),char(0),char(4),char(0),char(-128),char(0),char(4),char(0),char(-46),char(0),
+char(4),char(0),char(-45),char(0),char(4),char(0),char(-44),char(0),char(7),char(0),char(-43),char(0),char(7),char(0),char(-42),char(0),char(4),char(0),char(-41),char(0),
+char(4),char(0),char(-40),char(0),char(7),char(0),char(-39),char(0),char(4),char(0),char(-38),char(0),char(61),char(0),char(13),char(0),char(62),char(0),char(-48),char(0),
+char(62),char(0),char(-47),char(0),char(0),char(0),char(35),char(0),char(4),char(0),char(-128),char(0),char(4),char(0),char(-46),char(0),char(4),char(0),char(-45),char(0),
+char(4),char(0),char(-44),char(0),char(7),char(0),char(-43),char(0),char(7),char(0),char(-42),char(0),char(4),char(0),char(-41),char(0),char(4),char(0),char(-40),char(0),
+char(7),char(0),char(-39),char(0),char(4),char(0),char(-38),char(0),char(63),char(0),char(14),char(0),char(58),char(0),char(-48),char(0),char(58),char(0),char(-47),char(0),
+char(0),char(0),char(35),char(0),char(4),char(0),char(-128),char(0),char(4),char(0),char(-46),char(0),char(4),char(0),char(-45),char(0),char(4),char(0),char(-44),char(0),
+char(8),char(0),char(-43),char(0),char(8),char(0),char(-42),char(0),char(4),char(0),char(-41),char(0),char(4),char(0),char(-40),char(0),char(8),char(0),char(-39),char(0),
+char(4),char(0),char(-38),char(0),char(0),char(0),char(-37),char(0),char(64),char(0),char(3),char(0),char(61),char(0),char(-36),char(0),char(13),char(0),char(-35),char(0),
+char(13),char(0),char(-34),char(0),char(65),char(0),char(3),char(0),char(63),char(0),char(-36),char(0),char(14),char(0),char(-35),char(0),char(14),char(0),char(-34),char(0),
+char(66),char(0),char(3),char(0),char(61),char(0),char(-36),char(0),char(14),char(0),char(-35),char(0),char(14),char(0),char(-34),char(0),char(67),char(0),char(13),char(0),
+char(61),char(0),char(-36),char(0),char(20),char(0),char(-33),char(0),char(20),char(0),char(-32),char(0),char(4),char(0),char(-31),char(0),char(4),char(0),char(-30),char(0),
+char(4),char(0),char(-29),char(0),char(7),char(0),char(-28),char(0),char(7),char(0),char(-27),char(0),char(7),char(0),char(-26),char(0),char(7),char(0),char(-25),char(0),
+char(7),char(0),char(-24),char(0),char(7),char(0),char(-23),char(0),char(7),char(0),char(-22),char(0),char(68),char(0),char(13),char(0),char(61),char(0),char(-36),char(0),
+char(19),char(0),char(-33),char(0),char(19),char(0),char(-32),char(0),char(4),char(0),char(-31),char(0),char(4),char(0),char(-30),char(0),char(4),char(0),char(-29),char(0),
+char(7),char(0),char(-28),char(0),char(7),char(0),char(-27),char(0),char(7),char(0),char(-26),char(0),char(7),char(0),char(-25),char(0),char(7),char(0),char(-24),char(0),
+char(7),char(0),char(-23),char(0),char(7),char(0),char(-22),char(0),char(69),char(0),char(14),char(0),char(63),char(0),char(-36),char(0),char(20),char(0),char(-33),char(0),
+char(20),char(0),char(-32),char(0),char(4),char(0),char(-31),char(0),char(4),char(0),char(-30),char(0),char(4),char(0),char(-29),char(0),char(8),char(0),char(-28),char(0),
+char(8),char(0),char(-27),char(0),char(8),char(0),char(-26),char(0),char(8),char(0),char(-25),char(0),char(8),char(0),char(-24),char(0),char(8),char(0),char(-23),char(0),
+char(8),char(0),char(-22),char(0),char(0),char(0),char(-21),char(0),char(70),char(0),char(10),char(0),char(63),char(0),char(-36),char(0),char(20),char(0),char(-33),char(0),
+char(20),char(0),char(-32),char(0),char(8),char(0),char(-20),char(0),char(8),char(0),char(-19),char(0),char(8),char(0),char(-18),char(0),char(8),char(0),char(-24),char(0),
+char(8),char(0),char(-23),char(0),char(8),char(0),char(-22),char(0),char(8),char(0),char(-90),char(0),char(71),char(0),char(11),char(0),char(61),char(0),char(-36),char(0),
+char(19),char(0),char(-33),char(0),char(19),char(0),char(-32),char(0),char(7),char(0),char(-20),char(0),char(7),char(0),char(-19),char(0),char(7),char(0),char(-18),char(0),
+char(7),char(0),char(-24),char(0),char(7),char(0),char(-23),char(0),char(7),char(0),char(-22),char(0),char(7),char(0),char(-90),char(0),char(0),char(0),char(21),char(0),
+char(72),char(0),char(9),char(0),char(61),char(0),char(-36),char(0),char(19),char(0),char(-33),char(0),char(19),char(0),char(-32),char(0),char(13),char(0),char(-17),char(0),
+char(13),char(0),char(-16),char(0),char(13),char(0),char(-15),char(0),char(13),char(0),char(-14),char(0),char(4),char(0),char(-13),char(0),char(4),char(0),char(-12),char(0),
+char(73),char(0),char(9),char(0),char(63),char(0),char(-36),char(0),char(20),char(0),char(-33),char(0),char(20),char(0),char(-32),char(0),char(14),char(0),char(-17),char(0),
+char(14),char(0),char(-16),char(0),char(14),char(0),char(-15),char(0),char(14),char(0),char(-14),char(0),char(4),char(0),char(-13),char(0),char(4),char(0),char(-12),char(0),
+char(74),char(0),char(5),char(0),char(72),char(0),char(-11),char(0),char(4),char(0),char(-10),char(0),char(7),char(0),char(-9),char(0),char(7),char(0),char(-8),char(0),
+char(7),char(0),char(-7),char(0),char(75),char(0),char(5),char(0),char(73),char(0),char(-11),char(0),char(4),char(0),char(-10),char(0),char(8),char(0),char(-9),char(0),
+char(8),char(0),char(-8),char(0),char(8),char(0),char(-7),char(0),char(76),char(0),char(41),char(0),char(61),char(0),char(-36),char(0),char(19),char(0),char(-33),char(0),
+char(19),char(0),char(-32),char(0),char(13),char(0),char(-17),char(0),char(13),char(0),char(-16),char(0),char(13),char(0),char(-6),char(0),char(13),char(0),char(-5),char(0),
+char(13),char(0),char(-4),char(0),char(13),char(0),char(-3),char(0),char(13),char(0),char(-2),char(0),char(13),char(0),char(-1),char(0),char(13),char(0),char(0),char(1),
+char(13),char(0),char(1),char(1),char(13),char(0),char(2),char(1),char(13),char(0),char(3),char(1),char(13),char(0),char(4),char(1),char(0),char(0),char(5),char(1),
+char(0),char(0),char(6),char(1),char(0),char(0),char(7),char(1),char(0),char(0),char(8),char(1),char(0),char(0),char(9),char(1),char(0),char(0),char(-21),char(0),
+char(13),char(0),char(-15),char(0),char(13),char(0),char(-14),char(0),char(13),char(0),char(10),char(1),char(13),char(0),char(11),char(1),char(13),char(0),char(12),char(1),
+char(13),char(0),char(13),char(1),char(13),char(0),char(14),char(1),char(13),char(0),char(15),char(1),char(13),char(0),char(16),char(1),char(13),char(0),char(17),char(1),
+char(13),char(0),char(18),char(1),char(13),char(0),char(19),char(1),char(13),char(0),char(20),char(1),char(0),char(0),char(21),char(1),char(0),char(0),char(22),char(1),
+char(0),char(0),char(23),char(1),char(0),char(0),char(24),char(1),char(0),char(0),char(25),char(1),char(4),char(0),char(26),char(1),char(77),char(0),char(41),char(0),
+char(63),char(0),char(-36),char(0),char(20),char(0),char(-33),char(0),char(20),char(0),char(-32),char(0),char(14),char(0),char(-17),char(0),char(14),char(0),char(-16),char(0),
+char(14),char(0),char(-6),char(0),char(14),char(0),char(-5),char(0),char(14),char(0),char(-4),char(0),char(14),char(0),char(-3),char(0),char(14),char(0),char(-2),char(0),
+char(14),char(0),char(-1),char(0),char(14),char(0),char(0),char(1),char(14),char(0),char(1),char(1),char(14),char(0),char(2),char(1),char(14),char(0),char(3),char(1),
+char(14),char(0),char(4),char(1),char(0),char(0),char(5),char(1),char(0),char(0),char(6),char(1),char(0),char(0),char(7),char(1),char(0),char(0),char(8),char(1),
+char(0),char(0),char(9),char(1),char(0),char(0),char(-21),char(0),char(14),char(0),char(-15),char(0),char(14),char(0),char(-14),char(0),char(14),char(0),char(10),char(1),
+char(14),char(0),char(11),char(1),char(14),char(0),char(12),char(1),char(14),char(0),char(13),char(1),char(14),char(0),char(14),char(1),char(14),char(0),char(15),char(1),
+char(14),char(0),char(16),char(1),char(14),char(0),char(17),char(1),char(14),char(0),char(18),char(1),char(14),char(0),char(19),char(1),char(14),char(0),char(20),char(1),
+char(0),char(0),char(21),char(1),char(0),char(0),char(22),char(1),char(0),char(0),char(23),char(1),char(0),char(0),char(24),char(1),char(0),char(0),char(25),char(1),
+char(4),char(0),char(26),char(1),char(78),char(0),char(9),char(0),char(61),char(0),char(-36),char(0),char(19),char(0),char(-33),char(0),char(19),char(0),char(-32),char(0),
+char(7),char(0),char(-17),char(0),char(7),char(0),char(-16),char(0),char(7),char(0),char(-15),char(0),char(7),char(0),char(-14),char(0),char(4),char(0),char(-13),char(0),
+char(4),char(0),char(-12),char(0),char(79),char(0),char(9),char(0),char(63),char(0),char(-36),char(0),char(20),char(0),char(-33),char(0),char(20),char(0),char(-32),char(0),
+char(8),char(0),char(-17),char(0),char(8),char(0),char(-16),char(0),char(8),char(0),char(-15),char(0),char(8),char(0),char(-14),char(0),char(4),char(0),char(-13),char(0),
+char(4),char(0),char(-12),char(0),char(80),char(0),char(5),char(0),char(60),char(0),char(-36),char(0),char(13),char(0),char(27),char(1),char(13),char(0),char(28),char(1),
+char(7),char(0),char(29),char(1),char(0),char(0),char(37),char(0),char(81),char(0),char(4),char(0),char(63),char(0),char(-36),char(0),char(14),char(0),char(27),char(1),
+char(14),char(0),char(28),char(1),char(8),char(0),char(29),char(1),char(82),char(0),char(4),char(0),char(7),char(0),char(30),char(1),char(7),char(0),char(31),char(1),
+char(7),char(0),char(32),char(1),char(4),char(0),char(79),char(0),char(83),char(0),char(10),char(0),char(82),char(0),char(33),char(1),char(13),char(0),char(34),char(1),
+char(13),char(0),char(35),char(1),char(13),char(0),char(36),char(1),char(13),char(0),char(37),char(1),char(13),char(0),char(38),char(1),char(7),char(0),char(-60),char(0),
+char(7),char(0),char(39),char(1),char(4),char(0),char(40),char(1),char(4),char(0),char(53),char(0),char(84),char(0),char(4),char(0),char(82),char(0),char(33),char(1),
+char(4),char(0),char(41),char(1),char(7),char(0),char(42),char(1),char(4),char(0),char(43),char(1),char(85),char(0),char(4),char(0),char(13),char(0),char(38),char(1),
+char(82),char(0),char(33),char(1),char(4),char(0),char(44),char(1),char(7),char(0),char(45),char(1),char(86),char(0),char(7),char(0),char(13),char(0),char(46),char(1),
+char(82),char(0),char(33),char(1),char(4),char(0),char(47),char(1),char(7),char(0),char(48),char(1),char(7),char(0),char(49),char(1),char(7),char(0),char(50),char(1),
+char(4),char(0),char(53),char(0),char(87),char(0),char(6),char(0),char(17),char(0),char(51),char(1),char(13),char(0),char(49),char(1),char(13),char(0),char(52),char(1),
+char(62),char(0),char(53),char(1),char(4),char(0),char(54),char(1),char(7),char(0),char(50),char(1),char(88),char(0),char(26),char(0),char(4),char(0),char(55),char(1),
+char(7),char(0),char(56),char(1),char(7),char(0),char(-90),char(0),char(7),char(0),char(57),char(1),char(7),char(0),char(58),char(1),char(7),char(0),char(59),char(1),
+char(7),char(0),char(60),char(1),char(7),char(0),char(61),char(1),char(7),char(0),char(62),char(1),char(7),char(0),char(63),char(1),char(7),char(0),char(64),char(1),
+char(7),char(0),char(65),char(1),char(7),char(0),char(66),char(1),char(7),char(0),char(67),char(1),char(7),char(0),char(68),char(1),char(7),char(0),char(69),char(1),
+char(7),char(0),char(70),char(1),char(7),char(0),char(71),char(1),char(7),char(0),char(72),char(1),char(7),char(0),char(73),char(1),char(7),char(0),char(74),char(1),
+char(4),char(0),char(75),char(1),char(4),char(0),char(76),char(1),char(4),char(0),char(77),char(1),char(4),char(0),char(78),char(1),char(4),char(0),char(-100),char(0),
+char(89),char(0),char(12),char(0),char(17),char(0),char(79),char(1),char(17),char(0),char(80),char(1),char(17),char(0),char(81),char(1),char(13),char(0),char(82),char(1),
+char(13),char(0),char(83),char(1),char(7),char(0),char(84),char(1),char(4),char(0),char(85),char(1),char(4),char(0),char(86),char(1),char(4),char(0),char(87),char(1),
+char(4),char(0),char(88),char(1),char(7),char(0),char(48),char(1),char(4),char(0),char(53),char(0),char(90),char(0),char(27),char(0),char(19),char(0),char(89),char(1),
+char(17),char(0),char(90),char(1),char(17),char(0),char(91),char(1),char(13),char(0),char(82),char(1),char(13),char(0),char(92),char(1),char(13),char(0),char(93),char(1),
+char(13),char(0),char(94),char(1),char(13),char(0),char(95),char(1),char(13),char(0),char(96),char(1),char(4),char(0),char(97),char(1),char(7),char(0),char(98),char(1),
+char(4),char(0),char(99),char(1),char(4),char(0),char(100),char(1),char(4),char(0),char(101),char(1),char(7),char(0),char(102),char(1),char(7),char(0),char(103),char(1),
+char(4),char(0),char(104),char(1),char(4),char(0),char(105),char(1),char(7),char(0),char(106),char(1),char(7),char(0),char(107),char(1),char(7),char(0),char(108),char(1),
+char(7),char(0),char(109),char(1),char(7),char(0),char(110),char(1),char(7),char(0),char(111),char(1),char(4),char(0),char(112),char(1),char(4),char(0),char(113),char(1),
+char(4),char(0),char(114),char(1),char(91),char(0),char(12),char(0),char(9),char(0),char(115),char(1),char(9),char(0),char(116),char(1),char(13),char(0),char(117),char(1),
+char(7),char(0),char(118),char(1),char(7),char(0),char(-86),char(0),char(7),char(0),char(119),char(1),char(4),char(0),char(120),char(1),char(13),char(0),char(121),char(1),
+char(4),char(0),char(122),char(1),char(4),char(0),char(123),char(1),char(4),char(0),char(124),char(1),char(4),char(0),char(53),char(0),char(92),char(0),char(19),char(0),
+char(50),char(0),char(-70),char(0),char(89),char(0),char(125),char(1),char(82),char(0),char(126),char(1),char(83),char(0),char(127),char(1),char(84),char(0),char(-128),char(1),
+char(85),char(0),char(-127),char(1),char(86),char(0),char(-126),char(1),char(87),char(0),char(-125),char(1),char(90),char(0),char(-124),char(1),char(91),char(0),char(-123),char(1),
+char(4),char(0),char(-122),char(1),char(4),char(0),char(100),char(1),char(4),char(0),char(-121),char(1),char(4),char(0),char(-120),char(1),char(4),char(0),char(-119),char(1),
+char(4),char(0),char(-118),char(1),char(4),char(0),char(-117),char(1),char(4),char(0),char(-116),char(1),char(88),char(0),char(-115),char(1),char(93),char(0),char(28),char(0),
+char(16),char(0),char(-114),char(1),char(14),char(0),char(-113),char(1),char(14),char(0),char(-112),char(1),char(14),char(0),char(-111),char(1),char(14),char(0),char(-110),char(1),
+char(14),char(0),char(-109),char(1),char(14),char(0),char(-108),char(1),char(14),char(0),char(-107),char(1),char(14),char(0),char(-106),char(1),char(14),char(0),char(-105),char(1),
+char(8),char(0),char(-104),char(1),char(4),char(0),char(-103),char(1),char(4),char(0),char(124),char(1),char(4),char(0),char(-102),char(1),char(4),char(0),char(-101),char(1),
+char(8),char(0),char(-100),char(1),char(8),char(0),char(-99),char(1),char(8),char(0),char(-98),char(1),char(8),char(0),char(-97),char(1),char(8),char(0),char(-96),char(1),
+char(8),char(0),char(-95),char(1),char(8),char(0),char(-94),char(1),char(8),char(0),char(-93),char(1),char(8),char(0),char(-92),char(1),char(0),char(0),char(-91),char(1),
+char(0),char(0),char(-90),char(1),char(48),char(0),char(-89),char(1),char(0),char(0),char(-88),char(1),char(94),char(0),char(28),char(0),char(15),char(0),char(-114),char(1),
+char(13),char(0),char(-113),char(1),char(13),char(0),char(-112),char(1),char(13),char(0),char(-111),char(1),char(13),char(0),char(-110),char(1),char(13),char(0),char(-109),char(1),
+char(13),char(0),char(-108),char(1),char(13),char(0),char(-107),char(1),char(13),char(0),char(-106),char(1),char(13),char(0),char(-105),char(1),char(4),char(0),char(-102),char(1),
+char(7),char(0),char(-104),char(1),char(4),char(0),char(-103),char(1),char(4),char(0),char(124),char(1),char(7),char(0),char(-100),char(1),char(7),char(0),char(-99),char(1),
+char(7),char(0),char(-98),char(1),char(4),char(0),char(-101),char(1),char(7),char(0),char(-97),char(1),char(7),char(0),char(-96),char(1),char(7),char(0),char(-95),char(1),
+char(7),char(0),char(-94),char(1),char(7),char(0),char(-93),char(1),char(7),char(0),char(-92),char(1),char(0),char(0),char(-91),char(1),char(0),char(0),char(-90),char(1),
+char(50),char(0),char(-89),char(1),char(0),char(0),char(-88),char(1),char(95),char(0),char(11),char(0),char(14),char(0),char(-87),char(1),char(16),char(0),char(-86),char(1),
+char(14),char(0),char(-85),char(1),char(14),char(0),char(-84),char(1),char(14),char(0),char(-83),char(1),char(8),char(0),char(-82),char(1),char(4),char(0),char(-121),char(1),
+char(0),char(0),char(37),char(0),char(0),char(0),char(-81),char(1),char(93),char(0),char(-128),char(1),char(48),char(0),char(-80),char(1),char(96),char(0),char(10),char(0),
+char(13),char(0),char(-87),char(1),char(15),char(0),char(-86),char(1),char(13),char(0),char(-85),char(1),char(13),char(0),char(-84),char(1),char(13),char(0),char(-83),char(1),
+char(7),char(0),char(-82),char(1),char(4),char(0),char(-121),char(1),char(0),char(0),char(-81),char(1),char(94),char(0),char(-128),char(1),char(50),char(0),char(-80),char(1),
+char(97),char(0),char(4),char(0),char(50),char(0),char(-79),char(1),char(96),char(0),char(-78),char(1),char(4),char(0),char(-77),char(1),char(0),char(0),char(37),char(0),
+char(98),char(0),char(4),char(0),char(48),char(0),char(-79),char(1),char(95),char(0),char(-78),char(1),char(4),char(0),char(-77),char(1),char(0),char(0),char(37),char(0),
+};
int sBulletDNAlen= sizeof(sBulletDNAstr);
diff --git a/thirdparty/bullet/LinearMath/btSerializer.h b/thirdparty/bullet/LinearMath/btSerializer.h
index 89b4d74683..39be3f810e 100644
--- a/thirdparty/bullet/LinearMath/btSerializer.h
+++ b/thirdparty/bullet/LinearMath/btSerializer.h
@@ -62,7 +62,8 @@ enum btSerializationFlags
{
BT_SERIALIZE_NO_BVH = 1,
BT_SERIALIZE_NO_TRIANGLEINFOMAP = 2,
- BT_SERIALIZE_NO_DUPLICATE_ASSERT = 4
+ BT_SERIALIZE_NO_DUPLICATE_ASSERT = 4,
+ BT_SERIALIZE_CONTACT_MANIFOLDS = 8,
};
class btSerializer
@@ -115,6 +116,7 @@ public:
#define BT_MULTIBODY_CODE BT_MAKE_ID('M','B','D','Y')
+#define BT_MB_LINKCOLLIDER_CODE BT_MAKE_ID('M','B','L','C')
#define BT_SOFTBODY_CODE BT_MAKE_ID('S','B','D','Y')
#define BT_COLLISIONOBJECT_CODE BT_MAKE_ID('C','O','B','J')
#define BT_RIGIDBODY_CODE BT_MAKE_ID('R','B','D','Y')
@@ -127,9 +129,9 @@ public:
#define BT_SBMATERIAL_CODE BT_MAKE_ID('S','B','M','T')
#define BT_SBNODE_CODE BT_MAKE_ID('S','B','N','D')
#define BT_DYNAMICSWORLD_CODE BT_MAKE_ID('D','W','L','D')
+#define BT_CONTACTMANIFOLD_CODE BT_MAKE_ID('C','O','N','T')
#define BT_DNA_CODE BT_MAKE_ID('D','N','A','1')
-
struct btPointerUid
{
union
@@ -505,7 +507,7 @@ public:
buffer[9] = '2';
buffer[10] = '8';
- buffer[11] = '7';
+ buffer[11] = '8';
}
diff --git a/thirdparty/bullet/LinearMath/btSerializer64.cpp b/thirdparty/bullet/LinearMath/btSerializer64.cpp
index 05f59202d7..0aa5cbf30e 100644
--- a/thirdparty/bullet/LinearMath/btSerializer64.cpp
+++ b/thirdparty/bullet/LinearMath/btSerializer64.cpp
@@ -1,5 +1,5 @@
char sBulletDNAstr64[]= {
-char(83),char(68),char(78),char(65),char(78),char(65),char(77),char(69),char(-124),char(1),char(0),char(0),char(109),char(95),char(115),char(105),char(122),char(101),char(0),char(109),
+char(83),char(68),char(78),char(65),char(78),char(65),char(77),char(69),char(-76),char(1),char(0),char(0),char(109),char(95),char(115),char(105),char(122),char(101),char(0),char(109),
char(95),char(99),char(97),char(112),char(97),char(99),char(105),char(116),char(121),char(0),char(42),char(109),char(95),char(100),char(97),char(116),char(97),char(0),char(109),char(95),
char(99),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(83),char(104),char(97),char(112),char(101),char(115),char(0),char(109),char(95),char(99),char(111),
char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(79),char(98),char(106),char(101),char(99),char(116),char(115),char(0),char(109),char(95),char(99),char(111),char(110),
@@ -72,528 +72,618 @@ char(105),char(115),char(116),char(97),char(110),char(99),char(101),char(84),cha
char(101),char(114),char(111),char(65),char(114),char(101),char(97),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109),char(95),char(110),
char(101),char(120),char(116),char(83),char(105),char(122),char(101),char(0),char(109),char(95),char(104),char(97),char(115),char(104),char(84),char(97),char(98),char(108),char(101),char(83),
char(105),char(122),char(101),char(0),char(109),char(95),char(110),char(117),char(109),char(86),char(97),char(108),char(117),char(101),char(115),char(0),char(109),char(95),char(110),char(117),
-char(109),char(75),char(101),char(121),char(115),char(0),char(109),char(95),char(103),char(105),char(109),char(112),char(97),char(99),char(116),char(83),char(117),char(98),char(84),char(121),
-char(112),char(101),char(0),char(42),char(109),char(95),char(117),char(110),char(115),char(99),char(97),char(108),char(101),char(100),char(80),char(111),char(105),char(110),char(116),char(115),
-char(70),char(108),char(111),char(97),char(116),char(80),char(116),char(114),char(0),char(42),char(109),char(95),char(117),char(110),char(115),char(99),char(97),char(108),char(101),char(100),
-char(80),char(111),char(105),char(110),char(116),char(115),char(68),char(111),char(117),char(98),char(108),char(101),char(80),char(116),char(114),char(0),char(109),char(95),char(110),char(117),
-char(109),char(85),char(110),char(115),char(99),char(97),char(108),char(101),char(100),char(80),char(111),char(105),char(110),char(116),char(115),char(0),char(109),char(95),char(112),char(97),
-char(100),char(100),char(105),char(110),char(103),char(51),char(91),char(52),char(93),char(0),char(42),char(109),char(95),char(98),char(114),char(111),char(97),char(100),char(112),char(104),
-char(97),char(115),char(101),char(72),char(97),char(110),char(100),char(108),char(101),char(0),char(42),char(109),char(95),char(99),char(111),char(108),char(108),char(105),char(115),char(105),
-char(111),char(110),char(83),char(104),char(97),char(112),char(101),char(0),char(42),char(109),char(95),char(114),char(111),char(111),char(116),char(67),char(111),char(108),char(108),char(105),
-char(115),char(105),char(111),char(110),char(83),char(104),char(97),char(112),char(101),char(0),char(109),char(95),char(119),char(111),char(114),char(108),char(100),char(84),char(114),char(97),
-char(110),char(115),char(102),char(111),char(114),char(109),char(0),char(109),char(95),char(105),char(110),char(116),char(101),char(114),char(112),char(111),char(108),char(97),char(116),char(105),
-char(111),char(110),char(87),char(111),char(114),char(108),char(100),char(84),char(114),char(97),char(110),char(115),char(102),char(111),char(114),char(109),char(0),char(109),char(95),char(105),
-char(110),char(116),char(101),char(114),char(112),char(111),char(108),char(97),char(116),char(105),char(111),char(110),char(76),char(105),char(110),char(101),char(97),char(114),char(86),char(101),
-char(108),char(111),char(99),char(105),char(116),char(121),char(0),char(109),char(95),char(105),char(110),char(116),char(101),char(114),char(112),char(111),char(108),char(97),char(116),char(105),
-char(111),char(110),char(65),char(110),char(103),char(117),char(108),char(97),char(114),char(86),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(0),char(109),char(95),
-char(97),char(110),char(105),char(115),char(111),char(116),char(114),char(111),char(112),char(105),char(99),char(70),char(114),char(105),char(99),char(116),char(105),char(111),char(110),char(0),
-char(109),char(95),char(99),char(111),char(110),char(116),char(97),char(99),char(116),char(80),char(114),char(111),char(99),char(101),char(115),char(115),char(105),char(110),char(103),char(84),
-char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109),char(95),char(100),char(101),char(97),char(99),char(116),char(105),char(118),char(97),char(116),
-char(105),char(111),char(110),char(84),char(105),char(109),char(101),char(0),char(109),char(95),char(102),char(114),char(105),char(99),char(116),char(105),char(111),char(110),char(0),char(109),
-char(95),char(114),char(111),char(108),char(108),char(105),char(110),char(103),char(70),char(114),char(105),char(99),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(99),
-char(111),char(110),char(116),char(97),char(99),char(116),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(0),char(109),char(95),char(99),char(111),char(110),char(116),
-char(97),char(99),char(116),char(83),char(116),char(105),char(102),char(102),char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(114),char(101),char(115),char(116),char(105),
-char(116),char(117),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(104),char(105),char(116),char(70),char(114),char(97),char(99),char(116),char(105),char(111),char(110),
-char(0),char(109),char(95),char(99),char(99),char(100),char(83),char(119),char(101),char(112),char(116),char(83),char(112),char(104),char(101),char(114),char(101),char(82),char(97),char(100),
-char(105),char(117),char(115),char(0),char(109),char(95),char(99),char(99),char(100),char(77),char(111),char(116),char(105),char(111),char(110),char(84),char(104),char(114),char(101),char(115),
-char(104),char(111),char(108),char(100),char(0),char(109),char(95),char(104),char(97),char(115),char(65),char(110),char(105),char(115),char(111),char(116),char(114),char(111),char(112),char(105),
-char(99),char(70),char(114),char(105),char(99),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(99),char(111),char(108),char(108),char(105),char(115),char(105),char(111),
-char(110),char(70),char(108),char(97),char(103),char(115),char(0),char(109),char(95),char(105),char(115),char(108),char(97),char(110),char(100),char(84),char(97),char(103),char(49),char(0),
-char(109),char(95),char(99),char(111),char(109),char(112),char(97),char(110),char(105),char(111),char(110),char(73),char(100),char(0),char(109),char(95),char(97),char(99),char(116),char(105),
-char(118),char(97),char(116),char(105),char(111),char(110),char(83),char(116),char(97),char(116),char(101),char(49),char(0),char(109),char(95),char(105),char(110),char(116),char(101),char(114),
-char(110),char(97),char(108),char(84),char(121),char(112),char(101),char(0),char(109),char(95),char(99),char(104),char(101),char(99),char(107),char(67),char(111),char(108),char(108),char(105),
-char(100),char(101),char(87),char(105),char(116),char(104),char(0),char(109),char(95),char(116),char(97),char(117),char(0),char(109),char(95),char(100),char(97),char(109),char(112),char(105),
-char(110),char(103),char(0),char(109),char(95),char(116),char(105),char(109),char(101),char(83),char(116),char(101),char(112),char(0),char(109),char(95),char(109),char(97),char(120),char(69),
-char(114),char(114),char(111),char(114),char(82),char(101),char(100),char(117),char(99),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(115),char(111),char(114),char(0),
-char(109),char(95),char(101),char(114),char(112),char(0),char(109),char(95),char(101),char(114),char(112),char(50),char(0),char(109),char(95),char(103),char(108),char(111),char(98),char(97),
-char(108),char(67),char(102),char(109),char(0),char(109),char(95),char(115),char(112),char(108),char(105),char(116),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(80),
-char(101),char(110),char(101),char(116),char(114),char(97),char(116),char(105),char(111),char(110),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),
-char(109),char(95),char(115),char(112),char(108),char(105),char(116),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(84),char(117),char(114),char(110),char(69),char(114),
-char(112),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83),char(108),char(111),char(112),char(0),char(109),char(95),char(119),char(97),char(114),
-char(109),char(115),char(116),char(97),char(114),char(116),char(105),char(110),char(103),char(70),char(97),char(99),char(116),char(111),char(114),char(0),char(109),char(95),char(109),char(97),
-char(120),char(71),char(121),char(114),char(111),char(115),char(99),char(111),char(112),char(105),char(99),char(70),char(111),char(114),char(99),char(101),char(0),char(109),char(95),char(115),
-char(105),char(110),char(103),char(108),char(101),char(65),char(120),char(105),char(115),char(82),char(111),char(108),char(108),char(105),char(110),char(103),char(70),char(114),char(105),char(99),
-char(116),char(105),char(111),char(110),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109),char(95),char(110),char(117),char(109),char(73),
-char(116),char(101),char(114),char(97),char(116),char(105),char(111),char(110),char(115),char(0),char(109),char(95),char(115),char(111),char(108),char(118),char(101),char(114),char(77),char(111),
-char(100),char(101),char(0),char(109),char(95),char(114),char(101),char(115),char(116),char(105),char(110),char(103),char(67),char(111),char(110),char(116),char(97),char(99),char(116),char(82),
-char(101),char(115),char(116),char(105),char(116),char(117),char(116),char(105),char(111),char(110),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),
-char(109),char(95),char(109),char(105),char(110),char(105),char(109),char(117),char(109),char(83),char(111),char(108),char(118),char(101),char(114),char(66),char(97),char(116),char(99),char(104),
-char(83),char(105),char(122),char(101),char(0),char(109),char(95),char(115),char(112),char(108),char(105),char(116),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(0),
-char(109),char(95),char(115),char(111),char(108),char(118),char(101),char(114),char(73),char(110),char(102),char(111),char(0),char(109),char(95),char(103),char(114),char(97),char(118),char(105),
-char(116),char(121),char(0),char(109),char(95),char(99),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(79),char(98),char(106),char(101),char(99),char(116),
-char(68),char(97),char(116),char(97),char(0),char(109),char(95),char(105),char(110),char(118),char(73),char(110),char(101),char(114),char(116),char(105),char(97),char(84),char(101),char(110),
-char(115),char(111),char(114),char(87),char(111),char(114),char(108),char(100),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(86),char(101),char(108),
-char(111),char(99),char(105),char(116),char(121),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(86),char(101),char(108),char(111),char(99),
-char(105),char(116),char(121),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(70),char(97),char(99),char(116),char(111),char(114),char(0),
-char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(70),char(97),char(99),char(116),char(111),char(114),char(0),char(109),char(95),char(103),char(114),char(97),
-char(118),char(105),char(116),char(121),char(95),char(97),char(99),char(99),char(101),char(108),char(101),char(114),char(97),char(116),char(105),char(111),char(110),char(0),char(109),char(95),
-char(105),char(110),char(118),char(73),char(110),char(101),char(114),char(116),char(105),char(97),char(76),char(111),char(99),char(97),char(108),char(0),char(109),char(95),char(116),char(111),
-char(116),char(97),char(108),char(70),char(111),char(114),char(99),char(101),char(0),char(109),char(95),char(116),char(111),char(116),char(97),char(108),char(84),char(111),char(114),char(113),
-char(117),char(101),char(0),char(109),char(95),char(105),char(110),char(118),char(101),char(114),char(115),char(101),char(77),char(97),char(115),char(115),char(0),char(109),char(95),char(108),
-char(105),char(110),char(101),char(97),char(114),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),
-char(97),char(114),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(0),char(109),char(95),char(97),char(100),char(100),char(105),char(116),char(105),char(111),char(110),
-char(97),char(108),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(70),char(97),char(99),char(116),char(111),char(114),char(0),char(109),char(95),char(97),char(100),
-char(100),char(105),char(116),char(105),char(111),char(110),char(97),char(108),char(76),char(105),char(110),char(101),char(97),char(114),char(68),char(97),char(109),char(112),char(105),char(110),
-char(103),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(83),char(113),char(114),char(0),char(109),char(95),char(97),char(100),char(100),char(105),
-char(116),char(105),char(111),char(110),char(97),char(108),char(65),char(110),char(103),char(117),char(108),char(97),char(114),char(68),char(97),char(109),char(112),char(105),char(110),char(103),
-char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(83),char(113),char(114),char(0),char(109),char(95),char(97),char(100),char(100),char(105),char(116),
-char(105),char(111),char(110),char(97),char(108),char(65),char(110),char(103),char(117),char(108),char(97),char(114),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(70),
-char(97),char(99),char(116),char(111),char(114),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83),char(108),char(101),char(101),char(112),char(105),
-char(110),char(103),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),
-char(114),char(83),char(108),char(101),char(101),char(112),char(105),char(110),char(103),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109),
-char(95),char(97),char(100),char(100),char(105),char(116),char(105),char(111),char(110),char(97),char(108),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(0),char(109),
-char(95),char(110),char(117),char(109),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(82),char(111),char(119),char(115),char(0),char(110),
-char(117),char(98),char(0),char(42),char(109),char(95),char(114),char(98),char(65),char(0),char(42),char(109),char(95),char(114),char(98),char(66),char(0),char(109),char(95),char(111),
-char(98),char(106),char(101),char(99),char(116),char(84),char(121),char(112),char(101),char(0),char(109),char(95),char(117),char(115),char(101),char(114),char(67),char(111),char(110),char(115),
-char(116),char(114),char(97),char(105),char(110),char(116),char(84),char(121),char(112),char(101),char(0),char(109),char(95),char(117),char(115),char(101),char(114),char(67),char(111),char(110),
-char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(73),char(100),char(0),char(109),char(95),char(110),char(101),char(101),char(100),char(115),char(70),char(101),char(101),
-char(100),char(98),char(97),char(99),char(107),char(0),char(109),char(95),char(97),char(112),char(112),char(108),char(105),char(101),char(100),char(73),char(109),char(112),char(117),char(108),
-char(115),char(101),char(0),char(109),char(95),char(100),char(98),char(103),char(68),char(114),char(97),char(119),char(83),char(105),char(122),char(101),char(0),char(109),char(95),char(100),
-char(105),char(115),char(97),char(98),char(108),char(101),char(67),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(115),char(66),char(101),char(116),char(119),
-char(101),char(101),char(110),char(76),char(105),char(110),char(107),char(101),char(100),char(66),char(111),char(100),char(105),char(101),char(115),char(0),char(109),char(95),char(111),char(118),
-char(101),char(114),char(114),char(105),char(100),char(101),char(78),char(117),char(109),char(83),char(111),char(108),char(118),char(101),char(114),char(73),char(116),char(101),char(114),char(97),
-char(116),char(105),char(111),char(110),char(115),char(0),char(109),char(95),char(98),char(114),char(101),char(97),char(107),char(105),char(110),char(103),char(73),char(109),char(112),char(117),
-char(108),char(115),char(101),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109),char(95),char(105),char(115),char(69),char(110),char(97),
-char(98),char(108),char(101),char(100),char(0),char(112),char(97),char(100),char(100),char(105),char(110),char(103),char(91),char(52),char(93),char(0),char(109),char(95),char(116),char(121),
-char(112),char(101),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(97),char(116),char(97),char(0),char(109),char(95),char(112),
-char(105),char(118),char(111),char(116),char(73),char(110),char(65),char(0),char(109),char(95),char(112),char(105),char(118),char(111),char(116),char(73),char(110),char(66),char(0),char(109),
-char(95),char(114),char(98),char(65),char(70),char(114),char(97),char(109),char(101),char(0),char(109),char(95),char(114),char(98),char(66),char(70),char(114),char(97),char(109),char(101),
-char(0),char(109),char(95),char(117),char(115),char(101),char(82),char(101),char(102),char(101),char(114),char(101),char(110),char(99),char(101),char(70),char(114),char(97),char(109),char(101),
-char(65),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(79),char(110),char(108),char(121),char(0),char(109),char(95),char(101),char(110),
-char(97),char(98),char(108),char(101),char(65),char(110),char(103),char(117),char(108),char(97),char(114),char(77),char(111),char(116),char(111),char(114),char(0),char(109),char(95),char(109),
-char(111),char(116),char(111),char(114),char(84),char(97),char(114),char(103),char(101),char(116),char(86),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(0),char(109),
-char(95),char(109),char(97),char(120),char(77),char(111),char(116),char(111),char(114),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(0),char(109),char(95),char(108),
-char(111),char(119),char(101),char(114),char(76),char(105),char(109),char(105),char(116),char(0),char(109),char(95),char(117),char(112),char(112),char(101),char(114),char(76),char(105),char(109),
-char(105),char(116),char(0),char(109),char(95),char(108),char(105),char(109),char(105),char(116),char(83),char(111),char(102),char(116),char(110),char(101),char(115),char(115),char(0),char(109),
-char(95),char(98),char(105),char(97),char(115),char(70),char(97),char(99),char(116),char(111),char(114),char(0),char(109),char(95),char(114),char(101),char(108),char(97),char(120),char(97),
-char(116),char(105),char(111),char(110),char(70),char(97),char(99),char(116),char(111),char(114),char(0),char(109),char(95),char(112),char(97),char(100),char(100),char(105),char(110),char(103),
-char(49),char(91),char(52),char(93),char(0),char(109),char(95),char(115),char(119),char(105),char(110),char(103),char(83),char(112),char(97),char(110),char(49),char(0),char(109),char(95),
-char(115),char(119),char(105),char(110),char(103),char(83),char(112),char(97),char(110),char(50),char(0),char(109),char(95),char(116),char(119),char(105),char(115),char(116),char(83),char(112),
-char(97),char(110),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(85),char(112),char(112),char(101),char(114),char(76),char(105),char(109),char(105),
-char(116),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(76),char(111),char(119),char(101),char(114),char(76),char(105),char(109),char(105),char(116),
-char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(85),char(112),char(112),char(101),char(114),char(76),char(105),char(109),char(105),char(116),
-char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(76),char(111),char(119),char(101),char(114),char(76),char(105),char(109),char(105),char(116),
-char(0),char(109),char(95),char(117),char(115),char(101),char(76),char(105),char(110),char(101),char(97),char(114),char(82),char(101),char(102),char(101),char(114),char(101),char(110),char(99),
-char(101),char(70),char(114),char(97),char(109),char(101),char(65),char(0),char(109),char(95),char(117),char(115),char(101),char(79),char(102),char(102),char(115),char(101),char(116),char(70),
-char(111),char(114),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(70),char(114),char(97),char(109),char(101),char(0),char(109),char(95),
-char(54),char(100),char(111),char(102),char(68),char(97),char(116),char(97),char(0),char(109),char(95),char(115),char(112),char(114),char(105),char(110),char(103),char(69),char(110),char(97),
-char(98),char(108),char(101),char(100),char(91),char(54),char(93),char(0),char(109),char(95),char(101),char(113),char(117),char(105),char(108),char(105),char(98),char(114),char(105),char(117),
-char(109),char(80),char(111),char(105),char(110),char(116),char(91),char(54),char(93),char(0),char(109),char(95),char(115),char(112),char(114),char(105),char(110),char(103),char(83),char(116),
-char(105),char(102),char(102),char(110),char(101),char(115),char(115),char(91),char(54),char(93),char(0),char(109),char(95),char(115),char(112),char(114),char(105),char(110),char(103),char(68),
-char(97),char(109),char(112),char(105),char(110),char(103),char(91),char(54),char(93),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(66),char(111),
-char(117),char(110),char(99),char(101),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83),char(116),char(111),char(112),char(69),char(82),char(80),
-char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83),char(116),char(111),char(112),char(67),char(70),char(77),char(0),char(109),char(95),char(108),
-char(105),char(110),char(101),char(97),char(114),char(77),char(111),char(116),char(111),char(114),char(69),char(82),char(80),char(0),char(109),char(95),char(108),char(105),char(110),char(101),
-char(97),char(114),char(77),char(111),char(116),char(111),char(114),char(67),char(70),char(77),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(84),
-char(97),char(114),char(103),char(101),char(116),char(86),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(0),char(109),char(95),char(108),char(105),char(110),char(101),
-char(97),char(114),char(77),char(97),char(120),char(77),char(111),char(116),char(111),char(114),char(70),char(111),char(114),char(99),char(101),char(0),char(109),char(95),char(108),char(105),
-char(110),char(101),char(97),char(114),char(83),char(101),char(114),char(118),char(111),char(84),char(97),char(114),char(103),char(101),char(116),char(0),char(109),char(95),char(108),char(105),
-char(110),char(101),char(97),char(114),char(83),char(112),char(114),char(105),char(110),char(103),char(83),char(116),char(105),char(102),char(102),char(110),char(101),char(115),char(115),char(0),
-char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83),char(112),char(114),char(105),char(110),char(103),char(68),char(97),char(109),char(112),char(105),char(110),
-char(103),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(69),char(113),char(117),char(105),char(108),char(105),char(98),char(114),char(105),char(117),
-char(109),char(80),char(111),char(105),char(110),char(116),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(69),char(110),char(97),char(98),char(108),
-char(101),char(77),char(111),char(116),char(111),char(114),char(91),char(52),char(93),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83),char(101),
-char(114),char(118),char(111),char(77),char(111),char(116),char(111),char(114),char(91),char(52),char(93),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),
-char(69),char(110),char(97),char(98),char(108),char(101),char(83),char(112),char(114),char(105),char(110),char(103),char(91),char(52),char(93),char(0),char(109),char(95),char(108),char(105),
-char(110),char(101),char(97),char(114),char(83),char(112),char(114),char(105),char(110),char(103),char(83),char(116),char(105),char(102),char(102),char(110),char(101),char(115),char(115),char(76),
-char(105),char(109),char(105),char(116),char(101),char(100),char(91),char(52),char(93),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83),char(112),
-char(114),char(105),char(110),char(103),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(76),char(105),char(109),char(105),char(116),char(101),char(100),char(91),char(52),
-char(93),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(66),char(111),char(117),char(110),char(99),char(101),char(0),char(109),char(95),
-char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(83),char(116),char(111),char(112),char(69),char(82),char(80),char(0),char(109),char(95),char(97),char(110),char(103),
-char(117),char(108),char(97),char(114),char(83),char(116),char(111),char(112),char(67),char(70),char(77),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),
-char(114),char(77),char(111),char(116),char(111),char(114),char(69),char(82),char(80),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(77),
-char(111),char(116),char(111),char(114),char(67),char(70),char(77),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(84),char(97),char(114),
-char(103),char(101),char(116),char(86),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),
-char(114),char(77),char(97),char(120),char(77),char(111),char(116),char(111),char(114),char(70),char(111),char(114),char(99),char(101),char(0),char(109),char(95),char(97),char(110),char(103),
-char(117),char(108),char(97),char(114),char(83),char(101),char(114),char(118),char(111),char(84),char(97),char(114),char(103),char(101),char(116),char(0),char(109),char(95),char(97),char(110),
-char(103),char(117),char(108),char(97),char(114),char(83),char(112),char(114),char(105),char(110),char(103),char(83),char(116),char(105),char(102),char(102),char(110),char(101),char(115),char(115),
-char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(83),char(112),char(114),char(105),char(110),char(103),char(68),char(97),char(109),char(112),
-char(105),char(110),char(103),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(69),char(113),char(117),char(105),char(108),char(105),char(98),
-char(114),char(105),char(117),char(109),char(80),char(111),char(105),char(110),char(116),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(69),
-char(110),char(97),char(98),char(108),char(101),char(77),char(111),char(116),char(111),char(114),char(91),char(52),char(93),char(0),char(109),char(95),char(97),char(110),char(103),char(117),
-char(108),char(97),char(114),char(83),char(101),char(114),char(118),char(111),char(77),char(111),char(116),char(111),char(114),char(91),char(52),char(93),char(0),char(109),char(95),char(97),
-char(110),char(103),char(117),char(108),char(97),char(114),char(69),char(110),char(97),char(98),char(108),char(101),char(83),char(112),char(114),char(105),char(110),char(103),char(91),char(52),
-char(93),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(83),char(112),char(114),char(105),char(110),char(103),char(83),char(116),char(105),
-char(102),char(102),char(110),char(101),char(115),char(115),char(76),char(105),char(109),char(105),char(116),char(101),char(100),char(91),char(52),char(93),char(0),char(109),char(95),char(97),
-char(110),char(103),char(117),char(108),char(97),char(114),char(83),char(112),char(114),char(105),char(110),char(103),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(76),
-char(105),char(109),char(105),char(116),char(101),char(100),char(91),char(52),char(93),char(0),char(109),char(95),char(114),char(111),char(116),char(97),char(116),char(101),char(79),char(114),
-char(100),char(101),char(114),char(0),char(109),char(95),char(97),char(120),char(105),char(115),char(73),char(110),char(65),char(0),char(109),char(95),char(97),char(120),char(105),char(115),
-char(73),char(110),char(66),char(0),char(109),char(95),char(114),char(97),char(116),char(105),char(111),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),
-char(83),char(116),char(105),char(102),char(102),char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(83),
-char(116),char(105),char(102),char(102),char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(118),char(111),char(108),char(117),char(109),char(101),char(83),char(116),char(105),
-char(102),char(102),char(110),char(101),char(115),char(115),char(0),char(42),char(109),char(95),char(109),char(97),char(116),char(101),char(114),char(105),char(97),char(108),char(0),char(109),
-char(95),char(112),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(112),char(114),char(101),char(118),char(105),char(111),char(117),char(115),
-char(80),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(118),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(0),
-char(109),char(95),char(97),char(99),char(99),char(117),char(109),char(117),char(108),char(97),char(116),char(101),char(100),char(70),char(111),char(114),char(99),char(101),char(0),char(109),
-char(95),char(110),char(111),char(114),char(109),char(97),char(108),char(0),char(109),char(95),char(97),char(114),char(101),char(97),char(0),char(109),char(95),char(97),char(116),char(116),
-char(97),char(99),char(104),char(0),char(109),char(95),char(110),char(111),char(100),char(101),char(73),char(110),char(100),char(105),char(99),char(101),char(115),char(91),char(50),char(93),
-char(0),char(109),char(95),char(114),char(101),char(115),char(116),char(76),char(101),char(110),char(103),char(116),char(104),char(0),char(109),char(95),char(98),char(98),char(101),char(110),
-char(100),char(105),char(110),char(103),char(0),char(109),char(95),char(110),char(111),char(100),char(101),char(73),char(110),char(100),char(105),char(99),char(101),char(115),char(91),char(51),
-char(93),char(0),char(109),char(95),char(114),char(101),char(115),char(116),char(65),char(114),char(101),char(97),char(0),char(109),char(95),char(99),char(48),char(91),char(52),char(93),
-char(0),char(109),char(95),char(110),char(111),char(100),char(101),char(73),char(110),char(100),char(105),char(99),char(101),char(115),char(91),char(52),char(93),char(0),char(109),char(95),
-char(114),char(101),char(115),char(116),char(86),char(111),char(108),char(117),char(109),char(101),char(0),char(109),char(95),char(99),char(49),char(0),char(109),char(95),char(99),char(50),
-char(0),char(109),char(95),char(99),char(48),char(0),char(109),char(95),char(108),char(111),char(99),char(97),char(108),char(70),char(114),char(97),char(109),char(101),char(0),char(42),
-char(109),char(95),char(114),char(105),char(103),char(105),char(100),char(66),char(111),char(100),char(121),char(0),char(109),char(95),char(110),char(111),char(100),char(101),char(73),char(110),
-char(100),char(101),char(120),char(0),char(109),char(95),char(97),char(101),char(114),char(111),char(77),char(111),char(100),char(101),char(108),char(0),char(109),char(95),char(98),char(97),
-char(117),char(109),char(103),char(97),char(114),char(116),char(101),char(0),char(109),char(95),char(100),char(114),char(97),char(103),char(0),char(109),char(95),char(108),char(105),char(102),
-char(116),char(0),char(109),char(95),char(112),char(114),char(101),char(115),char(115),char(117),char(114),char(101),char(0),char(109),char(95),char(118),char(111),char(108),char(117),char(109),
-char(101),char(0),char(109),char(95),char(100),char(121),char(110),char(97),char(109),char(105),char(99),char(70),char(114),char(105),char(99),char(116),char(105),char(111),char(110),char(0),
-char(109),char(95),char(112),char(111),char(115),char(101),char(77),char(97),char(116),char(99),char(104),char(0),char(109),char(95),char(114),char(105),char(103),char(105),char(100),char(67),
-char(111),char(110),char(116),char(97),char(99),char(116),char(72),char(97),char(114),char(100),char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(107),char(105),char(110),
-char(101),char(116),char(105),char(99),char(67),char(111),char(110),char(116),char(97),char(99),char(116),char(72),char(97),char(114),char(100),char(110),char(101),char(115),char(115),char(0),
-char(109),char(95),char(115),char(111),char(102),char(116),char(67),char(111),char(110),char(116),char(97),char(99),char(116),char(72),char(97),char(114),char(100),char(110),char(101),char(115),
-char(115),char(0),char(109),char(95),char(97),char(110),char(99),char(104),char(111),char(114),char(72),char(97),char(114),char(100),char(110),char(101),char(115),char(115),char(0),char(109),
-char(95),char(115),char(111),char(102),char(116),char(82),char(105),char(103),char(105),char(100),char(67),char(108),char(117),char(115),char(116),char(101),char(114),char(72),char(97),char(114),
-char(100),char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(115),char(111),char(102),char(116),char(75),char(105),char(110),char(101),char(116),char(105),char(99),char(67),
-char(108),char(117),char(115),char(116),char(101),char(114),char(72),char(97),char(114),char(100),char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(115),char(111),char(102),
-char(116),char(83),char(111),char(102),char(116),char(67),char(108),char(117),char(115),char(116),char(101),char(114),char(72),char(97),char(114),char(100),char(110),char(101),char(115),char(115),
-char(0),char(109),char(95),char(115),char(111),char(102),char(116),char(82),char(105),char(103),char(105),char(100),char(67),char(108),char(117),char(115),char(116),char(101),char(114),char(73),
-char(109),char(112),char(117),char(108),char(115),char(101),char(83),char(112),char(108),char(105),char(116),char(0),char(109),char(95),char(115),char(111),char(102),char(116),char(75),char(105),
-char(110),char(101),char(116),char(105),char(99),char(67),char(108),char(117),char(115),char(116),char(101),char(114),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(83),
-char(112),char(108),char(105),char(116),char(0),char(109),char(95),char(115),char(111),char(102),char(116),char(83),char(111),char(102),char(116),char(67),char(108),char(117),char(115),char(116),
-char(101),char(114),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(83),char(112),char(108),char(105),char(116),char(0),char(109),char(95),char(109),char(97),char(120),
-char(86),char(111),char(108),char(117),char(109),char(101),char(0),char(109),char(95),char(116),char(105),char(109),char(101),char(83),char(99),char(97),char(108),char(101),char(0),char(109),
-char(95),char(118),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(73),char(116),char(101),char(114),char(97),char(116),char(105),char(111),char(110),char(115),char(0),
-char(109),char(95),char(112),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(73),char(116),char(101),char(114),char(97),char(116),char(105),char(111),char(110),char(115),
-char(0),char(109),char(95),char(100),char(114),char(105),char(102),char(116),char(73),char(116),char(101),char(114),char(97),char(116),char(105),char(111),char(110),char(115),char(0),char(109),
-char(95),char(99),char(108),char(117),char(115),char(116),char(101),char(114),char(73),char(116),char(101),char(114),char(97),char(116),char(105),char(111),char(110),char(115),char(0),char(109),
-char(95),char(114),char(111),char(116),char(0),char(109),char(95),char(115),char(99),char(97),char(108),char(101),char(0),char(109),char(95),char(97),char(113),char(113),char(0),char(109),
-char(95),char(99),char(111),char(109),char(0),char(42),char(109),char(95),char(112),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(115),char(0),char(42),char(109),
-char(95),char(119),char(101),char(105),char(103),char(104),char(116),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(80),char(111),char(115),char(105),char(116),char(105),
-char(111),char(110),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(87),char(101),char(105),char(103),char(116),char(115),char(0),char(109),char(95),char(98),char(118),
-char(111),char(108),char(117),char(109),char(101),char(0),char(109),char(95),char(98),char(102),char(114),char(97),char(109),char(101),char(0),char(109),char(95),char(102),char(114),char(97),
-char(109),char(101),char(120),char(102),char(111),char(114),char(109),char(0),char(109),char(95),char(108),char(111),char(99),char(105),char(105),char(0),char(109),char(95),char(105),char(110),
-char(118),char(119),char(105),char(0),char(109),char(95),char(118),char(105),char(109),char(112),char(117),char(108),char(115),char(101),char(115),char(91),char(50),char(93),char(0),char(109),
-char(95),char(100),char(105),char(109),char(112),char(117),char(108),char(115),char(101),char(115),char(91),char(50),char(93),char(0),char(109),char(95),char(108),char(118),char(0),char(109),
-char(95),char(97),char(118),char(0),char(42),char(109),char(95),char(102),char(114),char(97),char(109),char(101),char(114),char(101),char(102),char(115),char(0),char(42),char(109),char(95),
-char(110),char(111),char(100),char(101),char(73),char(110),char(100),char(105),char(99),char(101),char(115),char(0),char(42),char(109),char(95),char(109),char(97),char(115),char(115),char(101),
-char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(70),char(114),char(97),char(109),char(101),char(82),char(101),char(102),char(115),char(0),char(109),char(95),char(110),
-char(117),char(109),char(78),char(111),char(100),char(101),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(77),char(97),char(115),char(115),char(101),char(115),char(0),
-char(109),char(95),char(105),char(100),char(109),char(97),char(115),char(115),char(0),char(109),char(95),char(105),char(109),char(97),char(115),char(115),char(0),char(109),char(95),char(110),
-char(118),char(105),char(109),char(112),char(117),char(108),char(115),char(101),char(115),char(0),char(109),char(95),char(110),char(100),char(105),char(109),char(112),char(117),char(108),char(115),
-char(101),char(115),char(0),char(109),char(95),char(110),char(100),char(97),char(109),char(112),char(105),char(110),char(103),char(0),char(109),char(95),char(108),char(100),char(97),char(109),
-char(112),char(105),char(110),char(103),char(0),char(109),char(95),char(97),char(100),char(97),char(109),char(112),char(105),char(110),char(103),char(0),char(109),char(95),char(109),char(97),
-char(116),char(99),char(104),char(105),char(110),char(103),char(0),char(109),char(95),char(109),char(97),char(120),char(83),char(101),char(108),char(102),char(67),char(111),char(108),char(108),
-char(105),char(115),char(105),char(111),char(110),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(0),char(109),char(95),char(115),char(101),char(108),char(102),char(67),
-char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(70),char(97),char(99),char(116),char(111),
-char(114),char(0),char(109),char(95),char(99),char(111),char(110),char(116),char(97),char(105),char(110),char(115),char(65),char(110),char(99),char(104),char(111),char(114),char(0),char(109),
-char(95),char(99),char(111),char(108),char(108),char(105),char(100),char(101),char(0),char(109),char(95),char(99),char(108),char(117),char(115),char(116),char(101),char(114),char(73),char(110),
-char(100),char(101),char(120),char(0),char(42),char(109),char(95),char(98),char(111),char(100),char(121),char(65),char(0),char(42),char(109),char(95),char(98),char(111),char(100),char(121),
-char(66),char(0),char(109),char(95),char(114),char(101),char(102),char(115),char(91),char(50),char(93),char(0),char(109),char(95),char(99),char(102),char(109),char(0),char(109),char(95),
-char(115),char(112),char(108),char(105),char(116),char(0),char(109),char(95),char(100),char(101),char(108),char(101),char(116),char(101),char(0),char(109),char(95),char(114),char(101),char(108),
-char(80),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(91),char(50),char(93),char(0),char(109),char(95),char(98),char(111),char(100),char(121),char(65),char(116),
-char(121),char(112),char(101),char(0),char(109),char(95),char(98),char(111),char(100),char(121),char(66),char(116),char(121),char(112),char(101),char(0),char(109),char(95),char(106),char(111),
-char(105),char(110),char(116),char(84),char(121),char(112),char(101),char(0),char(42),char(109),char(95),char(112),char(111),char(115),char(101),char(0),char(42),char(42),char(109),char(95),
-char(109),char(97),char(116),char(101),char(114),char(105),char(97),char(108),char(115),char(0),char(42),char(109),char(95),char(110),char(111),char(100),char(101),char(115),char(0),char(42),
-char(109),char(95),char(108),char(105),char(110),char(107),char(115),char(0),char(42),char(109),char(95),char(102),char(97),char(99),char(101),char(115),char(0),char(42),char(109),char(95),
-char(116),char(101),char(116),char(114),char(97),char(104),char(101),char(100),char(114),char(97),char(0),char(42),char(109),char(95),char(97),char(110),char(99),char(104),char(111),char(114),
-char(115),char(0),char(42),char(109),char(95),char(99),char(108),char(117),char(115),char(116),char(101),char(114),char(115),char(0),char(42),char(109),char(95),char(106),char(111),char(105),
-char(110),char(116),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(77),char(97),char(116),char(101),char(114),char(105),char(97),char(108),char(115),char(0),char(109),
-char(95),char(110),char(117),char(109),char(76),char(105),char(110),char(107),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(70),char(97),char(99),char(101),char(115),
-char(0),char(109),char(95),char(110),char(117),char(109),char(84),char(101),char(116),char(114),char(97),char(104),char(101),char(100),char(114),char(97),char(0),char(109),char(95),char(110),
-char(117),char(109),char(65),char(110),char(99),char(104),char(111),char(114),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(67),char(108),char(117),char(115),char(116),
-char(101),char(114),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(74),char(111),char(105),char(110),char(116),char(115),char(0),char(109),char(95),char(99),char(111),
-char(110),char(102),char(105),char(103),char(0),char(109),char(95),char(122),char(101),char(114),char(111),char(82),char(111),char(116),char(80),char(97),char(114),char(101),char(110),char(116),
-char(84),char(111),char(84),char(104),char(105),char(115),char(0),char(109),char(95),char(112),char(97),char(114),char(101),char(110),char(116),char(67),char(111),char(109),char(84),char(111),
-char(84),char(104),char(105),char(115),char(67),char(111),char(109),char(79),char(102),char(102),char(115),char(101),char(116),char(0),char(109),char(95),char(116),char(104),char(105),char(115),
-char(80),char(105),char(118),char(111),char(116),char(84),char(111),char(84),char(104),char(105),char(115),char(67),char(111),char(109),char(79),char(102),char(102),char(115),char(101),char(116),
-char(0),char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(65),char(120),char(105),char(115),char(84),char(111),char(112),char(91),char(54),char(93),char(0),char(109),
-char(95),char(106),char(111),char(105),char(110),char(116),char(65),char(120),char(105),char(115),char(66),char(111),char(116),char(116),char(111),char(109),char(91),char(54),char(93),char(0),
-char(109),char(95),char(108),char(105),char(110),char(107),char(73),char(110),char(101),char(114),char(116),char(105),char(97),char(0),char(109),char(95),char(108),char(105),char(110),char(107),
-char(77),char(97),char(115),char(115),char(0),char(109),char(95),char(112),char(97),char(114),char(101),char(110),char(116),char(73),char(110),char(100),char(101),char(120),char(0),char(109),
-char(95),char(100),char(111),char(102),char(67),char(111),char(117),char(110),char(116),char(0),char(109),char(95),char(112),char(111),char(115),char(86),char(97),char(114),char(67),char(111),
-char(117),char(110),char(116),char(0),char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(80),char(111),char(115),char(91),char(55),char(93),char(0),char(109),char(95),
-char(106),char(111),char(105),char(110),char(116),char(86),char(101),char(108),char(91),char(54),char(93),char(0),char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(84),
-char(111),char(114),char(113),char(117),char(101),char(91),char(54),char(93),char(0),char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(68),char(97),char(109),char(112),
-char(105),char(110),char(103),char(0),char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(70),char(114),char(105),char(99),char(116),char(105),char(111),char(110),char(0),
-char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(76),char(111),char(119),char(101),char(114),char(76),char(105),char(109),char(105),char(116),char(0),char(109),char(95),
-char(106),char(111),char(105),char(110),char(116),char(85),char(112),char(112),char(101),char(114),char(76),char(105),char(109),char(105),char(116),char(0),char(109),char(95),char(106),char(111),
-char(105),char(110),char(116),char(77),char(97),char(120),char(70),char(111),char(114),char(99),char(101),char(0),char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(77),
-char(97),char(120),char(86),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(0),char(42),char(109),char(95),char(108),char(105),char(110),char(107),char(78),char(97),
-char(109),char(101),char(0),char(42),char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(78),char(97),char(109),char(101),char(0),char(42),char(109),char(95),char(108),
-char(105),char(110),char(107),char(67),char(111),char(108),char(108),char(105),char(100),char(101),char(114),char(0),char(42),char(109),char(95),char(112),char(97),char(100),char(100),char(105),
-char(110),char(103),char(80),char(116),char(114),char(0),char(109),char(95),char(98),char(97),char(115),char(101),char(87),char(111),char(114),char(108),char(100),char(84),char(114),char(97),
-char(110),char(115),char(102),char(111),char(114),char(109),char(0),char(109),char(95),char(98),char(97),char(115),char(101),char(73),char(110),char(101),char(114),char(116),char(105),char(97),
-char(0),char(109),char(95),char(98),char(97),char(115),char(101),char(77),char(97),char(115),char(115),char(0),char(42),char(109),char(95),char(98),char(97),char(115),char(101),char(78),
-char(97),char(109),char(101),char(0),char(42),char(109),char(95),char(98),char(97),char(115),char(101),char(67),char(111),char(108),char(108),char(105),char(100),char(101),char(114),char(0),
-char(84),char(89),char(80),char(69),char(95),char(0),char(0),char(0),char(99),char(104),char(97),char(114),char(0),char(117),char(99),char(104),char(97),char(114),char(0),char(115),
-char(104),char(111),char(114),char(116),char(0),char(117),char(115),char(104),char(111),char(114),char(116),char(0),char(105),char(110),char(116),char(0),char(108),char(111),char(110),char(103),
-char(0),char(117),char(108),char(111),char(110),char(103),char(0),char(102),char(108),char(111),char(97),char(116),char(0),char(100),char(111),char(117),char(98),char(108),char(101),char(0),
-char(118),char(111),char(105),char(100),char(0),char(80),char(111),char(105),char(110),char(116),char(101),char(114),char(65),char(114),char(114),char(97),char(121),char(0),char(98),char(116),
-char(80),char(104),char(121),char(115),char(105),char(99),char(115),char(83),char(121),char(115),char(116),char(101),char(109),char(0),char(76),char(105),char(115),char(116),char(66),char(97),
-char(115),char(101),char(0),char(98),char(116),char(86),char(101),char(99),char(116),char(111),char(114),char(51),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),
-char(97),char(0),char(98),char(116),char(86),char(101),char(99),char(116),char(111),char(114),char(51),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),
-char(97),char(0),char(98),char(116),char(81),char(117),char(97),char(116),char(101),char(114),char(110),char(105),char(111),char(110),char(70),char(108),char(111),char(97),char(116),char(68),
-char(97),char(116),char(97),char(0),char(98),char(116),char(81),char(117),char(97),char(116),char(101),char(114),char(110),char(105),char(111),char(110),char(68),char(111),char(117),char(98),
-char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(77),char(97),char(116),char(114),char(105),char(120),char(51),char(120),char(51),char(70),char(108),
-char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(77),char(97),char(116),char(114),char(105),char(120),char(51),char(120),char(51),char(68),
-char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(84),char(114),char(97),char(110),char(115),char(102),char(111),char(114),
-char(109),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(84),char(114),char(97),char(110),char(115),char(102),char(111),
-char(114),char(109),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(66),char(118),char(104),char(83),char(117),
-char(98),char(116),char(114),char(101),char(101),char(73),char(110),char(102),char(111),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(79),char(112),char(116),char(105),
-char(109),char(105),char(122),char(101),char(100),char(66),char(118),char(104),char(78),char(111),char(100),char(101),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),
+char(109),char(75),char(101),char(121),char(115),char(0),char(109),char(95),char(112),char(111),char(105),char(110),char(116),char(67),char(97),char(99),char(104),char(101),char(76),char(111),
+char(99),char(97),char(108),char(80),char(111),char(105),char(110),char(116),char(65),char(91),char(52),char(93),char(0),char(109),char(95),char(112),char(111),char(105),char(110),char(116),
+char(67),char(97),char(99),char(104),char(101),char(76),char(111),char(99),char(97),char(108),char(80),char(111),char(105),char(110),char(116),char(66),char(91),char(52),char(93),char(0),
+char(109),char(95),char(112),char(111),char(105),char(110),char(116),char(67),char(97),char(99),char(104),char(101),char(80),char(111),char(115),char(105),char(116),char(105),char(111),char(110),
+char(87),char(111),char(114),char(108),char(100),char(79),char(110),char(65),char(91),char(52),char(93),char(0),char(109),char(95),char(112),char(111),char(105),char(110),char(116),char(67),
+char(97),char(99),char(104),char(101),char(80),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(87),char(111),char(114),char(108),char(100),char(79),char(110),char(66),
+char(91),char(52),char(93),char(0),char(109),char(95),char(112),char(111),char(105),char(110),char(116),char(67),char(97),char(99),char(104),char(101),char(78),char(111),char(114),char(109),
+char(97),char(108),char(87),char(111),char(114),char(108),char(100),char(79),char(110),char(66),char(91),char(52),char(93),char(0),char(109),char(95),char(112),char(111),char(105),char(110),
+char(116),char(67),char(97),char(99),char(104),char(101),char(76),char(97),char(116),char(101),char(114),char(97),char(108),char(70),char(114),char(105),char(99),char(116),char(105),char(111),
+char(110),char(68),char(105),char(114),char(49),char(91),char(52),char(93),char(0),char(109),char(95),char(112),char(111),char(105),char(110),char(116),char(67),char(97),char(99),char(104),
+char(101),char(76),char(97),char(116),char(101),char(114),char(97),char(108),char(70),char(114),char(105),char(99),char(116),char(105),char(111),char(110),char(68),char(105),char(114),char(50),
+char(91),char(52),char(93),char(0),char(109),char(95),char(112),char(111),char(105),char(110),char(116),char(67),char(97),char(99),char(104),char(101),char(68),char(105),char(115),char(116),
+char(97),char(110),char(99),char(101),char(91),char(52),char(93),char(0),char(109),char(95),char(112),char(111),char(105),char(110),char(116),char(67),char(97),char(99),char(104),char(101),
+char(65),char(112),char(112),char(108),char(105),char(101),char(100),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(91),char(52),char(93),char(0),char(109),char(95),
+char(112),char(111),char(105),char(110),char(116),char(67),char(97),char(99),char(104),char(101),char(67),char(111),char(109),char(98),char(105),char(110),char(101),char(100),char(70),char(114),
+char(105),char(99),char(116),char(105),char(111),char(110),char(91),char(52),char(93),char(0),char(109),char(95),char(112),char(111),char(105),char(110),char(116),char(67),char(97),char(99),
+char(104),char(101),char(67),char(111),char(109),char(98),char(105),char(110),char(101),char(100),char(82),char(111),char(108),char(108),char(105),char(110),char(103),char(70),char(114),char(105),
+char(99),char(116),char(105),char(111),char(110),char(91),char(52),char(93),char(0),char(109),char(95),char(112),char(111),char(105),char(110),char(116),char(67),char(97),char(99),char(104),
+char(101),char(67),char(111),char(109),char(98),char(105),char(110),char(101),char(100),char(83),char(112),char(105),char(110),char(110),char(105),char(110),char(103),char(70),char(114),char(105),
+char(99),char(116),char(105),char(111),char(110),char(91),char(52),char(93),char(0),char(109),char(95),char(112),char(111),char(105),char(110),char(116),char(67),char(97),char(99),char(104),
+char(101),char(67),char(111),char(109),char(98),char(105),char(110),char(101),char(100),char(82),char(101),char(115),char(116),char(105),char(116),char(117),char(116),char(105),char(111),char(110),
+char(91),char(52),char(93),char(0),char(109),char(95),char(112),char(111),char(105),char(110),char(116),char(67),char(97),char(99),char(104),char(101),char(80),char(97),char(114),char(116),
+char(73),char(100),char(48),char(91),char(52),char(93),char(0),char(109),char(95),char(112),char(111),char(105),char(110),char(116),char(67),char(97),char(99),char(104),char(101),char(80),
+char(97),char(114),char(116),char(73),char(100),char(49),char(91),char(52),char(93),char(0),char(109),char(95),char(112),char(111),char(105),char(110),char(116),char(67),char(97),char(99),
+char(104),char(101),char(73),char(110),char(100),char(101),char(120),char(48),char(91),char(52),char(93),char(0),char(109),char(95),char(112),char(111),char(105),char(110),char(116),char(67),
+char(97),char(99),char(104),char(101),char(73),char(110),char(100),char(101),char(120),char(49),char(91),char(52),char(93),char(0),char(109),char(95),char(112),char(111),char(105),char(110),
+char(116),char(67),char(97),char(99),char(104),char(101),char(67),char(111),char(110),char(116),char(97),char(99),char(116),char(80),char(111),char(105),char(110),char(116),char(70),char(108),
+char(97),char(103),char(115),char(91),char(52),char(93),char(0),char(109),char(95),char(112),char(111),char(105),char(110),char(116),char(67),char(97),char(99),char(104),char(101),char(65),
+char(112),char(112),char(108),char(105),char(101),char(100),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(76),char(97),char(116),char(101),char(114),char(97),char(108),
+char(49),char(91),char(52),char(93),char(0),char(109),char(95),char(112),char(111),char(105),char(110),char(116),char(67),char(97),char(99),char(104),char(101),char(65),char(112),char(112),
+char(108),char(105),char(101),char(100),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(76),char(97),char(116),char(101),char(114),char(97),char(108),char(50),char(91),
+char(52),char(93),char(0),char(109),char(95),char(112),char(111),char(105),char(110),char(116),char(67),char(97),char(99),char(104),char(101),char(67),char(111),char(110),char(116),char(97),
+char(99),char(116),char(77),char(111),char(116),char(105),char(111),char(110),char(49),char(91),char(52),char(93),char(0),char(109),char(95),char(112),char(111),char(105),char(110),char(116),
+char(67),char(97),char(99),char(104),char(101),char(67),char(111),char(110),char(116),char(97),char(99),char(116),char(77),char(111),char(116),char(105),char(111),char(110),char(50),char(91),
+char(52),char(93),char(0),char(109),char(95),char(112),char(111),char(105),char(110),char(116),char(67),char(97),char(99),char(104),char(101),char(67),char(111),char(110),char(116),char(97),
+char(99),char(116),char(67),char(70),char(77),char(91),char(52),char(93),char(0),char(109),char(95),char(112),char(111),char(105),char(110),char(116),char(67),char(97),char(99),char(104),
+char(101),char(67),char(111),char(109),char(98),char(105),char(110),char(101),char(100),char(67),char(111),char(110),char(116),char(97),char(99),char(116),char(83),char(116),char(105),char(102),
+char(102),char(110),char(101),char(115),char(115),char(49),char(91),char(52),char(93),char(0),char(109),char(95),char(112),char(111),char(105),char(110),char(116),char(67),char(97),char(99),
+char(104),char(101),char(67),char(111),char(110),char(116),char(97),char(99),char(116),char(69),char(82),char(80),char(91),char(52),char(93),char(0),char(109),char(95),char(112),char(111),
+char(105),char(110),char(116),char(67),char(97),char(99),char(104),char(101),char(67),char(111),char(109),char(98),char(105),char(110),char(101),char(100),char(67),char(111),char(110),char(116),
+char(97),char(99),char(116),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(49),char(91),char(52),char(93),char(0),char(109),char(95),char(112),char(111),char(105),
+char(110),char(116),char(67),char(97),char(99),char(104),char(101),char(70),char(114),char(105),char(99),char(116),char(105),char(111),char(110),char(67),char(70),char(77),char(91),char(52),
+char(93),char(0),char(109),char(95),char(112),char(111),char(105),char(110),char(116),char(67),char(97),char(99),char(104),char(101),char(76),char(105),char(102),char(101),char(84),char(105),
+char(109),char(101),char(91),char(52),char(93),char(0),char(109),char(95),char(110),char(117),char(109),char(67),char(97),char(99),char(104),char(101),char(100),char(80),char(111),char(105),
+char(110),char(116),char(115),char(0),char(109),char(95),char(99),char(111),char(109),char(112),char(97),char(110),char(105),char(111),char(110),char(73),char(100),char(65),char(0),char(109),
+char(95),char(99),char(111),char(109),char(112),char(97),char(110),char(105),char(111),char(110),char(73),char(100),char(66),char(0),char(109),char(95),char(105),char(110),char(100),char(101),
+char(120),char(49),char(97),char(0),char(109),char(95),char(111),char(98),char(106),char(101),char(99),char(116),char(84),char(121),char(112),char(101),char(0),char(109),char(95),char(99),
+char(111),char(110),char(116),char(97),char(99),char(116),char(66),char(114),char(101),char(97),char(107),char(105),char(110),char(103),char(84),char(104),char(114),char(101),char(115),char(104),
+char(111),char(108),char(100),char(0),char(109),char(95),char(99),char(111),char(110),char(116),char(97),char(99),char(116),char(80),char(114),char(111),char(99),char(101),char(115),char(115),
+char(105),char(110),char(103),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(42),char(109),char(95),char(98),char(111),char(100),char(121),
+char(48),char(0),char(42),char(109),char(95),char(98),char(111),char(100),char(121),char(49),char(0),char(109),char(95),char(103),char(105),char(109),char(112),char(97),char(99),char(116),
+char(83),char(117),char(98),char(84),char(121),char(112),char(101),char(0),char(42),char(109),char(95),char(117),char(110),char(115),char(99),char(97),char(108),char(101),char(100),char(80),
+char(111),char(105),char(110),char(116),char(115),char(70),char(108),char(111),char(97),char(116),char(80),char(116),char(114),char(0),char(42),char(109),char(95),char(117),char(110),char(115),
+char(99),char(97),char(108),char(101),char(100),char(80),char(111),char(105),char(110),char(116),char(115),char(68),char(111),char(117),char(98),char(108),char(101),char(80),char(116),char(114),
+char(0),char(109),char(95),char(110),char(117),char(109),char(85),char(110),char(115),char(99),char(97),char(108),char(101),char(100),char(80),char(111),char(105),char(110),char(116),char(115),
+char(0),char(109),char(95),char(112),char(97),char(100),char(100),char(105),char(110),char(103),char(51),char(91),char(52),char(93),char(0),char(42),char(109),char(95),char(98),char(114),
+char(111),char(97),char(100),char(112),char(104),char(97),char(115),char(101),char(72),char(97),char(110),char(100),char(108),char(101),char(0),char(42),char(109),char(95),char(99),char(111),
+char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(83),char(104),char(97),char(112),char(101),char(0),char(42),char(109),char(95),char(114),char(111),char(111),char(116),
+char(67),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(83),char(104),char(97),char(112),char(101),char(0),char(109),char(95),char(119),char(111),char(114),
+char(108),char(100),char(84),char(114),char(97),char(110),char(115),char(102),char(111),char(114),char(109),char(0),char(109),char(95),char(105),char(110),char(116),char(101),char(114),char(112),
+char(111),char(108),char(97),char(116),char(105),char(111),char(110),char(87),char(111),char(114),char(108),char(100),char(84),char(114),char(97),char(110),char(115),char(102),char(111),char(114),
+char(109),char(0),char(109),char(95),char(105),char(110),char(116),char(101),char(114),char(112),char(111),char(108),char(97),char(116),char(105),char(111),char(110),char(76),char(105),char(110),
+char(101),char(97),char(114),char(86),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(0),char(109),char(95),char(105),char(110),char(116),char(101),char(114),char(112),
+char(111),char(108),char(97),char(116),char(105),char(111),char(110),char(65),char(110),char(103),char(117),char(108),char(97),char(114),char(86),char(101),char(108),char(111),char(99),char(105),
+char(116),char(121),char(0),char(109),char(95),char(97),char(110),char(105),char(115),char(111),char(116),char(114),char(111),char(112),char(105),char(99),char(70),char(114),char(105),char(99),
+char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(100),char(101),char(97),char(99),char(116),char(105),char(118),char(97),char(116),char(105),char(111),char(110),char(84),
+char(105),char(109),char(101),char(0),char(109),char(95),char(102),char(114),char(105),char(99),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(114),char(111),char(108),
+char(108),char(105),char(110),char(103),char(70),char(114),char(105),char(99),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(99),char(111),char(110),char(116),char(97),
+char(99),char(116),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(0),char(109),char(95),char(99),char(111),char(110),char(116),char(97),char(99),char(116),char(83),
+char(116),char(105),char(102),char(102),char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(114),char(101),char(115),char(116),char(105),char(116),char(117),char(116),char(105),
+char(111),char(110),char(0),char(109),char(95),char(104),char(105),char(116),char(70),char(114),char(97),char(99),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(99),
+char(99),char(100),char(83),char(119),char(101),char(112),char(116),char(83),char(112),char(104),char(101),char(114),char(101),char(82),char(97),char(100),char(105),char(117),char(115),char(0),
+char(109),char(95),char(99),char(99),char(100),char(77),char(111),char(116),char(105),char(111),char(110),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),
+char(0),char(109),char(95),char(104),char(97),char(115),char(65),char(110),char(105),char(115),char(111),char(116),char(114),char(111),char(112),char(105),char(99),char(70),char(114),char(105),
+char(99),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(99),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(70),char(108),char(97),
+char(103),char(115),char(0),char(109),char(95),char(105),char(115),char(108),char(97),char(110),char(100),char(84),char(97),char(103),char(49),char(0),char(109),char(95),char(99),char(111),
+char(109),char(112),char(97),char(110),char(105),char(111),char(110),char(73),char(100),char(0),char(109),char(95),char(97),char(99),char(116),char(105),char(118),char(97),char(116),char(105),
+char(111),char(110),char(83),char(116),char(97),char(116),char(101),char(49),char(0),char(109),char(95),char(105),char(110),char(116),char(101),char(114),char(110),char(97),char(108),char(84),
+char(121),char(112),char(101),char(0),char(109),char(95),char(99),char(104),char(101),char(99),char(107),char(67),char(111),char(108),char(108),char(105),char(100),char(101),char(87),char(105),
+char(116),char(104),char(0),char(109),char(95),char(99),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(70),char(105),char(108),char(116),char(101),char(114),
+char(71),char(114),char(111),char(117),char(112),char(0),char(109),char(95),char(99),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(70),char(105),char(108),
+char(116),char(101),char(114),char(77),char(97),char(115),char(107),char(0),char(109),char(95),char(117),char(110),char(105),char(113),char(117),char(101),char(73),char(100),char(0),char(109),
+char(95),char(116),char(97),char(117),char(0),char(109),char(95),char(100),char(97),char(109),char(112),char(105),char(110),char(103),char(0),char(109),char(95),char(116),char(105),char(109),
+char(101),char(83),char(116),char(101),char(112),char(0),char(109),char(95),char(109),char(97),char(120),char(69),char(114),char(114),char(111),char(114),char(82),char(101),char(100),char(117),
+char(99),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(115),char(111),char(114),char(0),char(109),char(95),char(101),char(114),char(112),char(0),char(109),char(95),
+char(101),char(114),char(112),char(50),char(0),char(109),char(95),char(103),char(108),char(111),char(98),char(97),char(108),char(67),char(102),char(109),char(0),char(109),char(95),char(115),
+char(112),char(108),char(105),char(116),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(80),char(101),char(110),char(101),char(116),char(114),char(97),char(116),char(105),
+char(111),char(110),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109),char(95),char(115),char(112),char(108),char(105),char(116),char(73),
+char(109),char(112),char(117),char(108),char(115),char(101),char(84),char(117),char(114),char(110),char(69),char(114),char(112),char(0),char(109),char(95),char(108),char(105),char(110),char(101),
+char(97),char(114),char(83),char(108),char(111),char(112),char(0),char(109),char(95),char(119),char(97),char(114),char(109),char(115),char(116),char(97),char(114),char(116),char(105),char(110),
+char(103),char(70),char(97),char(99),char(116),char(111),char(114),char(0),char(109),char(95),char(109),char(97),char(120),char(71),char(121),char(114),char(111),char(115),char(99),char(111),
+char(112),char(105),char(99),char(70),char(111),char(114),char(99),char(101),char(0),char(109),char(95),char(115),char(105),char(110),char(103),char(108),char(101),char(65),char(120),char(105),
+char(115),char(82),char(111),char(108),char(108),char(105),char(110),char(103),char(70),char(114),char(105),char(99),char(116),char(105),char(111),char(110),char(84),char(104),char(114),char(101),
+char(115),char(104),char(111),char(108),char(100),char(0),char(109),char(95),char(110),char(117),char(109),char(73),char(116),char(101),char(114),char(97),char(116),char(105),char(111),char(110),
+char(115),char(0),char(109),char(95),char(115),char(111),char(108),char(118),char(101),char(114),char(77),char(111),char(100),char(101),char(0),char(109),char(95),char(114),char(101),char(115),
+char(116),char(105),char(110),char(103),char(67),char(111),char(110),char(116),char(97),char(99),char(116),char(82),char(101),char(115),char(116),char(105),char(116),char(117),char(116),char(105),
+char(111),char(110),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109),char(95),char(109),char(105),char(110),char(105),char(109),char(117),
+char(109),char(83),char(111),char(108),char(118),char(101),char(114),char(66),char(97),char(116),char(99),char(104),char(83),char(105),char(122),char(101),char(0),char(109),char(95),char(115),
+char(112),char(108),char(105),char(116),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(0),char(109),char(95),char(115),char(111),char(108),char(118),char(101),char(114),
+char(73),char(110),char(102),char(111),char(0),char(109),char(95),char(103),char(114),char(97),char(118),char(105),char(116),char(121),char(0),char(109),char(95),char(99),char(111),char(108),
+char(108),char(105),char(115),char(105),char(111),char(110),char(79),char(98),char(106),char(101),char(99),char(116),char(68),char(97),char(116),char(97),char(0),char(109),char(95),char(105),
+char(110),char(118),char(73),char(110),char(101),char(114),char(116),char(105),char(97),char(84),char(101),char(110),char(115),char(111),char(114),char(87),char(111),char(114),char(108),char(100),
+char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(86),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(0),char(109),char(95),
+char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(86),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(0),char(109),char(95),char(97),char(110),
+char(103),char(117),char(108),char(97),char(114),char(70),char(97),char(99),char(116),char(111),char(114),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),
+char(70),char(97),char(99),char(116),char(111),char(114),char(0),char(109),char(95),char(103),char(114),char(97),char(118),char(105),char(116),char(121),char(95),char(97),char(99),char(99),
+char(101),char(108),char(101),char(114),char(97),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(105),char(110),char(118),char(73),char(110),char(101),char(114),char(116),
+char(105),char(97),char(76),char(111),char(99),char(97),char(108),char(0),char(109),char(95),char(116),char(111),char(116),char(97),char(108),char(70),char(111),char(114),char(99),char(101),
+char(0),char(109),char(95),char(116),char(111),char(116),char(97),char(108),char(84),char(111),char(114),char(113),char(117),char(101),char(0),char(109),char(95),char(105),char(110),char(118),
+char(101),char(114),char(115),char(101),char(77),char(97),char(115),char(115),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(68),char(97),char(109),
+char(112),char(105),char(110),char(103),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(68),char(97),char(109),char(112),char(105),char(110),
+char(103),char(0),char(109),char(95),char(97),char(100),char(100),char(105),char(116),char(105),char(111),char(110),char(97),char(108),char(68),char(97),char(109),char(112),char(105),char(110),
+char(103),char(70),char(97),char(99),char(116),char(111),char(114),char(0),char(109),char(95),char(97),char(100),char(100),char(105),char(116),char(105),char(111),char(110),char(97),char(108),
+char(76),char(105),char(110),char(101),char(97),char(114),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(84),char(104),char(114),char(101),char(115),char(104),char(111),
+char(108),char(100),char(83),char(113),char(114),char(0),char(109),char(95),char(97),char(100),char(100),char(105),char(116),char(105),char(111),char(110),char(97),char(108),char(65),char(110),
+char(103),char(117),char(108),char(97),char(114),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),
+char(100),char(83),char(113),char(114),char(0),char(109),char(95),char(97),char(100),char(100),char(105),char(116),char(105),char(111),char(110),char(97),char(108),char(65),char(110),char(103),
+char(117),char(108),char(97),char(114),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(70),char(97),char(99),char(116),char(111),char(114),char(0),char(109),char(95),
+char(108),char(105),char(110),char(101),char(97),char(114),char(83),char(108),char(101),char(101),char(112),char(105),char(110),char(103),char(84),char(104),char(114),char(101),char(115),char(104),
+char(111),char(108),char(100),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(83),char(108),char(101),char(101),char(112),char(105),char(110),
+char(103),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109),char(95),char(97),char(100),char(100),char(105),char(116),char(105),char(111),
+char(110),char(97),char(108),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(0),char(109),char(95),char(110),char(117),char(109),char(67),char(111),char(110),char(115),
+char(116),char(114),char(97),char(105),char(110),char(116),char(82),char(111),char(119),char(115),char(0),char(110),char(117),char(98),char(0),char(42),char(109),char(95),char(114),char(98),
+char(65),char(0),char(42),char(109),char(95),char(114),char(98),char(66),char(0),char(109),char(95),char(117),char(115),char(101),char(114),char(67),char(111),char(110),char(115),char(116),
+char(114),char(97),char(105),char(110),char(116),char(84),char(121),char(112),char(101),char(0),char(109),char(95),char(117),char(115),char(101),char(114),char(67),char(111),char(110),char(115),
+char(116),char(114),char(97),char(105),char(110),char(116),char(73),char(100),char(0),char(109),char(95),char(110),char(101),char(101),char(100),char(115),char(70),char(101),char(101),char(100),
+char(98),char(97),char(99),char(107),char(0),char(109),char(95),char(97),char(112),char(112),char(108),char(105),char(101),char(100),char(73),char(109),char(112),char(117),char(108),char(115),
+char(101),char(0),char(109),char(95),char(100),char(98),char(103),char(68),char(114),char(97),char(119),char(83),char(105),char(122),char(101),char(0),char(109),char(95),char(100),char(105),
+char(115),char(97),char(98),char(108),char(101),char(67),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(115),char(66),char(101),char(116),char(119),char(101),
+char(101),char(110),char(76),char(105),char(110),char(107),char(101),char(100),char(66),char(111),char(100),char(105),char(101),char(115),char(0),char(109),char(95),char(111),char(118),char(101),
+char(114),char(114),char(105),char(100),char(101),char(78),char(117),char(109),char(83),char(111),char(108),char(118),char(101),char(114),char(73),char(116),char(101),char(114),char(97),char(116),
+char(105),char(111),char(110),char(115),char(0),char(109),char(95),char(98),char(114),char(101),char(97),char(107),char(105),char(110),char(103),char(73),char(109),char(112),char(117),char(108),
+char(115),char(101),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109),char(95),char(105),char(115),char(69),char(110),char(97),char(98),
+char(108),char(101),char(100),char(0),char(112),char(97),char(100),char(100),char(105),char(110),char(103),char(91),char(52),char(93),char(0),char(109),char(95),char(116),char(121),char(112),
+char(101),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(97),char(116),char(97),char(0),char(109),char(95),char(112),char(105),
+char(118),char(111),char(116),char(73),char(110),char(65),char(0),char(109),char(95),char(112),char(105),char(118),char(111),char(116),char(73),char(110),char(66),char(0),char(109),char(95),
+char(114),char(98),char(65),char(70),char(114),char(97),char(109),char(101),char(0),char(109),char(95),char(114),char(98),char(66),char(70),char(114),char(97),char(109),char(101),char(0),
+char(109),char(95),char(117),char(115),char(101),char(82),char(101),char(102),char(101),char(114),char(101),char(110),char(99),char(101),char(70),char(114),char(97),char(109),char(101),char(65),
+char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(79),char(110),char(108),char(121),char(0),char(109),char(95),char(101),char(110),char(97),
+char(98),char(108),char(101),char(65),char(110),char(103),char(117),char(108),char(97),char(114),char(77),char(111),char(116),char(111),char(114),char(0),char(109),char(95),char(109),char(111),
+char(116),char(111),char(114),char(84),char(97),char(114),char(103),char(101),char(116),char(86),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(0),char(109),char(95),
+char(109),char(97),char(120),char(77),char(111),char(116),char(111),char(114),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(0),char(109),char(95),char(108),char(111),
+char(119),char(101),char(114),char(76),char(105),char(109),char(105),char(116),char(0),char(109),char(95),char(117),char(112),char(112),char(101),char(114),char(76),char(105),char(109),char(105),
+char(116),char(0),char(109),char(95),char(108),char(105),char(109),char(105),char(116),char(83),char(111),char(102),char(116),char(110),char(101),char(115),char(115),char(0),char(109),char(95),
+char(98),char(105),char(97),char(115),char(70),char(97),char(99),char(116),char(111),char(114),char(0),char(109),char(95),char(114),char(101),char(108),char(97),char(120),char(97),char(116),
+char(105),char(111),char(110),char(70),char(97),char(99),char(116),char(111),char(114),char(0),char(109),char(95),char(112),char(97),char(100),char(100),char(105),char(110),char(103),char(49),
+char(91),char(52),char(93),char(0),char(109),char(95),char(115),char(119),char(105),char(110),char(103),char(83),char(112),char(97),char(110),char(49),char(0),char(109),char(95),char(115),
+char(119),char(105),char(110),char(103),char(83),char(112),char(97),char(110),char(50),char(0),char(109),char(95),char(116),char(119),char(105),char(115),char(116),char(83),char(112),char(97),
+char(110),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(85),char(112),char(112),char(101),char(114),char(76),char(105),char(109),char(105),char(116),
+char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(76),char(111),char(119),char(101),char(114),char(76),char(105),char(109),char(105),char(116),char(0),
+char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(85),char(112),char(112),char(101),char(114),char(76),char(105),char(109),char(105),char(116),char(0),
+char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(76),char(111),char(119),char(101),char(114),char(76),char(105),char(109),char(105),char(116),char(0),
+char(109),char(95),char(117),char(115),char(101),char(76),char(105),char(110),char(101),char(97),char(114),char(82),char(101),char(102),char(101),char(114),char(101),char(110),char(99),char(101),
+char(70),char(114),char(97),char(109),char(101),char(65),char(0),char(109),char(95),char(117),char(115),char(101),char(79),char(102),char(102),char(115),char(101),char(116),char(70),char(111),
+char(114),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(70),char(114),char(97),char(109),char(101),char(0),char(109),char(95),char(54),
+char(100),char(111),char(102),char(68),char(97),char(116),char(97),char(0),char(109),char(95),char(115),char(112),char(114),char(105),char(110),char(103),char(69),char(110),char(97),char(98),
+char(108),char(101),char(100),char(91),char(54),char(93),char(0),char(109),char(95),char(101),char(113),char(117),char(105),char(108),char(105),char(98),char(114),char(105),char(117),char(109),
+char(80),char(111),char(105),char(110),char(116),char(91),char(54),char(93),char(0),char(109),char(95),char(115),char(112),char(114),char(105),char(110),char(103),char(83),char(116),char(105),
+char(102),char(102),char(110),char(101),char(115),char(115),char(91),char(54),char(93),char(0),char(109),char(95),char(115),char(112),char(114),char(105),char(110),char(103),char(68),char(97),
+char(109),char(112),char(105),char(110),char(103),char(91),char(54),char(93),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(66),char(111),char(117),
+char(110),char(99),char(101),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83),char(116),char(111),char(112),char(69),char(82),char(80),char(0),
+char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83),char(116),char(111),char(112),char(67),char(70),char(77),char(0),char(109),char(95),char(108),char(105),
+char(110),char(101),char(97),char(114),char(77),char(111),char(116),char(111),char(114),char(69),char(82),char(80),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),
+char(114),char(77),char(111),char(116),char(111),char(114),char(67),char(70),char(77),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(84),char(97),
+char(114),char(103),char(101),char(116),char(86),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),
+char(114),char(77),char(97),char(120),char(77),char(111),char(116),char(111),char(114),char(70),char(111),char(114),char(99),char(101),char(0),char(109),char(95),char(108),char(105),char(110),
+char(101),char(97),char(114),char(83),char(101),char(114),char(118),char(111),char(84),char(97),char(114),char(103),char(101),char(116),char(0),char(109),char(95),char(108),char(105),char(110),
+char(101),char(97),char(114),char(83),char(112),char(114),char(105),char(110),char(103),char(83),char(116),char(105),char(102),char(102),char(110),char(101),char(115),char(115),char(0),char(109),
+char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83),char(112),char(114),char(105),char(110),char(103),char(68),char(97),char(109),char(112),char(105),char(110),char(103),
+char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(69),char(113),char(117),char(105),char(108),char(105),char(98),char(114),char(105),char(117),char(109),
+char(80),char(111),char(105),char(110),char(116),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(69),char(110),char(97),char(98),char(108),char(101),
+char(77),char(111),char(116),char(111),char(114),char(91),char(52),char(93),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83),char(101),char(114),
+char(118),char(111),char(77),char(111),char(116),char(111),char(114),char(91),char(52),char(93),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(69),
+char(110),char(97),char(98),char(108),char(101),char(83),char(112),char(114),char(105),char(110),char(103),char(91),char(52),char(93),char(0),char(109),char(95),char(108),char(105),char(110),
+char(101),char(97),char(114),char(83),char(112),char(114),char(105),char(110),char(103),char(83),char(116),char(105),char(102),char(102),char(110),char(101),char(115),char(115),char(76),char(105),
+char(109),char(105),char(116),char(101),char(100),char(91),char(52),char(93),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83),char(112),char(114),
+char(105),char(110),char(103),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(76),char(105),char(109),char(105),char(116),char(101),char(100),char(91),char(52),char(93),
+char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(66),char(111),char(117),char(110),char(99),char(101),char(0),char(109),char(95),char(97),
+char(110),char(103),char(117),char(108),char(97),char(114),char(83),char(116),char(111),char(112),char(69),char(82),char(80),char(0),char(109),char(95),char(97),char(110),char(103),char(117),
+char(108),char(97),char(114),char(83),char(116),char(111),char(112),char(67),char(70),char(77),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),
+char(77),char(111),char(116),char(111),char(114),char(69),char(82),char(80),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(77),char(111),
+char(116),char(111),char(114),char(67),char(70),char(77),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(84),char(97),char(114),char(103),
+char(101),char(116),char(86),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),
+char(77),char(97),char(120),char(77),char(111),char(116),char(111),char(114),char(70),char(111),char(114),char(99),char(101),char(0),char(109),char(95),char(97),char(110),char(103),char(117),
+char(108),char(97),char(114),char(83),char(101),char(114),char(118),char(111),char(84),char(97),char(114),char(103),char(101),char(116),char(0),char(109),char(95),char(97),char(110),char(103),
+char(117),char(108),char(97),char(114),char(83),char(112),char(114),char(105),char(110),char(103),char(83),char(116),char(105),char(102),char(102),char(110),char(101),char(115),char(115),char(0),
+char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(83),char(112),char(114),char(105),char(110),char(103),char(68),char(97),char(109),char(112),char(105),
+char(110),char(103),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(69),char(113),char(117),char(105),char(108),char(105),char(98),char(114),
+char(105),char(117),char(109),char(80),char(111),char(105),char(110),char(116),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(69),char(110),
+char(97),char(98),char(108),char(101),char(77),char(111),char(116),char(111),char(114),char(91),char(52),char(93),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),
+char(97),char(114),char(83),char(101),char(114),char(118),char(111),char(77),char(111),char(116),char(111),char(114),char(91),char(52),char(93),char(0),char(109),char(95),char(97),char(110),
+char(103),char(117),char(108),char(97),char(114),char(69),char(110),char(97),char(98),char(108),char(101),char(83),char(112),char(114),char(105),char(110),char(103),char(91),char(52),char(93),
+char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(83),char(112),char(114),char(105),char(110),char(103),char(83),char(116),char(105),char(102),
+char(102),char(110),char(101),char(115),char(115),char(76),char(105),char(109),char(105),char(116),char(101),char(100),char(91),char(52),char(93),char(0),char(109),char(95),char(97),char(110),
+char(103),char(117),char(108),char(97),char(114),char(83),char(112),char(114),char(105),char(110),char(103),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(76),char(105),
+char(109),char(105),char(116),char(101),char(100),char(91),char(52),char(93),char(0),char(109),char(95),char(114),char(111),char(116),char(97),char(116),char(101),char(79),char(114),char(100),
+char(101),char(114),char(0),char(109),char(95),char(97),char(120),char(105),char(115),char(73),char(110),char(65),char(0),char(109),char(95),char(97),char(120),char(105),char(115),char(73),
+char(110),char(66),char(0),char(109),char(95),char(114),char(97),char(116),char(105),char(111),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83),
+char(116),char(105),char(102),char(102),char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(83),char(116),
+char(105),char(102),char(102),char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(118),char(111),char(108),char(117),char(109),char(101),char(83),char(116),char(105),char(102),
+char(102),char(110),char(101),char(115),char(115),char(0),char(42),char(109),char(95),char(109),char(97),char(116),char(101),char(114),char(105),char(97),char(108),char(0),char(109),char(95),
+char(112),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(112),char(114),char(101),char(118),char(105),char(111),char(117),char(115),char(80),
+char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(118),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(0),char(109),
+char(95),char(97),char(99),char(99),char(117),char(109),char(117),char(108),char(97),char(116),char(101),char(100),char(70),char(111),char(114),char(99),char(101),char(0),char(109),char(95),
+char(110),char(111),char(114),char(109),char(97),char(108),char(0),char(109),char(95),char(97),char(114),char(101),char(97),char(0),char(109),char(95),char(97),char(116),char(116),char(97),
+char(99),char(104),char(0),char(109),char(95),char(110),char(111),char(100),char(101),char(73),char(110),char(100),char(105),char(99),char(101),char(115),char(91),char(50),char(93),char(0),
+char(109),char(95),char(114),char(101),char(115),char(116),char(76),char(101),char(110),char(103),char(116),char(104),char(0),char(109),char(95),char(98),char(98),char(101),char(110),char(100),
+char(105),char(110),char(103),char(0),char(109),char(95),char(110),char(111),char(100),char(101),char(73),char(110),char(100),char(105),char(99),char(101),char(115),char(91),char(51),char(93),
+char(0),char(109),char(95),char(114),char(101),char(115),char(116),char(65),char(114),char(101),char(97),char(0),char(109),char(95),char(99),char(48),char(91),char(52),char(93),char(0),
+char(109),char(95),char(110),char(111),char(100),char(101),char(73),char(110),char(100),char(105),char(99),char(101),char(115),char(91),char(52),char(93),char(0),char(109),char(95),char(114),
+char(101),char(115),char(116),char(86),char(111),char(108),char(117),char(109),char(101),char(0),char(109),char(95),char(99),char(49),char(0),char(109),char(95),char(99),char(50),char(0),
+char(109),char(95),char(99),char(48),char(0),char(109),char(95),char(108),char(111),char(99),char(97),char(108),char(70),char(114),char(97),char(109),char(101),char(0),char(42),char(109),
+char(95),char(114),char(105),char(103),char(105),char(100),char(66),char(111),char(100),char(121),char(0),char(109),char(95),char(110),char(111),char(100),char(101),char(73),char(110),char(100),
+char(101),char(120),char(0),char(109),char(95),char(97),char(101),char(114),char(111),char(77),char(111),char(100),char(101),char(108),char(0),char(109),char(95),char(98),char(97),char(117),
+char(109),char(103),char(97),char(114),char(116),char(101),char(0),char(109),char(95),char(100),char(114),char(97),char(103),char(0),char(109),char(95),char(108),char(105),char(102),char(116),
+char(0),char(109),char(95),char(112),char(114),char(101),char(115),char(115),char(117),char(114),char(101),char(0),char(109),char(95),char(118),char(111),char(108),char(117),char(109),char(101),
+char(0),char(109),char(95),char(100),char(121),char(110),char(97),char(109),char(105),char(99),char(70),char(114),char(105),char(99),char(116),char(105),char(111),char(110),char(0),char(109),
+char(95),char(112),char(111),char(115),char(101),char(77),char(97),char(116),char(99),char(104),char(0),char(109),char(95),char(114),char(105),char(103),char(105),char(100),char(67),char(111),
+char(110),char(116),char(97),char(99),char(116),char(72),char(97),char(114),char(100),char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(107),char(105),char(110),char(101),
+char(116),char(105),char(99),char(67),char(111),char(110),char(116),char(97),char(99),char(116),char(72),char(97),char(114),char(100),char(110),char(101),char(115),char(115),char(0),char(109),
+char(95),char(115),char(111),char(102),char(116),char(67),char(111),char(110),char(116),char(97),char(99),char(116),char(72),char(97),char(114),char(100),char(110),char(101),char(115),char(115),
+char(0),char(109),char(95),char(97),char(110),char(99),char(104),char(111),char(114),char(72),char(97),char(114),char(100),char(110),char(101),char(115),char(115),char(0),char(109),char(95),
+char(115),char(111),char(102),char(116),char(82),char(105),char(103),char(105),char(100),char(67),char(108),char(117),char(115),char(116),char(101),char(114),char(72),char(97),char(114),char(100),
+char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(115),char(111),char(102),char(116),char(75),char(105),char(110),char(101),char(116),char(105),char(99),char(67),char(108),
+char(117),char(115),char(116),char(101),char(114),char(72),char(97),char(114),char(100),char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(115),char(111),char(102),char(116),
+char(83),char(111),char(102),char(116),char(67),char(108),char(117),char(115),char(116),char(101),char(114),char(72),char(97),char(114),char(100),char(110),char(101),char(115),char(115),char(0),
+char(109),char(95),char(115),char(111),char(102),char(116),char(82),char(105),char(103),char(105),char(100),char(67),char(108),char(117),char(115),char(116),char(101),char(114),char(73),char(109),
+char(112),char(117),char(108),char(115),char(101),char(83),char(112),char(108),char(105),char(116),char(0),char(109),char(95),char(115),char(111),char(102),char(116),char(75),char(105),char(110),
+char(101),char(116),char(105),char(99),char(67),char(108),char(117),char(115),char(116),char(101),char(114),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(83),char(112),
+char(108),char(105),char(116),char(0),char(109),char(95),char(115),char(111),char(102),char(116),char(83),char(111),char(102),char(116),char(67),char(108),char(117),char(115),char(116),char(101),
+char(114),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(83),char(112),char(108),char(105),char(116),char(0),char(109),char(95),char(109),char(97),char(120),char(86),
+char(111),char(108),char(117),char(109),char(101),char(0),char(109),char(95),char(116),char(105),char(109),char(101),char(83),char(99),char(97),char(108),char(101),char(0),char(109),char(95),
+char(118),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(73),char(116),char(101),char(114),char(97),char(116),char(105),char(111),char(110),char(115),char(0),char(109),
+char(95),char(112),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(73),char(116),char(101),char(114),char(97),char(116),char(105),char(111),char(110),char(115),char(0),
+char(109),char(95),char(100),char(114),char(105),char(102),char(116),char(73),char(116),char(101),char(114),char(97),char(116),char(105),char(111),char(110),char(115),char(0),char(109),char(95),
+char(99),char(108),char(117),char(115),char(116),char(101),char(114),char(73),char(116),char(101),char(114),char(97),char(116),char(105),char(111),char(110),char(115),char(0),char(109),char(95),
+char(114),char(111),char(116),char(0),char(109),char(95),char(115),char(99),char(97),char(108),char(101),char(0),char(109),char(95),char(97),char(113),char(113),char(0),char(109),char(95),
+char(99),char(111),char(109),char(0),char(42),char(109),char(95),char(112),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(115),char(0),char(42),char(109),char(95),
+char(119),char(101),char(105),char(103),char(104),char(116),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(80),char(111),char(115),char(105),char(116),char(105),char(111),
+char(110),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(87),char(101),char(105),char(103),char(116),char(115),char(0),char(109),char(95),char(98),char(118),char(111),
+char(108),char(117),char(109),char(101),char(0),char(109),char(95),char(98),char(102),char(114),char(97),char(109),char(101),char(0),char(109),char(95),char(102),char(114),char(97),char(109),
+char(101),char(120),char(102),char(111),char(114),char(109),char(0),char(109),char(95),char(108),char(111),char(99),char(105),char(105),char(0),char(109),char(95),char(105),char(110),char(118),
+char(119),char(105),char(0),char(109),char(95),char(118),char(105),char(109),char(112),char(117),char(108),char(115),char(101),char(115),char(91),char(50),char(93),char(0),char(109),char(95),
+char(100),char(105),char(109),char(112),char(117),char(108),char(115),char(101),char(115),char(91),char(50),char(93),char(0),char(109),char(95),char(108),char(118),char(0),char(109),char(95),
+char(97),char(118),char(0),char(42),char(109),char(95),char(102),char(114),char(97),char(109),char(101),char(114),char(101),char(102),char(115),char(0),char(42),char(109),char(95),char(110),
+char(111),char(100),char(101),char(73),char(110),char(100),char(105),char(99),char(101),char(115),char(0),char(42),char(109),char(95),char(109),char(97),char(115),char(115),char(101),char(115),
+char(0),char(109),char(95),char(110),char(117),char(109),char(70),char(114),char(97),char(109),char(101),char(82),char(101),char(102),char(115),char(0),char(109),char(95),char(110),char(117),
+char(109),char(78),char(111),char(100),char(101),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(77),char(97),char(115),char(115),char(101),char(115),char(0),char(109),
+char(95),char(105),char(100),char(109),char(97),char(115),char(115),char(0),char(109),char(95),char(105),char(109),char(97),char(115),char(115),char(0),char(109),char(95),char(110),char(118),
+char(105),char(109),char(112),char(117),char(108),char(115),char(101),char(115),char(0),char(109),char(95),char(110),char(100),char(105),char(109),char(112),char(117),char(108),char(115),char(101),
+char(115),char(0),char(109),char(95),char(110),char(100),char(97),char(109),char(112),char(105),char(110),char(103),char(0),char(109),char(95),char(108),char(100),char(97),char(109),char(112),
+char(105),char(110),char(103),char(0),char(109),char(95),char(97),char(100),char(97),char(109),char(112),char(105),char(110),char(103),char(0),char(109),char(95),char(109),char(97),char(116),
+char(99),char(104),char(105),char(110),char(103),char(0),char(109),char(95),char(109),char(97),char(120),char(83),char(101),char(108),char(102),char(67),char(111),char(108),char(108),char(105),
+char(115),char(105),char(111),char(110),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(0),char(109),char(95),char(115),char(101),char(108),char(102),char(67),char(111),
+char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(70),char(97),char(99),char(116),char(111),char(114),
+char(0),char(109),char(95),char(99),char(111),char(110),char(116),char(97),char(105),char(110),char(115),char(65),char(110),char(99),char(104),char(111),char(114),char(0),char(109),char(95),
+char(99),char(111),char(108),char(108),char(105),char(100),char(101),char(0),char(109),char(95),char(99),char(108),char(117),char(115),char(116),char(101),char(114),char(73),char(110),char(100),
+char(101),char(120),char(0),char(42),char(109),char(95),char(98),char(111),char(100),char(121),char(65),char(0),char(42),char(109),char(95),char(98),char(111),char(100),char(121),char(66),
+char(0),char(109),char(95),char(114),char(101),char(102),char(115),char(91),char(50),char(93),char(0),char(109),char(95),char(99),char(102),char(109),char(0),char(109),char(95),char(115),
+char(112),char(108),char(105),char(116),char(0),char(109),char(95),char(100),char(101),char(108),char(101),char(116),char(101),char(0),char(109),char(95),char(114),char(101),char(108),char(80),
+char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(91),char(50),char(93),char(0),char(109),char(95),char(98),char(111),char(100),char(121),char(65),char(116),char(121),
+char(112),char(101),char(0),char(109),char(95),char(98),char(111),char(100),char(121),char(66),char(116),char(121),char(112),char(101),char(0),char(109),char(95),char(106),char(111),char(105),
+char(110),char(116),char(84),char(121),char(112),char(101),char(0),char(42),char(109),char(95),char(112),char(111),char(115),char(101),char(0),char(42),char(42),char(109),char(95),char(109),
+char(97),char(116),char(101),char(114),char(105),char(97),char(108),char(115),char(0),char(42),char(109),char(95),char(110),char(111),char(100),char(101),char(115),char(0),char(42),char(109),
+char(95),char(108),char(105),char(110),char(107),char(115),char(0),char(42),char(109),char(95),char(102),char(97),char(99),char(101),char(115),char(0),char(42),char(109),char(95),char(116),
+char(101),char(116),char(114),char(97),char(104),char(101),char(100),char(114),char(97),char(0),char(42),char(109),char(95),char(97),char(110),char(99),char(104),char(111),char(114),char(115),
+char(0),char(42),char(109),char(95),char(99),char(108),char(117),char(115),char(116),char(101),char(114),char(115),char(0),char(42),char(109),char(95),char(106),char(111),char(105),char(110),
+char(116),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(77),char(97),char(116),char(101),char(114),char(105),char(97),char(108),char(115),char(0),char(109),char(95),
+char(110),char(117),char(109),char(76),char(105),char(110),char(107),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(70),char(97),char(99),char(101),char(115),char(0),
+char(109),char(95),char(110),char(117),char(109),char(84),char(101),char(116),char(114),char(97),char(104),char(101),char(100),char(114),char(97),char(0),char(109),char(95),char(110),char(117),
+char(109),char(65),char(110),char(99),char(104),char(111),char(114),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(67),char(108),char(117),char(115),char(116),char(101),
+char(114),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(74),char(111),char(105),char(110),char(116),char(115),char(0),char(109),char(95),char(99),char(111),char(110),
+char(102),char(105),char(103),char(0),char(109),char(95),char(122),char(101),char(114),char(111),char(82),char(111),char(116),char(80),char(97),char(114),char(101),char(110),char(116),char(84),
+char(111),char(84),char(104),char(105),char(115),char(0),char(109),char(95),char(112),char(97),char(114),char(101),char(110),char(116),char(67),char(111),char(109),char(84),char(111),char(84),
+char(104),char(105),char(115),char(80),char(105),char(118),char(111),char(116),char(79),char(102),char(102),char(115),char(101),char(116),char(0),char(109),char(95),char(116),char(104),char(105),
+char(115),char(80),char(105),char(118),char(111),char(116),char(84),char(111),char(84),char(104),char(105),char(115),char(67),char(111),char(109),char(79),char(102),char(102),char(115),char(101),
+char(116),char(0),char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(65),char(120),char(105),char(115),char(84),char(111),char(112),char(91),char(54),char(93),char(0),
+char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(65),char(120),char(105),char(115),char(66),char(111),char(116),char(116),char(111),char(109),char(91),char(54),char(93),
+char(0),char(109),char(95),char(108),char(105),char(110),char(107),char(73),char(110),char(101),char(114),char(116),char(105),char(97),char(0),char(109),char(95),char(97),char(98),char(115),
+char(70),char(114),char(97),char(109),char(101),char(84),char(111),char(116),char(86),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(84),char(111),char(112),char(0),
+char(109),char(95),char(97),char(98),char(115),char(70),char(114),char(97),char(109),char(101),char(84),char(111),char(116),char(86),char(101),char(108),char(111),char(99),char(105),char(116),
+char(121),char(66),char(111),char(116),char(116),char(111),char(109),char(0),char(109),char(95),char(97),char(98),char(115),char(70),char(114),char(97),char(109),char(101),char(76),char(111),
+char(99),char(86),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(84),char(111),char(112),char(0),char(109),char(95),char(97),char(98),char(115),char(70),char(114),
+char(97),char(109),char(101),char(76),char(111),char(99),char(86),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(66),char(111),char(116),char(116),char(111),char(109),
+char(0),char(109),char(95),char(108),char(105),char(110),char(107),char(77),char(97),char(115),char(115),char(0),char(109),char(95),char(112),char(97),char(114),char(101),char(110),char(116),
+char(73),char(110),char(100),char(101),char(120),char(0),char(109),char(95),char(100),char(111),char(102),char(67),char(111),char(117),char(110),char(116),char(0),char(109),char(95),char(112),
+char(111),char(115),char(86),char(97),char(114),char(67),char(111),char(117),char(110),char(116),char(0),char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(80),char(111),
+char(115),char(91),char(55),char(93),char(0),char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(86),char(101),char(108),char(91),char(54),char(93),char(0),char(109),
+char(95),char(106),char(111),char(105),char(110),char(116),char(84),char(111),char(114),char(113),char(117),char(101),char(91),char(54),char(93),char(0),char(109),char(95),char(106),char(111),
+char(105),char(110),char(116),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(0),char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(70),char(114),
+char(105),char(99),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(76),char(111),char(119),char(101),char(114),char(76),
+char(105),char(109),char(105),char(116),char(0),char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(85),char(112),char(112),char(101),char(114),char(76),char(105),char(109),
+char(105),char(116),char(0),char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(77),char(97),char(120),char(70),char(111),char(114),char(99),char(101),char(0),char(109),
+char(95),char(106),char(111),char(105),char(110),char(116),char(77),char(97),char(120),char(86),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(0),char(42),char(109),
+char(95),char(108),char(105),char(110),char(107),char(78),char(97),char(109),char(101),char(0),char(42),char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(78),char(97),
+char(109),char(101),char(0),char(42),char(109),char(95),char(108),char(105),char(110),char(107),char(67),char(111),char(108),char(108),char(105),char(100),char(101),char(114),char(0),char(42),
+char(109),char(95),char(112),char(97),char(100),char(100),char(105),char(110),char(103),char(80),char(116),char(114),char(0),char(109),char(95),char(98),char(97),char(115),char(101),char(87),
+char(111),char(114),char(108),char(100),char(80),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(98),char(97),char(115),char(101),char(87),
+char(111),char(114),char(108),char(100),char(79),char(114),char(105),char(101),char(110),char(116),char(97),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(98),char(97),
+char(115),char(101),char(76),char(105),char(110),char(101),char(97),char(114),char(86),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(0),char(109),char(95),char(98),
+char(97),char(115),char(101),char(65),char(110),char(103),char(117),char(108),char(97),char(114),char(86),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(0),char(109),
+char(95),char(98),char(97),char(115),char(101),char(73),char(110),char(101),char(114),char(116),char(105),char(97),char(0),char(109),char(95),char(98),char(97),char(115),char(101),char(77),
+char(97),char(115),char(115),char(0),char(42),char(109),char(95),char(98),char(97),char(115),char(101),char(78),char(97),char(109),char(101),char(0),char(42),char(109),char(95),char(98),
+char(97),char(115),char(101),char(67),char(111),char(108),char(108),char(105),char(100),char(101),char(114),char(0),char(109),char(95),char(99),char(111),char(108),char(79),char(98),char(106),
+char(68),char(97),char(116),char(97),char(0),char(42),char(109),char(95),char(109),char(117),char(108),char(116),char(105),char(66),char(111),char(100),char(121),char(0),char(109),char(95),
+char(108),char(105),char(110),char(107),char(0),char(0),char(0),char(0),char(84),char(89),char(80),char(69),char(99),char(0),char(0),char(0),char(99),char(104),char(97),char(114),
+char(0),char(117),char(99),char(104),char(97),char(114),char(0),char(115),char(104),char(111),char(114),char(116),char(0),char(117),char(115),char(104),char(111),char(114),char(116),char(0),
+char(105),char(110),char(116),char(0),char(108),char(111),char(110),char(103),char(0),char(117),char(108),char(111),char(110),char(103),char(0),char(102),char(108),char(111),char(97),char(116),
+char(0),char(100),char(111),char(117),char(98),char(108),char(101),char(0),char(118),char(111),char(105),char(100),char(0),char(80),char(111),char(105),char(110),char(116),char(101),char(114),
+char(65),char(114),char(114),char(97),char(121),char(0),char(98),char(116),char(80),char(104),char(121),char(115),char(105),char(99),char(115),char(83),char(121),char(115),char(116),char(101),
+char(109),char(0),char(76),char(105),char(115),char(116),char(66),char(97),char(115),char(101),char(0),char(98),char(116),char(86),char(101),char(99),char(116),char(111),char(114),char(51),
+char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(86),char(101),char(99),char(116),char(111),char(114),char(51),char(68),
+char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(81),char(117),char(97),char(116),char(101),char(114),char(110),char(105),
+char(111),char(110),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(81),char(117),char(97),char(116),char(101),char(114),
+char(110),char(105),char(111),char(110),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(77),char(97),char(116),
+char(114),char(105),char(120),char(51),char(120),char(51),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(77),char(97),
+char(116),char(114),char(105),char(120),char(51),char(120),char(51),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),
+char(84),char(114),char(97),char(110),char(115),char(102),char(111),char(114),char(109),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),
+char(116),char(84),char(114),char(97),char(110),char(115),char(102),char(111),char(114),char(109),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),
+char(0),char(98),char(116),char(66),char(118),char(104),char(83),char(117),char(98),char(116),char(114),char(101),char(101),char(73),char(110),char(102),char(111),char(68),char(97),char(116),
char(97),char(0),char(98),char(116),char(79),char(112),char(116),char(105),char(109),char(105),char(122),char(101),char(100),char(66),char(118),char(104),char(78),char(111),char(100),char(101),
-char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(81),char(117),char(97),char(110),char(116),char(105),char(122),
-char(101),char(100),char(66),char(118),char(104),char(78),char(111),char(100),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(81),char(117),char(97),char(110),
-char(116),char(105),char(122),char(101),char(100),char(66),char(118),char(104),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),
-char(81),char(117),char(97),char(110),char(116),char(105),char(122),char(101),char(100),char(66),char(118),char(104),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),
-char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(83),char(104),char(97),char(112),char(101),char(68),
-char(97),char(116),char(97),char(0),char(98),char(116),char(83),char(116),char(97),char(116),char(105),char(99),char(80),char(108),char(97),char(110),char(101),char(83),char(104),char(97),
-char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(110),char(118),char(101),char(120),char(73),char(110),char(116),char(101),char(114),
-char(110),char(97),char(108),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(80),char(111),char(115),char(105),char(116),
-char(105),char(111),char(110),char(65),char(110),char(100),char(82),char(97),char(100),char(105),char(117),char(115),char(0),char(98),char(116),char(77),char(117),char(108),char(116),char(105),
-char(83),char(112),char(104),char(101),char(114),char(101),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(73),char(110),
-char(116),char(73),char(110),char(100),char(101),char(120),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(83),char(104),char(111),char(114),char(116),char(73),char(110),
-char(116),char(73),char(110),char(100),char(101),char(120),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(83),char(104),char(111),char(114),char(116),char(73),char(110),
-char(116),char(73),char(110),char(100),char(101),char(120),char(84),char(114),char(105),char(112),char(108),char(101),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),
-char(67),char(104),char(97),char(114),char(73),char(110),char(100),char(101),char(120),char(84),char(114),char(105),char(112),char(108),char(101),char(116),char(68),char(97),char(116),char(97),
-char(0),char(98),char(116),char(77),char(101),char(115),char(104),char(80),char(97),char(114),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(83),char(116),
-char(114),char(105),char(100),char(105),char(110),char(103),char(77),char(101),char(115),char(104),char(73),char(110),char(116),char(101),char(114),char(102),char(97),char(99),char(101),char(68),
-char(97),char(116),char(97),char(0),char(98),char(116),char(84),char(114),char(105),char(97),char(110),char(103),char(108),char(101),char(77),char(101),char(115),char(104),char(83),char(104),
+char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(79),char(112),char(116),char(105),char(109),char(105),char(122),char(101),
+char(100),char(66),char(118),char(104),char(78),char(111),char(100),char(101),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),
+char(116),char(81),char(117),char(97),char(110),char(116),char(105),char(122),char(101),char(100),char(66),char(118),char(104),char(78),char(111),char(100),char(101),char(68),char(97),char(116),
+char(97),char(0),char(98),char(116),char(81),char(117),char(97),char(110),char(116),char(105),char(122),char(101),char(100),char(66),char(118),char(104),char(70),char(108),char(111),char(97),
+char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(81),char(117),char(97),char(110),char(116),char(105),char(122),char(101),char(100),char(66),char(118),char(104),
+char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(108),char(108),char(105),char(115),char(105),
+char(111),char(110),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(83),char(116),char(97),char(116),char(105),char(99),
+char(80),char(108),char(97),char(110),char(101),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(110),
+char(118),char(101),char(120),char(73),char(110),char(116),char(101),char(114),char(110),char(97),char(108),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),
+char(0),char(98),char(116),char(80),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(65),char(110),char(100),char(82),char(97),char(100),char(105),char(117),char(115),
+char(0),char(98),char(116),char(77),char(117),char(108),char(116),char(105),char(83),char(112),char(104),char(101),char(114),char(101),char(83),char(104),char(97),char(112),char(101),char(68),
+char(97),char(116),char(97),char(0),char(98),char(116),char(73),char(110),char(116),char(73),char(110),char(100),char(101),char(120),char(68),char(97),char(116),char(97),char(0),char(98),
+char(116),char(83),char(104),char(111),char(114),char(116),char(73),char(110),char(116),char(73),char(110),char(100),char(101),char(120),char(68),char(97),char(116),char(97),char(0),char(98),
+char(116),char(83),char(104),char(111),char(114),char(116),char(73),char(110),char(116),char(73),char(110),char(100),char(101),char(120),char(84),char(114),char(105),char(112),char(108),char(101),
+char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(104),char(97),char(114),char(73),char(110),char(100),char(101),char(120),char(84),char(114),char(105),
+char(112),char(108),char(101),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(77),char(101),char(115),char(104),char(80),char(97),char(114),char(116),char(68),
+char(97),char(116),char(97),char(0),char(98),char(116),char(83),char(116),char(114),char(105),char(100),char(105),char(110),char(103),char(77),char(101),char(115),char(104),char(73),char(110),
+char(116),char(101),char(114),char(102),char(97),char(99),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(84),char(114),char(105),char(97),char(110),char(103),
+char(108),char(101),char(77),char(101),char(115),char(104),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(84),char(114),
+char(105),char(97),char(110),char(103),char(108),char(101),char(73),char(110),char(102),char(111),char(77),char(97),char(112),char(68),char(97),char(116),char(97),char(0),char(98),char(116),
+char(83),char(99),char(97),char(108),char(101),char(100),char(84),char(114),char(105),char(97),char(110),char(103),char(108),char(101),char(77),char(101),char(115),char(104),char(83),char(104),
+char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(109),char(112),char(111),char(117),char(110),char(100),char(83),char(104),
+char(97),char(112),char(101),char(67),char(104),char(105),char(108),char(100),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(109),char(112),char(111),
+char(117),char(110),char(100),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(121),char(108),char(105),char(110),
+char(100),char(101),char(114),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(110),char(101),char(83),
+char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(97),char(112),char(115),char(117),char(108),char(101),char(83),char(104),
char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(84),char(114),char(105),char(97),char(110),char(103),char(108),char(101),char(73),char(110),
-char(102),char(111),char(77),char(97),char(112),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(83),char(99),char(97),char(108),char(101),char(100),char(84),char(114),
-char(105),char(97),char(110),char(103),char(108),char(101),char(77),char(101),char(115),char(104),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),
-char(98),char(116),char(67),char(111),char(109),char(112),char(111),char(117),char(110),char(100),char(83),char(104),char(97),char(112),char(101),char(67),char(104),char(105),char(108),char(100),
-char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(109),char(112),char(111),char(117),char(110),char(100),char(83),char(104),char(97),char(112),char(101),
-char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(121),char(108),char(105),char(110),char(100),char(101),char(114),char(83),char(104),char(97),char(112),char(101),
-char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(110),char(101),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),
-char(0),char(98),char(116),char(67),char(97),char(112),char(115),char(117),char(108),char(101),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),
-char(98),char(116),char(84),char(114),char(105),char(97),char(110),char(103),char(108),char(101),char(73),char(110),char(102),char(111),char(68),char(97),char(116),char(97),char(0),char(98),
-char(116),char(71),char(73),char(109),char(112),char(97),char(99),char(116),char(77),char(101),char(115),char(104),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),
-char(97),char(0),char(98),char(116),char(67),char(111),char(110),char(118),char(101),char(120),char(72),char(117),char(108),char(108),char(83),char(104),char(97),char(112),char(101),char(68),
-char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(79),char(98),char(106),char(101),char(99),
-char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(108),char(108),char(105),char(115),
-char(105),char(111),char(110),char(79),char(98),char(106),char(101),char(99),char(116),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),
-char(116),char(67),char(111),char(110),char(116),char(97),char(99),char(116),char(83),char(111),char(108),char(118),char(101),char(114),char(73),char(110),char(102),char(111),char(68),char(111),
-char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(110),char(116),char(97),char(99),char(116),char(83),char(111),
-char(108),char(118),char(101),char(114),char(73),char(110),char(102),char(111),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),
-char(68),char(121),char(110),char(97),char(109),char(105),char(99),char(115),char(87),char(111),char(114),char(108),char(100),char(68),char(111),char(117),char(98),char(108),char(101),char(68),
-char(97),char(116),char(97),char(0),char(98),char(116),char(68),char(121),char(110),char(97),char(109),char(105),char(99),char(115),char(87),char(111),char(114),char(108),char(100),char(70),
-char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(82),char(105),char(103),char(105),char(100),char(66),char(111),char(100),char(121),
-char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(82),char(105),char(103),char(105),char(100),char(66),char(111),char(100),
-char(121),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(110),char(115),char(116),char(114),
-char(97),char(105),char(110),char(116),char(73),char(110),char(102),char(111),char(49),char(0),char(98),char(116),char(84),char(121),char(112),char(101),char(100),char(67),char(111),char(110),
-char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(84),
-char(121),char(112),char(101),char(100),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(97),char(116),char(97),char(0),char(98),
-char(116),char(82),char(105),char(103),char(105),char(100),char(66),char(111),char(100),char(121),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(84),char(121),char(112),
-char(101),char(100),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),
-char(116),char(97),char(0),char(98),char(116),char(80),char(111),char(105),char(110),char(116),char(50),char(80),char(111),char(105),char(110),char(116),char(67),char(111),char(110),char(115),
-char(116),char(114),char(97),char(105),char(110),char(116),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(80),char(111),
-char(105),char(110),char(116),char(50),char(80),char(111),char(105),char(110),char(116),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),
-char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(50),char(0),char(98),char(116),char(80),char(111),char(105),char(110),char(116),char(50),char(80),
-char(111),char(105),char(110),char(116),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),
-char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(72),char(105),char(110),char(103),char(101),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),
-char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(72),char(105),char(110),char(103),char(101),
-char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),
-char(98),char(116),char(72),char(105),char(110),char(103),char(101),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111),char(117),
-char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(50),char(0),char(98),char(116),char(67),char(111),char(110),char(101),char(84),char(119),char(105),char(115),char(116),
-char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),
-char(0),char(98),char(116),char(67),char(111),char(110),char(101),char(84),char(119),char(105),char(115),char(116),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),
-char(110),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(71),char(101),char(110),char(101),char(114),char(105),char(99),char(54),char(68),char(111),char(102),
-char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(71),char(101),char(110),
-char(101),char(114),char(105),char(99),char(54),char(68),char(111),char(102),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111),
-char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(50),char(0),char(98),char(116),char(71),char(101),char(110),char(101),char(114),char(105),char(99),char(54),
-char(68),char(111),char(102),char(83),char(112),char(114),char(105),char(110),char(103),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),
-char(97),char(116),char(97),char(0),char(98),char(116),char(71),char(101),char(110),char(101),char(114),char(105),char(99),char(54),char(68),char(111),char(102),char(83),char(112),char(114),
-char(105),char(110),char(103),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),
-char(97),char(116),char(97),char(50),char(0),char(98),char(116),char(71),char(101),char(110),char(101),char(114),char(105),char(99),char(54),char(68),char(111),char(102),char(83),char(112),
-char(114),char(105),char(110),char(103),char(50),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(97),char(116),char(97),char(0),
-char(98),char(116),char(71),char(101),char(110),char(101),char(114),char(105),char(99),char(54),char(68),char(111),char(102),char(83),char(112),char(114),char(105),char(110),char(103),char(50),
-char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),
-char(50),char(0),char(98),char(116),char(83),char(108),char(105),char(100),char(101),char(114),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),
-char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(83),char(108),char(105),char(100),char(101),char(114),char(67),char(111),char(110),char(115),char(116),char(114),char(97),
-char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(71),char(101),char(97),char(114),
-char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),
-char(98),char(116),char(71),char(101),char(97),char(114),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111),char(117),char(98),
-char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(77),char(97),char(116),char(101),char(114),
-char(105),char(97),char(108),char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(78),char(111),char(100),char(101),
-char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(76),char(105),char(110),char(107),char(68),char(97),char(116),
-char(97),char(0),char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(70),char(97),char(99),char(101),char(68),char(97),char(116),char(97),char(0),char(83),
-char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(84),char(101),char(116),char(114),char(97),char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102),
-char(116),char(82),char(105),char(103),char(105),char(100),char(65),char(110),char(99),char(104),char(111),char(114),char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102),
-char(116),char(66),char(111),char(100),char(121),char(67),char(111),char(110),char(102),char(105),char(103),char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102),char(116),
-char(66),char(111),char(100),char(121),char(80),char(111),char(115),char(101),char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102),char(116),char(66),char(111),char(100),
-char(121),char(67),char(108),char(117),char(115),char(116),char(101),char(114),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(83),char(111),char(102),char(116),char(66),
-char(111),char(100),char(121),char(74),char(111),char(105),char(110),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(83),char(111),char(102),char(116),char(66),
-char(111),char(100),char(121),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(77),char(117),char(108),char(116),char(105),
-char(66),char(111),char(100),char(121),char(76),char(105),char(110),char(107),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),
-char(116),char(77),char(117),char(108),char(116),char(105),char(66),char(111),char(100),char(121),char(76),char(105),char(110),char(107),char(70),char(108),char(111),char(97),char(116),char(68),
-char(97),char(116),char(97),char(0),char(98),char(116),char(77),char(117),char(108),char(116),char(105),char(66),char(111),char(100),char(121),char(68),char(111),char(117),char(98),char(108),
-char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(77),char(117),char(108),char(116),char(105),char(66),char(111),char(100),char(121),char(70),char(108),char(111),
-char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(0),char(84),char(76),char(69),char(78),char(1),char(0),char(1),char(0),char(2),char(0),char(2),char(0),
-char(4),char(0),char(4),char(0),char(4),char(0),char(4),char(0),char(8),char(0),char(0),char(0),char(16),char(0),char(48),char(0),char(16),char(0),char(16),char(0),
-char(32),char(0),char(16),char(0),char(32),char(0),char(48),char(0),char(96),char(0),char(64),char(0),char(-128),char(0),char(20),char(0),char(48),char(0),char(80),char(0),
-char(16),char(0),char(96),char(0),char(-112),char(0),char(16),char(0),char(56),char(0),char(56),char(0),char(20),char(0),char(72),char(0),char(4),char(0),char(4),char(0),
-char(8),char(0),char(4),char(0),char(56),char(0),char(32),char(0),char(80),char(0),char(72),char(0),char(96),char(0),char(80),char(0),char(32),char(0),char(64),char(0),
-char(64),char(0),char(64),char(0),char(16),char(0),char(72),char(0),char(80),char(0),char(-16),char(1),char(24),char(1),char(-104),char(0),char(88),char(0),char(-72),char(0),
-char(104),char(0),char(0),char(2),char(-64),char(3),char(8),char(0),char(64),char(0),char(64),char(0),char(0),char(0),char(80),char(0),char(96),char(0),char(-112),char(0),
+char(102),char(111),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(80),char(101),char(114),char(115),char(105),char(115),char(116),char(101),char(110),char(116),char(77),
+char(97),char(110),char(105),char(102),char(111),char(108),char(100),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),
+char(67),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(79),char(98),char(106),char(101),char(99),char(116),char(68),char(111),char(117),char(98),char(108),
+char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(80),char(101),char(114),char(115),char(105),char(115),char(116),char(101),char(110),char(116),char(77),char(97),
+char(110),char(105),char(102),char(111),char(108),char(100),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),
+char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(79),char(98),char(106),char(101),char(99),char(116),char(70),char(108),char(111),char(97),char(116),char(68),char(97),
+char(116),char(97),char(0),char(98),char(116),char(71),char(73),char(109),char(112),char(97),char(99),char(116),char(77),char(101),char(115),char(104),char(83),char(104),char(97),char(112),
+char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(110),char(118),char(101),char(120),char(72),char(117),char(108),char(108),char(83),char(104),
+char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(110),char(116),char(97),char(99),char(116),char(83),char(111),char(108),
+char(118),char(101),char(114),char(73),char(110),char(102),char(111),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),
+char(67),char(111),char(110),char(116),char(97),char(99),char(116),char(83),char(111),char(108),char(118),char(101),char(114),char(73),char(110),char(102),char(111),char(70),char(108),char(111),
+char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(68),char(121),char(110),char(97),char(109),char(105),char(99),char(115),char(87),char(111),char(114),
+char(108),char(100),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(68),char(121),char(110),char(97),char(109),
+char(105),char(99),char(115),char(87),char(111),char(114),char(108),char(100),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),
+char(82),char(105),char(103),char(105),char(100),char(66),char(111),char(100),char(121),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),
+char(116),char(82),char(105),char(103),char(105),char(100),char(66),char(111),char(100),char(121),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),
+char(0),char(98),char(116),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(73),char(110),char(102),char(111),char(49),char(0),char(98),
+char(116),char(84),char(121),char(112),char(101),char(100),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(70),char(108),char(111),char(97),
+char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(84),char(121),char(112),char(101),char(100),char(67),char(111),char(110),char(115),char(116),char(114),char(97),
+char(105),char(110),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(82),char(105),char(103),char(105),char(100),char(66),char(111),char(100),char(121),char(68),
+char(97),char(116),char(97),char(0),char(98),char(116),char(84),char(121),char(112),char(101),char(100),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),
+char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(80),char(111),char(105),char(110),char(116),char(50),
+char(80),char(111),char(105),char(110),char(116),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(70),char(108),char(111),char(97),char(116),
+char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(80),char(111),char(105),char(110),char(116),char(50),char(80),char(111),char(105),char(110),char(116),char(67),char(111),
+char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(50),char(0),
+char(98),char(116),char(80),char(111),char(105),char(110),char(116),char(50),char(80),char(111),char(105),char(110),char(116),char(67),char(111),char(110),char(115),char(116),char(114),char(97),
+char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(72),char(105),char(110),char(103),
+char(101),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),
+char(97),char(0),char(98),char(116),char(72),char(105),char(110),char(103),char(101),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(70),
+char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(72),char(105),char(110),char(103),char(101),char(67),char(111),char(110),char(115),
+char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(50),char(0),char(98),char(116),
+char(67),char(111),char(110),char(101),char(84),char(119),char(105),char(115),char(116),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),
+char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(110),char(101),char(84),char(119),char(105),char(115),
+char(116),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(71),char(101),
+char(110),char(101),char(114),char(105),char(99),char(54),char(68),char(111),char(102),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),
+char(97),char(116),char(97),char(0),char(98),char(116),char(71),char(101),char(110),char(101),char(114),char(105),char(99),char(54),char(68),char(111),char(102),char(67),char(111),char(110),
+char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(50),char(0),char(98),
+char(116),char(71),char(101),char(110),char(101),char(114),char(105),char(99),char(54),char(68),char(111),char(102),char(83),char(112),char(114),char(105),char(110),char(103),char(67),char(111),
+char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(71),char(101),char(110),char(101),char(114),
+char(105),char(99),char(54),char(68),char(111),char(102),char(83),char(112),char(114),char(105),char(110),char(103),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),
+char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(50),char(0),char(98),char(116),char(71),char(101),char(110),char(101),
+char(114),char(105),char(99),char(54),char(68),char(111),char(102),char(83),char(112),char(114),char(105),char(110),char(103),char(50),char(67),char(111),char(110),char(115),char(116),char(114),
+char(97),char(105),char(110),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(71),char(101),char(110),char(101),char(114),char(105),char(99),char(54),char(68),
+char(111),char(102),char(83),char(112),char(114),char(105),char(110),char(103),char(50),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),
+char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(50),char(0),char(98),char(116),char(83),char(108),char(105),char(100),char(101),char(114),char(67),
+char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(83),char(108),char(105),char(100),
+char(101),char(114),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),
+char(116),char(97),char(0),char(98),char(116),char(71),char(101),char(97),char(114),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(70),
+char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(71),char(101),char(97),char(114),char(67),char(111),char(110),char(115),char(116),
+char(114),char(97),char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102),char(116),
+char(66),char(111),char(100),char(121),char(77),char(97),char(116),char(101),char(114),char(105),char(97),char(108),char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102),
+char(116),char(66),char(111),char(100),char(121),char(78),char(111),char(100),char(101),char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102),char(116),char(66),char(111),
+char(100),char(121),char(76),char(105),char(110),char(107),char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(70),
+char(97),char(99),char(101),char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(84),char(101),char(116),char(114),
+char(97),char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102),char(116),char(82),char(105),char(103),char(105),char(100),char(65),char(110),char(99),char(104),char(111),
+char(114),char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(67),char(111),char(110),char(102),char(105),char(103),
+char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(80),char(111),char(115),char(101),char(68),char(97),char(116),
+char(97),char(0),char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(67),char(108),char(117),char(115),char(116),char(101),char(114),char(68),char(97),char(116),
+char(97),char(0),char(98),char(116),char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(74),char(111),char(105),char(110),char(116),char(68),char(97),char(116),
+char(97),char(0),char(98),char(116),char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),
+char(97),char(0),char(98),char(116),char(77),char(117),char(108),char(116),char(105),char(66),char(111),char(100),char(121),char(76),char(105),char(110),char(107),char(68),char(111),char(117),
+char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(77),char(117),char(108),char(116),char(105),char(66),char(111),char(100),char(121),char(76),
+char(105),char(110),char(107),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(77),char(117),char(108),char(116),char(105),
+char(66),char(111),char(100),char(121),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(77),char(117),char(108),
+char(116),char(105),char(66),char(111),char(100),char(121),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(77),char(117),
+char(108),char(116),char(105),char(66),char(111),char(100),char(121),char(76),char(105),char(110),char(107),char(67),char(111),char(108),char(108),char(105),char(100),char(101),char(114),char(70),
+char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(77),char(117),char(108),char(116),char(105),char(66),char(111),char(100),char(121),
+char(76),char(105),char(110),char(107),char(67),char(111),char(108),char(108),char(105),char(100),char(101),char(114),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),
+char(116),char(97),char(0),char(0),char(84),char(76),char(69),char(78),char(1),char(0),char(1),char(0),char(2),char(0),char(2),char(0),char(4),char(0),char(4),char(0),
+char(4),char(0),char(4),char(0),char(8),char(0),char(0),char(0),char(16),char(0),char(48),char(0),char(16),char(0),char(16),char(0),char(32),char(0),char(16),char(0),
+char(32),char(0),char(48),char(0),char(96),char(0),char(64),char(0),char(-128),char(0),char(20),char(0),char(48),char(0),char(80),char(0),char(16),char(0),char(96),char(0),
+char(-112),char(0),char(16),char(0),char(56),char(0),char(56),char(0),char(20),char(0),char(72),char(0),char(4),char(0),char(4),char(0),char(8),char(0),char(4),char(0),
+char(56),char(0),char(32),char(0),char(80),char(0),char(72),char(0),char(96),char(0),char(80),char(0),char(32),char(0),char(64),char(0),char(64),char(0),char(64),char(0),
+char(16),char(0),char(-8),char(5),char(-8),char(1),char(64),char(3),char(32),char(1),char(72),char(0),char(80),char(0),char(-104),char(0),char(88),char(0),char(-72),char(0),
+char(104),char(0),char(8),char(2),char(-56),char(3),char(8),char(0),char(64),char(0),char(64),char(0),char(0),char(0),char(80),char(0),char(96),char(0),char(-112),char(0),
char(-128),char(0),char(104),char(1),char(-24),char(0),char(-104),char(1),char(-120),char(1),char(-32),char(0),char(8),char(1),char(-40),char(1),char(104),char(1),char(-128),char(2),
char(-112),char(2),char(-64),char(4),char(-40),char(0),char(120),char(1),char(104),char(0),char(-104),char(0),char(16),char(0),char(104),char(0),char(24),char(0),char(40),char(0),
-char(104),char(0),char(96),char(0),char(104),char(0),char(-56),char(0),char(104),char(1),char(112),char(0),char(-24),char(1),char(0),char(3),char(-104),char(1),char(-48),char(0),
-char(112),char(0),char(0),char(0),char(83),char(84),char(82),char(67),char(84),char(0),char(0),char(0),char(10),char(0),char(3),char(0),char(4),char(0),char(0),char(0),
-char(4),char(0),char(1),char(0),char(9),char(0),char(2),char(0),char(11),char(0),char(3),char(0),char(10),char(0),char(3),char(0),char(10),char(0),char(4),char(0),
-char(10),char(0),char(5),char(0),char(12),char(0),char(2),char(0),char(9),char(0),char(6),char(0),char(9),char(0),char(7),char(0),char(13),char(0),char(1),char(0),
-char(7),char(0),char(8),char(0),char(14),char(0),char(1),char(0),char(8),char(0),char(8),char(0),char(15),char(0),char(1),char(0),char(7),char(0),char(8),char(0),
-char(16),char(0),char(1),char(0),char(8),char(0),char(8),char(0),char(17),char(0),char(1),char(0),char(13),char(0),char(9),char(0),char(18),char(0),char(1),char(0),
-char(14),char(0),char(9),char(0),char(19),char(0),char(2),char(0),char(17),char(0),char(10),char(0),char(13),char(0),char(11),char(0),char(20),char(0),char(2),char(0),
-char(18),char(0),char(10),char(0),char(14),char(0),char(11),char(0),char(21),char(0),char(4),char(0),char(4),char(0),char(12),char(0),char(4),char(0),char(13),char(0),
-char(2),char(0),char(14),char(0),char(2),char(0),char(15),char(0),char(22),char(0),char(6),char(0),char(13),char(0),char(16),char(0),char(13),char(0),char(17),char(0),
-char(4),char(0),char(18),char(0),char(4),char(0),char(19),char(0),char(4),char(0),char(20),char(0),char(0),char(0),char(21),char(0),char(23),char(0),char(6),char(0),
-char(14),char(0),char(16),char(0),char(14),char(0),char(17),char(0),char(4),char(0),char(18),char(0),char(4),char(0),char(19),char(0),char(4),char(0),char(20),char(0),
-char(0),char(0),char(21),char(0),char(24),char(0),char(3),char(0),char(2),char(0),char(14),char(0),char(2),char(0),char(15),char(0),char(4),char(0),char(22),char(0),
-char(25),char(0),char(12),char(0),char(13),char(0),char(23),char(0),char(13),char(0),char(24),char(0),char(13),char(0),char(25),char(0),char(4),char(0),char(26),char(0),
-char(4),char(0),char(27),char(0),char(4),char(0),char(28),char(0),char(4),char(0),char(29),char(0),char(22),char(0),char(30),char(0),char(24),char(0),char(31),char(0),
-char(21),char(0),char(32),char(0),char(4),char(0),char(33),char(0),char(4),char(0),char(34),char(0),char(26),char(0),char(12),char(0),char(14),char(0),char(23),char(0),
-char(14),char(0),char(24),char(0),char(14),char(0),char(25),char(0),char(4),char(0),char(26),char(0),char(4),char(0),char(27),char(0),char(4),char(0),char(28),char(0),
-char(4),char(0),char(29),char(0),char(23),char(0),char(30),char(0),char(24),char(0),char(31),char(0),char(4),char(0),char(33),char(0),char(4),char(0),char(34),char(0),
-char(21),char(0),char(32),char(0),char(27),char(0),char(3),char(0),char(0),char(0),char(35),char(0),char(4),char(0),char(36),char(0),char(0),char(0),char(37),char(0),
-char(28),char(0),char(5),char(0),char(27),char(0),char(38),char(0),char(13),char(0),char(39),char(0),char(13),char(0),char(40),char(0),char(7),char(0),char(41),char(0),
-char(0),char(0),char(21),char(0),char(29),char(0),char(5),char(0),char(27),char(0),char(38),char(0),char(13),char(0),char(39),char(0),char(13),char(0),char(42),char(0),
-char(7),char(0),char(43),char(0),char(4),char(0),char(44),char(0),char(30),char(0),char(2),char(0),char(13),char(0),char(45),char(0),char(7),char(0),char(46),char(0),
-char(31),char(0),char(4),char(0),char(29),char(0),char(47),char(0),char(30),char(0),char(48),char(0),char(4),char(0),char(49),char(0),char(0),char(0),char(37),char(0),
-char(32),char(0),char(1),char(0),char(4),char(0),char(50),char(0),char(33),char(0),char(2),char(0),char(2),char(0),char(50),char(0),char(0),char(0),char(51),char(0),
-char(34),char(0),char(2),char(0),char(2),char(0),char(52),char(0),char(0),char(0),char(51),char(0),char(35),char(0),char(2),char(0),char(0),char(0),char(52),char(0),
-char(0),char(0),char(53),char(0),char(36),char(0),char(8),char(0),char(13),char(0),char(54),char(0),char(14),char(0),char(55),char(0),char(32),char(0),char(56),char(0),
-char(34),char(0),char(57),char(0),char(35),char(0),char(58),char(0),char(33),char(0),char(59),char(0),char(4),char(0),char(60),char(0),char(4),char(0),char(61),char(0),
-char(37),char(0),char(4),char(0),char(36),char(0),char(62),char(0),char(13),char(0),char(63),char(0),char(4),char(0),char(64),char(0),char(0),char(0),char(37),char(0),
-char(38),char(0),char(7),char(0),char(27),char(0),char(38),char(0),char(37),char(0),char(65),char(0),char(25),char(0),char(66),char(0),char(26),char(0),char(67),char(0),
-char(39),char(0),char(68),char(0),char(7),char(0),char(43),char(0),char(0),char(0),char(69),char(0),char(40),char(0),char(2),char(0),char(38),char(0),char(70),char(0),
-char(13),char(0),char(39),char(0),char(41),char(0),char(4),char(0),char(19),char(0),char(71),char(0),char(27),char(0),char(72),char(0),char(4),char(0),char(73),char(0),
-char(7),char(0),char(74),char(0),char(42),char(0),char(4),char(0),char(27),char(0),char(38),char(0),char(41),char(0),char(75),char(0),char(4),char(0),char(76),char(0),
-char(7),char(0),char(43),char(0),char(43),char(0),char(3),char(0),char(29),char(0),char(47),char(0),char(4),char(0),char(77),char(0),char(0),char(0),char(37),char(0),
-char(44),char(0),char(3),char(0),char(29),char(0),char(47),char(0),char(4),char(0),char(78),char(0),char(0),char(0),char(37),char(0),char(45),char(0),char(3),char(0),
-char(29),char(0),char(47),char(0),char(4),char(0),char(77),char(0),char(0),char(0),char(37),char(0),char(46),char(0),char(4),char(0),char(4),char(0),char(79),char(0),
-char(7),char(0),char(80),char(0),char(7),char(0),char(81),char(0),char(7),char(0),char(82),char(0),char(39),char(0),char(14),char(0),char(4),char(0),char(83),char(0),
-char(4),char(0),char(84),char(0),char(46),char(0),char(85),char(0),char(4),char(0),char(86),char(0),char(7),char(0),char(87),char(0),char(7),char(0),char(88),char(0),
-char(7),char(0),char(89),char(0),char(7),char(0),char(90),char(0),char(7),char(0),char(91),char(0),char(4),char(0),char(92),char(0),char(4),char(0),char(93),char(0),
-char(4),char(0),char(94),char(0),char(4),char(0),char(95),char(0),char(0),char(0),char(37),char(0),char(47),char(0),char(5),char(0),char(27),char(0),char(38),char(0),
-char(37),char(0),char(65),char(0),char(13),char(0),char(39),char(0),char(7),char(0),char(43),char(0),char(4),char(0),char(96),char(0),char(48),char(0),char(5),char(0),
-char(29),char(0),char(47),char(0),char(13),char(0),char(97),char(0),char(14),char(0),char(98),char(0),char(4),char(0),char(99),char(0),char(0),char(0),char(100),char(0),
-char(49),char(0),char(27),char(0),char(9),char(0),char(101),char(0),char(9),char(0),char(102),char(0),char(27),char(0),char(103),char(0),char(0),char(0),char(35),char(0),
-char(20),char(0),char(104),char(0),char(20),char(0),char(105),char(0),char(14),char(0),char(106),char(0),char(14),char(0),char(107),char(0),char(14),char(0),char(108),char(0),
-char(8),char(0),char(109),char(0),char(8),char(0),char(110),char(0),char(8),char(0),char(111),char(0),char(8),char(0),char(112),char(0),char(8),char(0),char(113),char(0),
-char(8),char(0),char(114),char(0),char(8),char(0),char(115),char(0),char(8),char(0),char(116),char(0),char(8),char(0),char(117),char(0),char(8),char(0),char(118),char(0),
-char(4),char(0),char(119),char(0),char(4),char(0),char(120),char(0),char(4),char(0),char(121),char(0),char(4),char(0),char(122),char(0),char(4),char(0),char(123),char(0),
-char(4),char(0),char(124),char(0),char(4),char(0),char(125),char(0),char(0),char(0),char(37),char(0),char(50),char(0),char(27),char(0),char(9),char(0),char(101),char(0),
-char(9),char(0),char(102),char(0),char(27),char(0),char(103),char(0),char(0),char(0),char(35),char(0),char(19),char(0),char(104),char(0),char(19),char(0),char(105),char(0),
-char(13),char(0),char(106),char(0),char(13),char(0),char(107),char(0),char(13),char(0),char(108),char(0),char(7),char(0),char(109),char(0),char(7),char(0),char(110),char(0),
-char(7),char(0),char(111),char(0),char(7),char(0),char(112),char(0),char(7),char(0),char(113),char(0),char(7),char(0),char(114),char(0),char(7),char(0),char(115),char(0),
-char(7),char(0),char(116),char(0),char(7),char(0),char(117),char(0),char(7),char(0),char(118),char(0),char(4),char(0),char(119),char(0),char(4),char(0),char(120),char(0),
-char(4),char(0),char(121),char(0),char(4),char(0),char(122),char(0),char(4),char(0),char(123),char(0),char(4),char(0),char(124),char(0),char(4),char(0),char(125),char(0),
-char(0),char(0),char(37),char(0),char(51),char(0),char(22),char(0),char(8),char(0),char(126),char(0),char(8),char(0),char(127),char(0),char(8),char(0),char(111),char(0),
-char(8),char(0),char(-128),char(0),char(8),char(0),char(115),char(0),char(8),char(0),char(-127),char(0),char(8),char(0),char(-126),char(0),char(8),char(0),char(-125),char(0),
-char(8),char(0),char(-124),char(0),char(8),char(0),char(-123),char(0),char(8),char(0),char(-122),char(0),char(8),char(0),char(-121),char(0),char(8),char(0),char(-120),char(0),
-char(8),char(0),char(-119),char(0),char(8),char(0),char(-118),char(0),char(8),char(0),char(-117),char(0),char(4),char(0),char(-116),char(0),char(4),char(0),char(-115),char(0),
-char(4),char(0),char(-114),char(0),char(4),char(0),char(-113),char(0),char(4),char(0),char(-112),char(0),char(0),char(0),char(37),char(0),char(52),char(0),char(22),char(0),
-char(7),char(0),char(126),char(0),char(7),char(0),char(127),char(0),char(7),char(0),char(111),char(0),char(7),char(0),char(-128),char(0),char(7),char(0),char(115),char(0),
-char(7),char(0),char(-127),char(0),char(7),char(0),char(-126),char(0),char(7),char(0),char(-125),char(0),char(7),char(0),char(-124),char(0),char(7),char(0),char(-123),char(0),
-char(7),char(0),char(-122),char(0),char(7),char(0),char(-121),char(0),char(7),char(0),char(-120),char(0),char(7),char(0),char(-119),char(0),char(7),char(0),char(-118),char(0),
-char(7),char(0),char(-117),char(0),char(4),char(0),char(-116),char(0),char(4),char(0),char(-115),char(0),char(4),char(0),char(-114),char(0),char(4),char(0),char(-113),char(0),
-char(4),char(0),char(-112),char(0),char(0),char(0),char(37),char(0),char(53),char(0),char(2),char(0),char(51),char(0),char(-111),char(0),char(14),char(0),char(-110),char(0),
-char(54),char(0),char(2),char(0),char(52),char(0),char(-111),char(0),char(13),char(0),char(-110),char(0),char(55),char(0),char(21),char(0),char(50),char(0),char(-109),char(0),
-char(17),char(0),char(-108),char(0),char(13),char(0),char(-107),char(0),char(13),char(0),char(-106),char(0),char(13),char(0),char(-105),char(0),char(13),char(0),char(-104),char(0),
-char(13),char(0),char(-110),char(0),char(13),char(0),char(-103),char(0),char(13),char(0),char(-102),char(0),char(13),char(0),char(-101),char(0),char(13),char(0),char(-100),char(0),
-char(7),char(0),char(-99),char(0),char(7),char(0),char(-98),char(0),char(7),char(0),char(-97),char(0),char(7),char(0),char(-96),char(0),char(7),char(0),char(-95),char(0),
-char(7),char(0),char(-94),char(0),char(7),char(0),char(-93),char(0),char(7),char(0),char(-92),char(0),char(7),char(0),char(-91),char(0),char(4),char(0),char(-90),char(0),
-char(56),char(0),char(22),char(0),char(49),char(0),char(-109),char(0),char(18),char(0),char(-108),char(0),char(14),char(0),char(-107),char(0),char(14),char(0),char(-106),char(0),
-char(14),char(0),char(-105),char(0),char(14),char(0),char(-104),char(0),char(14),char(0),char(-110),char(0),char(14),char(0),char(-103),char(0),char(14),char(0),char(-102),char(0),
-char(14),char(0),char(-101),char(0),char(14),char(0),char(-100),char(0),char(8),char(0),char(-99),char(0),char(8),char(0),char(-98),char(0),char(8),char(0),char(-97),char(0),
-char(8),char(0),char(-96),char(0),char(8),char(0),char(-95),char(0),char(8),char(0),char(-94),char(0),char(8),char(0),char(-93),char(0),char(8),char(0),char(-92),char(0),
-char(8),char(0),char(-91),char(0),char(4),char(0),char(-90),char(0),char(0),char(0),char(37),char(0),char(57),char(0),char(2),char(0),char(4),char(0),char(-89),char(0),
-char(4),char(0),char(-88),char(0),char(58),char(0),char(13),char(0),char(55),char(0),char(-87),char(0),char(55),char(0),char(-86),char(0),char(0),char(0),char(35),char(0),
-char(4),char(0),char(-85),char(0),char(4),char(0),char(-84),char(0),char(4),char(0),char(-83),char(0),char(4),char(0),char(-82),char(0),char(7),char(0),char(-81),char(0),
-char(7),char(0),char(-80),char(0),char(4),char(0),char(-79),char(0),char(4),char(0),char(-78),char(0),char(7),char(0),char(-77),char(0),char(4),char(0),char(-76),char(0),
-char(59),char(0),char(13),char(0),char(60),char(0),char(-87),char(0),char(60),char(0),char(-86),char(0),char(0),char(0),char(35),char(0),char(4),char(0),char(-85),char(0),
-char(4),char(0),char(-84),char(0),char(4),char(0),char(-83),char(0),char(4),char(0),char(-82),char(0),char(7),char(0),char(-81),char(0),char(7),char(0),char(-80),char(0),
-char(4),char(0),char(-79),char(0),char(4),char(0),char(-78),char(0),char(7),char(0),char(-77),char(0),char(4),char(0),char(-76),char(0),char(61),char(0),char(14),char(0),
-char(56),char(0),char(-87),char(0),char(56),char(0),char(-86),char(0),char(0),char(0),char(35),char(0),char(4),char(0),char(-85),char(0),char(4),char(0),char(-84),char(0),
-char(4),char(0),char(-83),char(0),char(4),char(0),char(-82),char(0),char(8),char(0),char(-81),char(0),char(8),char(0),char(-80),char(0),char(4),char(0),char(-79),char(0),
-char(4),char(0),char(-78),char(0),char(8),char(0),char(-77),char(0),char(4),char(0),char(-76),char(0),char(0),char(0),char(-75),char(0),char(62),char(0),char(3),char(0),
-char(59),char(0),char(-74),char(0),char(13),char(0),char(-73),char(0),char(13),char(0),char(-72),char(0),char(63),char(0),char(3),char(0),char(61),char(0),char(-74),char(0),
-char(14),char(0),char(-73),char(0),char(14),char(0),char(-72),char(0),char(64),char(0),char(3),char(0),char(59),char(0),char(-74),char(0),char(14),char(0),char(-73),char(0),
-char(14),char(0),char(-72),char(0),char(65),char(0),char(13),char(0),char(59),char(0),char(-74),char(0),char(20),char(0),char(-71),char(0),char(20),char(0),char(-70),char(0),
-char(4),char(0),char(-69),char(0),char(4),char(0),char(-68),char(0),char(4),char(0),char(-67),char(0),char(7),char(0),char(-66),char(0),char(7),char(0),char(-65),char(0),
-char(7),char(0),char(-64),char(0),char(7),char(0),char(-63),char(0),char(7),char(0),char(-62),char(0),char(7),char(0),char(-61),char(0),char(7),char(0),char(-60),char(0),
-char(66),char(0),char(13),char(0),char(59),char(0),char(-74),char(0),char(19),char(0),char(-71),char(0),char(19),char(0),char(-70),char(0),char(4),char(0),char(-69),char(0),
-char(4),char(0),char(-68),char(0),char(4),char(0),char(-67),char(0),char(7),char(0),char(-66),char(0),char(7),char(0),char(-65),char(0),char(7),char(0),char(-64),char(0),
-char(7),char(0),char(-63),char(0),char(7),char(0),char(-62),char(0),char(7),char(0),char(-61),char(0),char(7),char(0),char(-60),char(0),char(67),char(0),char(14),char(0),
-char(61),char(0),char(-74),char(0),char(20),char(0),char(-71),char(0),char(20),char(0),char(-70),char(0),char(4),char(0),char(-69),char(0),char(4),char(0),char(-68),char(0),
-char(4),char(0),char(-67),char(0),char(8),char(0),char(-66),char(0),char(8),char(0),char(-65),char(0),char(8),char(0),char(-64),char(0),char(8),char(0),char(-63),char(0),
-char(8),char(0),char(-62),char(0),char(8),char(0),char(-61),char(0),char(8),char(0),char(-60),char(0),char(0),char(0),char(-59),char(0),char(68),char(0),char(10),char(0),
-char(61),char(0),char(-74),char(0),char(20),char(0),char(-71),char(0),char(20),char(0),char(-70),char(0),char(8),char(0),char(-58),char(0),char(8),char(0),char(-57),char(0),
-char(8),char(0),char(-56),char(0),char(8),char(0),char(-62),char(0),char(8),char(0),char(-61),char(0),char(8),char(0),char(-60),char(0),char(8),char(0),char(127),char(0),
-char(69),char(0),char(11),char(0),char(59),char(0),char(-74),char(0),char(19),char(0),char(-71),char(0),char(19),char(0),char(-70),char(0),char(7),char(0),char(-58),char(0),
-char(7),char(0),char(-57),char(0),char(7),char(0),char(-56),char(0),char(7),char(0),char(-62),char(0),char(7),char(0),char(-61),char(0),char(7),char(0),char(-60),char(0),
-char(7),char(0),char(127),char(0),char(0),char(0),char(21),char(0),char(70),char(0),char(9),char(0),char(59),char(0),char(-74),char(0),char(19),char(0),char(-71),char(0),
-char(19),char(0),char(-70),char(0),char(13),char(0),char(-55),char(0),char(13),char(0),char(-54),char(0),char(13),char(0),char(-53),char(0),char(13),char(0),char(-52),char(0),
-char(4),char(0),char(-51),char(0),char(4),char(0),char(-50),char(0),char(71),char(0),char(9),char(0),char(61),char(0),char(-74),char(0),char(20),char(0),char(-71),char(0),
-char(20),char(0),char(-70),char(0),char(14),char(0),char(-55),char(0),char(14),char(0),char(-54),char(0),char(14),char(0),char(-53),char(0),char(14),char(0),char(-52),char(0),
-char(4),char(0),char(-51),char(0),char(4),char(0),char(-50),char(0),char(72),char(0),char(5),char(0),char(70),char(0),char(-49),char(0),char(4),char(0),char(-48),char(0),
-char(7),char(0),char(-47),char(0),char(7),char(0),char(-46),char(0),char(7),char(0),char(-45),char(0),char(73),char(0),char(5),char(0),char(71),char(0),char(-49),char(0),
-char(4),char(0),char(-48),char(0),char(8),char(0),char(-47),char(0),char(8),char(0),char(-46),char(0),char(8),char(0),char(-45),char(0),char(74),char(0),char(41),char(0),
-char(59),char(0),char(-74),char(0),char(19),char(0),char(-71),char(0),char(19),char(0),char(-70),char(0),char(13),char(0),char(-55),char(0),char(13),char(0),char(-54),char(0),
-char(13),char(0),char(-44),char(0),char(13),char(0),char(-43),char(0),char(13),char(0),char(-42),char(0),char(13),char(0),char(-41),char(0),char(13),char(0),char(-40),char(0),
-char(13),char(0),char(-39),char(0),char(13),char(0),char(-38),char(0),char(13),char(0),char(-37),char(0),char(13),char(0),char(-36),char(0),char(13),char(0),char(-35),char(0),
-char(13),char(0),char(-34),char(0),char(0),char(0),char(-33),char(0),char(0),char(0),char(-32),char(0),char(0),char(0),char(-31),char(0),char(0),char(0),char(-30),char(0),
-char(0),char(0),char(-29),char(0),char(0),char(0),char(-59),char(0),char(13),char(0),char(-53),char(0),char(13),char(0),char(-52),char(0),char(13),char(0),char(-28),char(0),
-char(13),char(0),char(-27),char(0),char(13),char(0),char(-26),char(0),char(13),char(0),char(-25),char(0),char(13),char(0),char(-24),char(0),char(13),char(0),char(-23),char(0),
-char(13),char(0),char(-22),char(0),char(13),char(0),char(-21),char(0),char(13),char(0),char(-20),char(0),char(13),char(0),char(-19),char(0),char(13),char(0),char(-18),char(0),
-char(0),char(0),char(-17),char(0),char(0),char(0),char(-16),char(0),char(0),char(0),char(-15),char(0),char(0),char(0),char(-14),char(0),char(0),char(0),char(-13),char(0),
-char(4),char(0),char(-12),char(0),char(75),char(0),char(41),char(0),char(61),char(0),char(-74),char(0),char(20),char(0),char(-71),char(0),char(20),char(0),char(-70),char(0),
-char(14),char(0),char(-55),char(0),char(14),char(0),char(-54),char(0),char(14),char(0),char(-44),char(0),char(14),char(0),char(-43),char(0),char(14),char(0),char(-42),char(0),
-char(14),char(0),char(-41),char(0),char(14),char(0),char(-40),char(0),char(14),char(0),char(-39),char(0),char(14),char(0),char(-38),char(0),char(14),char(0),char(-37),char(0),
-char(14),char(0),char(-36),char(0),char(14),char(0),char(-35),char(0),char(14),char(0),char(-34),char(0),char(0),char(0),char(-33),char(0),char(0),char(0),char(-32),char(0),
-char(0),char(0),char(-31),char(0),char(0),char(0),char(-30),char(0),char(0),char(0),char(-29),char(0),char(0),char(0),char(-59),char(0),char(14),char(0),char(-53),char(0),
-char(14),char(0),char(-52),char(0),char(14),char(0),char(-28),char(0),char(14),char(0),char(-27),char(0),char(14),char(0),char(-26),char(0),char(14),char(0),char(-25),char(0),
-char(14),char(0),char(-24),char(0),char(14),char(0),char(-23),char(0),char(14),char(0),char(-22),char(0),char(14),char(0),char(-21),char(0),char(14),char(0),char(-20),char(0),
-char(14),char(0),char(-19),char(0),char(14),char(0),char(-18),char(0),char(0),char(0),char(-17),char(0),char(0),char(0),char(-16),char(0),char(0),char(0),char(-15),char(0),
-char(0),char(0),char(-14),char(0),char(0),char(0),char(-13),char(0),char(4),char(0),char(-12),char(0),char(76),char(0),char(9),char(0),char(59),char(0),char(-74),char(0),
-char(19),char(0),char(-71),char(0),char(19),char(0),char(-70),char(0),char(7),char(0),char(-55),char(0),char(7),char(0),char(-54),char(0),char(7),char(0),char(-53),char(0),
-char(7),char(0),char(-52),char(0),char(4),char(0),char(-51),char(0),char(4),char(0),char(-50),char(0),char(77),char(0),char(9),char(0),char(61),char(0),char(-74),char(0),
-char(20),char(0),char(-71),char(0),char(20),char(0),char(-70),char(0),char(8),char(0),char(-55),char(0),char(8),char(0),char(-54),char(0),char(8),char(0),char(-53),char(0),
-char(8),char(0),char(-52),char(0),char(4),char(0),char(-51),char(0),char(4),char(0),char(-50),char(0),char(78),char(0),char(5),char(0),char(58),char(0),char(-74),char(0),
-char(13),char(0),char(-11),char(0),char(13),char(0),char(-10),char(0),char(7),char(0),char(-9),char(0),char(0),char(0),char(37),char(0),char(79),char(0),char(4),char(0),
-char(61),char(0),char(-74),char(0),char(14),char(0),char(-11),char(0),char(14),char(0),char(-10),char(0),char(8),char(0),char(-9),char(0),char(80),char(0),char(4),char(0),
-char(7),char(0),char(-8),char(0),char(7),char(0),char(-7),char(0),char(7),char(0),char(-6),char(0),char(4),char(0),char(79),char(0),char(81),char(0),char(10),char(0),
-char(80),char(0),char(-5),char(0),char(13),char(0),char(-4),char(0),char(13),char(0),char(-3),char(0),char(13),char(0),char(-2),char(0),char(13),char(0),char(-1),char(0),
-char(13),char(0),char(0),char(1),char(7),char(0),char(-99),char(0),char(7),char(0),char(1),char(1),char(4),char(0),char(2),char(1),char(4),char(0),char(53),char(0),
-char(82),char(0),char(4),char(0),char(80),char(0),char(-5),char(0),char(4),char(0),char(3),char(1),char(7),char(0),char(4),char(1),char(4),char(0),char(5),char(1),
-char(83),char(0),char(4),char(0),char(13),char(0),char(0),char(1),char(80),char(0),char(-5),char(0),char(4),char(0),char(6),char(1),char(7),char(0),char(7),char(1),
-char(84),char(0),char(7),char(0),char(13),char(0),char(8),char(1),char(80),char(0),char(-5),char(0),char(4),char(0),char(9),char(1),char(7),char(0),char(10),char(1),
-char(7),char(0),char(11),char(1),char(7),char(0),char(12),char(1),char(4),char(0),char(53),char(0),char(85),char(0),char(6),char(0),char(17),char(0),char(13),char(1),
-char(13),char(0),char(11),char(1),char(13),char(0),char(14),char(1),char(60),char(0),char(15),char(1),char(4),char(0),char(16),char(1),char(7),char(0),char(12),char(1),
-char(86),char(0),char(26),char(0),char(4),char(0),char(17),char(1),char(7),char(0),char(18),char(1),char(7),char(0),char(127),char(0),char(7),char(0),char(19),char(1),
-char(7),char(0),char(20),char(1),char(7),char(0),char(21),char(1),char(7),char(0),char(22),char(1),char(7),char(0),char(23),char(1),char(7),char(0),char(24),char(1),
-char(7),char(0),char(25),char(1),char(7),char(0),char(26),char(1),char(7),char(0),char(27),char(1),char(7),char(0),char(28),char(1),char(7),char(0),char(29),char(1),
-char(7),char(0),char(30),char(1),char(7),char(0),char(31),char(1),char(7),char(0),char(32),char(1),char(7),char(0),char(33),char(1),char(7),char(0),char(34),char(1),
-char(7),char(0),char(35),char(1),char(7),char(0),char(36),char(1),char(4),char(0),char(37),char(1),char(4),char(0),char(38),char(1),char(4),char(0),char(39),char(1),
-char(4),char(0),char(40),char(1),char(4),char(0),char(120),char(0),char(87),char(0),char(12),char(0),char(17),char(0),char(41),char(1),char(17),char(0),char(42),char(1),
-char(17),char(0),char(43),char(1),char(13),char(0),char(44),char(1),char(13),char(0),char(45),char(1),char(7),char(0),char(46),char(1),char(4),char(0),char(47),char(1),
-char(4),char(0),char(48),char(1),char(4),char(0),char(49),char(1),char(4),char(0),char(50),char(1),char(7),char(0),char(10),char(1),char(4),char(0),char(53),char(0),
-char(88),char(0),char(27),char(0),char(19),char(0),char(51),char(1),char(17),char(0),char(52),char(1),char(17),char(0),char(53),char(1),char(13),char(0),char(44),char(1),
-char(13),char(0),char(54),char(1),char(13),char(0),char(55),char(1),char(13),char(0),char(56),char(1),char(13),char(0),char(57),char(1),char(13),char(0),char(58),char(1),
-char(4),char(0),char(59),char(1),char(7),char(0),char(60),char(1),char(4),char(0),char(61),char(1),char(4),char(0),char(62),char(1),char(4),char(0),char(63),char(1),
-char(7),char(0),char(64),char(1),char(7),char(0),char(65),char(1),char(4),char(0),char(66),char(1),char(4),char(0),char(67),char(1),char(7),char(0),char(68),char(1),
-char(7),char(0),char(69),char(1),char(7),char(0),char(70),char(1),char(7),char(0),char(71),char(1),char(7),char(0),char(72),char(1),char(7),char(0),char(73),char(1),
-char(4),char(0),char(74),char(1),char(4),char(0),char(75),char(1),char(4),char(0),char(76),char(1),char(89),char(0),char(12),char(0),char(9),char(0),char(77),char(1),
-char(9),char(0),char(78),char(1),char(13),char(0),char(79),char(1),char(7),char(0),char(80),char(1),char(7),char(0),char(-125),char(0),char(7),char(0),char(81),char(1),
-char(4),char(0),char(82),char(1),char(13),char(0),char(83),char(1),char(4),char(0),char(84),char(1),char(4),char(0),char(85),char(1),char(4),char(0),char(86),char(1),
-char(4),char(0),char(53),char(0),char(90),char(0),char(19),char(0),char(50),char(0),char(-109),char(0),char(87),char(0),char(87),char(1),char(80),char(0),char(88),char(1),
-char(81),char(0),char(89),char(1),char(82),char(0),char(90),char(1),char(83),char(0),char(91),char(1),char(84),char(0),char(92),char(1),char(85),char(0),char(93),char(1),
-char(88),char(0),char(94),char(1),char(89),char(0),char(95),char(1),char(4),char(0),char(96),char(1),char(4),char(0),char(62),char(1),char(4),char(0),char(97),char(1),
-char(4),char(0),char(98),char(1),char(4),char(0),char(99),char(1),char(4),char(0),char(100),char(1),char(4),char(0),char(101),char(1),char(4),char(0),char(102),char(1),
-char(86),char(0),char(103),char(1),char(91),char(0),char(24),char(0),char(16),char(0),char(104),char(1),char(14),char(0),char(105),char(1),char(14),char(0),char(106),char(1),
-char(14),char(0),char(107),char(1),char(14),char(0),char(108),char(1),char(14),char(0),char(109),char(1),char(8),char(0),char(110),char(1),char(4),char(0),char(111),char(1),
-char(4),char(0),char(86),char(1),char(4),char(0),char(112),char(1),char(4),char(0),char(113),char(1),char(8),char(0),char(114),char(1),char(8),char(0),char(115),char(1),
-char(8),char(0),char(116),char(1),char(8),char(0),char(117),char(1),char(8),char(0),char(118),char(1),char(8),char(0),char(119),char(1),char(8),char(0),char(120),char(1),
-char(8),char(0),char(121),char(1),char(8),char(0),char(122),char(1),char(0),char(0),char(123),char(1),char(0),char(0),char(124),char(1),char(49),char(0),char(125),char(1),
-char(0),char(0),char(126),char(1),char(92),char(0),char(24),char(0),char(15),char(0),char(104),char(1),char(13),char(0),char(105),char(1),char(13),char(0),char(106),char(1),
-char(13),char(0),char(107),char(1),char(13),char(0),char(108),char(1),char(13),char(0),char(109),char(1),char(4),char(0),char(112),char(1),char(7),char(0),char(110),char(1),
-char(4),char(0),char(111),char(1),char(4),char(0),char(86),char(1),char(7),char(0),char(114),char(1),char(7),char(0),char(115),char(1),char(7),char(0),char(116),char(1),
-char(4),char(0),char(113),char(1),char(7),char(0),char(117),char(1),char(7),char(0),char(118),char(1),char(7),char(0),char(119),char(1),char(7),char(0),char(120),char(1),
-char(7),char(0),char(121),char(1),char(7),char(0),char(122),char(1),char(0),char(0),char(123),char(1),char(0),char(0),char(124),char(1),char(50),char(0),char(125),char(1),
-char(0),char(0),char(126),char(1),char(93),char(0),char(9),char(0),char(20),char(0),char(127),char(1),char(14),char(0),char(-128),char(1),char(8),char(0),char(-127),char(1),
-char(0),char(0),char(-126),char(1),char(91),char(0),char(90),char(1),char(49),char(0),char(-125),char(1),char(0),char(0),char(126),char(1),char(4),char(0),char(97),char(1),
-char(0),char(0),char(37),char(0),char(94),char(0),char(7),char(0),char(0),char(0),char(-126),char(1),char(92),char(0),char(90),char(1),char(50),char(0),char(-125),char(1),
-char(19),char(0),char(127),char(1),char(13),char(0),char(-128),char(1),char(7),char(0),char(-127),char(1),char(4),char(0),char(97),char(1),};
+char(104),char(0),char(96),char(0),char(104),char(0),char(-56),char(0),char(104),char(1),char(112),char(0),char(-16),char(1),char(-128),char(3),char(-40),char(1),char(-56),char(0),
+char(112),char(0),char(48),char(1),char(8),char(2),char(0),char(0),char(83),char(84),char(82),char(67),char(88),char(0),char(0),char(0),char(10),char(0),char(3),char(0),
+char(4),char(0),char(0),char(0),char(4),char(0),char(1),char(0),char(9),char(0),char(2),char(0),char(11),char(0),char(3),char(0),char(10),char(0),char(3),char(0),
+char(10),char(0),char(4),char(0),char(10),char(0),char(5),char(0),char(12),char(0),char(2),char(0),char(9),char(0),char(6),char(0),char(9),char(0),char(7),char(0),
+char(13),char(0),char(1),char(0),char(7),char(0),char(8),char(0),char(14),char(0),char(1),char(0),char(8),char(0),char(8),char(0),char(15),char(0),char(1),char(0),
+char(7),char(0),char(8),char(0),char(16),char(0),char(1),char(0),char(8),char(0),char(8),char(0),char(17),char(0),char(1),char(0),char(13),char(0),char(9),char(0),
+char(18),char(0),char(1),char(0),char(14),char(0),char(9),char(0),char(19),char(0),char(2),char(0),char(17),char(0),char(10),char(0),char(13),char(0),char(11),char(0),
+char(20),char(0),char(2),char(0),char(18),char(0),char(10),char(0),char(14),char(0),char(11),char(0),char(21),char(0),char(4),char(0),char(4),char(0),char(12),char(0),
+char(4),char(0),char(13),char(0),char(2),char(0),char(14),char(0),char(2),char(0),char(15),char(0),char(22),char(0),char(6),char(0),char(13),char(0),char(16),char(0),
+char(13),char(0),char(17),char(0),char(4),char(0),char(18),char(0),char(4),char(0),char(19),char(0),char(4),char(0),char(20),char(0),char(0),char(0),char(21),char(0),
+char(23),char(0),char(6),char(0),char(14),char(0),char(16),char(0),char(14),char(0),char(17),char(0),char(4),char(0),char(18),char(0),char(4),char(0),char(19),char(0),
+char(4),char(0),char(20),char(0),char(0),char(0),char(21),char(0),char(24),char(0),char(3),char(0),char(2),char(0),char(14),char(0),char(2),char(0),char(15),char(0),
+char(4),char(0),char(22),char(0),char(25),char(0),char(12),char(0),char(13),char(0),char(23),char(0),char(13),char(0),char(24),char(0),char(13),char(0),char(25),char(0),
+char(4),char(0),char(26),char(0),char(4),char(0),char(27),char(0),char(4),char(0),char(28),char(0),char(4),char(0),char(29),char(0),char(22),char(0),char(30),char(0),
+char(24),char(0),char(31),char(0),char(21),char(0),char(32),char(0),char(4),char(0),char(33),char(0),char(4),char(0),char(34),char(0),char(26),char(0),char(12),char(0),
+char(14),char(0),char(23),char(0),char(14),char(0),char(24),char(0),char(14),char(0),char(25),char(0),char(4),char(0),char(26),char(0),char(4),char(0),char(27),char(0),
+char(4),char(0),char(28),char(0),char(4),char(0),char(29),char(0),char(23),char(0),char(30),char(0),char(24),char(0),char(31),char(0),char(4),char(0),char(33),char(0),
+char(4),char(0),char(34),char(0),char(21),char(0),char(32),char(0),char(27),char(0),char(3),char(0),char(0),char(0),char(35),char(0),char(4),char(0),char(36),char(0),
+char(0),char(0),char(37),char(0),char(28),char(0),char(5),char(0),char(27),char(0),char(38),char(0),char(13),char(0),char(39),char(0),char(13),char(0),char(40),char(0),
+char(7),char(0),char(41),char(0),char(0),char(0),char(21),char(0),char(29),char(0),char(5),char(0),char(27),char(0),char(38),char(0),char(13),char(0),char(39),char(0),
+char(13),char(0),char(42),char(0),char(7),char(0),char(43),char(0),char(4),char(0),char(44),char(0),char(30),char(0),char(2),char(0),char(13),char(0),char(45),char(0),
+char(7),char(0),char(46),char(0),char(31),char(0),char(4),char(0),char(29),char(0),char(47),char(0),char(30),char(0),char(48),char(0),char(4),char(0),char(49),char(0),
+char(0),char(0),char(37),char(0),char(32),char(0),char(1),char(0),char(4),char(0),char(50),char(0),char(33),char(0),char(2),char(0),char(2),char(0),char(50),char(0),
+char(0),char(0),char(51),char(0),char(34),char(0),char(2),char(0),char(2),char(0),char(52),char(0),char(0),char(0),char(51),char(0),char(35),char(0),char(2),char(0),
+char(0),char(0),char(52),char(0),char(0),char(0),char(53),char(0),char(36),char(0),char(8),char(0),char(13),char(0),char(54),char(0),char(14),char(0),char(55),char(0),
+char(32),char(0),char(56),char(0),char(34),char(0),char(57),char(0),char(35),char(0),char(58),char(0),char(33),char(0),char(59),char(0),char(4),char(0),char(60),char(0),
+char(4),char(0),char(61),char(0),char(37),char(0),char(4),char(0),char(36),char(0),char(62),char(0),char(13),char(0),char(63),char(0),char(4),char(0),char(64),char(0),
+char(0),char(0),char(37),char(0),char(38),char(0),char(7),char(0),char(27),char(0),char(38),char(0),char(37),char(0),char(65),char(0),char(25),char(0),char(66),char(0),
+char(26),char(0),char(67),char(0),char(39),char(0),char(68),char(0),char(7),char(0),char(43),char(0),char(0),char(0),char(69),char(0),char(40),char(0),char(2),char(0),
+char(38),char(0),char(70),char(0),char(13),char(0),char(39),char(0),char(41),char(0),char(4),char(0),char(19),char(0),char(71),char(0),char(27),char(0),char(72),char(0),
+char(4),char(0),char(73),char(0),char(7),char(0),char(74),char(0),char(42),char(0),char(4),char(0),char(27),char(0),char(38),char(0),char(41),char(0),char(75),char(0),
+char(4),char(0),char(76),char(0),char(7),char(0),char(43),char(0),char(43),char(0),char(3),char(0),char(29),char(0),char(47),char(0),char(4),char(0),char(77),char(0),
+char(0),char(0),char(37),char(0),char(44),char(0),char(3),char(0),char(29),char(0),char(47),char(0),char(4),char(0),char(78),char(0),char(0),char(0),char(37),char(0),
+char(45),char(0),char(3),char(0),char(29),char(0),char(47),char(0),char(4),char(0),char(77),char(0),char(0),char(0),char(37),char(0),char(46),char(0),char(4),char(0),
+char(4),char(0),char(79),char(0),char(7),char(0),char(80),char(0),char(7),char(0),char(81),char(0),char(7),char(0),char(82),char(0),char(39),char(0),char(14),char(0),
+char(4),char(0),char(83),char(0),char(4),char(0),char(84),char(0),char(46),char(0),char(85),char(0),char(4),char(0),char(86),char(0),char(7),char(0),char(87),char(0),
+char(7),char(0),char(88),char(0),char(7),char(0),char(89),char(0),char(7),char(0),char(90),char(0),char(7),char(0),char(91),char(0),char(4),char(0),char(92),char(0),
+char(4),char(0),char(93),char(0),char(4),char(0),char(94),char(0),char(4),char(0),char(95),char(0),char(0),char(0),char(37),char(0),char(47),char(0),char(38),char(0),
+char(14),char(0),char(96),char(0),char(14),char(0),char(97),char(0),char(14),char(0),char(98),char(0),char(14),char(0),char(99),char(0),char(14),char(0),char(100),char(0),
+char(14),char(0),char(101),char(0),char(14),char(0),char(102),char(0),char(8),char(0),char(103),char(0),char(8),char(0),char(104),char(0),char(8),char(0),char(105),char(0),
+char(8),char(0),char(106),char(0),char(8),char(0),char(107),char(0),char(8),char(0),char(108),char(0),char(4),char(0),char(109),char(0),char(4),char(0),char(110),char(0),
+char(4),char(0),char(111),char(0),char(4),char(0),char(112),char(0),char(4),char(0),char(113),char(0),char(8),char(0),char(114),char(0),char(8),char(0),char(115),char(0),
+char(8),char(0),char(116),char(0),char(8),char(0),char(117),char(0),char(8),char(0),char(118),char(0),char(8),char(0),char(119),char(0),char(8),char(0),char(120),char(0),
+char(8),char(0),char(121),char(0),char(8),char(0),char(122),char(0),char(4),char(0),char(123),char(0),char(4),char(0),char(124),char(0),char(4),char(0),char(125),char(0),
+char(4),char(0),char(126),char(0),char(4),char(0),char(127),char(0),char(4),char(0),char(-128),char(0),char(8),char(0),char(-127),char(0),char(8),char(0),char(-126),char(0),
+char(4),char(0),char(44),char(0),char(48),char(0),char(-125),char(0),char(48),char(0),char(-124),char(0),char(49),char(0),char(38),char(0),char(13),char(0),char(96),char(0),
+char(13),char(0),char(97),char(0),char(13),char(0),char(98),char(0),char(13),char(0),char(99),char(0),char(13),char(0),char(100),char(0),char(13),char(0),char(101),char(0),
+char(13),char(0),char(102),char(0),char(7),char(0),char(103),char(0),char(7),char(0),char(104),char(0),char(7),char(0),char(105),char(0),char(7),char(0),char(106),char(0),
+char(7),char(0),char(107),char(0),char(7),char(0),char(108),char(0),char(4),char(0),char(109),char(0),char(4),char(0),char(110),char(0),char(4),char(0),char(111),char(0),
+char(4),char(0),char(112),char(0),char(4),char(0),char(113),char(0),char(7),char(0),char(114),char(0),char(7),char(0),char(115),char(0),char(7),char(0),char(116),char(0),
+char(7),char(0),char(117),char(0),char(7),char(0),char(118),char(0),char(7),char(0),char(119),char(0),char(7),char(0),char(120),char(0),char(7),char(0),char(121),char(0),
+char(7),char(0),char(122),char(0),char(4),char(0),char(123),char(0),char(4),char(0),char(124),char(0),char(4),char(0),char(125),char(0),char(4),char(0),char(126),char(0),
+char(4),char(0),char(127),char(0),char(4),char(0),char(-128),char(0),char(7),char(0),char(-127),char(0),char(7),char(0),char(-126),char(0),char(4),char(0),char(44),char(0),
+char(50),char(0),char(-125),char(0),char(50),char(0),char(-124),char(0),char(51),char(0),char(5),char(0),char(27),char(0),char(38),char(0),char(37),char(0),char(65),char(0),
+char(13),char(0),char(39),char(0),char(7),char(0),char(43),char(0),char(4),char(0),char(-123),char(0),char(52),char(0),char(5),char(0),char(29),char(0),char(47),char(0),
+char(13),char(0),char(-122),char(0),char(14),char(0),char(-121),char(0),char(4),char(0),char(-120),char(0),char(0),char(0),char(-119),char(0),char(48),char(0),char(29),char(0),
+char(9),char(0),char(-118),char(0),char(9),char(0),char(-117),char(0),char(27),char(0),char(-116),char(0),char(0),char(0),char(35),char(0),char(20),char(0),char(-115),char(0),
+char(20),char(0),char(-114),char(0),char(14),char(0),char(-113),char(0),char(14),char(0),char(-112),char(0),char(14),char(0),char(-111),char(0),char(8),char(0),char(-126),char(0),
+char(8),char(0),char(-110),char(0),char(8),char(0),char(-109),char(0),char(8),char(0),char(-108),char(0),char(8),char(0),char(-107),char(0),char(8),char(0),char(-106),char(0),
+char(8),char(0),char(-105),char(0),char(8),char(0),char(-104),char(0),char(8),char(0),char(-103),char(0),char(8),char(0),char(-102),char(0),char(4),char(0),char(-101),char(0),
+char(4),char(0),char(-100),char(0),char(4),char(0),char(-99),char(0),char(4),char(0),char(-98),char(0),char(4),char(0),char(-97),char(0),char(4),char(0),char(-96),char(0),
+char(4),char(0),char(-95),char(0),char(4),char(0),char(-94),char(0),char(4),char(0),char(-93),char(0),char(4),char(0),char(-92),char(0),char(50),char(0),char(29),char(0),
+char(9),char(0),char(-118),char(0),char(9),char(0),char(-117),char(0),char(27),char(0),char(-116),char(0),char(0),char(0),char(35),char(0),char(19),char(0),char(-115),char(0),
+char(19),char(0),char(-114),char(0),char(13),char(0),char(-113),char(0),char(13),char(0),char(-112),char(0),char(13),char(0),char(-111),char(0),char(7),char(0),char(-126),char(0),
+char(7),char(0),char(-110),char(0),char(7),char(0),char(-109),char(0),char(7),char(0),char(-108),char(0),char(7),char(0),char(-107),char(0),char(7),char(0),char(-106),char(0),
+char(7),char(0),char(-105),char(0),char(7),char(0),char(-104),char(0),char(7),char(0),char(-103),char(0),char(7),char(0),char(-102),char(0),char(4),char(0),char(-101),char(0),
+char(4),char(0),char(-100),char(0),char(4),char(0),char(-99),char(0),char(4),char(0),char(-98),char(0),char(4),char(0),char(-97),char(0),char(4),char(0),char(-96),char(0),
+char(4),char(0),char(-95),char(0),char(4),char(0),char(-94),char(0),char(4),char(0),char(-93),char(0),char(4),char(0),char(-92),char(0),char(53),char(0),char(22),char(0),
+char(8),char(0),char(-91),char(0),char(8),char(0),char(-90),char(0),char(8),char(0),char(-109),char(0),char(8),char(0),char(-89),char(0),char(8),char(0),char(-105),char(0),
+char(8),char(0),char(-88),char(0),char(8),char(0),char(-87),char(0),char(8),char(0),char(-86),char(0),char(8),char(0),char(-85),char(0),char(8),char(0),char(-84),char(0),
+char(8),char(0),char(-83),char(0),char(8),char(0),char(-82),char(0),char(8),char(0),char(-81),char(0),char(8),char(0),char(-80),char(0),char(8),char(0),char(-79),char(0),
+char(8),char(0),char(-78),char(0),char(4),char(0),char(-77),char(0),char(4),char(0),char(-76),char(0),char(4),char(0),char(-75),char(0),char(4),char(0),char(-74),char(0),
+char(4),char(0),char(-73),char(0),char(0),char(0),char(37),char(0),char(54),char(0),char(22),char(0),char(7),char(0),char(-91),char(0),char(7),char(0),char(-90),char(0),
+char(7),char(0),char(-109),char(0),char(7),char(0),char(-89),char(0),char(7),char(0),char(-105),char(0),char(7),char(0),char(-88),char(0),char(7),char(0),char(-87),char(0),
+char(7),char(0),char(-86),char(0),char(7),char(0),char(-85),char(0),char(7),char(0),char(-84),char(0),char(7),char(0),char(-83),char(0),char(7),char(0),char(-82),char(0),
+char(7),char(0),char(-81),char(0),char(7),char(0),char(-80),char(0),char(7),char(0),char(-79),char(0),char(7),char(0),char(-78),char(0),char(4),char(0),char(-77),char(0),
+char(4),char(0),char(-76),char(0),char(4),char(0),char(-75),char(0),char(4),char(0),char(-74),char(0),char(4),char(0),char(-73),char(0),char(0),char(0),char(37),char(0),
+char(55),char(0),char(2),char(0),char(53),char(0),char(-72),char(0),char(14),char(0),char(-71),char(0),char(56),char(0),char(2),char(0),char(54),char(0),char(-72),char(0),
+char(13),char(0),char(-71),char(0),char(57),char(0),char(21),char(0),char(50),char(0),char(-70),char(0),char(17),char(0),char(-69),char(0),char(13),char(0),char(-68),char(0),
+char(13),char(0),char(-67),char(0),char(13),char(0),char(-66),char(0),char(13),char(0),char(-65),char(0),char(13),char(0),char(-71),char(0),char(13),char(0),char(-64),char(0),
+char(13),char(0),char(-63),char(0),char(13),char(0),char(-62),char(0),char(13),char(0),char(-61),char(0),char(7),char(0),char(-60),char(0),char(7),char(0),char(-59),char(0),
+char(7),char(0),char(-58),char(0),char(7),char(0),char(-57),char(0),char(7),char(0),char(-56),char(0),char(7),char(0),char(-55),char(0),char(7),char(0),char(-54),char(0),
+char(7),char(0),char(-53),char(0),char(7),char(0),char(-52),char(0),char(4),char(0),char(-51),char(0),char(58),char(0),char(22),char(0),char(48),char(0),char(-70),char(0),
+char(18),char(0),char(-69),char(0),char(14),char(0),char(-68),char(0),char(14),char(0),char(-67),char(0),char(14),char(0),char(-66),char(0),char(14),char(0),char(-65),char(0),
+char(14),char(0),char(-71),char(0),char(14),char(0),char(-64),char(0),char(14),char(0),char(-63),char(0),char(14),char(0),char(-62),char(0),char(14),char(0),char(-61),char(0),
+char(8),char(0),char(-60),char(0),char(8),char(0),char(-59),char(0),char(8),char(0),char(-58),char(0),char(8),char(0),char(-57),char(0),char(8),char(0),char(-56),char(0),
+char(8),char(0),char(-55),char(0),char(8),char(0),char(-54),char(0),char(8),char(0),char(-53),char(0),char(8),char(0),char(-52),char(0),char(4),char(0),char(-51),char(0),
+char(0),char(0),char(37),char(0),char(59),char(0),char(2),char(0),char(4),char(0),char(-50),char(0),char(4),char(0),char(-49),char(0),char(60),char(0),char(13),char(0),
+char(57),char(0),char(-48),char(0),char(57),char(0),char(-47),char(0),char(0),char(0),char(35),char(0),char(4),char(0),char(-128),char(0),char(4),char(0),char(-46),char(0),
+char(4),char(0),char(-45),char(0),char(4),char(0),char(-44),char(0),char(7),char(0),char(-43),char(0),char(7),char(0),char(-42),char(0),char(4),char(0),char(-41),char(0),
+char(4),char(0),char(-40),char(0),char(7),char(0),char(-39),char(0),char(4),char(0),char(-38),char(0),char(61),char(0),char(13),char(0),char(62),char(0),char(-48),char(0),
+char(62),char(0),char(-47),char(0),char(0),char(0),char(35),char(0),char(4),char(0),char(-128),char(0),char(4),char(0),char(-46),char(0),char(4),char(0),char(-45),char(0),
+char(4),char(0),char(-44),char(0),char(7),char(0),char(-43),char(0),char(7),char(0),char(-42),char(0),char(4),char(0),char(-41),char(0),char(4),char(0),char(-40),char(0),
+char(7),char(0),char(-39),char(0),char(4),char(0),char(-38),char(0),char(63),char(0),char(14),char(0),char(58),char(0),char(-48),char(0),char(58),char(0),char(-47),char(0),
+char(0),char(0),char(35),char(0),char(4),char(0),char(-128),char(0),char(4),char(0),char(-46),char(0),char(4),char(0),char(-45),char(0),char(4),char(0),char(-44),char(0),
+char(8),char(0),char(-43),char(0),char(8),char(0),char(-42),char(0),char(4),char(0),char(-41),char(0),char(4),char(0),char(-40),char(0),char(8),char(0),char(-39),char(0),
+char(4),char(0),char(-38),char(0),char(0),char(0),char(-37),char(0),char(64),char(0),char(3),char(0),char(61),char(0),char(-36),char(0),char(13),char(0),char(-35),char(0),
+char(13),char(0),char(-34),char(0),char(65),char(0),char(3),char(0),char(63),char(0),char(-36),char(0),char(14),char(0),char(-35),char(0),char(14),char(0),char(-34),char(0),
+char(66),char(0),char(3),char(0),char(61),char(0),char(-36),char(0),char(14),char(0),char(-35),char(0),char(14),char(0),char(-34),char(0),char(67),char(0),char(13),char(0),
+char(61),char(0),char(-36),char(0),char(20),char(0),char(-33),char(0),char(20),char(0),char(-32),char(0),char(4),char(0),char(-31),char(0),char(4),char(0),char(-30),char(0),
+char(4),char(0),char(-29),char(0),char(7),char(0),char(-28),char(0),char(7),char(0),char(-27),char(0),char(7),char(0),char(-26),char(0),char(7),char(0),char(-25),char(0),
+char(7),char(0),char(-24),char(0),char(7),char(0),char(-23),char(0),char(7),char(0),char(-22),char(0),char(68),char(0),char(13),char(0),char(61),char(0),char(-36),char(0),
+char(19),char(0),char(-33),char(0),char(19),char(0),char(-32),char(0),char(4),char(0),char(-31),char(0),char(4),char(0),char(-30),char(0),char(4),char(0),char(-29),char(0),
+char(7),char(0),char(-28),char(0),char(7),char(0),char(-27),char(0),char(7),char(0),char(-26),char(0),char(7),char(0),char(-25),char(0),char(7),char(0),char(-24),char(0),
+char(7),char(0),char(-23),char(0),char(7),char(0),char(-22),char(0),char(69),char(0),char(14),char(0),char(63),char(0),char(-36),char(0),char(20),char(0),char(-33),char(0),
+char(20),char(0),char(-32),char(0),char(4),char(0),char(-31),char(0),char(4),char(0),char(-30),char(0),char(4),char(0),char(-29),char(0),char(8),char(0),char(-28),char(0),
+char(8),char(0),char(-27),char(0),char(8),char(0),char(-26),char(0),char(8),char(0),char(-25),char(0),char(8),char(0),char(-24),char(0),char(8),char(0),char(-23),char(0),
+char(8),char(0),char(-22),char(0),char(0),char(0),char(-21),char(0),char(70),char(0),char(10),char(0),char(63),char(0),char(-36),char(0),char(20),char(0),char(-33),char(0),
+char(20),char(0),char(-32),char(0),char(8),char(0),char(-20),char(0),char(8),char(0),char(-19),char(0),char(8),char(0),char(-18),char(0),char(8),char(0),char(-24),char(0),
+char(8),char(0),char(-23),char(0),char(8),char(0),char(-22),char(0),char(8),char(0),char(-90),char(0),char(71),char(0),char(11),char(0),char(61),char(0),char(-36),char(0),
+char(19),char(0),char(-33),char(0),char(19),char(0),char(-32),char(0),char(7),char(0),char(-20),char(0),char(7),char(0),char(-19),char(0),char(7),char(0),char(-18),char(0),
+char(7),char(0),char(-24),char(0),char(7),char(0),char(-23),char(0),char(7),char(0),char(-22),char(0),char(7),char(0),char(-90),char(0),char(0),char(0),char(21),char(0),
+char(72),char(0),char(9),char(0),char(61),char(0),char(-36),char(0),char(19),char(0),char(-33),char(0),char(19),char(0),char(-32),char(0),char(13),char(0),char(-17),char(0),
+char(13),char(0),char(-16),char(0),char(13),char(0),char(-15),char(0),char(13),char(0),char(-14),char(0),char(4),char(0),char(-13),char(0),char(4),char(0),char(-12),char(0),
+char(73),char(0),char(9),char(0),char(63),char(0),char(-36),char(0),char(20),char(0),char(-33),char(0),char(20),char(0),char(-32),char(0),char(14),char(0),char(-17),char(0),
+char(14),char(0),char(-16),char(0),char(14),char(0),char(-15),char(0),char(14),char(0),char(-14),char(0),char(4),char(0),char(-13),char(0),char(4),char(0),char(-12),char(0),
+char(74),char(0),char(5),char(0),char(72),char(0),char(-11),char(0),char(4),char(0),char(-10),char(0),char(7),char(0),char(-9),char(0),char(7),char(0),char(-8),char(0),
+char(7),char(0),char(-7),char(0),char(75),char(0),char(5),char(0),char(73),char(0),char(-11),char(0),char(4),char(0),char(-10),char(0),char(8),char(0),char(-9),char(0),
+char(8),char(0),char(-8),char(0),char(8),char(0),char(-7),char(0),char(76),char(0),char(41),char(0),char(61),char(0),char(-36),char(0),char(19),char(0),char(-33),char(0),
+char(19),char(0),char(-32),char(0),char(13),char(0),char(-17),char(0),char(13),char(0),char(-16),char(0),char(13),char(0),char(-6),char(0),char(13),char(0),char(-5),char(0),
+char(13),char(0),char(-4),char(0),char(13),char(0),char(-3),char(0),char(13),char(0),char(-2),char(0),char(13),char(0),char(-1),char(0),char(13),char(0),char(0),char(1),
+char(13),char(0),char(1),char(1),char(13),char(0),char(2),char(1),char(13),char(0),char(3),char(1),char(13),char(0),char(4),char(1),char(0),char(0),char(5),char(1),
+char(0),char(0),char(6),char(1),char(0),char(0),char(7),char(1),char(0),char(0),char(8),char(1),char(0),char(0),char(9),char(1),char(0),char(0),char(-21),char(0),
+char(13),char(0),char(-15),char(0),char(13),char(0),char(-14),char(0),char(13),char(0),char(10),char(1),char(13),char(0),char(11),char(1),char(13),char(0),char(12),char(1),
+char(13),char(0),char(13),char(1),char(13),char(0),char(14),char(1),char(13),char(0),char(15),char(1),char(13),char(0),char(16),char(1),char(13),char(0),char(17),char(1),
+char(13),char(0),char(18),char(1),char(13),char(0),char(19),char(1),char(13),char(0),char(20),char(1),char(0),char(0),char(21),char(1),char(0),char(0),char(22),char(1),
+char(0),char(0),char(23),char(1),char(0),char(0),char(24),char(1),char(0),char(0),char(25),char(1),char(4),char(0),char(26),char(1),char(77),char(0),char(41),char(0),
+char(63),char(0),char(-36),char(0),char(20),char(0),char(-33),char(0),char(20),char(0),char(-32),char(0),char(14),char(0),char(-17),char(0),char(14),char(0),char(-16),char(0),
+char(14),char(0),char(-6),char(0),char(14),char(0),char(-5),char(0),char(14),char(0),char(-4),char(0),char(14),char(0),char(-3),char(0),char(14),char(0),char(-2),char(0),
+char(14),char(0),char(-1),char(0),char(14),char(0),char(0),char(1),char(14),char(0),char(1),char(1),char(14),char(0),char(2),char(1),char(14),char(0),char(3),char(1),
+char(14),char(0),char(4),char(1),char(0),char(0),char(5),char(1),char(0),char(0),char(6),char(1),char(0),char(0),char(7),char(1),char(0),char(0),char(8),char(1),
+char(0),char(0),char(9),char(1),char(0),char(0),char(-21),char(0),char(14),char(0),char(-15),char(0),char(14),char(0),char(-14),char(0),char(14),char(0),char(10),char(1),
+char(14),char(0),char(11),char(1),char(14),char(0),char(12),char(1),char(14),char(0),char(13),char(1),char(14),char(0),char(14),char(1),char(14),char(0),char(15),char(1),
+char(14),char(0),char(16),char(1),char(14),char(0),char(17),char(1),char(14),char(0),char(18),char(1),char(14),char(0),char(19),char(1),char(14),char(0),char(20),char(1),
+char(0),char(0),char(21),char(1),char(0),char(0),char(22),char(1),char(0),char(0),char(23),char(1),char(0),char(0),char(24),char(1),char(0),char(0),char(25),char(1),
+char(4),char(0),char(26),char(1),char(78),char(0),char(9),char(0),char(61),char(0),char(-36),char(0),char(19),char(0),char(-33),char(0),char(19),char(0),char(-32),char(0),
+char(7),char(0),char(-17),char(0),char(7),char(0),char(-16),char(0),char(7),char(0),char(-15),char(0),char(7),char(0),char(-14),char(0),char(4),char(0),char(-13),char(0),
+char(4),char(0),char(-12),char(0),char(79),char(0),char(9),char(0),char(63),char(0),char(-36),char(0),char(20),char(0),char(-33),char(0),char(20),char(0),char(-32),char(0),
+char(8),char(0),char(-17),char(0),char(8),char(0),char(-16),char(0),char(8),char(0),char(-15),char(0),char(8),char(0),char(-14),char(0),char(4),char(0),char(-13),char(0),
+char(4),char(0),char(-12),char(0),char(80),char(0),char(5),char(0),char(60),char(0),char(-36),char(0),char(13),char(0),char(27),char(1),char(13),char(0),char(28),char(1),
+char(7),char(0),char(29),char(1),char(0),char(0),char(37),char(0),char(81),char(0),char(4),char(0),char(63),char(0),char(-36),char(0),char(14),char(0),char(27),char(1),
+char(14),char(0),char(28),char(1),char(8),char(0),char(29),char(1),char(82),char(0),char(4),char(0),char(7),char(0),char(30),char(1),char(7),char(0),char(31),char(1),
+char(7),char(0),char(32),char(1),char(4),char(0),char(79),char(0),char(83),char(0),char(10),char(0),char(82),char(0),char(33),char(1),char(13),char(0),char(34),char(1),
+char(13),char(0),char(35),char(1),char(13),char(0),char(36),char(1),char(13),char(0),char(37),char(1),char(13),char(0),char(38),char(1),char(7),char(0),char(-60),char(0),
+char(7),char(0),char(39),char(1),char(4),char(0),char(40),char(1),char(4),char(0),char(53),char(0),char(84),char(0),char(4),char(0),char(82),char(0),char(33),char(1),
+char(4),char(0),char(41),char(1),char(7),char(0),char(42),char(1),char(4),char(0),char(43),char(1),char(85),char(0),char(4),char(0),char(13),char(0),char(38),char(1),
+char(82),char(0),char(33),char(1),char(4),char(0),char(44),char(1),char(7),char(0),char(45),char(1),char(86),char(0),char(7),char(0),char(13),char(0),char(46),char(1),
+char(82),char(0),char(33),char(1),char(4),char(0),char(47),char(1),char(7),char(0),char(48),char(1),char(7),char(0),char(49),char(1),char(7),char(0),char(50),char(1),
+char(4),char(0),char(53),char(0),char(87),char(0),char(6),char(0),char(17),char(0),char(51),char(1),char(13),char(0),char(49),char(1),char(13),char(0),char(52),char(1),
+char(62),char(0),char(53),char(1),char(4),char(0),char(54),char(1),char(7),char(0),char(50),char(1),char(88),char(0),char(26),char(0),char(4),char(0),char(55),char(1),
+char(7),char(0),char(56),char(1),char(7),char(0),char(-90),char(0),char(7),char(0),char(57),char(1),char(7),char(0),char(58),char(1),char(7),char(0),char(59),char(1),
+char(7),char(0),char(60),char(1),char(7),char(0),char(61),char(1),char(7),char(0),char(62),char(1),char(7),char(0),char(63),char(1),char(7),char(0),char(64),char(1),
+char(7),char(0),char(65),char(1),char(7),char(0),char(66),char(1),char(7),char(0),char(67),char(1),char(7),char(0),char(68),char(1),char(7),char(0),char(69),char(1),
+char(7),char(0),char(70),char(1),char(7),char(0),char(71),char(1),char(7),char(0),char(72),char(1),char(7),char(0),char(73),char(1),char(7),char(0),char(74),char(1),
+char(4),char(0),char(75),char(1),char(4),char(0),char(76),char(1),char(4),char(0),char(77),char(1),char(4),char(0),char(78),char(1),char(4),char(0),char(-100),char(0),
+char(89),char(0),char(12),char(0),char(17),char(0),char(79),char(1),char(17),char(0),char(80),char(1),char(17),char(0),char(81),char(1),char(13),char(0),char(82),char(1),
+char(13),char(0),char(83),char(1),char(7),char(0),char(84),char(1),char(4),char(0),char(85),char(1),char(4),char(0),char(86),char(1),char(4),char(0),char(87),char(1),
+char(4),char(0),char(88),char(1),char(7),char(0),char(48),char(1),char(4),char(0),char(53),char(0),char(90),char(0),char(27),char(0),char(19),char(0),char(89),char(1),
+char(17),char(0),char(90),char(1),char(17),char(0),char(91),char(1),char(13),char(0),char(82),char(1),char(13),char(0),char(92),char(1),char(13),char(0),char(93),char(1),
+char(13),char(0),char(94),char(1),char(13),char(0),char(95),char(1),char(13),char(0),char(96),char(1),char(4),char(0),char(97),char(1),char(7),char(0),char(98),char(1),
+char(4),char(0),char(99),char(1),char(4),char(0),char(100),char(1),char(4),char(0),char(101),char(1),char(7),char(0),char(102),char(1),char(7),char(0),char(103),char(1),
+char(4),char(0),char(104),char(1),char(4),char(0),char(105),char(1),char(7),char(0),char(106),char(1),char(7),char(0),char(107),char(1),char(7),char(0),char(108),char(1),
+char(7),char(0),char(109),char(1),char(7),char(0),char(110),char(1),char(7),char(0),char(111),char(1),char(4),char(0),char(112),char(1),char(4),char(0),char(113),char(1),
+char(4),char(0),char(114),char(1),char(91),char(0),char(12),char(0),char(9),char(0),char(115),char(1),char(9),char(0),char(116),char(1),char(13),char(0),char(117),char(1),
+char(7),char(0),char(118),char(1),char(7),char(0),char(-86),char(0),char(7),char(0),char(119),char(1),char(4),char(0),char(120),char(1),char(13),char(0),char(121),char(1),
+char(4),char(0),char(122),char(1),char(4),char(0),char(123),char(1),char(4),char(0),char(124),char(1),char(4),char(0),char(53),char(0),char(92),char(0),char(19),char(0),
+char(50),char(0),char(-70),char(0),char(89),char(0),char(125),char(1),char(82),char(0),char(126),char(1),char(83),char(0),char(127),char(1),char(84),char(0),char(-128),char(1),
+char(85),char(0),char(-127),char(1),char(86),char(0),char(-126),char(1),char(87),char(0),char(-125),char(1),char(90),char(0),char(-124),char(1),char(91),char(0),char(-123),char(1),
+char(4),char(0),char(-122),char(1),char(4),char(0),char(100),char(1),char(4),char(0),char(-121),char(1),char(4),char(0),char(-120),char(1),char(4),char(0),char(-119),char(1),
+char(4),char(0),char(-118),char(1),char(4),char(0),char(-117),char(1),char(4),char(0),char(-116),char(1),char(88),char(0),char(-115),char(1),char(93),char(0),char(28),char(0),
+char(16),char(0),char(-114),char(1),char(14),char(0),char(-113),char(1),char(14),char(0),char(-112),char(1),char(14),char(0),char(-111),char(1),char(14),char(0),char(-110),char(1),
+char(14),char(0),char(-109),char(1),char(14),char(0),char(-108),char(1),char(14),char(0),char(-107),char(1),char(14),char(0),char(-106),char(1),char(14),char(0),char(-105),char(1),
+char(8),char(0),char(-104),char(1),char(4),char(0),char(-103),char(1),char(4),char(0),char(124),char(1),char(4),char(0),char(-102),char(1),char(4),char(0),char(-101),char(1),
+char(8),char(0),char(-100),char(1),char(8),char(0),char(-99),char(1),char(8),char(0),char(-98),char(1),char(8),char(0),char(-97),char(1),char(8),char(0),char(-96),char(1),
+char(8),char(0),char(-95),char(1),char(8),char(0),char(-94),char(1),char(8),char(0),char(-93),char(1),char(8),char(0),char(-92),char(1),char(0),char(0),char(-91),char(1),
+char(0),char(0),char(-90),char(1),char(48),char(0),char(-89),char(1),char(0),char(0),char(-88),char(1),char(94),char(0),char(28),char(0),char(15),char(0),char(-114),char(1),
+char(13),char(0),char(-113),char(1),char(13),char(0),char(-112),char(1),char(13),char(0),char(-111),char(1),char(13),char(0),char(-110),char(1),char(13),char(0),char(-109),char(1),
+char(13),char(0),char(-108),char(1),char(13),char(0),char(-107),char(1),char(13),char(0),char(-106),char(1),char(13),char(0),char(-105),char(1),char(4),char(0),char(-102),char(1),
+char(7),char(0),char(-104),char(1),char(4),char(0),char(-103),char(1),char(4),char(0),char(124),char(1),char(7),char(0),char(-100),char(1),char(7),char(0),char(-99),char(1),
+char(7),char(0),char(-98),char(1),char(4),char(0),char(-101),char(1),char(7),char(0),char(-97),char(1),char(7),char(0),char(-96),char(1),char(7),char(0),char(-95),char(1),
+char(7),char(0),char(-94),char(1),char(7),char(0),char(-93),char(1),char(7),char(0),char(-92),char(1),char(0),char(0),char(-91),char(1),char(0),char(0),char(-90),char(1),
+char(50),char(0),char(-89),char(1),char(0),char(0),char(-88),char(1),char(95),char(0),char(11),char(0),char(14),char(0),char(-87),char(1),char(16),char(0),char(-86),char(1),
+char(14),char(0),char(-85),char(1),char(14),char(0),char(-84),char(1),char(14),char(0),char(-83),char(1),char(8),char(0),char(-82),char(1),char(4),char(0),char(-121),char(1),
+char(0),char(0),char(37),char(0),char(0),char(0),char(-81),char(1),char(93),char(0),char(-128),char(1),char(48),char(0),char(-80),char(1),char(96),char(0),char(10),char(0),
+char(13),char(0),char(-87),char(1),char(15),char(0),char(-86),char(1),char(13),char(0),char(-85),char(1),char(13),char(0),char(-84),char(1),char(13),char(0),char(-83),char(1),
+char(7),char(0),char(-82),char(1),char(4),char(0),char(-121),char(1),char(0),char(0),char(-81),char(1),char(94),char(0),char(-128),char(1),char(50),char(0),char(-80),char(1),
+char(97),char(0),char(4),char(0),char(50),char(0),char(-79),char(1),char(96),char(0),char(-78),char(1),char(4),char(0),char(-77),char(1),char(0),char(0),char(37),char(0),
+char(98),char(0),char(4),char(0),char(48),char(0),char(-79),char(1),char(95),char(0),char(-78),char(1),char(4),char(0),char(-77),char(1),char(0),char(0),char(37),char(0),
+};
int sBulletDNAlen64= sizeof(sBulletDNAstr64);
diff --git a/thirdparty/bullet/LinearMath/btThreads.cpp b/thirdparty/bullet/LinearMath/btThreads.cpp
index 59a7ea36e9..c037626ffb 100644
--- a/thirdparty/bullet/LinearMath/btThreads.cpp
+++ b/thirdparty/bullet/LinearMath/btThreads.cpp
@@ -453,6 +453,33 @@ void btParallelFor( int iBegin, int iEnd, int grainSize, const btIParallelForBod
#endif// #if BT_THREADSAFE
}
+btScalar btParallelSum( int iBegin, int iEnd, int grainSize, const btIParallelSumBody& body )
+{
+#if BT_THREADSAFE
+
+#if BT_DETECT_BAD_THREAD_INDEX
+ if ( !btThreadsAreRunning() )
+ {
+ // clear out thread ids
+ for ( int i = 0; i < BT_MAX_THREAD_COUNT; ++i )
+ {
+ gDebugThreadIds[ i ] = kInvalidThreadId;
+ }
+ }
+#endif // #if BT_DETECT_BAD_THREAD_INDEX
+
+ btAssert( gBtTaskScheduler != NULL ); // call btSetTaskScheduler() with a valid task scheduler first!
+ return gBtTaskScheduler->parallelSum( iBegin, iEnd, grainSize, body );
+
+#else // #if BT_THREADSAFE
+
+ // non-parallel version of btParallelSum
+ btAssert( !"called btParallelFor in non-threadsafe build. enable BT_THREADSAFE" );
+ return body.sumLoop( iBegin, iEnd );
+
+#endif //#else // #if BT_THREADSAFE
+}
+
///
/// btTaskSchedulerSequential -- non-threaded implementation of task scheduler
@@ -470,6 +497,11 @@ public:
BT_PROFILE( "parallelFor_sequential" );
body.forLoop( iBegin, iEnd );
}
+ virtual btScalar parallelSum( int iBegin, int iEnd, int grainSize, const btIParallelSumBody& body ) BT_OVERRIDE
+ {
+ BT_PROFILE( "parallelSum_sequential" );
+ return body.sumLoop( iBegin, iEnd );
+ }
};
@@ -514,11 +546,25 @@ public:
#pragma omp parallel for schedule( static, 1 )
for ( int i = iBegin; i < iEnd; i += grainSize )
{
- BT_PROFILE( "OpenMP_job" );
+ BT_PROFILE( "OpenMP_forJob" );
body.forLoop( i, ( std::min )( i + grainSize, iEnd ) );
}
btPopThreadsAreRunning();
}
+ virtual btScalar parallelSum( int iBegin, int iEnd, int grainSize, const btIParallelSumBody& body ) BT_OVERRIDE
+ {
+ BT_PROFILE( "parallelFor_OpenMP" );
+ btPushThreadsAreRunning();
+ btScalar sum = btScalar( 0 );
+#pragma omp parallel for schedule( static, 1 ) reduction(+:sum)
+ for ( int i = iBegin; i < iEnd; i += grainSize )
+ {
+ BT_PROFILE( "OpenMP_sumJob" );
+ sum += body.sumLoop( i, ( std::min )( i + grainSize, iEnd ) );
+ }
+ btPopThreadsAreRunning();
+ return sum;
+ }
};
#endif // #if BT_USE_OPENMP && BT_THREADSAFE
@@ -571,22 +617,21 @@ public:
btResetThreadIndexCounter();
}
}
- struct BodyAdapter
+ struct ForBodyAdapter
{
const btIParallelForBody* mBody;
+ ForBodyAdapter( const btIParallelForBody* body ) : mBody( body ) {}
void operator()( const tbb::blocked_range<int>& range ) const
{
- BT_PROFILE( "TBB_job" );
+ BT_PROFILE( "TBB_forJob" );
mBody->forLoop( range.begin(), range.end() );
}
};
virtual void parallelFor( int iBegin, int iEnd, int grainSize, const btIParallelForBody& body ) BT_OVERRIDE
{
BT_PROFILE( "parallelFor_TBB" );
- // TBB dispatch
- BodyAdapter tbbBody;
- tbbBody.mBody = &body;
+ ForBodyAdapter tbbBody( &body );
btPushThreadsAreRunning();
tbb::parallel_for( tbb::blocked_range<int>( iBegin, iEnd, grainSize ),
tbbBody,
@@ -594,6 +639,29 @@ public:
);
btPopThreadsAreRunning();
}
+ struct SumBodyAdapter
+ {
+ const btIParallelSumBody* mBody;
+ btScalar mSum;
+
+ SumBodyAdapter( const btIParallelSumBody* body ) : mBody( body ), mSum( btScalar( 0 ) ) {}
+ SumBodyAdapter( const SumBodyAdapter& src, tbb::split ) : mBody( src.mBody ), mSum( btScalar( 0 ) ) {}
+ void join( const SumBodyAdapter& src ) { mSum += src.mSum; }
+ void operator()( const tbb::blocked_range<int>& range )
+ {
+ BT_PROFILE( "TBB_sumJob" );
+ mSum += mBody->sumLoop( range.begin(), range.end() );
+ }
+ };
+ virtual btScalar parallelSum( int iBegin, int iEnd, int grainSize, const btIParallelSumBody& body ) BT_OVERRIDE
+ {
+ BT_PROFILE( "parallelSum_TBB" );
+ SumBodyAdapter tbbBody( &body );
+ btPushThreadsAreRunning();
+ tbb::parallel_deterministic_reduce( tbb::blocked_range<int>( iBegin, iEnd, grainSize ), tbbBody );
+ btPopThreadsAreRunning();
+ return tbbBody.mSum;
+ }
};
#endif // #if BT_USE_TBB && BT_THREADSAFE
@@ -605,6 +673,7 @@ public:
class btTaskSchedulerPPL : public btITaskScheduler
{
int m_numThreads;
+ concurrency::combinable<btScalar> m_sum; // for parallelSum
public:
btTaskSchedulerPPL() : btITaskScheduler( "PPL" )
{
@@ -644,15 +713,16 @@ public:
btResetThreadIndexCounter();
}
}
- struct BodyAdapter
+ struct ForBodyAdapter
{
const btIParallelForBody* mBody;
int mGrainSize;
int mIndexEnd;
+ ForBodyAdapter( const btIParallelForBody* body, int grainSize, int end ) : mBody( body ), mGrainSize( grainSize ), mIndexEnd( end ) {}
void operator()( int i ) const
{
- BT_PROFILE( "PPL_job" );
+ BT_PROFILE( "PPL_forJob" );
mBody->forLoop( i, ( std::min )( i + mGrainSize, mIndexEnd ) );
}
};
@@ -660,10 +730,36 @@ public:
{
BT_PROFILE( "parallelFor_PPL" );
// PPL dispatch
- BodyAdapter pplBody;
- pplBody.mBody = &body;
- pplBody.mGrainSize = grainSize;
- pplBody.mIndexEnd = iEnd;
+ ForBodyAdapter pplBody( &body, grainSize, iEnd );
+ btPushThreadsAreRunning();
+ // note: MSVC 2010 doesn't support partitioner args, so avoid them
+ concurrency::parallel_for( iBegin,
+ iEnd,
+ grainSize,
+ pplBody
+ );
+ btPopThreadsAreRunning();
+ }
+ struct SumBodyAdapter
+ {
+ const btIParallelSumBody* mBody;
+ concurrency::combinable<btScalar>* mSum;
+ int mGrainSize;
+ int mIndexEnd;
+
+ SumBodyAdapter( const btIParallelSumBody* body, concurrency::combinable<btScalar>* sum, int grainSize, int end ) : mBody( body ), mSum(sum), mGrainSize( grainSize ), mIndexEnd( end ) {}
+ void operator()( int i ) const
+ {
+ BT_PROFILE( "PPL_sumJob" );
+ mSum->local() += mBody->sumLoop( i, ( std::min )( i + mGrainSize, mIndexEnd ) );
+ }
+ };
+ static btScalar sumFunc( btScalar a, btScalar b ) { return a + b; }
+ virtual btScalar parallelSum( int iBegin, int iEnd, int grainSize, const btIParallelSumBody& body ) BT_OVERRIDE
+ {
+ BT_PROFILE( "parallelSum_PPL" );
+ m_sum.clear();
+ SumBodyAdapter pplBody( &body, &m_sum, grainSize, iEnd );
btPushThreadsAreRunning();
// note: MSVC 2010 doesn't support partitioner args, so avoid them
concurrency::parallel_for( iBegin,
@@ -672,6 +768,7 @@ public:
pplBody
);
btPopThreadsAreRunning();
+ return m_sum.combine( sumFunc );
}
};
#endif // #if BT_USE_PPL && BT_THREADSAFE
diff --git a/thirdparty/bullet/LinearMath/btThreads.h b/thirdparty/bullet/LinearMath/btThreads.h
index 05fd15ec82..921fd088c0 100644
--- a/thirdparty/bullet/LinearMath/btThreads.h
+++ b/thirdparty/bullet/LinearMath/btThreads.h
@@ -28,6 +28,8 @@ subject to the following restrictions:
#define BT_OVERRIDE
#endif
+// Don't set this to larger than 64, without modifying btThreadSupportPosix
+// and btThreadSupportWin32. They use UINT64 bit-masks.
const unsigned int BT_MAX_THREAD_COUNT = 64; // only if BT_THREADSAFE is 1
// for internal use only
@@ -72,6 +74,8 @@ SIMD_FORCE_INLINE void btMutexLock( btSpinMutex* mutex )
{
#if BT_THREADSAFE
mutex->lock();
+#else
+ (void)mutex;
#endif // #if BT_THREADSAFE
}
@@ -79,6 +83,8 @@ SIMD_FORCE_INLINE void btMutexUnlock( btSpinMutex* mutex )
{
#if BT_THREADSAFE
mutex->unlock();
+#else
+ (void)mutex;
#endif // #if BT_THREADSAFE
}
@@ -87,6 +93,7 @@ SIMD_FORCE_INLINE bool btMutexTryLock( btSpinMutex* mutex )
#if BT_THREADSAFE
return mutex->tryLock();
#else
+ (void)mutex;
return true;
#endif // #if BT_THREADSAFE
}
@@ -103,6 +110,17 @@ public:
};
//
+// btIParallelSumBody -- subclass this to express work that can be done in parallel
+// and produces a sum over all loop elements
+//
+class btIParallelSumBody
+{
+public:
+ virtual ~btIParallelSumBody() {}
+ virtual btScalar sumLoop( int iBegin, int iEnd ) const = 0;
+};
+
+//
// btITaskScheduler -- subclass this to implement a task scheduler that can dispatch work to
// worker threads
//
@@ -117,6 +135,8 @@ public:
virtual int getNumThreads() const = 0;
virtual void setNumThreads( int numThreads ) = 0;
virtual void parallelFor( int iBegin, int iEnd, int grainSize, const btIParallelForBody& body ) = 0;
+ virtual btScalar parallelSum( int iBegin, int iEnd, int grainSize, const btIParallelSumBody& body ) = 0;
+ virtual void sleepWorkerThreadsHint() {} // hint the task scheduler that we may not be using these threads for a little while
// internal use only
virtual void activate();
@@ -138,6 +158,9 @@ btITaskScheduler* btGetTaskScheduler();
// get non-threaded task scheduler (always available)
btITaskScheduler* btGetSequentialTaskScheduler();
+// create a default task scheduler (Win32 or pthreads based)
+btITaskScheduler* btCreateDefaultTaskScheduler();
+
// get OpenMP task scheduler (if available, otherwise returns null)
btITaskScheduler* btGetOpenMPTaskScheduler();
@@ -151,5 +174,9 @@ btITaskScheduler* btGetPPLTaskScheduler();
// (iterations may be done out of order, so no dependencies are allowed)
void btParallelFor( int iBegin, int iEnd, int grainSize, const btIParallelForBody& body );
+// btParallelSum -- call this to dispatch work like a for-loop, returns the sum of all iterations
+// (iterations may be done out of order, so no dependencies are allowed)
+btScalar btParallelSum( int iBegin, int iEnd, int grainSize, const btIParallelSumBody& body );
+
#endif
diff --git a/thirdparty/bullet/LinearMath/btVector3.h b/thirdparty/bullet/LinearMath/btVector3.h
index c69effa96e..76024f1236 100644
--- a/thirdparty/bullet/LinearMath/btVector3.h
+++ b/thirdparty/bullet/LinearMath/btVector3.h
@@ -705,7 +705,9 @@ public:
SIMD_FORCE_INLINE void serialize(struct btVector3Data& dataOut) const;
- SIMD_FORCE_INLINE void deSerialize(const struct btVector3Data& dataIn);
+ SIMD_FORCE_INLINE void deSerialize(const struct btVector3DoubleData& dataIn);
+
+ SIMD_FORCE_INLINE void deSerialize(const struct btVector3FloatData& dataIn);
SIMD_FORCE_INLINE void serializeFloat(struct btVector3FloatData& dataOut) const;
@@ -1236,9 +1238,9 @@ public:
///btSwapVector3Endian swaps vector endianness, useful for network and cross-platform serialization
SIMD_FORCE_INLINE void btSwapScalarEndian(const btScalar& sourceVal, btScalar& destVal)
{
- #ifdef BT_USE_DOUBLE_PRECISION
+#ifdef BT_USE_DOUBLE_PRECISION
unsigned char* dest = (unsigned char*) &destVal;
- unsigned char* src = (unsigned char*) &sourceVal;
+ const unsigned char* src = (const unsigned char*) &sourceVal;
dest[0] = src[7];
dest[1] = src[6];
dest[2] = src[5];
@@ -1249,7 +1251,7 @@ SIMD_FORCE_INLINE void btSwapScalarEndian(const btScalar& sourceVal, btScalar& d
dest[7] = src[0];
#else
unsigned char* dest = (unsigned char*) &destVal;
- unsigned char* src = (unsigned char*) &sourceVal;
+ const unsigned char* src = (const unsigned char*) &sourceVal;
dest[0] = src[3];
dest[1] = src[2];
dest[2] = src[1];
@@ -1354,10 +1356,18 @@ SIMD_FORCE_INLINE void btVector3::serialize(struct btVector3Data& dataOut) const
dataOut.m_floats[i] = m_floats[i];
}
-SIMD_FORCE_INLINE void btVector3::deSerialize(const struct btVector3Data& dataIn)
+
+SIMD_FORCE_INLINE void btVector3::deSerialize(const struct btVector3FloatData& dataIn)
+{
+ for (int i = 0; i<4; i++)
+ m_floats[i] = (btScalar)dataIn.m_floats[i];
+}
+
+
+SIMD_FORCE_INLINE void btVector3::deSerialize(const struct btVector3DoubleData& dataIn)
{
for (int i=0;i<4;i++)
- m_floats[i] = dataIn.m_floats[i];
+ m_floats[i] = (btScalar)dataIn.m_floats[i];
}
#endif //BT_VECTOR3_H
diff --git a/thirdparty/bullet/clew/clew.c b/thirdparty/bullet/clew/clew.c
index a07b0aad75..5afc42a485 100644
--- a/thirdparty/bullet/clew/clew.c
+++ b/thirdparty/bullet/clew/clew.c
@@ -15,7 +15,7 @@
typedef HMODULE CLEW_DYNLIB_HANDLE;
- #define CLEW_DYNLIB_OPEN LoadLibrary
+ #define CLEW_DYNLIB_OPEN LoadLibraryA
#define CLEW_DYNLIB_CLOSE FreeLibrary
#define CLEW_DYNLIB_IMPORT GetProcAddress
#else
diff --git a/thirdparty/cvtt/ConvectionKernels.cpp b/thirdparty/cvtt/ConvectionKernels.cpp
new file mode 100644
index 0000000000..8d379344e1
--- /dev/null
+++ b/thirdparty/cvtt/ConvectionKernels.cpp
@@ -0,0 +1,7586 @@
+/*
+Convection Texture Tools
+Copyright (c) 2018 Eric Lasota
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject
+to the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+-------------------------------------------------------------------------------------
+
+Portions based on DirectX Texture Library (DirectXTex)
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+Licensed under the MIT License.
+
+http://go.microsoft.com/fwlink/?LinkId=248926
+*/
+#include "ConvectionKernels.h"
+#include "ConvectionKernels_BC7_SingleColor.h"
+
+#if (defined(_M_IX86_FP) && _M_IX86_FP >= 2) || defined(_M_X64) || defined(__SSE2__)
+#define CVTT_USE_SSE2
+#endif
+
+#ifdef CVTT_USE_SSE2
+#include <emmintrin.h>
+#endif
+
+#include <float.h>
+#include <assert.h>
+#include <string.h>
+#include <algorithm>
+#include <math.h>
+
+#define UNREFERENCED_PARAMETER(n) ((void)n)
+
+namespace cvtt
+{
+#ifdef CVTT_USE_SSE2
+ // SSE2 version
+ struct ParallelMath
+ {
+ typedef uint16_t ScalarUInt16;
+ typedef int16_t ScalarSInt16;
+
+ template<unsigned int TRoundingMode>
+ struct RoundForScope
+ {
+ unsigned int m_oldCSR;
+
+ RoundForScope()
+ {
+ m_oldCSR = _mm_getcsr();
+ _mm_setcsr((m_oldCSR & ~_MM_ROUND_MASK) | (TRoundingMode));
+ }
+
+ ~RoundForScope()
+ {
+ _mm_setcsr(m_oldCSR);
+ }
+ };
+
+ struct RoundTowardZeroForScope : RoundForScope<_MM_ROUND_TOWARD_ZERO>
+ {
+ };
+
+ struct RoundTowardNearestForScope : RoundForScope<_MM_ROUND_NEAREST>
+ {
+ };
+
+ struct RoundUpForScope : RoundForScope<_MM_ROUND_UP>
+ {
+ };
+
+ struct RoundDownForScope : RoundForScope<_MM_ROUND_DOWN>
+ {
+ };
+
+ static const int ParallelSize = 8;
+
+ enum Int16Subtype
+ {
+ IntSubtype_Signed,
+ IntSubtype_UnsignedFull,
+ IntSubtype_UnsignedTruncated,
+ IntSubtype_Abstract,
+ };
+
+ template<int TSubtype>
+ struct VInt16
+ {
+ __m128i m_value;
+
+ inline VInt16 operator+(int16_t other) const
+ {
+ VInt16 result;
+ result.m_value = _mm_add_epi16(m_value, _mm_set1_epi16(static_cast<int16_t>(other)));
+ return result;
+ }
+
+ inline VInt16 operator+(const VInt16 &other) const
+ {
+ VInt16 result;
+ result.m_value = _mm_add_epi16(m_value, other.m_value);
+ return result;
+ }
+
+ inline VInt16 operator|(const VInt16 &other) const
+ {
+ VInt16 result;
+ result.m_value = _mm_or_si128(m_value, other.m_value);
+ return result;
+ }
+
+ inline VInt16 operator&(const VInt16 &other) const
+ {
+ VInt16 result;
+ result.m_value = _mm_and_si128(m_value, other.m_value);
+ return result;
+ }
+
+ inline VInt16 operator-(const VInt16 &other) const
+ {
+ VInt16 result;
+ result.m_value = _mm_sub_epi16(m_value, other.m_value);
+ return result;
+ }
+
+ inline VInt16 operator<<(int bits) const
+ {
+ VInt16 result;
+ result.m_value = _mm_slli_epi16(m_value, bits);
+ return result;
+ }
+ };
+
+ typedef VInt16<IntSubtype_Signed> SInt16;
+ typedef VInt16<IntSubtype_UnsignedFull> UInt16;
+ typedef VInt16<IntSubtype_UnsignedTruncated> UInt15;
+ typedef VInt16<IntSubtype_Abstract> AInt16;
+
+ template<int TSubtype>
+ struct VInt32
+ {
+ __m128i m_values[2];
+
+ inline VInt32 operator+(const VInt32& other) const
+ {
+ VInt32 result;
+ result.m_values[0] = _mm_add_epi32(m_values[0], other.m_values[0]);
+ result.m_values[1] = _mm_add_epi32(m_values[1], other.m_values[1]);
+ return result;
+ }
+
+ inline VInt32 operator-(const VInt32& other) const
+ {
+ VInt32 result;
+ result.m_values[0] = _mm_sub_epi32(m_values[0], other.m_values[0]);
+ result.m_values[1] = _mm_sub_epi32(m_values[1], other.m_values[1]);
+ return result;
+ }
+
+ inline VInt32 operator<<(const int other) const
+ {
+ VInt32 result;
+ result.m_values[0] = _mm_slli_epi32(m_values[0], other);
+ result.m_values[1] = _mm_slli_epi32(m_values[1], other);
+ return result;
+ }
+ };
+
+ typedef VInt32<IntSubtype_Signed> SInt32;
+ typedef VInt32<IntSubtype_UnsignedTruncated> UInt31;
+ typedef VInt32<IntSubtype_UnsignedFull> UInt32;
+ typedef VInt32<IntSubtype_Abstract> AInt32;
+
+ template<class TTargetType>
+ struct LosslessCast
+ {
+#ifdef CVTT_PERMIT_ALIASING
+ template<int TSrcSubtype>
+ static const TTargetType& Cast(const VInt32<TSrcSubtype> &src)
+ {
+ return reinterpret_cast<VInt32<TSubtype>&>(src);
+ }
+
+ template<int TSrcSubtype>
+ static const TTargetType& Cast(const VInt16<TSrcSubtype> &src)
+ {
+ return reinterpret_cast<VInt16<TSubtype>&>(src);
+ }
+#else
+ template<int TSrcSubtype>
+ static TTargetType Cast(const VInt32<TSrcSubtype> &src)
+ {
+ TTargetType result;
+ result.m_values[0] = src.m_values[0];
+ result.m_values[1] = src.m_values[1];
+ return result;
+ }
+
+ template<int TSrcSubtype>
+ static TTargetType Cast(const VInt16<TSrcSubtype> &src)
+ {
+ TTargetType result;
+ result.m_value = src.m_value;
+ return result;
+ }
+#endif
+ };
+
+ struct Int64
+ {
+ __m128i m_values[4];
+ };
+
+ struct Float
+ {
+ __m128 m_values[2];
+
+ inline Float operator+(const Float &other) const
+ {
+ Float result;
+ result.m_values[0] = _mm_add_ps(m_values[0], other.m_values[0]);
+ result.m_values[1] = _mm_add_ps(m_values[1], other.m_values[1]);
+ return result;
+ }
+
+ inline Float operator+(float other) const
+ {
+ Float result;
+ result.m_values[0] = _mm_add_ps(m_values[0], _mm_set1_ps(other));
+ result.m_values[1] = _mm_add_ps(m_values[1], _mm_set1_ps(other));
+ return result;
+ }
+
+ inline Float operator-(const Float& other) const
+ {
+ Float result;
+ result.m_values[0] = _mm_sub_ps(m_values[0], other.m_values[0]);
+ result.m_values[1] = _mm_sub_ps(m_values[1], other.m_values[1]);
+ return result;
+ }
+
+ inline Float operator-() const
+ {
+ Float result;
+ result.m_values[0] = _mm_sub_ps(_mm_setzero_ps(), m_values[0]);
+ result.m_values[1] = _mm_sub_ps(_mm_setzero_ps(), m_values[1]);
+ return result;
+ }
+
+ inline Float operator*(const Float& other) const
+ {
+ Float result;
+ result.m_values[0] = _mm_mul_ps(m_values[0], other.m_values[0]);
+ result.m_values[1] = _mm_mul_ps(m_values[1], other.m_values[1]);
+ return result;
+ }
+
+ inline Float operator*(float other) const
+ {
+ Float result;
+ result.m_values[0] = _mm_mul_ps(m_values[0], _mm_set1_ps(other));
+ result.m_values[1] = _mm_mul_ps(m_values[1], _mm_set1_ps(other));
+ return result;
+ }
+
+ inline Float operator/(const Float &other) const
+ {
+ Float result;
+ result.m_values[0] = _mm_div_ps(m_values[0], other.m_values[0]);
+ result.m_values[1] = _mm_div_ps(m_values[1], other.m_values[1]);
+ return result;
+ }
+
+ inline Float operator/(float other) const
+ {
+ Float result;
+ result.m_values[0] = _mm_div_ps(m_values[0], _mm_set1_ps(other));
+ result.m_values[1] = _mm_div_ps(m_values[1], _mm_set1_ps(other));
+ return result;
+ }
+ };
+
+ struct Int16CompFlag
+ {
+ __m128i m_value;
+
+ inline Int16CompFlag operator&(const Int16CompFlag &other) const
+ {
+ Int16CompFlag result;
+ result.m_value = _mm_and_si128(m_value, other.m_value);
+ return result;
+ }
+
+ inline Int16CompFlag operator|(const Int16CompFlag &other) const
+ {
+ Int16CompFlag result;
+ result.m_value = _mm_or_si128(m_value, other.m_value);
+ return result;
+ }
+ };
+
+ struct FloatCompFlag
+ {
+ __m128 m_values[2];
+ };
+
+ template<int TSubtype>
+ static VInt16<TSubtype> AbstractAdd(const VInt16<TSubtype> &a, const VInt16<TSubtype> &b)
+ {
+ VInt16<TSubtype> result;
+ result.m_value = _mm_add_epi16(a.m_value, b.m_value);
+ return result;
+ }
+
+ template<int TSubtype>
+ static VInt16<TSubtype> AbstractSubtract(const VInt16<TSubtype> &a, const VInt16<TSubtype> &b)
+ {
+ VInt16<TSubtype> result;
+ result.m_value = _mm_sub_epi16(a.m_value, b.m_value);
+ return result;
+ }
+
+ static Float Select(const FloatCompFlag &flag, const Float &a, const Float &b)
+ {
+ Float result;
+ for (int i = 0; i < 2; i++)
+ result.m_values[i] = _mm_or_ps(_mm_and_ps(flag.m_values[i], a.m_values[i]), _mm_andnot_ps(flag.m_values[i], b.m_values[i]));
+ return result;
+ }
+
+ template<int TSubtype>
+ static VInt16<TSubtype> Select(const Int16CompFlag &flag, const VInt16<TSubtype> &a, const VInt16<TSubtype> &b)
+ {
+ VInt16<TSubtype> result;
+ result.m_value = _mm_or_si128(_mm_and_si128(flag.m_value, a.m_value), _mm_andnot_si128(flag.m_value, b.m_value));
+ return result;
+ }
+
+ template<int TSubtype>
+ static VInt16<TSubtype> SelectOrZero(const Int16CompFlag &flag, const VInt16<TSubtype> &a)
+ {
+ VInt16<TSubtype> result;
+ result.m_value = _mm_and_si128(flag.m_value, a.m_value);
+ return result;
+ }
+
+ template<int TSubtype>
+ static void ConditionalSet(VInt16<TSubtype> &dest, const Int16CompFlag &flag, const VInt16<TSubtype> &src)
+ {
+ dest.m_value = _mm_or_si128(_mm_andnot_si128(flag.m_value, dest.m_value), _mm_and_si128(flag.m_value, src.m_value));
+ }
+
+ static SInt16 ConditionalNegate(const Int16CompFlag &flag, const SInt16 &v)
+ {
+ SInt16 result;
+ result.m_value = _mm_add_epi16(_mm_xor_si128(flag.m_value, v.m_value), _mm_srli_epi16(flag.m_value, 15));
+ return result;
+ }
+
+ template<int TSubtype>
+ static void NotConditionalSet(VInt16<TSubtype> &dest, const Int16CompFlag &flag, const VInt16<TSubtype> &src)
+ {
+ dest.m_value = _mm_or_si128(_mm_and_si128(flag.m_value, dest.m_value), _mm_andnot_si128(flag.m_value, src.m_value));
+ }
+
+ static void ConditionalSet(Float &dest, const FloatCompFlag &flag, const Float &src)
+ {
+ for (int i = 0; i < 2; i++)
+ dest.m_values[i] = _mm_or_ps(_mm_andnot_ps(flag.m_values[i], dest.m_values[i]), _mm_and_ps(flag.m_values[i], src.m_values[i]));
+ }
+
+ static void NotConditionalSet(Float &dest, const FloatCompFlag &flag, const Float &src)
+ {
+ for (int i = 0; i < 2; i++)
+ dest.m_values[i] = _mm_or_ps(_mm_and_ps(flag.m_values[i], dest.m_values[i]), _mm_andnot_ps(flag.m_values[i], src.m_values[i]));
+ }
+
+ static void MakeSafeDenominator(Float& v)
+ {
+ ConditionalSet(v, Equal(v, MakeFloatZero()), MakeFloat(1.0f));
+ }
+
+ static SInt16 TruncateToPrecisionSigned(const SInt16 &v, int precision)
+ {
+ int lostBits = 16 - precision;
+ if (lostBits == 0)
+ return v;
+
+ SInt16 result;
+ result.m_value = _mm_srai_epi16(_mm_slli_epi16(v.m_value, lostBits), lostBits);
+ return result;
+ }
+
+ static UInt16 TruncateToPrecisionUnsigned(const UInt16 &v, int precision)
+ {
+ int lostBits = 16 - precision;
+ if (lostBits == 0)
+ return v;
+
+ UInt16 result;
+ result.m_value = _mm_srli_epi16(_mm_slli_epi16(v.m_value, lostBits), lostBits);
+ return result;
+ }
+
+ static UInt16 Min(const UInt16 &a, const UInt16 &b)
+ {
+ __m128i bitFlip = _mm_set1_epi16(-32768);
+
+ UInt16 result;
+ result.m_value = _mm_xor_si128(_mm_min_epi16(_mm_xor_si128(a.m_value, bitFlip), _mm_xor_si128(b.m_value, bitFlip)), bitFlip);
+ return result;
+ }
+
+ static SInt16 Min(const SInt16 &a, const SInt16 &b)
+ {
+ SInt16 result;
+ result.m_value = _mm_min_epi16(a.m_value, b.m_value);
+ return result;
+ }
+
+ static UInt15 Min(const UInt15 &a, const UInt15 &b)
+ {
+ UInt15 result;
+ result.m_value = _mm_min_epi16(a.m_value, b.m_value);
+ return result;
+ }
+
+ static Float Min(const Float &a, const Float &b)
+ {
+ Float result;
+ for (int i = 0; i < 2; i++)
+ result.m_values[i] = _mm_min_ps(a.m_values[i], b.m_values[i]);
+ return result;
+ }
+
+ static UInt16 Max(const UInt16 &a, const UInt16 &b)
+ {
+ __m128i bitFlip = _mm_set1_epi16(-32768);
+
+ UInt16 result;
+ result.m_value = _mm_xor_si128(_mm_max_epi16(_mm_xor_si128(a.m_value, bitFlip), _mm_xor_si128(b.m_value, bitFlip)), bitFlip);
+ return result;
+ }
+
+ static SInt16 Max(const SInt16 &a, const SInt16 &b)
+ {
+ SInt16 result;
+ result.m_value = _mm_max_epi16(a.m_value, b.m_value);
+ return result;
+ }
+
+ static UInt15 Max(const UInt15 &a, const UInt15 &b)
+ {
+ UInt15 result;
+ result.m_value = _mm_max_epi16(a.m_value, b.m_value);
+ return result;
+ }
+
+ static Float Max(const Float &a, const Float &b)
+ {
+ Float result;
+ for (int i = 0; i < 2; i++)
+ result.m_values[i] = _mm_max_ps(a.m_values[i], b.m_values[i]);
+ return result;
+ }
+
+ static Float Clamp(const Float &v, float min, float max)
+ {
+ Float result;
+ for (int i = 0; i < 2; i++)
+ result.m_values[i] = _mm_max_ps(_mm_min_ps(v.m_values[i], _mm_set1_ps(max)), _mm_set1_ps(min));
+ return result;
+ }
+
+ static Float Reciprocal(const Float &v)
+ {
+ Float result;
+ for (int i = 0; i < 2; i++)
+ result.m_values[i] = _mm_rcp_ps(v.m_values[i]);
+ return result;
+ }
+
+ static void ConvertLDRInputs(const PixelBlockU8* inputBlocks, int pxOffset, int channel, UInt15 &chOut)
+ {
+ int16_t values[8];
+ for (int i = 0; i < 8; i++)
+ values[i] = inputBlocks[i].m_pixels[pxOffset][channel];
+
+ chOut.m_value = _mm_set_epi16(values[7], values[6], values[5], values[4], values[3], values[2], values[1], values[0]);
+ }
+
+ static void ConvertHDRInputs(const PixelBlockF16* inputBlocks, int pxOffset, int channel, SInt16 &chOut)
+ {
+ int16_t values[8];
+ for (int i = 0; i < 8; i++)
+ values[i] = inputBlocks[i].m_pixels[pxOffset][channel];
+
+ chOut.m_value = _mm_set_epi16(values[7], values[6], values[5], values[4], values[3], values[2], values[1], values[0]);
+ }
+
+ static Float MakeFloat(float v)
+ {
+ Float f;
+ f.m_values[0] = f.m_values[1] = _mm_set1_ps(v);
+ return f;
+ }
+
+ static Float MakeFloatZero()
+ {
+ Float f;
+ f.m_values[0] = f.m_values[1] = _mm_setzero_ps();
+ return f;
+ }
+
+ static UInt16 MakeUInt16(uint16_t v)
+ {
+ UInt16 result;
+ result.m_value = _mm_set1_epi16(static_cast<short>(v));
+ return result;
+ }
+
+ static SInt16 MakeSInt16(int16_t v)
+ {
+ SInt16 result;
+ result.m_value = _mm_set1_epi16(static_cast<short>(v));
+ return result;
+ }
+
+ static AInt16 MakeAInt16(int16_t v)
+ {
+ AInt16 result;
+ result.m_value = _mm_set1_epi16(static_cast<short>(v));
+ return result;
+ }
+
+ static UInt15 MakeUInt15(uint16_t v)
+ {
+ UInt15 result;
+ result.m_value = _mm_set1_epi16(static_cast<short>(v));
+ return result;
+ }
+
+ static SInt32 MakeSInt32(int32_t v)
+ {
+ SInt32 result;
+ result.m_values[0] = _mm_set1_epi32(v);
+ result.m_values[1] = _mm_set1_epi32(v);
+ return result;
+ }
+
+ static UInt31 MakeUInt31(uint32_t v)
+ {
+ UInt31 result;
+ result.m_values[0] = _mm_set1_epi32(v);
+ result.m_values[1] = _mm_set1_epi32(v);
+ return result;
+ }
+
+ static uint16_t Extract(const UInt16 &v, int offset)
+ {
+ return reinterpret_cast<const uint16_t*>(&v.m_value)[offset];
+ }
+
+ static int16_t Extract(const SInt16 &v, int offset)
+ {
+ return reinterpret_cast<const int16_t*>(&v.m_value)[offset];
+ }
+
+ static uint16_t Extract(const UInt15 &v, int offset)
+ {
+ return reinterpret_cast<const uint16_t*>(&v.m_value)[offset];
+ }
+
+ static int16_t Extract(const AInt16 &v, int offset)
+ {
+ return reinterpret_cast<const int16_t*>(&v.m_value)[offset];
+ }
+
+ static void PutUInt16(UInt16 &dest, int offset, uint16_t v)
+ {
+ reinterpret_cast<uint16_t*>(&dest)[offset] = v;
+ }
+
+ static void PutUInt15(UInt15 &dest, int offset, uint16_t v)
+ {
+ reinterpret_cast<uint16_t*>(&dest)[offset] = v;
+ }
+
+ static void PutSInt16(SInt16 &dest, int offset, int16_t v)
+ {
+ reinterpret_cast<int16_t*>(&dest)[offset] = v;
+ }
+
+ static float ExtractFloat(const Float& v, int offset)
+ {
+ return reinterpret_cast<const float*>(&v)[offset];
+ }
+
+ static void PutFloat(Float &dest, int offset, float v)
+ {
+ reinterpret_cast<float*>(&dest)[offset] = v;
+ }
+
+ static Int16CompFlag Less(const SInt16 &a, const SInt16 &b)
+ {
+ Int16CompFlag result;
+ result.m_value = _mm_cmplt_epi16(a.m_value, b.m_value);
+ return result;
+ }
+
+ static Int16CompFlag Less(const UInt15 &a, const UInt15 &b)
+ {
+ Int16CompFlag result;
+ result.m_value = _mm_cmplt_epi16(a.m_value, b.m_value);
+ return result;
+ }
+
+ static Int16CompFlag LessOrEqual(const UInt15 &a, const UInt15 &b)
+ {
+ Int16CompFlag result;
+ result.m_value = _mm_cmplt_epi16(a.m_value, b.m_value);
+ return result;
+ }
+
+ static FloatCompFlag Less(const Float &a, const Float &b)
+ {
+ FloatCompFlag result;
+ for (int i = 0; i < 2; i++)
+ result.m_values[i] = _mm_cmplt_ps(a.m_values[i], b.m_values[i]);
+ return result;
+ }
+
+ static FloatCompFlag LessOrEqual(const Float &a, const Float &b)
+ {
+ FloatCompFlag result;
+ for (int i = 0; i < 2; i++)
+ result.m_values[i] = _mm_cmple_ps(a.m_values[i], b.m_values[i]);
+ return result;
+ }
+
+ template<int TSubtype>
+ static Int16CompFlag Equal(const VInt16<TSubtype> &a, const VInt16<TSubtype> &b)
+ {
+ Int16CompFlag result;
+ result.m_value = _mm_cmpeq_epi16(a.m_value, b.m_value);
+ return result;
+ }
+
+ static FloatCompFlag Equal(const Float &a, const Float &b)
+ {
+ FloatCompFlag result;
+ for (int i = 0; i < 2; i++)
+ result.m_values[i] = _mm_cmpeq_ps(a.m_values[i], b.m_values[i]);
+ return result;
+ }
+
+ static Float ToFloat(const UInt16 &v)
+ {
+ Float result;
+ result.m_values[0] = _mm_cvtepi32_ps(_mm_unpacklo_epi16(v.m_value, _mm_setzero_si128()));
+ result.m_values[1] = _mm_cvtepi32_ps(_mm_unpackhi_epi16(v.m_value, _mm_setzero_si128()));
+ return result;
+ }
+
+ static UInt31 ToUInt31(const UInt16 &v)
+ {
+ UInt31 result;
+ result.m_values[0] = _mm_unpacklo_epi16(v.m_value, _mm_setzero_si128());
+ result.m_values[1] = _mm_unpackhi_epi16(v.m_value, _mm_setzero_si128());
+ return result;
+ }
+
+ static SInt32 ToInt32(const UInt16 &v)
+ {
+ SInt32 result;
+ result.m_values[0] = _mm_unpacklo_epi16(v.m_value, _mm_setzero_si128());
+ result.m_values[1] = _mm_unpackhi_epi16(v.m_value, _mm_setzero_si128());
+ return result;
+ }
+
+ static SInt32 ToInt32(const SInt16 &v)
+ {
+ SInt32 result;
+ result.m_values[0] = _mm_srai_epi32(_mm_unpacklo_epi16(_mm_setzero_si128(), v.m_value), 16);
+ result.m_values[1] = _mm_srai_epi32(_mm_unpackhi_epi16(_mm_setzero_si128(), v.m_value), 16);
+ return result;
+ }
+
+ static Float ToFloat(const SInt16 &v)
+ {
+ Float result;
+ result.m_values[0] = _mm_cvtepi32_ps(_mm_srai_epi32(_mm_unpacklo_epi16(_mm_setzero_si128(), v.m_value), 16));
+ result.m_values[1] = _mm_cvtepi32_ps(_mm_srai_epi32(_mm_unpackhi_epi16(_mm_setzero_si128(), v.m_value), 16));
+ return result;
+ }
+
+ static Float ToFloat(const UInt15 &v)
+ {
+ Float result;
+ result.m_values[0] = _mm_cvtepi32_ps(_mm_unpacklo_epi16(v.m_value, _mm_setzero_si128()));
+ result.m_values[1] = _mm_cvtepi32_ps(_mm_unpackhi_epi16(v.m_value, _mm_setzero_si128()));
+ return result;
+ }
+
+ static Float ToFloat(const UInt31 &v)
+ {
+ Float result;
+ result.m_values[0] = _mm_cvtepi32_ps(v.m_values[0]);
+ result.m_values[1] = _mm_cvtepi32_ps(v.m_values[1]);
+ return result;
+ }
+
+ static Int16CompFlag FloatFlagToInt16(const FloatCompFlag &v)
+ {
+ __m128i lo = _mm_castps_si128(v.m_values[0]);
+ __m128i hi = _mm_castps_si128(v.m_values[1]);
+
+ Int16CompFlag result;
+ result.m_value = _mm_packs_epi32(lo, hi);
+ return result;
+ }
+
+ static FloatCompFlag Int16FlagToFloat(const Int16CompFlag &v)
+ {
+ __m128i lo = _mm_unpacklo_epi16(v.m_value, v.m_value);
+ __m128i hi = _mm_unpackhi_epi16(v.m_value, v.m_value);
+
+ FloatCompFlag result;
+ result.m_values[0] = _mm_castsi128_ps(lo);
+ result.m_values[1] = _mm_castsi128_ps(hi);
+ return result;
+ }
+
+ static Int16CompFlag MakeBoolInt16(bool b)
+ {
+ Int16CompFlag result;
+ if (b)
+ result.m_value = _mm_set1_epi16(-1);
+ else
+ result.m_value = _mm_setzero_si128();
+ return result;
+ }
+
+ static FloatCompFlag MakeBoolFloat(bool b)
+ {
+ FloatCompFlag result;
+ if (b)
+ result.m_values[0] = result.m_values[1] = _mm_castsi128_ps(_mm_set1_epi32(-1));
+ else
+ result.m_values[0] = result.m_values[1] = _mm_setzero_ps();
+ return result;
+ }
+
+ static Int16CompFlag AndNot(const Int16CompFlag &a, const Int16CompFlag &b)
+ {
+ Int16CompFlag result;
+ result.m_value = _mm_andnot_si128(b.m_value, a.m_value);
+ return result;
+ }
+
+ static UInt16 RoundAndConvertToU16(const Float &v, const void* /*roundingMode*/)
+ {
+ __m128i lo = _mm_cvtps_epi32(_mm_add_ps(v.m_values[0], _mm_set1_ps(-32768)));
+ __m128i hi = _mm_cvtps_epi32(_mm_add_ps(v.m_values[1], _mm_set1_ps(-32768)));
+
+ __m128i packed = _mm_packs_epi32(lo, hi);
+
+ UInt16 result;
+ result.m_value = _mm_xor_si128(packed, _mm_set1_epi16(-32768));
+ return result;
+ }
+
+ static UInt15 RoundAndConvertToU15(const Float &v, const void* /*roundingMode*/)
+ {
+ __m128i lo = _mm_cvtps_epi32(v.m_values[0]);
+ __m128i hi = _mm_cvtps_epi32(v.m_values[1]);
+
+ __m128i packed = _mm_packs_epi32(lo, hi);
+
+ UInt15 result;
+ result.m_value = _mm_packs_epi32(lo, hi);
+ return result;
+ }
+
+ static SInt16 RoundAndConvertToS16(const Float &v, const void* /*roundingMode*/)
+ {
+ __m128i lo = _mm_cvtps_epi32(v.m_values[0]);
+ __m128i hi = _mm_cvtps_epi32(v.m_values[1]);
+
+ __m128i packed = _mm_packs_epi32(lo, hi);
+
+ SInt16 result;
+ result.m_value = _mm_packs_epi32(lo, hi);
+ return result;
+ }
+
+ static Float Sqrt(const Float &f)
+ {
+ Float result;
+ for (int i = 0; i < 2; i++)
+ result.m_values[i] = _mm_sqrt_ps(f.m_values[i]);
+ return result;
+ }
+
+ static UInt16 Abs(const SInt16 &a)
+ {
+ __m128i signBitsXor = _mm_srai_epi16(a.m_value, 15);
+ __m128i signBitsAdd = _mm_srli_epi16(a.m_value, 15);
+
+ UInt16 result;
+ result.m_value = _mm_add_epi16(_mm_xor_si128(a.m_value, signBitsXor), signBitsAdd);
+ return result;
+ }
+
+ static Float Abs(const Float& a)
+ {
+ __m128 invMask = _mm_set1_ps(-0.0f);
+
+ Float result;
+ result.m_values[0] = _mm_andnot_ps(invMask, a.m_values[0]);
+ result.m_values[1] = _mm_andnot_ps(invMask, a.m_values[1]);
+ return result;
+ }
+
+ static UInt16 SqDiffUInt8(const UInt15 &a, const UInt15 &b)
+ {
+ __m128i diff = _mm_sub_epi16(a.m_value, b.m_value);
+
+ UInt16 result;
+ result.m_value = _mm_mullo_epi16(diff, diff);
+ return result;
+ }
+
+ static Float SqDiffSInt16(const SInt16 &a, const SInt16 &b)
+ {
+ __m128i diffU = _mm_sub_epi16(_mm_max_epi16(a.m_value, b.m_value), _mm_min_epi16(a.m_value, b.m_value));
+
+ __m128i mulHi = _mm_mulhi_epu16(diffU, diffU);
+ __m128i mulLo = _mm_mullo_epi16(diffU, diffU);
+ __m128i sqDiffHi = _mm_unpackhi_epi16(mulLo, mulHi);
+ __m128i sqDiffLo = _mm_unpacklo_epi16(mulLo, mulHi);
+
+ Float result;
+ result.m_values[0] = _mm_cvtepi32_ps(sqDiffLo);
+ result.m_values[1] = _mm_cvtepi32_ps(sqDiffHi);
+
+ return result;
+ }
+
+ static Float TwosCLHalfToFloat(const SInt16 &v)
+ {
+ __m128i absV = _mm_add_epi16(_mm_xor_si128(v.m_value, _mm_srai_epi16(v.m_value, 15)), _mm_srli_epi16(v.m_value, 15));
+
+ __m128i signBits = _mm_and_si128(v.m_value, _mm_set1_epi16(-32768));
+ __m128i mantissa = _mm_and_si128(v.m_value, _mm_set1_epi16(0x03ff));
+ __m128i exponent = _mm_and_si128(v.m_value, _mm_set1_epi16(0x7c00));
+
+ __m128i isDenormal = _mm_cmpeq_epi16(exponent, _mm_setzero_si128());
+
+ // Convert exponent to high-bits
+ exponent = _mm_add_epi16(_mm_srli_epi16(exponent, 3), _mm_set1_epi16(14336));
+
+ __m128i denormalCorrectionHigh = _mm_and_si128(isDenormal, _mm_or_si128(signBits, _mm_set1_epi16(14336)));
+
+ __m128i highBits = _mm_or_si128(signBits, _mm_or_si128(exponent, _mm_srli_epi16(mantissa, 3)));
+ __m128i lowBits = _mm_slli_epi16(mantissa, 13);
+
+ __m128i flow = _mm_unpacklo_epi16(lowBits, highBits);
+ __m128i fhigh = _mm_unpackhi_epi16(lowBits, highBits);
+
+ __m128i correctionLow = _mm_unpacklo_epi16(_mm_setzero_si128(), denormalCorrectionHigh);
+ __m128i correctionHigh = _mm_unpackhi_epi16(_mm_setzero_si128(), denormalCorrectionHigh);
+
+ Float result;
+ result.m_values[0] = _mm_sub_ps(_mm_castsi128_ps(flow), _mm_castsi128_ps(correctionLow));
+ result.m_values[1] = _mm_sub_ps(_mm_castsi128_ps(fhigh), _mm_castsi128_ps(correctionHigh));
+
+ return result;
+ }
+
+ static Float SqDiff2CLFloat(const SInt16 &a, const Float &b)
+ {
+ Float fa = TwosCLHalfToFloat(a);
+
+ Float diff = fa - b;
+ return diff * diff;
+ }
+
+ static Float SqDiff2CL(const SInt16 &a, const SInt16 &b)
+ {
+ Float fa = TwosCLHalfToFloat(a);
+ Float fb = TwosCLHalfToFloat(b);
+
+ Float diff = fa - fb;
+ return diff * diff;
+ }
+
+ static Float SqDiff2CLFloat(const SInt16 &a, float aWeight, const Float &b)
+ {
+ Float fa = TwosCLHalfToFloat(a) * aWeight;
+
+ Float diff = fa - b;
+ return diff * diff;
+ }
+
+ static UInt16 RightShift(const UInt16 &v, int bits)
+ {
+ UInt16 result;
+ result.m_value = _mm_srli_epi16(v.m_value, bits);
+ return result;
+ }
+
+ static UInt31 RightShift(const UInt31 &v, int bits)
+ {
+ UInt31 result;
+ result.m_values[0] = _mm_srli_epi32(v.m_values[0], bits);
+ result.m_values[1] = _mm_srli_epi32(v.m_values[1], bits);
+ return result;
+ }
+
+ static SInt16 RightShift(const SInt16 &v, int bits)
+ {
+ SInt16 result;
+ result.m_value = _mm_srai_epi16(v.m_value, bits);
+ return result;
+ }
+
+ static UInt15 RightShift(const UInt15 &v, int bits)
+ {
+ UInt15 result;
+ result.m_value = _mm_srli_epi16(v.m_value, bits);
+ return result;
+ }
+
+ static SInt32 RightShift(const SInt32 &v, int bits)
+ {
+ SInt32 result;
+ result.m_values[0] = _mm_srai_epi32(v.m_values[0], bits);
+ result.m_values[1] = _mm_srai_epi32(v.m_values[1], bits);
+ return result;
+ }
+
+ static SInt16 ToSInt16(const SInt32 &v)
+ {
+ SInt16 result;
+ result.m_value = _mm_packs_epi32(v.m_values[0], v.m_values[1]);
+ return result;
+ }
+
+ static UInt16 ToUInt16(const UInt32 &v)
+ {
+ __m128i low = _mm_srai_epi32(_mm_slli_epi32(v.m_values[0], 16), 16);
+ __m128i high = _mm_srai_epi32(_mm_slli_epi32(v.m_values[1], 16), 16);
+
+ UInt16 result;
+ result.m_value = _mm_packs_epi32(low, high);
+ return result;
+ }
+
+ static UInt16 ToUInt16(const UInt31 &v)
+ {
+ __m128i low = _mm_srai_epi32(_mm_slli_epi32(v.m_values[0], 16), 16);
+ __m128i high = _mm_srai_epi32(_mm_slli_epi32(v.m_values[1], 16), 16);
+
+ UInt16 result;
+ result.m_value = _mm_packs_epi32(low, high);
+ return result;
+ }
+
+ static UInt15 ToUInt15(const UInt31 &v)
+ {
+ UInt15 result;
+ result.m_value = _mm_packs_epi32(v.m_values[0], v.m_values[1]);
+ return result;
+ }
+
+ static SInt32 XMultiply(const SInt16 &a, const SInt16 &b)
+ {
+ __m128i high = _mm_mulhi_epi16(a.m_value, b.m_value);
+ __m128i low = _mm_mullo_epi16(a.m_value, b.m_value);
+
+ SInt32 result;
+ result.m_values[0] = _mm_unpacklo_epi16(low, high);
+ result.m_values[1] = _mm_unpackhi_epi16(low, high);
+ return result;
+ }
+
+ static SInt32 XMultiply(const SInt16 &a, const UInt15 &b)
+ {
+ __m128i high = _mm_mulhi_epi16(a.m_value, b.m_value);
+ __m128i low = _mm_mullo_epi16(a.m_value, b.m_value);
+
+ SInt32 result;
+ result.m_values[0] = _mm_unpacklo_epi16(low, high);
+ result.m_values[1] = _mm_unpackhi_epi16(low, high);
+ return result;
+ }
+
+ static SInt32 XMultiply(const UInt15 &a, const SInt16 &b)
+ {
+ return XMultiply(b, a);
+ }
+
+ static UInt32 XMultiply(const UInt16 &a, const UInt16 &b)
+ {
+ __m128i high = _mm_mulhi_epu16(a.m_value, b.m_value);
+ __m128i low = _mm_mullo_epi16(a.m_value, b.m_value);
+
+ UInt32 result;
+ result.m_values[0] = _mm_unpacklo_epi16(low, high);
+ result.m_values[1] = _mm_unpackhi_epi16(low, high);
+ return result;
+ }
+
+ static UInt16 CompactMultiply(const UInt16 &a, const UInt15 &b)
+ {
+ UInt16 result;
+ result.m_value = _mm_mullo_epi16(a.m_value, b.m_value);
+ return result;
+ }
+
+ static UInt16 CompactMultiply(const UInt15 &a, const UInt15 &b)
+ {
+ UInt16 result;
+ result.m_value = _mm_mullo_epi16(a.m_value, b.m_value);
+ return result;
+ }
+
+ static UInt31 XMultiply(const UInt15 &a, const UInt15 &b)
+ {
+ __m128i high = _mm_mulhi_epu16(a.m_value, b.m_value);
+ __m128i low = _mm_mullo_epi16(a.m_value, b.m_value);
+
+ UInt31 result;
+ result.m_values[0] = _mm_unpacklo_epi16(low, high);
+ result.m_values[1] = _mm_unpackhi_epi16(low, high);
+ return result;
+ }
+
+ static UInt31 XMultiply(const UInt16 &a, const UInt15 &b)
+ {
+ __m128i high = _mm_mulhi_epu16(a.m_value, b.m_value);
+ __m128i low = _mm_mullo_epi16(a.m_value, b.m_value);
+
+ UInt31 result;
+ result.m_values[0] = _mm_unpacklo_epi16(low, high);
+ result.m_values[1] = _mm_unpackhi_epi16(low, high);
+ return result;
+ }
+
+ static UInt31 XMultiply(const UInt15 &a, const UInt16 &b)
+ {
+ return XMultiply(b, a);
+ }
+
+ static bool AnySet(const Int16CompFlag &v)
+ {
+ return _mm_movemask_epi8(v.m_value) != 0;
+ }
+
+ static bool AllSet(const Int16CompFlag &v)
+ {
+ return _mm_movemask_epi8(v.m_value) == 0xffff;
+ }
+
+ static bool AnySet(const FloatCompFlag &v)
+ {
+ return _mm_movemask_ps(v.m_values[0]) != 0 || _mm_movemask_ps(v.m_values[1]) != 0;
+ }
+
+ static bool AllSet(const FloatCompFlag &v)
+ {
+ return _mm_movemask_ps(v.m_values[0]) == 0xf && _mm_movemask_ps(v.m_values[1]) == 0xf;
+ }
+ };
+
+#else
+ // Scalar version
+ struct ParallelMath
+ {
+ struct RoundTowardZeroForScope
+ {
+ };
+
+ struct RoundTowardNearestForScope
+ {
+ };
+
+ struct RoundUpForScope
+ {
+ };
+
+ struct RoundDownForScope
+ {
+ };
+
+ static const int ParallelSize = 1;
+
+ enum Int16Subtype
+ {
+ IntSubtype_Signed,
+ IntSubtype_UnsignedFull,
+ IntSubtype_UnsignedTruncated,
+ IntSubtype_Abstract,
+ };
+
+ typedef int32_t SInt16;
+ typedef int32_t UInt15;
+ typedef int32_t UInt16;
+ typedef int32_t AInt16;
+
+ typedef int32_t SInt32;
+ typedef int32_t UInt31;
+ typedef int32_t UInt32;
+ typedef int32_t AInt32;
+
+ typedef int32_t ScalarUInt16;
+ typedef int32_t ScalarSInt16;
+
+ typedef float Float;
+
+ template<class TTargetType>
+ struct LosslessCast
+ {
+ static const int32_t& Cast(const int32_t &src)
+ {
+ return src;
+ }
+ };
+
+ typedef bool Int16CompFlag;
+ typedef bool FloatCompFlag;
+
+ static int32_t AbstractAdd(const int32_t &a, const int32_t &b)
+ {
+ return a + b;
+ }
+
+ static int32_t AbstractSubtract(const int32_t &a, const int32_t &b)
+ {
+ return a - b;
+ }
+
+ static float Select(bool flag, float a, float b)
+ {
+ return flag ? a : b;
+ }
+
+ static int32_t Select(bool flag, int32_t a, int32_t b)
+ {
+ return flag ? a : b;
+ }
+
+ static int32_t SelectOrZero(bool flag, int32_t a)
+ {
+ return flag ? a : 0;
+ }
+
+ static void ConditionalSet(int32_t& dest, bool flag, int32_t src)
+ {
+ if (flag)
+ dest = src;
+ }
+
+ static int32_t ConditionalNegate(bool flag, int32_t v)
+ {
+ return (flag) ? -v : v;
+ }
+
+ static void NotConditionalSet(int32_t& dest, bool flag, int32_t src)
+ {
+ if (!flag)
+ dest = src;
+ }
+
+ static void ConditionalSet(float& dest, bool flag, float src)
+ {
+ if (flag)
+ dest = src;
+ }
+
+ static void NotConditionalSet(float& dest, bool flag, float src)
+ {
+ if (!flag)
+ dest = src;
+ }
+
+ static void MakeSafeDenominator(float& v)
+ {
+ if (v == 0.0f)
+ v = 1.0f;
+ }
+
+ static int32_t SignedRightShift(int32_t v, int bits)
+ {
+ return v >> bits;
+ }
+
+ static int32_t TruncateToPrecisionSigned(int32_t v, int precision)
+ {
+ v = (v << (32 - precision)) & 0xffffffff;
+ return SignedRightShift(v, 32 - precision);
+ }
+
+ static int32_t TruncateToPrecisionUnsigned(int32_t v, int precision)
+ {
+ return v & ((1 << precision) - 1);
+ }
+
+ static int32_t Min(int32_t a, int32_t b)
+ {
+ if (a < b)
+ return a;
+ return b;
+ }
+
+ static float Min(float a, float b)
+ {
+ if (a < b)
+ return a;
+ return b;
+ }
+
+ static int32_t Max(int32_t a, int32_t b)
+ {
+ if (a > b)
+ return a;
+ return b;
+ }
+
+ static float Max(float a, float b)
+ {
+ if (a > b)
+ return a;
+ return b;
+ }
+
+ static float Abs(float a)
+ {
+ return fabsf(a);
+ }
+
+ static int32_t Abs(int32_t a)
+ {
+ if (a < 0)
+ return -a;
+ return a;
+ }
+
+ static float Clamp(float v, float min, float max)
+ {
+ if (v < min)
+ return min;
+ if (v > max)
+ return max;
+ return v;
+ }
+
+ static float Reciprocal(float v)
+ {
+ return 1.0f / v;
+ }
+
+ static void ConvertLDRInputs(const PixelBlockU8* inputBlocks, int pxOffset, int channel, int32_t& chOut)
+ {
+ chOut = inputBlocks[0].m_pixels[pxOffset][channel];
+ }
+
+ static void ConvertHDRInputs(const PixelBlockF16* inputBlocks, int pxOffset, int channel, int32_t& chOut)
+ {
+ chOut = inputBlocks[0].m_pixels[pxOffset][channel];
+ }
+
+ static float MakeFloat(float v)
+ {
+ return v;
+ }
+
+ static float MakeFloatZero()
+ {
+ return 0.0f;
+ }
+
+ static int32_t MakeUInt16(uint16_t v)
+ {
+ return v;
+ }
+
+ static int32_t MakeSInt16(int16_t v)
+ {
+ return v;
+ }
+
+ static int32_t MakeAInt16(int16_t v)
+ {
+ return v;
+ }
+
+ static int32_t MakeUInt15(uint16_t v)
+ {
+ return v;
+ }
+
+ static int32_t MakeSInt32(int32_t v)
+ {
+ return v;
+ }
+
+ static int32_t MakeUInt31(int32_t v)
+ {
+ return v;
+ }
+
+ static int32_t Extract(int32_t v, int offset)
+ {
+ UNREFERENCED_PARAMETER(offset);
+ return v;
+ }
+
+ static void PutUInt16(int32_t &dest, int offset, ParallelMath::ScalarUInt16 v)
+ {
+ UNREFERENCED_PARAMETER(offset);
+ dest = v;
+ }
+
+ static void PutUInt15(int32_t &dest, int offset, ParallelMath::ScalarUInt16 v)
+ {
+ UNREFERENCED_PARAMETER(offset);
+ dest = v;
+ }
+
+ static void PutSInt16(int32_t &dest, int offset, ParallelMath::ScalarSInt16 v)
+ {
+ UNREFERENCED_PARAMETER(offset);
+ dest = v;
+ }
+
+ static float ExtractFloat(float v, int offset)
+ {
+ UNREFERENCED_PARAMETER(offset);
+ return v;
+ }
+
+ static void PutFloat(float &dest, int offset, float v)
+ {
+ UNREFERENCED_PARAMETER(offset);
+ dest = v;
+ }
+
+ static bool Less(int32_t a, int32_t b)
+ {
+ return a < b;
+ }
+
+ static bool Less(float a, float b)
+ {
+ return a < b;
+ }
+
+ static bool LessOrEqual(int32_t a, int32_t b)
+ {
+ return a < b;
+ }
+
+ static bool LessOrEqual(float a, float b)
+ {
+ return a < b;
+ }
+
+ static bool Equal(int32_t a, int32_t b)
+ {
+ return a == b;
+ }
+
+ static bool Equal(float a, float b)
+ {
+ return a == b;
+ }
+
+ static float ToFloat(int32_t v)
+ {
+ return static_cast<float>(v);
+ }
+
+ static int32_t ToUInt31(int32_t v)
+ {
+ return v;
+ }
+
+ static int32_t ToInt32(int32_t v)
+ {
+ return v;
+ }
+
+ static bool FloatFlagToInt16(bool v)
+ {
+ return v;
+ }
+
+ static bool Int16FlagToFloat(bool v)
+ {
+ return v;
+ }
+
+ static bool MakeBoolInt16(bool b)
+ {
+ return b;
+ }
+
+ static bool MakeBoolFloat(bool b)
+ {
+ return b;
+ }
+
+ static bool AndNot(bool a, bool b)
+ {
+ return a && !b;
+ }
+
+ static int32_t RoundAndConvertToInt(float v, const ParallelMath::RoundTowardZeroForScope *rtz)
+ {
+ UNREFERENCED_PARAMETER(rtz);
+ return static_cast<int>(v);
+ }
+
+ static int32_t RoundAndConvertToInt(float v, const ParallelMath::RoundUpForScope *ru)
+ {
+ UNREFERENCED_PARAMETER(ru);
+ return static_cast<int>(ceilf(v));
+ }
+
+ static int32_t RoundAndConvertToInt(float v, const ParallelMath::RoundDownForScope *rd)
+ {
+ UNREFERENCED_PARAMETER(rd);
+ return static_cast<int>(floorf(v));
+ }
+
+ static int32_t RoundAndConvertToInt(float v, const ParallelMath::RoundTowardNearestForScope *rtn)
+ {
+ UNREFERENCED_PARAMETER(rtn);
+ return static_cast<int>(floorf(v + 0.5f));
+ }
+
+ template<class TRoundMode>
+ static int32_t RoundAndConvertToU16(float v, const TRoundMode *roundingMode)
+ {
+ return RoundAndConvertToInt(v, roundingMode);
+ }
+
+ template<class TRoundMode>
+ static int32_t RoundAndConvertToU15(float v, const TRoundMode *roundingMode)
+ {
+ return RoundAndConvertToInt(v, roundingMode);
+ }
+
+ template<class TRoundMode>
+ static int32_t RoundAndConvertToS16(float v, const TRoundMode *roundingMode)
+ {
+ return RoundAndConvertToInt(v, roundingMode);
+ }
+
+ static float Sqrt(float f)
+ {
+ return sqrtf(f);
+ }
+
+ static int32_t SqDiffUInt8(int32_t a, int32_t b)
+ {
+ int32_t delta = a - b;
+ return delta * delta;
+ }
+
+ static int32_t SqDiffInt16(int32_t a, int32_t b)
+ {
+ int32_t delta = a - b;
+ return delta * delta;
+ }
+
+ static int32_t SqDiffSInt16(int32_t a, int32_t b)
+ {
+ int32_t delta = a - b;
+ return delta * delta;
+ }
+
+ static float TwosCLHalfToFloat(int32_t v)
+ {
+ int32_t absV = (v < 0) ? -v : v;
+
+ int32_t signBits = (absV & -32768);
+ int32_t mantissa = (absV & 0x03ff);
+ int32_t exponent = (absV & 0x7c00);
+
+ bool isDenormal = (exponent == 0);
+
+ // Convert exponent to high-bits
+ exponent = (exponent >> 3) + 14336;
+
+ int32_t denormalCorrection = (isDenormal ? (signBits | 14336) : 0) << 16;
+
+ int32_t fBits = ((exponent | signBits) << 16) | (mantissa << 13);
+
+ float f, correction;
+ memcpy(&f, &fBits, 4);
+ memcpy(&correction, &denormalCorrection, 4);
+
+ return f - correction;
+ }
+
+ static Float SqDiff2CLFloat(const SInt16 &a, const Float &b)
+ {
+ Float fa = TwosCLHalfToFloat(a);
+
+ Float diff = fa - b;
+ return diff * diff;
+ }
+
+ static Float SqDiff2CL(const SInt16 &a, const SInt16 &b)
+ {
+ Float fa = TwosCLHalfToFloat(a);
+ Float fb = TwosCLHalfToFloat(b);
+
+ Float diff = fa - fb;
+ return diff * diff;
+ }
+
+ static Float SqDiff2CLFloat(const SInt16 &a, float aWeight, const Float &b)
+ {
+ Float fa = TwosCLHalfToFloat(a) * aWeight;
+
+ Float diff = fa - b;
+ return diff * diff;
+ }
+
+ static int32_t RightShift(int32_t v, int bits)
+ {
+ return SignedRightShift(v, bits);
+ }
+
+ static int32_t ToSInt16(int32_t v)
+ {
+ return v;
+ }
+
+ static int32_t ToUInt16(int32_t v)
+ {
+ return v;
+ }
+
+ static int32_t ToUInt15(int32_t v)
+ {
+ return v;
+ }
+
+ static int32_t XMultiply(int32_t a, int32_t b)
+ {
+ return a * b;
+ }
+
+ static int32_t CompactMultiply(int32_t a, int32_t b)
+ {
+ return a * b;
+ }
+
+ static bool AnySet(bool v)
+ {
+ return v;
+ }
+
+ static bool AllSet(bool v)
+ {
+ return v;
+ }
+ };
+
+#endif
+
+ namespace Internal
+ {
+ namespace BC7Data
+ {
+ enum AlphaMode
+ {
+ AlphaMode_Combined,
+ AlphaMode_Separate,
+ AlphaMode_None,
+ };
+
+ enum PBitMode
+ {
+ PBitMode_PerEndpoint,
+ PBitMode_PerSubset,
+ PBitMode_None
+ };
+
+ struct BC7ModeInfo
+ {
+ PBitMode m_pBitMode;
+ AlphaMode m_alphaMode;
+ int m_rgbBits;
+ int m_alphaBits;
+ int m_partitionBits;
+ int m_numSubsets;
+ int m_indexBits;
+ int m_alphaIndexBits;
+ bool m_hasIndexSelector;
+ };
+
+ BC7ModeInfo g_modes[] =
+ {
+ { PBitMode_PerEndpoint, AlphaMode_None, 4, 0, 4, 3, 3, 0, false }, // 0
+ { PBitMode_PerSubset, AlphaMode_None, 6, 0, 6, 2, 3, 0, false }, // 1
+ { PBitMode_None, AlphaMode_None, 5, 0, 6, 3, 2, 0, false }, // 2
+ { PBitMode_PerEndpoint, AlphaMode_None, 7, 0, 6, 2, 2, 0, false }, // 3 (Mode reference has an error, P-bit is really per-endpoint)
+
+ { PBitMode_None, AlphaMode_Separate, 5, 6, 0, 1, 2, 3, true }, // 4
+ { PBitMode_None, AlphaMode_Separate, 7, 8, 0, 1, 2, 2, false }, // 5
+ { PBitMode_PerEndpoint, AlphaMode_Combined, 7, 7, 0, 1, 4, 0, false }, // 6
+ { PBitMode_PerEndpoint, AlphaMode_Combined, 5, 5, 6, 2, 2, 0, false } // 7
+ };
+
+ const int g_weight2[] = { 0, 21, 43, 64 };
+ const int g_weight3[] = { 0, 9, 18, 27, 37, 46, 55, 64 };
+ const int g_weight4[] = { 0, 4, 9, 13, 17, 21, 26, 30, 34, 38, 43, 47, 51, 55, 60, 64 };
+
+ const int *g_weightTables[] =
+ {
+ NULL,
+ NULL,
+ g_weight2,
+ g_weight3,
+ g_weight4
+ };
+
+ struct BC6HModeInfo
+ {
+ uint16_t m_modeID;
+ bool m_partitioned;
+ bool m_transformed;
+ int m_aPrec;
+ int m_bPrec[3];
+ };
+
+ // [partitioned][precision]
+ bool g_hdrModesExistForPrecision[2][17] =
+ {
+ //0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
+ { false, false, false, false, false, false, false, false, false, false, true, true, true, false, false, false, true },
+ { false, false, false, false, false, false, true, true, true, true, true, true, false, false, false, false, false },
+ };
+
+ BC6HModeInfo g_hdrModes[] =
+ {
+ { 0x00, true, true, 10,{ 5, 5, 5 } },
+ { 0x01, true, true, 7,{ 6, 6, 6 } },
+ { 0x02, true, true, 11,{ 5, 4, 4 } },
+ { 0x06, true, true, 11,{ 4, 5, 4 } },
+ { 0x0a, true, true, 11,{ 4, 4, 5 } },
+ { 0x0e, true, true, 9,{ 5, 5, 5 } },
+ { 0x12, true, true, 8,{ 6, 5, 5 } },
+ { 0x16, true, true, 8,{ 5, 6, 5 } },
+ { 0x1a, true, true, 8,{ 5, 5, 6 } },
+ { 0x1e, true, false, 6,{ 6, 6, 6 } },
+ { 0x03, false, false, 10,{ 10, 10, 10 } },
+ { 0x07, false, true, 11,{ 9, 9, 9 } },
+ { 0x0b, false, true, 12,{ 8, 8, 8 } },
+ { 0x0f, false, true, 16,{ 4, 4, 4 } },
+ };
+
+ const int g_maxHDRPrecision = 16;
+
+ static const size_t g_numHDRModes = sizeof(g_hdrModes) / sizeof(g_hdrModes[0]);
+
+ static uint16_t g_partitionMap[64] =
+ {
+ 0xCCCC, 0x8888, 0xEEEE, 0xECC8,
+ 0xC880, 0xFEEC, 0xFEC8, 0xEC80,
+ 0xC800, 0xFFEC, 0xFE80, 0xE800,
+ 0xFFE8, 0xFF00, 0xFFF0, 0xF000,
+ 0xF710, 0x008E, 0x7100, 0x08CE,
+ 0x008C, 0x7310, 0x3100, 0x8CCE,
+ 0x088C, 0x3110, 0x6666, 0x366C,
+ 0x17E8, 0x0FF0, 0x718E, 0x399C,
+ 0xaaaa, 0xf0f0, 0x5a5a, 0x33cc,
+ 0x3c3c, 0x55aa, 0x9696, 0xa55a,
+ 0x73ce, 0x13c8, 0x324c, 0x3bdc,
+ 0x6996, 0xc33c, 0x9966, 0x660,
+ 0x272, 0x4e4, 0x4e40, 0x2720,
+ 0xc936, 0x936c, 0x39c6, 0x639c,
+ 0x9336, 0x9cc6, 0x817e, 0xe718,
+ 0xccf0, 0xfcc, 0x7744, 0xee22,
+ };
+
+ static uint32_t g_partitionMap2[64] =
+ {
+ 0xaa685050, 0x6a5a5040, 0x5a5a4200, 0x5450a0a8,
+ 0xa5a50000, 0xa0a05050, 0x5555a0a0, 0x5a5a5050,
+ 0xaa550000, 0xaa555500, 0xaaaa5500, 0x90909090,
+ 0x94949494, 0xa4a4a4a4, 0xa9a59450, 0x2a0a4250,
+ 0xa5945040, 0x0a425054, 0xa5a5a500, 0x55a0a0a0,
+ 0xa8a85454, 0x6a6a4040, 0xa4a45000, 0x1a1a0500,
+ 0x0050a4a4, 0xaaa59090, 0x14696914, 0x69691400,
+ 0xa08585a0, 0xaa821414, 0x50a4a450, 0x6a5a0200,
+ 0xa9a58000, 0x5090a0a8, 0xa8a09050, 0x24242424,
+ 0x00aa5500, 0x24924924, 0x24499224, 0x50a50a50,
+ 0x500aa550, 0xaaaa4444, 0x66660000, 0xa5a0a5a0,
+ 0x50a050a0, 0x69286928, 0x44aaaa44, 0x66666600,
+ 0xaa444444, 0x54a854a8, 0x95809580, 0x96969600,
+ 0xa85454a8, 0x80959580, 0xaa141414, 0x96960000,
+ 0xaaaa1414, 0xa05050a0, 0xa0a5a5a0, 0x96000000,
+ 0x40804080, 0xa9a8a9a8, 0xaaaaaa44, 0x2a4a5254,
+ };
+
+ static int g_fixupIndexes2[64] =
+ {
+ 15,15,15,15,
+ 15,15,15,15,
+ 15,15,15,15,
+ 15,15,15,15,
+ 15, 2, 8, 2,
+ 2, 8, 8,15,
+ 2, 8, 2, 2,
+ 8, 8, 2, 2,
+
+ 15,15, 6, 8,
+ 2, 8,15,15,
+ 2, 8, 2, 2,
+ 2,15,15, 6,
+ 6, 2, 6, 8,
+ 15,15, 2, 2,
+ 15,15,15,15,
+ 15, 2, 2,15,
+ };
+
+ static int g_fixupIndexes3[64][2] =
+ {
+ { 3,15 },{ 3, 8 },{ 15, 8 },{ 15, 3 },
+ { 8,15 },{ 3,15 },{ 15, 3 },{ 15, 8 },
+ { 8,15 },{ 8,15 },{ 6,15 },{ 6,15 },
+ { 6,15 },{ 5,15 },{ 3,15 },{ 3, 8 },
+ { 3,15 },{ 3, 8 },{ 8,15 },{ 15, 3 },
+ { 3,15 },{ 3, 8 },{ 6,15 },{ 10, 8 },
+ { 5, 3 },{ 8,15 },{ 8, 6 },{ 6,10 },
+ { 8,15 },{ 5,15 },{ 15,10 },{ 15, 8 },
+
+ { 8,15 },{ 15, 3 },{ 3,15 },{ 5,10 },
+ { 6,10 },{ 10, 8 },{ 8, 9 },{ 15,10 },
+ { 15, 6 },{ 3,15 },{ 15, 8 },{ 5,15 },
+ { 15, 3 },{ 15, 6 },{ 15, 6 },{ 15, 8 },
+ { 3,15 },{ 15, 3 },{ 5,15 },{ 5,15 },
+ { 5,15 },{ 8,15 },{ 5,15 },{ 10,15 },
+ { 5,15 },{ 10,15 },{ 8,15 },{ 13,15 },
+ { 15, 3 },{ 12,15 },{ 3,15 },{ 3, 8 },
+ };
+
+ static const unsigned char g_fragments[] =
+ {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, // 0, 16
+ 0, 1, 2, 3, // 16, 4
+ 0, 1, 4, // 20, 3
+ 0, 1, 2, 4, // 23, 4
+ 2, 3, 7, // 27, 3
+ 1, 2, 3, 7, // 30, 4
+ 0, 1, 2, 3, 4, 5, 6, 7, // 34, 8
+ 0, 1, 4, 8, // 42, 4
+ 0, 1, 2, 4, 5, 8, // 46, 6
+ 0, 1, 2, 3, 4, 5, 6, 8, // 52, 8
+ 1, 4, 5, 6, 9, // 60, 5
+ 2, 5, 6, 7, 10, // 65, 5
+ 5, 6, 9, 10, // 70, 4
+ 2, 3, 7, 11, // 74, 4
+ 1, 2, 3, 6, 7, 11, // 78, 6
+ 0, 1, 2, 3, 5, 6, 7, 11, // 84, 8
+ 0, 1, 2, 3, 8, 9, 10, 11, // 92, 8
+ 2, 3, 6, 7, 8, 9, 10, 11, // 100, 8
+ 4, 5, 6, 7, 8, 9, 10, 11, // 108, 8
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, // 116, 12
+ 0, 4, 8, 12, // 128, 4
+ 0, 2, 3, 4, 6, 7, 8, 12, // 132, 8
+ 0, 1, 2, 4, 5, 8, 9, 12, // 140, 8
+ 0, 1, 2, 3, 4, 5, 6, 8, 9, 12, // 148, 10
+ 3, 6, 7, 8, 9, 12, // 158, 6
+ 3, 5, 6, 7, 8, 9, 10, 12, // 164, 8
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, // 172, 12
+ 0, 1, 2, 5, 6, 7, 11, 12, // 184, 8
+ 5, 8, 9, 10, 13, // 192, 5
+ 8, 12, 13, // 197, 3
+ 4, 8, 12, 13, // 200, 4
+ 2, 3, 6, 9, 12, 13, // 204, 6
+ 0, 1, 2, 3, 8, 9, 12, 13, // 210, 8
+ 0, 1, 4, 5, 8, 9, 12, 13, // 218, 8
+ 2, 3, 6, 7, 8, 9, 12, 13, // 226, 8
+ 2, 3, 5, 6, 9, 10, 12, 13, // 234, 8
+ 0, 3, 6, 7, 9, 10, 12, 13, // 242, 8
+ 0, 1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 13, // 250, 12
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 13, // 262, 13
+ 2, 3, 4, 7, 8, 11, 12, 13, // 275, 8
+ 1, 2, 6, 7, 8, 11, 12, 13, // 283, 8
+ 2, 3, 4, 6, 7, 8, 9, 11, 12, 13, // 291, 10
+ 2, 3, 4, 5, 10, 11, 12, 13, // 301, 8
+ 0, 1, 6, 7, 10, 11, 12, 13, // 309, 8
+ 6, 9, 10, 11, 14, // 317, 5
+ 0, 2, 4, 6, 8, 10, 12, 14, // 322, 8
+ 1, 3, 5, 7, 8, 10, 12, 14, // 330, 8
+ 1, 3, 4, 6, 9, 11, 12, 14, // 338, 8
+ 0, 2, 5, 7, 9, 11, 12, 14, // 346, 8
+ 0, 3, 4, 5, 8, 9, 13, 14, // 354, 8
+ 2, 3, 4, 7, 8, 9, 13, 14, // 362, 8
+ 1, 2, 5, 6, 9, 10, 13, 14, // 370, 8
+ 0, 3, 4, 7, 9, 10, 13, 14, // 378, 8
+ 0, 3, 5, 6, 8, 11, 13, 14, // 386, 8
+ 1, 2, 4, 7, 8, 11, 13, 14, // 394, 8
+ 0, 1, 4, 7, 10, 11, 13, 14, // 402, 8
+ 0, 3, 6, 7, 10, 11, 13, 14, // 410, 8
+ 8, 12, 13, 14, // 418, 4
+ 1, 2, 3, 7, 8, 12, 13, 14, // 422, 8
+ 4, 8, 9, 12, 13, 14, // 430, 6
+ 0, 4, 5, 8, 9, 12, 13, 14, // 436, 8
+ 1, 2, 3, 6, 7, 8, 9, 12, 13, 14, // 444, 10
+ 2, 6, 8, 9, 10, 12, 13, 14, // 454, 8
+ 0, 1, 2, 4, 5, 6, 8, 9, 10, 12, 13, 14, // 462, 12
+ 0, 7, 9, 10, 11, 12, 13, 14, // 474, 8
+ 1, 2, 3, 4, 5, 6, 8, 15, // 482, 8
+ 3, 7, 11, 15, // 490, 4
+ 0, 1, 3, 4, 5, 7, 11, 15, // 494, 8
+ 0, 4, 5, 10, 11, 15, // 502, 6
+ 1, 2, 3, 6, 7, 10, 11, 15, // 508, 8
+ 0, 1, 2, 3, 5, 6, 7, 10, 11, 15, // 516, 10
+ 0, 4, 5, 6, 9, 10, 11, 15, // 526, 8
+ 0, 1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 15, // 534, 12
+ 1, 2, 4, 5, 8, 9, 12, 15, // 546, 8
+ 2, 3, 5, 6, 8, 9, 12, 15, // 554, 8
+ 0, 3, 5, 6, 9, 10, 12, 15, // 562, 8
+ 1, 2, 4, 7, 9, 10, 12, 15, // 570, 8
+ 1, 2, 5, 6, 8, 11, 12, 15, // 578, 8
+ 0, 3, 4, 7, 8, 11, 12, 15, // 586, 8
+ 0, 1, 5, 6, 10, 11, 12, 15, // 594, 8
+ 1, 2, 6, 7, 10, 11, 12, 15, // 602, 8
+ 1, 3, 4, 6, 8, 10, 13, 15, // 610, 8
+ 0, 2, 5, 7, 8, 10, 13, 15, // 618, 8
+ 0, 2, 4, 6, 9, 11, 13, 15, // 626, 8
+ 1, 3, 5, 7, 9, 11, 13, 15, // 634, 8
+ 0, 1, 2, 3, 4, 5, 7, 8, 12, 13, 15, // 642, 11
+ 2, 3, 4, 5, 8, 9, 14, 15, // 653, 8
+ 0, 1, 6, 7, 8, 9, 14, 15, // 661, 8
+ 0, 1, 5, 10, 14, 15, // 669, 6
+ 0, 3, 4, 5, 9, 10, 14, 15, // 675, 8
+ 0, 1, 5, 6, 9, 10, 14, 15, // 683, 8
+ 11, 14, 15, // 691, 3
+ 7, 11, 14, 15, // 694, 4
+ 1, 2, 4, 5, 8, 11, 14, 15, // 698, 8
+ 0, 1, 4, 7, 8, 11, 14, 15, // 706, 8
+ 0, 1, 4, 5, 10, 11, 14, 15, // 714, 8
+ 2, 3, 6, 7, 10, 11, 14, 15, // 722, 8
+ 4, 5, 6, 7, 10, 11, 14, 15, // 730, 8
+ 0, 1, 4, 5, 7, 8, 10, 11, 14, 15, // 738, 10
+ 0, 1, 2, 3, 5, 6, 7, 9, 10, 11, 14, 15, // 748, 12
+ 0, 1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 14, 15, // 760, 13
+ 0, 1, 2, 3, 4, 6, 7, 11, 12, 14, 15, // 773, 11
+ 3, 4, 8, 9, 10, 13, 14, 15, // 784, 8
+ 11, 13, 14, 15, // 792, 4
+ 0, 1, 2, 4, 11, 13, 14, 15, // 796, 8
+ 0, 1, 2, 4, 5, 10, 11, 13, 14, 15, // 804, 10
+ 7, 10, 11, 13, 14, 15, // 814, 6
+ 3, 6, 7, 10, 11, 13, 14, 15, // 820, 8
+ 1, 5, 9, 10, 11, 13, 14, 15, // 828, 8
+ 1, 2, 3, 5, 6, 7, 9, 10, 11, 13, 14, 15, // 836, 12
+ 12, 13, 14, 15, // 848, 4
+ 0, 1, 2, 3, 12, 13, 14, 15, // 852, 8
+ 0, 1, 4, 5, 12, 13, 14, 15, // 860, 8
+ 4, 5, 6, 7, 12, 13, 14, 15, // 868, 8
+ 4, 8, 9, 10, 12, 13, 14, 15, // 876, 8
+ 0, 4, 5, 8, 9, 10, 12, 13, 14, 15, // 884, 10
+ 0, 1, 4, 5, 6, 8, 9, 10, 12, 13, 14, 15, // 894, 12
+ 0, 1, 2, 3, 4, 7, 8, 11, 12, 13, 14, 15, // 906, 12
+ 0, 1, 3, 4, 8, 9, 11, 12, 13, 14, 15, // 918, 11
+ 0, 2, 3, 7, 8, 10, 11, 12, 13, 14, 15, // 929, 11
+ 7, 9, 10, 11, 12, 13, 14, 15, // 940, 8
+ 3, 6, 7, 9, 10, 11, 12, 13, 14, 15, // 948, 10
+ 2, 3, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, // 958, 12
+ 8, 9, 10, 11, 12, 13, 14, 15, // 970, 8
+ 0, 4, 5, 6, 8, 9, 10, 11, 12, 13, 14, 15, // 978, 12
+ 0, 1, 4, 5, 6, 8, 9, 10, 11, 12, 13, 14, 15, // 990, 13
+ 3, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, // 1003, 12
+ 2, 3, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, // 1015, 13
+ 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, // 1028, 12
+ 0, 2, // 1040, 2
+ 1, 3, // 1042, 2
+ 0, 1, 4, 5, // 1044, 4
+ 0, 1, 2, 4, 5, // 1048, 5
+ 2, 3, 6, // 1053, 3
+ 0, 2, 4, 6, // 1056, 4
+ 1, 2, 5, 6, // 1060, 4
+ 0, 1, 2, 3, 5, 6, // 1064, 6
+ 0, 1, 2, 4, 5, 6, // 1070, 6
+ 0, 1, 2, 3, 4, 5, 6, // 1076, 7
+ 0, 3, 4, 7, // 1083, 4
+ 0, 1, 2, 3, 4, 7, // 1087, 6
+ 1, 3, 5, 7, // 1093, 4
+ 2, 3, 6, 7, // 1097, 4
+ 1, 2, 3, 6, 7, // 1101, 5
+ 1, 2, 3, 5, 6, 7, // 1106, 6
+ 0, 1, 2, 3, 5, 6, 7, // 1112, 7
+ 4, 5, 6, 7, // 1119, 4
+ 0, 8, // 1123, 2
+ 0, 1, 4, 5, 8, // 1125, 5
+ 0, 1, 8, 9, // 1130, 4
+ 4, 5, 8, 9, // 1134, 4
+ 0, 1, 4, 5, 8, 9, // 1138, 6
+ 2, 6, 8, 9, // 1144, 4
+ 6, 7, 8, 9, // 1148, 4
+ 0, 2, 4, 6, 8, 10, // 1152, 6
+ 1, 2, 5, 6, 9, 10, // 1158, 6
+ 0, 3, 4, 7, 9, 10, // 1164, 6
+ 0, 1, 2, 8, 9, 10, // 1170, 6
+ 4, 5, 6, 8, 9, 10, // 1176, 6
+ 3, 11, // 1182, 2
+ 2, 3, 6, 7, 11, // 1184, 5
+ 0, 3, 8, 11, // 1189, 4
+ 0, 3, 4, 7, 8, 11, // 1193, 6
+ 1, 3, 5, 7, 9, 11, // 1199, 6
+ 2, 3, 10, 11, // 1205, 4
+ 1, 5, 10, 11, // 1209, 4
+ 4, 5, 10, 11, // 1213, 4
+ 6, 7, 10, 11, // 1217, 4
+ 2, 3, 6, 7, 10, 11, // 1221, 6
+ 1, 2, 3, 9, 10, 11, // 1227, 6
+ 5, 6, 7, 9, 10, 11, // 1233, 6
+ 8, 9, 10, 11, // 1239, 4
+ 4, 12, // 1243, 2
+ 0, 1, 2, 3, 4, 5, 8, 12, // 1245, 8
+ 8, 9, 12, // 1253, 3
+ 0, 4, 5, 8, 9, 12, // 1256, 6
+ 0, 1, 4, 5, 8, 9, 12, // 1262, 7
+ 2, 3, 5, 6, 8, 9, 12, // 1269, 7
+ 1, 5, 9, 13, // 1276, 4
+ 6, 7, 9, 13, // 1280, 4
+ 1, 4, 7, 10, 13, // 1284, 5
+ 1, 6, 8, 11, 13, // 1289, 5
+ 0, 1, 12, 13, // 1294, 4
+ 4, 5, 12, 13, // 1298, 4
+ 0, 1, 6, 7, 12, 13, // 1302, 6
+ 0, 1, 4, 8, 12, 13, // 1308, 6
+ 8, 9, 12, 13, // 1314, 4
+ 4, 8, 9, 12, 13, // 1318, 5
+ 4, 5, 8, 9, 12, 13, // 1323, 6
+ 0, 4, 5, 8, 9, 12, 13, // 1329, 7
+ 0, 1, 6, 10, 12, 13, // 1336, 6
+ 3, 6, 7, 9, 10, 12, 13, // 1342, 7
+ 0, 1, 10, 11, 12, 13, // 1349, 6
+ 2, 4, 7, 9, 14, // 1355, 5
+ 4, 5, 10, 14, // 1360, 4
+ 2, 6, 10, 14, // 1364, 4
+ 2, 5, 8, 11, 14, // 1368, 5
+ 0, 2, 12, 14, // 1373, 4
+ 8, 10, 12, 14, // 1377, 4
+ 4, 6, 8, 10, 12, 14, // 1381, 6
+ 13, 14, // 1387, 2
+ 9, 10, 13, 14, // 1389, 4
+ 5, 6, 9, 10, 13, 14, // 1393, 6
+ 0, 1, 2, 12, 13, 14, // 1399, 6
+ 4, 5, 6, 12, 13, 14, // 1405, 6
+ 8, 9, 12, 13, 14, // 1411, 5
+ 8, 9, 10, 12, 13, 14, // 1416, 6
+ 7, 15, // 1422, 2
+ 0, 5, 10, 15, // 1424, 4
+ 0, 1, 2, 3, 6, 7, 11, 15, // 1428, 8
+ 10, 11, 15, // 1436, 3
+ 0, 1, 5, 6, 10, 11, 15, // 1439, 7
+ 3, 6, 7, 10, 11, 15, // 1446, 6
+ 12, 15, // 1452, 2
+ 0, 3, 12, 15, // 1454, 4
+ 4, 7, 12, 15, // 1458, 4
+ 0, 3, 6, 9, 12, 15, // 1462, 6
+ 0, 3, 5, 10, 12, 15, // 1468, 6
+ 8, 11, 12, 15, // 1474, 4
+ 5, 6, 8, 11, 12, 15, // 1478, 6
+ 4, 7, 8, 11, 12, 15, // 1484, 6
+ 1, 3, 13, 15, // 1490, 4
+ 9, 11, 13, 15, // 1494, 4
+ 5, 7, 9, 11, 13, 15, // 1498, 6
+ 2, 3, 14, 15, // 1504, 4
+ 2, 3, 4, 5, 14, 15, // 1508, 6
+ 6, 7, 14, 15, // 1514, 4
+ 2, 3, 5, 9, 14, 15, // 1518, 6
+ 2, 3, 8, 9, 14, 15, // 1524, 6
+ 10, 14, 15, // 1530, 3
+ 0, 4, 5, 9, 10, 14, 15, // 1533, 7
+ 2, 3, 7, 11, 14, 15, // 1540, 6
+ 10, 11, 14, 15, // 1546, 4
+ 7, 10, 11, 14, 15, // 1550, 5
+ 6, 7, 10, 11, 14, 15, // 1555, 6
+ 1, 2, 3, 13, 14, 15, // 1561, 6
+ 5, 6, 7, 13, 14, 15, // 1567, 6
+ 10, 11, 13, 14, 15, // 1573, 5
+ 9, 10, 11, 13, 14, 15, // 1578, 6
+ 0, 4, 8, 9, 12, 13, 14, 15, // 1584, 8
+ 9, 10, 12, 13, 14, 15, // 1592, 6
+ 8, 11, 12, 13, 14, 15, // 1598, 6
+ 3, 7, 10, 11, 12, 13, 14, 15, // 1604, 8
+ };
+ static const int g_shapeRanges[][2] =
+ {
+ { 0, 16 },{ 16, 4 },{ 20, 3 },{ 23, 4 },{ 27, 3 },{ 30, 4 },{ 34, 8 },{ 42, 4 },{ 46, 6 },{ 52, 8 },{ 60, 5 },
+ { 65, 5 },{ 70, 4 },{ 74, 4 },{ 78, 6 },{ 84, 8 },{ 92, 8 },{ 100, 8 },{ 108, 8 },{ 116, 12 },{ 128, 4 },{ 132, 8 },
+ { 140, 8 },{ 148, 10 },{ 158, 6 },{ 164, 8 },{ 172, 12 },{ 184, 8 },{ 192, 5 },{ 197, 3 },{ 200, 4 },{ 204, 6 },{ 210, 8 },
+ { 218, 8 },{ 226, 8 },{ 234, 8 },{ 242, 8 },{ 250, 12 },{ 262, 13 },{ 275, 8 },{ 283, 8 },{ 291, 10 },{ 301, 8 },{ 309, 8 },
+ { 317, 5 },{ 322, 8 },{ 330, 8 },{ 338, 8 },{ 346, 8 },{ 354, 8 },{ 362, 8 },{ 370, 8 },{ 378, 8 },{ 386, 8 },{ 394, 8 },
+ { 402, 8 },{ 410, 8 },{ 418, 4 },{ 422, 8 },{ 430, 6 },{ 436, 8 },{ 444, 10 },{ 454, 8 },{ 462, 12 },{ 474, 8 },{ 482, 8 },
+ { 490, 4 },{ 494, 8 },{ 502, 6 },{ 508, 8 },{ 516, 10 },{ 526, 8 },{ 534, 12 },{ 546, 8 },{ 554, 8 },{ 562, 8 },{ 570, 8 },
+ { 578, 8 },{ 586, 8 },{ 594, 8 },{ 602, 8 },{ 610, 8 },{ 618, 8 },{ 626, 8 },{ 634, 8 },{ 642, 11 },{ 653, 8 },{ 661, 8 },
+ { 669, 6 },{ 675, 8 },{ 683, 8 },{ 691, 3 },{ 694, 4 },{ 698, 8 },{ 706, 8 },{ 714, 8 },{ 722, 8 },{ 730, 8 },{ 738, 10 },
+ { 748, 12 },{ 760, 13 },{ 773, 11 },{ 784, 8 },{ 792, 4 },{ 796, 8 },{ 804, 10 },{ 814, 6 },{ 820, 8 },{ 828, 8 },{ 836, 12 },
+ { 848, 4 },{ 852, 8 },{ 860, 8 },{ 868, 8 },{ 876, 8 },{ 884, 10 },{ 894, 12 },{ 906, 12 },{ 918, 11 },{ 929, 11 },{ 940, 8 },
+ { 948, 10 },{ 958, 12 },{ 970, 8 },{ 978, 12 },{ 990, 13 },{ 1003, 12 },{ 1015, 13 },{ 1028, 12 },{ 1040, 2 },{ 1042, 2 },{ 1044, 4 },
+ { 1048, 5 },{ 1053, 3 },{ 1056, 4 },{ 1060, 4 },{ 1064, 6 },{ 1070, 6 },{ 1076, 7 },{ 1083, 4 },{ 1087, 6 },{ 1093, 4 },{ 1097, 4 },
+ { 1101, 5 },{ 1106, 6 },{ 1112, 7 },{ 1119, 4 },{ 1123, 2 },{ 1125, 5 },{ 1130, 4 },{ 1134, 4 },{ 1138, 6 },{ 1144, 4 },{ 1148, 4 },
+ { 1152, 6 },{ 1158, 6 },{ 1164, 6 },{ 1170, 6 },{ 1176, 6 },{ 1182, 2 },{ 1184, 5 },{ 1189, 4 },{ 1193, 6 },{ 1199, 6 },{ 1205, 4 },
+ { 1209, 4 },{ 1213, 4 },{ 1217, 4 },{ 1221, 6 },{ 1227, 6 },{ 1233, 6 },{ 1239, 4 },{ 1243, 2 },{ 1245, 8 },{ 1253, 3 },{ 1256, 6 },
+ { 1262, 7 },{ 1269, 7 },{ 1276, 4 },{ 1280, 4 },{ 1284, 5 },{ 1289, 5 },{ 1294, 4 },{ 1298, 4 },{ 1302, 6 },{ 1308, 6 },{ 1314, 4 },
+ { 1318, 5 },{ 1323, 6 },{ 1329, 7 },{ 1336, 6 },{ 1342, 7 },{ 1349, 6 },{ 1355, 5 },{ 1360, 4 },{ 1364, 4 },{ 1368, 5 },{ 1373, 4 },
+ { 1377, 4 },{ 1381, 6 },{ 1387, 2 },{ 1389, 4 },{ 1393, 6 },{ 1399, 6 },{ 1405, 6 },{ 1411, 5 },{ 1416, 6 },{ 1422, 2 },{ 1424, 4 },
+ { 1428, 8 },{ 1436, 3 },{ 1439, 7 },{ 1446, 6 },{ 1452, 2 },{ 1454, 4 },{ 1458, 4 },{ 1462, 6 },{ 1468, 6 },{ 1474, 4 },{ 1478, 6 },
+ { 1484, 6 },{ 1490, 4 },{ 1494, 4 },{ 1498, 6 },{ 1504, 4 },{ 1508, 6 },{ 1514, 4 },{ 1518, 6 },{ 1524, 6 },{ 1530, 3 },{ 1533, 7 },
+ { 1540, 6 },{ 1546, 4 },{ 1550, 5 },{ 1555, 6 },{ 1561, 6 },{ 1567, 6 },{ 1573, 5 },{ 1578, 6 },{ 1584, 8 },{ 1592, 6 },{ 1598, 6 },
+ { 1604, 8 },
+ };
+ static const int g_shapes1[][2] =
+ {
+ { 0, 16 }
+ };
+ static const int g_shapes2[64][2] =
+ {
+ { 33, 96 },{ 63, 66 },{ 20, 109 },{ 22, 107 },{ 37, 92 },{ 7, 122 },{ 8, 121 },{ 23, 106 },
+ { 38, 91 },{ 2, 127 },{ 9, 120 },{ 26, 103 },{ 3, 126 },{ 6, 123 },{ 1, 128 },{ 19, 110 },
+ { 15, 114 },{ 124, 5 },{ 72, 57 },{ 115, 14 },{ 125, 4 },{ 70, 59 },{ 100, 29 },{ 60, 69 },
+ { 116, 13 },{ 99, 30 },{ 78, 51 },{ 94, 35 },{ 104, 25 },{ 111, 18 },{ 71, 58 },{ 90, 39 },
+ { 45, 84 },{ 16, 113 },{ 82, 47 },{ 95, 34 },{ 87, 42 },{ 83, 46 },{ 53, 76 },{ 48, 81 },
+ { 68, 61 },{ 105, 24 },{ 98, 31 },{ 88, 41 },{ 75, 54 },{ 43, 86 },{ 52, 77 },{ 117, 12 },
+ { 119, 10 },{ 118, 11 },{ 85, 44 },{ 101, 28 },{ 36, 93 },{ 55, 74 },{ 89, 40 },{ 79, 50 },
+ { 56, 73 },{ 49, 80 },{ 64, 65 },{ 27, 102 },{ 32, 97 },{ 112, 17 },{ 67, 62 },{ 21, 108 },
+ };
+ static const int g_shapes3[64][3] =
+ {
+ { 148, 160, 240 },{ 132, 212, 205 },{ 136, 233, 187 },{ 175, 237, 143 },{ 6, 186, 232 },{ 33, 142, 232 },{ 131, 123, 142 },{ 131, 96, 186 },
+ { 6, 171, 110 },{ 1, 18, 110 },{ 1, 146, 123 },{ 33, 195, 66 },{ 20, 51, 66 },{ 20, 178, 96 },{ 2, 177, 106 },{ 211, 4, 59 },
+ { 8, 191, 91 },{ 230, 14, 29 },{ 1, 188, 234 },{ 151, 110, 168 },{ 20, 144, 238 },{ 137, 66, 206 },{ 173, 179, 232 },{ 209, 194, 186 },
+ { 239, 165, 142 },{ 131, 152, 242 },{ 214, 54, 12 },{ 140, 219, 201 },{ 190, 150, 231 },{ 156, 135, 241 },{ 185, 227, 167 },{ 145, 210, 59 },
+ { 138, 174, 106 },{ 189, 229, 14 },{ 176, 133, 106 },{ 78, 178, 195 },{ 111, 146, 171 },{ 216, 180, 196 },{ 217, 181, 193 },{ 184, 228, 166 },
+ { 192, 225, 153 },{ 134, 141, 123 },{ 6, 222, 198 },{ 149, 183, 96 },{ 33, 226, 164 },{ 161, 215, 51 },{ 197, 221, 18 },{ 1, 223, 199 },
+ { 154, 163, 110 },{ 20, 236, 169 },{ 157, 204, 66 },{ 1, 202, 220 },{ 20, 170, 235 },{ 203, 158, 66 },{ 162, 155, 110 },{ 6, 201, 218 },
+ { 139, 135, 123 },{ 33, 167, 224 },{ 182, 150, 96 },{ 19, 200, 213 },{ 63, 207, 159 },{ 147, 172, 109 },{ 129, 130, 128 },{ 208, 14, 59 },
+ };
+
+ static const int g_shapeList1[] =
+ {
+ 0,
+ };
+
+ static const int g_shapeList1Collapse[] =
+ {
+ 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1,
+ };
+ static const int g_shapeList2[] =
+ {
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
+ 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
+ 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
+ 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
+ 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55,
+ 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66,
+ 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77,
+ 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88,
+ 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99,
+ 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110,
+ 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121,
+ 122, 123, 124, 125, 126, 127, 128,
+ };
+ static const int g_shapeList2Collapse[] =
+ {
+ -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
+ 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42,
+ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
+ 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64,
+ 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75,
+ 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86,
+ 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97,
+ 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108,
+ 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
+ 120, 121, 122, 123, 124, 125, 126, 127, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1,
+ };
+
+ static const int g_shapeList12[] =
+ {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
+ 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+ 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
+ 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43,
+ 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,
+ 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65,
+ 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76,
+ 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87,
+ 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98,
+ 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109,
+ 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120,
+ 121, 122, 123, 124, 125, 126, 127, 128,
+ };
+
+ static const int g_shapeList12Collapse[] =
+ {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
+ 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+ 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
+ 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43,
+ 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,
+ 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65,
+ 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76,
+ 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87,
+ 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98,
+ 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109,
+ 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120,
+ 121, 122, 123, 124, 125, 126, 127, 128, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1,
+ };
+
+ static const int g_shapeList3[] =
+ {
+ 1, 2, 4, 6, 8, 12, 14, 18, 19, 20, 29,
+ 33, 51, 54, 59, 63, 66, 78, 91, 96, 106, 109,
+ 110, 111, 123, 128, 129, 130, 131, 132, 133, 134, 135,
+ 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146,
+ 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157,
+ 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168,
+ 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179,
+ 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190,
+ 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201,
+ 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212,
+ 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223,
+ 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234,
+ 235, 236, 237, 238, 239, 240, 241, 242,
+ };
+
+ static const int g_shapeList3Collapse[] =
+ {
+ -1, 0, 1, -1, 2, -1, 3, -1, 4, -1, -1,
+ -1, 5, -1, 6, -1, -1, -1, 7, 8, 9, -1,
+ -1, -1, -1, -1, -1, -1, -1, 10, -1, -1, -1,
+ 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 12, -1, -1, 13,
+ -1, -1, -1, -1, 14, -1, -1, -1, 15, -1, -1,
+ 16, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 17, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 18, -1, -1, -1, -1, 19, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 20, -1, -1, 21,
+ 22, 23, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 24, -1, -1, -1, -1, 25, 26, 27, 28,
+ 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
+ 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
+ 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,
+ 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72,
+ 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83,
+ 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94,
+ 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105,
+ 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116,
+ 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
+ 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138,
+ 139,
+ };
+
+ static const int g_shapeList3Short[] =
+ {
+ 1, 2, 4, 6, 18, 20, 33, 51, 59, 66, 96,
+ 106, 110, 123, 131, 132, 136, 142, 143, 146, 148, 160,
+ 171, 175, 177, 178, 186, 187, 195, 205, 211, 212, 232,
+ 233, 237, 240,
+ };
+
+ static const int g_shapeList3ShortCollapse[] =
+ {
+ -1, 0, 1, -1, 2, -1, 3, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 4, -1, 5, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 7, -1, -1, -1,
+ -1, -1, -1, -1, 8, -1, -1, -1, -1, -1, -1,
+ 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 10, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 11, -1, -1, -1,
+ 12, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 13, -1, -1, -1, -1, -1, -1, -1, 14,
+ 15, -1, -1, -1, 16, -1, -1, -1, -1, -1, 17,
+ 18, -1, -1, 19, -1, 20, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 21, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 22, -1, -1, -1, 23,
+ -1, 24, 25, -1, -1, -1, -1, -1, -1, -1, 26,
+ 27, -1, -1, -1, -1, -1, -1, -1, 28, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 29, -1, -1, -1,
+ -1, -1, 30, 31, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 32, 33, -1, -1, -1, 34, -1, -1, 35, -1,
+ -1,
+ };
+
+ static const int g_shapeListAll[] =
+ {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
+ 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+ 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
+ 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43,
+ 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,
+ 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65,
+ 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76,
+ 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87,
+ 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98,
+ 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109,
+ 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120,
+ 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131,
+ 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142,
+ 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153,
+ 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164,
+ 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175,
+ 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186,
+ 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197,
+ 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208,
+ 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219,
+ 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230,
+ 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241,
+ 242,
+ };
+
+ static const int g_numShapes1 = sizeof(g_shapeList1) / sizeof(g_shapeList1[0]);
+ static const int g_numShapes2 = sizeof(g_shapeList2) / sizeof(g_shapeList2[0]);
+ static const int g_numShapes12 = sizeof(g_shapeList12) / sizeof(g_shapeList12[0]);
+ static const int g_numShapes3 = sizeof(g_shapeList3) / sizeof(g_shapeList3[0]);
+ static const int g_numShapes3Short = sizeof(g_shapeList3Short) / sizeof(g_shapeList3Short[0]);
+ static const int g_numShapesAll = sizeof(g_shapeListAll) / sizeof(g_shapeListAll[0]);
+ static const int g_numFragments = sizeof(g_fragments) / sizeof(g_fragments[0]);
+
+ static const int g_maxFragmentsPerMode = (g_numShapes2 > g_numShapes3) ? g_numShapes2 : g_numShapes3;
+ }
+
+ namespace BC6HData
+ {
+ enum EField
+ {
+ NA, // N/A
+ M, // Mode
+ D, // Shape
+ RW,
+ RX,
+ RY,
+ RZ,
+ GW,
+ GX,
+ GY,
+ GZ,
+ BW,
+ BX,
+ BY,
+ BZ,
+ };
+
+ struct ModeDescriptor
+ {
+ EField m_eField;
+ uint8_t m_uBit;
+ };
+
+ const ModeDescriptor g_modeDescriptors[14][82] =
+ {
+ { // Mode 1 (0x00) - 10 5 5 5
+ { M, 0 },{ M, 1 },{ GY, 4 },{ BY, 4 },{ BZ, 4 },{ RW, 0 },{ RW, 1 },{ RW, 2 },{ RW, 3 },{ RW, 4 },
+ { RW, 5 },{ RW, 6 },{ RW, 7 },{ RW, 8 },{ RW, 9 },{ GW, 0 },{ GW, 1 },{ GW, 2 },{ GW, 3 },{ GW, 4 },
+ { GW, 5 },{ GW, 6 },{ GW, 7 },{ GW, 8 },{ GW, 9 },{ BW, 0 },{ BW, 1 },{ BW, 2 },{ BW, 3 },{ BW, 4 },
+ { BW, 5 },{ BW, 6 },{ BW, 7 },{ BW, 8 },{ BW, 9 },{ RX, 0 },{ RX, 1 },{ RX, 2 },{ RX, 3 },{ RX, 4 },
+ { GZ, 4 },{ GY, 0 },{ GY, 1 },{ GY, 2 },{ GY, 3 },{ GX, 0 },{ GX, 1 },{ GX, 2 },{ GX, 3 },{ GX, 4 },
+ { BZ, 0 },{ GZ, 0 },{ GZ, 1 },{ GZ, 2 },{ GZ, 3 },{ BX, 0 },{ BX, 1 },{ BX, 2 },{ BX, 3 },{ BX, 4 },
+ { BZ, 1 },{ BY, 0 },{ BY, 1 },{ BY, 2 },{ BY, 3 },{ RY, 0 },{ RY, 1 },{ RY, 2 },{ RY, 3 },{ RY, 4 },
+ { BZ, 2 },{ RZ, 0 },{ RZ, 1 },{ RZ, 2 },{ RZ, 3 },{ RZ, 4 },{ BZ, 3 },{ D, 0 },{ D, 1 },{ D, 2 },
+ { D, 3 },{ D, 4 },
+ },
+
+ { // Mode 2 (0x01) - 7 6 6 6
+ { M, 0 },{ M, 1 },{ GY, 5 },{ GZ, 4 },{ GZ, 5 },{ RW, 0 },{ RW, 1 },{ RW, 2 },{ RW, 3 },{ RW, 4 },
+ { RW, 5 },{ RW, 6 },{ BZ, 0 },{ BZ, 1 },{ BY, 4 },{ GW, 0 },{ GW, 1 },{ GW, 2 },{ GW, 3 },{ GW, 4 },
+ { GW, 5 },{ GW, 6 },{ BY, 5 },{ BZ, 2 },{ GY, 4 },{ BW, 0 },{ BW, 1 },{ BW, 2 },{ BW, 3 },{ BW, 4 },
+ { BW, 5 },{ BW, 6 },{ BZ, 3 },{ BZ, 5 },{ BZ, 4 },{ RX, 0 },{ RX, 1 },{ RX, 2 },{ RX, 3 },{ RX, 4 },
+ { RX, 5 },{ GY, 0 },{ GY, 1 },{ GY, 2 },{ GY, 3 },{ GX, 0 },{ GX, 1 },{ GX, 2 },{ GX, 3 },{ GX, 4 },
+ { GX, 5 },{ GZ, 0 },{ GZ, 1 },{ GZ, 2 },{ GZ, 3 },{ BX, 0 },{ BX, 1 },{ BX, 2 },{ BX, 3 },{ BX, 4 },
+ { BX, 5 },{ BY, 0 },{ BY, 1 },{ BY, 2 },{ BY, 3 },{ RY, 0 },{ RY, 1 },{ RY, 2 },{ RY, 3 },{ RY, 4 },
+ { RY, 5 },{ RZ, 0 },{ RZ, 1 },{ RZ, 2 },{ RZ, 3 },{ RZ, 4 },{ RZ, 5 },{ D, 0 },{ D, 1 },{ D, 2 },
+ { D, 3 },{ D, 4 },
+ },
+
+ { // Mode 3 (0x02) - 11 5 4 4
+ { M, 0 },{ M, 1 },{ M, 2 },{ M, 3 },{ M, 4 },{ RW, 0 },{ RW, 1 },{ RW, 2 },{ RW, 3 },{ RW, 4 },
+ { RW, 5 },{ RW, 6 },{ RW, 7 },{ RW, 8 },{ RW, 9 },{ GW, 0 },{ GW, 1 },{ GW, 2 },{ GW, 3 },{ GW, 4 },
+ { GW, 5 },{ GW, 6 },{ GW, 7 },{ GW, 8 },{ GW, 9 },{ BW, 0 },{ BW, 1 },{ BW, 2 },{ BW, 3 },{ BW, 4 },
+ { BW, 5 },{ BW, 6 },{ BW, 7 },{ BW, 8 },{ BW, 9 },{ RX, 0 },{ RX, 1 },{ RX, 2 },{ RX, 3 },{ RX, 4 },
+ { RW,10 },{ GY, 0 },{ GY, 1 },{ GY, 2 },{ GY, 3 },{ GX, 0 },{ GX, 1 },{ GX, 2 },{ GX, 3 },{ GW,10 },
+ { BZ, 0 },{ GZ, 0 },{ GZ, 1 },{ GZ, 2 },{ GZ, 3 },{ BX, 0 },{ BX, 1 },{ BX, 2 },{ BX, 3 },{ BW,10 },
+ { BZ, 1 },{ BY, 0 },{ BY, 1 },{ BY, 2 },{ BY, 3 },{ RY, 0 },{ RY, 1 },{ RY, 2 },{ RY, 3 },{ RY, 4 },
+ { BZ, 2 },{ RZ, 0 },{ RZ, 1 },{ RZ, 2 },{ RZ, 3 },{ RZ, 4 },{ BZ, 3 },{ D, 0 },{ D, 1 },{ D, 2 },
+ { D, 3 },{ D, 4 },
+ },
+
+ { // Mode 4 (0x06) - 11 4 5 4
+ { M, 0 },{ M, 1 },{ M, 2 },{ M, 3 },{ M, 4 },{ RW, 0 },{ RW, 1 },{ RW, 2 },{ RW, 3 },{ RW, 4 },
+ { RW, 5 },{ RW, 6 },{ RW, 7 },{ RW, 8 },{ RW, 9 },{ GW, 0 },{ GW, 1 },{ GW, 2 },{ GW, 3 },{ GW, 4 },
+ { GW, 5 },{ GW, 6 },{ GW, 7 },{ GW, 8 },{ GW, 9 },{ BW, 0 },{ BW, 1 },{ BW, 2 },{ BW, 3 },{ BW, 4 },
+ { BW, 5 },{ BW, 6 },{ BW, 7 },{ BW, 8 },{ BW, 9 },{ RX, 0 },{ RX, 1 },{ RX, 2 },{ RX, 3 },{ RW,10 },
+ { GZ, 4 },{ GY, 0 },{ GY, 1 },{ GY, 2 },{ GY, 3 },{ GX, 0 },{ GX, 1 },{ GX, 2 },{ GX, 3 },{ GX, 4 },
+ { GW,10 },{ GZ, 0 },{ GZ, 1 },{ GZ, 2 },{ GZ, 3 },{ BX, 0 },{ BX, 1 },{ BX, 2 },{ BX, 3 },{ BW,10 },
+ { BZ, 1 },{ BY, 0 },{ BY, 1 },{ BY, 2 },{ BY, 3 },{ RY, 0 },{ RY, 1 },{ RY, 2 },{ RY, 3 },{ BZ, 0 },
+ { BZ, 2 },{ RZ, 0 },{ RZ, 1 },{ RZ, 2 },{ RZ, 3 },{ GY, 4 },{ BZ, 3 },{ D, 0 },{ D, 1 },{ D, 2 },
+ { D, 3 },{ D, 4 },
+ },
+
+ { // Mode 5 (0x0a) - 11 4 4 5
+ { M, 0 },{ M, 1 },{ M, 2 },{ M, 3 },{ M, 4 },{ RW, 0 },{ RW, 1 },{ RW, 2 },{ RW, 3 },{ RW, 4 },
+ { RW, 5 },{ RW, 6 },{ RW, 7 },{ RW, 8 },{ RW, 9 },{ GW, 0 },{ GW, 1 },{ GW, 2 },{ GW, 3 },{ GW, 4 },
+ { GW, 5 },{ GW, 6 },{ GW, 7 },{ GW, 8 },{ GW, 9 },{ BW, 0 },{ BW, 1 },{ BW, 2 },{ BW, 3 },{ BW, 4 },
+ { BW, 5 },{ BW, 6 },{ BW, 7 },{ BW, 8 },{ BW, 9 },{ RX, 0 },{ RX, 1 },{ RX, 2 },{ RX, 3 },{ RW,10 },
+ { BY, 4 },{ GY, 0 },{ GY, 1 },{ GY, 2 },{ GY, 3 },{ GX, 0 },{ GX, 1 },{ GX, 2 },{ GX, 3 },{ GW,10 },
+ { BZ, 0 },{ GZ, 0 },{ GZ, 1 },{ GZ, 2 },{ GZ, 3 },{ BX, 0 },{ BX, 1 },{ BX, 2 },{ BX, 3 },{ BX, 4 },
+ { BW,10 },{ BY, 0 },{ BY, 1 },{ BY, 2 },{ BY, 3 },{ RY, 0 },{ RY, 1 },{ RY, 2 },{ RY, 3 },{ BZ, 1 },
+ { BZ, 2 },{ RZ, 0 },{ RZ, 1 },{ RZ, 2 },{ RZ, 3 },{ BZ, 4 },{ BZ, 3 },{ D, 0 },{ D, 1 },{ D, 2 },
+ { D, 3 },{ D, 4 },
+ },
+
+ { // Mode 6 (0x0e) - 9 5 5 5
+ { M, 0 },{ M, 1 },{ M, 2 },{ M, 3 },{ M, 4 },{ RW, 0 },{ RW, 1 },{ RW, 2 },{ RW, 3 },{ RW, 4 },
+ { RW, 5 },{ RW, 6 },{ RW, 7 },{ RW, 8 },{ BY, 4 },{ GW, 0 },{ GW, 1 },{ GW, 2 },{ GW, 3 },{ GW, 4 },
+ { GW, 5 },{ GW, 6 },{ GW, 7 },{ GW, 8 },{ GY, 4 },{ BW, 0 },{ BW, 1 },{ BW, 2 },{ BW, 3 },{ BW, 4 },
+ { BW, 5 },{ BW, 6 },{ BW, 7 },{ BW, 8 },{ BZ, 4 },{ RX, 0 },{ RX, 1 },{ RX, 2 },{ RX, 3 },{ RX, 4 },
+ { GZ, 4 },{ GY, 0 },{ GY, 1 },{ GY, 2 },{ GY, 3 },{ GX, 0 },{ GX, 1 },{ GX, 2 },{ GX, 3 },{ GX, 4 },
+ { BZ, 0 },{ GZ, 0 },{ GZ, 1 },{ GZ, 2 },{ GZ, 3 },{ BX, 0 },{ BX, 1 },{ BX, 2 },{ BX, 3 },{ BX, 4 },
+ { BZ, 1 },{ BY, 0 },{ BY, 1 },{ BY, 2 },{ BY, 3 },{ RY, 0 },{ RY, 1 },{ RY, 2 },{ RY, 3 },{ RY, 4 },
+ { BZ, 2 },{ RZ, 0 },{ RZ, 1 },{ RZ, 2 },{ RZ, 3 },{ RZ, 4 },{ BZ, 3 },{ D, 0 },{ D, 1 },{ D, 2 },
+ { D, 3 },{ D, 4 },
+ },
+
+ { // Mode 7 (0x12) - 8 6 5 5
+ { M, 0 },{ M, 1 },{ M, 2 },{ M, 3 },{ M, 4 },{ RW, 0 },{ RW, 1 },{ RW, 2 },{ RW, 3 },{ RW, 4 },
+ { RW, 5 },{ RW, 6 },{ RW, 7 },{ GZ, 4 },{ BY, 4 },{ GW, 0 },{ GW, 1 },{ GW, 2 },{ GW, 3 },{ GW, 4 },
+ { GW, 5 },{ GW, 6 },{ GW, 7 },{ BZ, 2 },{ GY, 4 },{ BW, 0 },{ BW, 1 },{ BW, 2 },{ BW, 3 },{ BW, 4 },
+ { BW, 5 },{ BW, 6 },{ BW, 7 },{ BZ, 3 },{ BZ, 4 },{ RX, 0 },{ RX, 1 },{ RX, 2 },{ RX, 3 },{ RX, 4 },
+ { RX, 5 },{ GY, 0 },{ GY, 1 },{ GY, 2 },{ GY, 3 },{ GX, 0 },{ GX, 1 },{ GX, 2 },{ GX, 3 },{ GX, 4 },
+ { BZ, 0 },{ GZ, 0 },{ GZ, 1 },{ GZ, 2 },{ GZ, 3 },{ BX, 0 },{ BX, 1 },{ BX, 2 },{ BX, 3 },{ BX, 4 },
+ { BZ, 1 },{ BY, 0 },{ BY, 1 },{ BY, 2 },{ BY, 3 },{ RY, 0 },{ RY, 1 },{ RY, 2 },{ RY, 3 },{ RY, 4 },
+ { RY, 5 },{ RZ, 0 },{ RZ, 1 },{ RZ, 2 },{ RZ, 3 },{ RZ, 4 },{ RZ, 5 },{ D, 0 },{ D, 1 },{ D, 2 },
+ { D, 3 },{ D, 4 },
+ },
+
+ { // Mode 8 (0x16) - 8 5 6 5
+ { M, 0 },{ M, 1 },{ M, 2 },{ M, 3 },{ M, 4 },{ RW, 0 },{ RW, 1 },{ RW, 2 },{ RW, 3 },{ RW, 4 },
+ { RW, 5 },{ RW, 6 },{ RW, 7 },{ BZ, 0 },{ BY, 4 },{ GW, 0 },{ GW, 1 },{ GW, 2 },{ GW, 3 },{ GW, 4 },
+ { GW, 5 },{ GW, 6 },{ GW, 7 },{ GY, 5 },{ GY, 4 },{ BW, 0 },{ BW, 1 },{ BW, 2 },{ BW, 3 },{ BW, 4 },
+ { BW, 5 },{ BW, 6 },{ BW, 7 },{ GZ, 5 },{ BZ, 4 },{ RX, 0 },{ RX, 1 },{ RX, 2 },{ RX, 3 },{ RX, 4 },
+ { GZ, 4 },{ GY, 0 },{ GY, 1 },{ GY, 2 },{ GY, 3 },{ GX, 0 },{ GX, 1 },{ GX, 2 },{ GX, 3 },{ GX, 4 },
+ { GX, 5 },{ GZ, 0 },{ GZ, 1 },{ GZ, 2 },{ GZ, 3 },{ BX, 0 },{ BX, 1 },{ BX, 2 },{ BX, 3 },{ BX, 4 },
+ { BZ, 1 },{ BY, 0 },{ BY, 1 },{ BY, 2 },{ BY, 3 },{ RY, 0 },{ RY, 1 },{ RY, 2 },{ RY, 3 },{ RY, 4 },
+ { BZ, 2 },{ RZ, 0 },{ RZ, 1 },{ RZ, 2 },{ RZ, 3 },{ RZ, 4 },{ BZ, 3 },{ D, 0 },{ D, 1 },{ D, 2 },
+ { D, 3 },{ D, 4 },
+ },
+
+ { // Mode 9 (0x1a) - 8 5 5 6
+ { M, 0 },{ M, 1 },{ M, 2 },{ M, 3 },{ M, 4 },{ RW, 0 },{ RW, 1 },{ RW, 2 },{ RW, 3 },{ RW, 4 },
+ { RW, 5 },{ RW, 6 },{ RW, 7 },{ BZ, 1 },{ BY, 4 },{ GW, 0 },{ GW, 1 },{ GW, 2 },{ GW, 3 },{ GW, 4 },
+ { GW, 5 },{ GW, 6 },{ GW, 7 },{ BY, 5 },{ GY, 4 },{ BW, 0 },{ BW, 1 },{ BW, 2 },{ BW, 3 },{ BW, 4 },
+ { BW, 5 },{ BW, 6 },{ BW, 7 },{ BZ, 5 },{ BZ, 4 },{ RX, 0 },{ RX, 1 },{ RX, 2 },{ RX, 3 },{ RX, 4 },
+ { GZ, 4 },{ GY, 0 },{ GY, 1 },{ GY, 2 },{ GY, 3 },{ GX, 0 },{ GX, 1 },{ GX, 2 },{ GX, 3 },{ GX, 4 },
+ { BZ, 0 },{ GZ, 0 },{ GZ, 1 },{ GZ, 2 },{ GZ, 3 },{ BX, 0 },{ BX, 1 },{ BX, 2 },{ BX, 3 },{ BX, 4 },
+ { BX, 5 },{ BY, 0 },{ BY, 1 },{ BY, 2 },{ BY, 3 },{ RY, 0 },{ RY, 1 },{ RY, 2 },{ RY, 3 },{ RY, 4 },
+ { BZ, 2 },{ RZ, 0 },{ RZ, 1 },{ RZ, 2 },{ RZ, 3 },{ RZ, 4 },{ BZ, 3 },{ D, 0 },{ D, 1 },{ D, 2 },
+ { D, 3 },{ D, 4 },
+ },
+
+ { // Mode 10 (0x1e) - 6 6 6 6
+ { M, 0 },{ M, 1 },{ M, 2 },{ M, 3 },{ M, 4 },{ RW, 0 },{ RW, 1 },{ RW, 2 },{ RW, 3 },{ RW, 4 },
+ { RW, 5 },{ GZ, 4 },{ BZ, 0 },{ BZ, 1 },{ BY, 4 },{ GW, 0 },{ GW, 1 },{ GW, 2 },{ GW, 3 },{ GW, 4 },
+ { GW, 5 },{ GY, 5 },{ BY, 5 },{ BZ, 2 },{ GY, 4 },{ BW, 0 },{ BW, 1 },{ BW, 2 },{ BW, 3 },{ BW, 4 },
+ { BW, 5 },{ GZ, 5 },{ BZ, 3 },{ BZ, 5 },{ BZ, 4 },{ RX, 0 },{ RX, 1 },{ RX, 2 },{ RX, 3 },{ RX, 4 },
+ { RX, 5 },{ GY, 0 },{ GY, 1 },{ GY, 2 },{ GY, 3 },{ GX, 0 },{ GX, 1 },{ GX, 2 },{ GX, 3 },{ GX, 4 },
+ { GX, 5 },{ GZ, 0 },{ GZ, 1 },{ GZ, 2 },{ GZ, 3 },{ BX, 0 },{ BX, 1 },{ BX, 2 },{ BX, 3 },{ BX, 4 },
+ { BX, 5 },{ BY, 0 },{ BY, 1 },{ BY, 2 },{ BY, 3 },{ RY, 0 },{ RY, 1 },{ RY, 2 },{ RY, 3 },{ RY, 4 },
+ { RY, 5 },{ RZ, 0 },{ RZ, 1 },{ RZ, 2 },{ RZ, 3 },{ RZ, 4 },{ RZ, 5 },{ D, 0 },{ D, 1 },{ D, 2 },
+ { D, 3 },{ D, 4 },
+ },
+
+ { // Mode 11 (0x03) - 10 10
+ { M, 0 },{ M, 1 },{ M, 2 },{ M, 3 },{ M, 4 },{ RW, 0 },{ RW, 1 },{ RW, 2 },{ RW, 3 },{ RW, 4 },
+ { RW, 5 },{ RW, 6 },{ RW, 7 },{ RW, 8 },{ RW, 9 },{ GW, 0 },{ GW, 1 },{ GW, 2 },{ GW, 3 },{ GW, 4 },
+ { GW, 5 },{ GW, 6 },{ GW, 7 },{ GW, 8 },{ GW, 9 },{ BW, 0 },{ BW, 1 },{ BW, 2 },{ BW, 3 },{ BW, 4 },
+ { BW, 5 },{ BW, 6 },{ BW, 7 },{ BW, 8 },{ BW, 9 },{ RX, 0 },{ RX, 1 },{ RX, 2 },{ RX, 3 },{ RX, 4 },
+ { RX, 5 },{ RX, 6 },{ RX, 7 },{ RX, 8 },{ RX, 9 },{ GX, 0 },{ GX, 1 },{ GX, 2 },{ GX, 3 },{ GX, 4 },
+ { GX, 5 },{ GX, 6 },{ GX, 7 },{ GX, 8 },{ GX, 9 },{ BX, 0 },{ BX, 1 },{ BX, 2 },{ BX, 3 },{ BX, 4 },
+ { BX, 5 },{ BX, 6 },{ BX, 7 },{ BX, 8 },{ BX, 9 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },
+ { NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },
+ { NA, 0 },{ NA, 0 },
+ },
+
+ { // Mode 12 (0x07) - 11 9
+ { M, 0 },{ M, 1 },{ M, 2 },{ M, 3 },{ M, 4 },{ RW, 0 },{ RW, 1 },{ RW, 2 },{ RW, 3 },{ RW, 4 },
+ { RW, 5 },{ RW, 6 },{ RW, 7 },{ RW, 8 },{ RW, 9 },{ GW, 0 },{ GW, 1 },{ GW, 2 },{ GW, 3 },{ GW, 4 },
+ { GW, 5 },{ GW, 6 },{ GW, 7 },{ GW, 8 },{ GW, 9 },{ BW, 0 },{ BW, 1 },{ BW, 2 },{ BW, 3 },{ BW, 4 },
+ { BW, 5 },{ BW, 6 },{ BW, 7 },{ BW, 8 },{ BW, 9 },{ RX, 0 },{ RX, 1 },{ RX, 2 },{ RX, 3 },{ RX, 4 },
+ { RX, 5 },{ RX, 6 },{ RX, 7 },{ RX, 8 },{ RW,10 },{ GX, 0 },{ GX, 1 },{ GX, 2 },{ GX, 3 },{ GX, 4 },
+ { GX, 5 },{ GX, 6 },{ GX, 7 },{ GX, 8 },{ GW,10 },{ BX, 0 },{ BX, 1 },{ BX, 2 },{ BX, 3 },{ BX, 4 },
+ { BX, 5 },{ BX, 6 },{ BX, 7 },{ BX, 8 },{ BW,10 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },
+ { NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },
+ { NA, 0 },{ NA, 0 },
+ },
+
+ { // Mode 13 (0x0b) - 12 8
+ { M, 0 },{ M, 1 },{ M, 2 },{ M, 3 },{ M, 4 },{ RW, 0 },{ RW, 1 },{ RW, 2 },{ RW, 3 },{ RW, 4 },
+ { RW, 5 },{ RW, 6 },{ RW, 7 },{ RW, 8 },{ RW, 9 },{ GW, 0 },{ GW, 1 },{ GW, 2 },{ GW, 3 },{ GW, 4 },
+ { GW, 5 },{ GW, 6 },{ GW, 7 },{ GW, 8 },{ GW, 9 },{ BW, 0 },{ BW, 1 },{ BW, 2 },{ BW, 3 },{ BW, 4 },
+ { BW, 5 },{ BW, 6 },{ BW, 7 },{ BW, 8 },{ BW, 9 },{ RX, 0 },{ RX, 1 },{ RX, 2 },{ RX, 3 },{ RX, 4 },
+ { RX, 5 },{ RX, 6 },{ RX, 7 },{ RW,11 },{ RW,10 },{ GX, 0 },{ GX, 1 },{ GX, 2 },{ GX, 3 },{ GX, 4 },
+ { GX, 5 },{ GX, 6 },{ GX, 7 },{ GW,11 },{ GW,10 },{ BX, 0 },{ BX, 1 },{ BX, 2 },{ BX, 3 },{ BX, 4 },
+ { BX, 5 },{ BX, 6 },{ BX, 7 },{ BW,11 },{ BW,10 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },
+ { NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },
+ { NA, 0 },{ NA, 0 },
+ },
+
+ { // Mode 14 (0x0f) - 16 4
+ { M, 0 },{ M, 1 },{ M, 2 },{ M, 3 },{ M, 4 },{ RW, 0 },{ RW, 1 },{ RW, 2 },{ RW, 3 },{ RW, 4 },
+ { RW, 5 },{ RW, 6 },{ RW, 7 },{ RW, 8 },{ RW, 9 },{ GW, 0 },{ GW, 1 },{ GW, 2 },{ GW, 3 },{ GW, 4 },
+ { GW, 5 },{ GW, 6 },{ GW, 7 },{ GW, 8 },{ GW, 9 },{ BW, 0 },{ BW, 1 },{ BW, 2 },{ BW, 3 },{ BW, 4 },
+ { BW, 5 },{ BW, 6 },{ BW, 7 },{ BW, 8 },{ BW, 9 },{ RX, 0 },{ RX, 1 },{ RX, 2 },{ RX, 3 },{ RW,15 },
+ { RW,14 },{ RW,13 },{ RW,12 },{ RW,11 },{ RW,10 },{ GX, 0 },{ GX, 1 },{ GX, 2 },{ GX, 3 },{ GW,15 },
+ { GW,14 },{ GW,13 },{ GW,12 },{ GW,11 },{ GW,10 },{ BX, 0 },{ BX, 1 },{ BX, 2 },{ BX, 3 },{ BW,15 },
+ { BW,14 },{ BW,13 },{ BW,12 },{ BW,11 },{ BW,10 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },
+ { NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },
+ { NA, 0 },{ NA, 0 },
+ },
+ };
+ }
+
+ struct PackingVector
+ {
+ uint32_t m_vector[4];
+ int m_offset;
+
+ void Init()
+ {
+ for (int i = 0; i < 4; i++)
+ m_vector[i] = 0;
+
+ m_offset = 0;
+ }
+
+ inline void Pack(ParallelMath::ScalarUInt16 value, int bits)
+ {
+ int vOffset = m_offset >> 5;
+ int bitOffset = m_offset & 0x1f;
+
+ m_vector[vOffset] |= (static_cast<uint32_t>(value) << bitOffset) & static_cast<uint32_t>(0xffffffff);
+
+ int overflowBits = bitOffset + bits - 32;
+ if (overflowBits > 0)
+ m_vector[vOffset + 1] |= (static_cast<uint32_t>(value) >> (bits - overflowBits));
+
+ m_offset += bits;
+ }
+
+ inline void Flush(uint8_t* output)
+ {
+ assert(m_offset == 128);
+
+ for (int v = 0; v < 4; v++)
+ {
+ uint32_t chunk = m_vector[v];
+ for (int b = 0; b < 4; b++)
+ output[v * 4 + b] = static_cast<uint8_t>((chunk >> (b * 8)) & 0xff);
+ }
+ }
+ };
+
+
+ struct UnpackingVector
+ {
+ uint32_t m_vector[4];
+
+ void Init(const uint8_t *bytes)
+ {
+ for (int i = 0; i < 4; i++)
+ m_vector[i] = 0;
+
+ for (int b = 0; b < 16; b++)
+ m_vector[b / 4] |= (bytes[b] << ((b % 4) * 8));
+ }
+
+ inline ParallelMath::ScalarUInt16 Unpack(int bits)
+ {
+ uint32_t bitMask = (1 << bits) - 1;
+
+ ParallelMath::ScalarUInt16 result = static_cast<ParallelMath::ScalarUInt16>(m_vector[0] & bitMask);
+
+ for (int i = 0; i < 4; i++)
+ {
+ m_vector[i] >>= bits;
+ if (i != 3)
+ m_vector[i] |= (m_vector[i + 1] & bitMask) << (32 - bits);
+ }
+
+ return result;
+ }
+ };
+
+ void ComputeTweakFactors(int tweak, int range, float *outFactors)
+ {
+ int totalUnits = range - 1;
+ int minOutsideUnits = ((tweak >> 1) & 1);
+ int maxOutsideUnits = (tweak & 1);
+ int insideUnits = totalUnits - minOutsideUnits - maxOutsideUnits;
+
+ outFactors[0] = -static_cast<float>(minOutsideUnits) / static_cast<float>(insideUnits);
+ outFactors[1] = static_cast<float>(maxOutsideUnits) / static_cast<float>(insideUnits) + 1.0f;
+ }
+
+ ParallelMath::Float ScaleHDRValue(const ParallelMath::Float &v, bool isSigned)
+ {
+ if (isSigned)
+ {
+ ParallelMath::Float offset = ParallelMath::Select(ParallelMath::Less(v, ParallelMath::MakeFloatZero()), ParallelMath::MakeFloat(-30.0f), ParallelMath::MakeFloat(30.0f));
+ return (v * 32.0f + offset) / 31.0f;
+ }
+ else
+ return (v * 64.0f + 30.0f) / 31.0f;
+ }
+
+ ParallelMath::SInt16 UnscaleHDRValueSigned(const ParallelMath::SInt16 &v)
+ {
+#ifdef CVTT_ENABLE_ASSERTS
+ for (int i = 0; i < ParallelMath::ParallelSize; i++)
+ assert(ParallelMath::Extract(v, i) != -32768)
+#endif
+
+ ParallelMath::Int16CompFlag negative = ParallelMath::Less(v, ParallelMath::MakeSInt16(0));
+ ParallelMath::UInt15 absComp = ParallelMath::LosslessCast<ParallelMath::UInt15>::Cast(ParallelMath::Select(negative, ParallelMath::SInt16(ParallelMath::MakeSInt16(0) - v), v));
+
+ ParallelMath::UInt31 multiplied = ParallelMath::XMultiply(absComp, ParallelMath::MakeUInt15(31));
+ ParallelMath::UInt31 shifted = ParallelMath::RightShift(multiplied, 5);
+ ParallelMath::UInt15 absCompScaled = ParallelMath::ToUInt15(shifted);
+ ParallelMath::SInt16 signBits = ParallelMath::SelectOrZero(negative, ParallelMath::MakeSInt16(-32768));
+
+ return ParallelMath::LosslessCast<ParallelMath::SInt16>::Cast(absCompScaled) | signBits;
+ }
+
+ ParallelMath::UInt15 UnscaleHDRValueUnsigned(const ParallelMath::UInt16 &v)
+ {
+ return ParallelMath::ToUInt15(ParallelMath::RightShift(ParallelMath::XMultiply(v, ParallelMath::MakeUInt15(31)), 6));
+ }
+
+ void UnscaleHDREndpoints(const ParallelMath::AInt16 inEP[2][3], ParallelMath::AInt16 outEP[2][3], bool isSigned)
+ {
+ for (int epi = 0; epi < 2; epi++)
+ {
+ for (int ch = 0; ch < 3; ch++)
+ {
+ if (isSigned)
+ outEP[epi][ch] = ParallelMath::LosslessCast<ParallelMath::AInt16>::Cast(UnscaleHDRValueSigned(ParallelMath::LosslessCast<ParallelMath::SInt16>::Cast(inEP[epi][ch])));
+ else
+ outEP[epi][ch] = ParallelMath::LosslessCast<ParallelMath::AInt16>::Cast(UnscaleHDRValueUnsigned(ParallelMath::LosslessCast<ParallelMath::UInt16>::Cast(inEP[epi][ch])));
+ }
+ }
+ }
+
+ template<int TVectorSize>
+ class UnfinishedEndpoints
+ {
+ public:
+ typedef ParallelMath::Float MFloat;
+ typedef ParallelMath::UInt16 MUInt16;
+ typedef ParallelMath::UInt15 MUInt15;
+ typedef ParallelMath::SInt16 MSInt16;
+ typedef ParallelMath::SInt32 MSInt32;
+
+ UnfinishedEndpoints()
+ {
+ }
+
+ UnfinishedEndpoints(const MFloat *base, const MFloat *offset)
+ {
+ for (int ch = 0; ch < TVectorSize; ch++)
+ m_base[ch] = base[ch];
+ for (int ch = 0; ch < TVectorSize; ch++)
+ m_offset[ch] = offset[ch];
+ }
+
+ UnfinishedEndpoints(const UnfinishedEndpoints& other)
+ {
+ for (int ch = 0; ch < TVectorSize; ch++)
+ m_base[ch] = other.m_base[ch];
+ for (int ch = 0; ch < TVectorSize; ch++)
+ m_offset[ch] = other.m_offset[ch];
+ }
+
+ void FinishHDRUnsigned(int tweak, int range, MSInt16 *outEP0, MSInt16 *outEP1, ParallelMath::RoundTowardNearestForScope *roundingMode)
+ {
+ float tweakFactors[2];
+ ComputeTweakFactors(tweak, range, tweakFactors);
+
+ for (int ch = 0; ch < TVectorSize; ch++)
+ {
+ MUInt15 channelEPs[2];
+ for (int epi = 0; epi < 2; epi++)
+ {
+ MFloat f = ParallelMath::Clamp(m_base[ch] + m_offset[ch] * tweakFactors[epi], 0.0f, 31743.0f);
+ channelEPs[epi] = ParallelMath::RoundAndConvertToU15(f, roundingMode);
+ }
+
+ outEP0[ch] = ParallelMath::LosslessCast<MSInt16>::Cast(channelEPs[0]);
+ outEP1[ch] = ParallelMath::LosslessCast<MSInt16>::Cast(channelEPs[1]);
+ }
+ }
+
+ void FinishHDRSigned(int tweak, int range, MSInt16* outEP0, MSInt16* outEP1, ParallelMath::RoundTowardNearestForScope* roundingMode)
+ {
+ float tweakFactors[2];
+ ComputeTweakFactors(tweak, range, tweakFactors);
+
+ for (int ch = 0; ch < TVectorSize; ch++)
+ {
+ MSInt16 channelEPs[2];
+ for (int epi = 0; epi < 2; epi++)
+ {
+ MFloat f = ParallelMath::Clamp(m_base[ch] + m_offset[ch] * tweakFactors[epi], -31743.0f, 31743.0f);
+ channelEPs[epi] = ParallelMath::RoundAndConvertToS16(f, roundingMode);
+ }
+
+ outEP0[ch] = channelEPs[0];
+ outEP1[ch] = channelEPs[1];
+ }
+ }
+
+ void FinishLDR(int tweak, int range, MUInt15* outEP0, MUInt15* outEP1)
+ {
+ ParallelMath::RoundTowardNearestForScope roundingMode;
+
+ float tweakFactors[2];
+ ComputeTweakFactors(tweak, range, tweakFactors);
+
+ for (int ch = 0; ch < TVectorSize; ch++)
+ {
+ MFloat ep0f = ParallelMath::Clamp(m_base[ch] + m_offset[ch] * tweakFactors[0], 0.0f, 255.0f);
+ MFloat ep1f = ParallelMath::Clamp(m_base[ch] + m_offset[ch] * tweakFactors[1], 0.0f, 255.0f);
+ outEP0[ch] = ParallelMath::RoundAndConvertToU15(ep0f, &roundingMode);
+ outEP1[ch] = ParallelMath::RoundAndConvertToU15(ep1f, &roundingMode);
+ }
+ }
+
+ template<int TNewVectorSize>
+ UnfinishedEndpoints<TNewVectorSize> ExpandTo(float filler)
+ {
+ MFloat newBase[TNewVectorSize];
+ MFloat newOffset[TNewVectorSize];
+
+ for (int ch = 0; ch < TNewVectorSize && ch < TVectorSize; ch++)
+ {
+ newBase[ch] = m_base[ch];
+ newOffset[ch] = m_offset[ch];
+ }
+
+ MFloat fillerV = ParallelMath::MakeFloat(filler);
+
+ for (int ch = TVectorSize; ch < TNewVectorSize; ch++)
+ {
+ newBase[ch] = fillerV;
+ newOffset[ch] = ParallelMath::MakeFloatZero();
+ }
+
+ return UnfinishedEndpoints<TNewVectorSize>(newBase, newOffset);
+ }
+
+ private:
+ MFloat m_base[TVectorSize];
+ MFloat m_offset[TVectorSize];
+ };
+
+ template<int TMatrixSize>
+ class PackedCovarianceMatrix
+ {
+ public:
+ // 0: xx,
+ // 1: xy, yy
+ // 3: xz, yz, zz
+ // 6: xw, yw, zw, ww
+ // ... etc.
+ static const int PyramidSize = (TMatrixSize * (TMatrixSize + 1)) / 2;
+
+ typedef ParallelMath::Float MFloat;
+
+ PackedCovarianceMatrix()
+ {
+ for (int i = 0; i < PyramidSize; i++)
+ m_values[i] = ParallelMath::MakeFloatZero();
+ }
+
+ void Add(const ParallelMath::Float *vec, const ParallelMath::Float &weight)
+ {
+ int index = 0;
+ for (int row = 0; row < TMatrixSize; row++)
+ {
+ for (int col = 0; col <= row; col++)
+ {
+ m_values[index] = m_values[index] + vec[row] * vec[col] * weight;
+ index++;
+ }
+ }
+ }
+
+ void Product(MFloat *outVec, const MFloat *inVec)
+ {
+ for (int row = 0; row < TMatrixSize; row++)
+ {
+ MFloat sum = ParallelMath::MakeFloatZero();
+
+ int index = (row * (row + 1)) >> 1;
+ for (int col = 0; col < TMatrixSize; col++)
+ {
+ sum = sum + inVec[col] * m_values[index];
+ if (col >= row)
+ index += col + 1;
+ else
+ index++;
+ }
+
+ outVec[row] = sum;
+ }
+ }
+
+ private:
+ ParallelMath::Float m_values[PyramidSize];
+ };
+
+ static const int NumEndpointSelectorPasses = 3;
+
+ template<int TVectorSize, int TIterationCount>
+ class EndpointSelector
+ {
+ public:
+ typedef ParallelMath::Float MFloat;
+
+ EndpointSelector()
+ {
+ for (int ch = 0; ch < TVectorSize; ch++)
+ {
+ m_centroid[ch] = ParallelMath::MakeFloatZero();
+ m_direction[ch] = ParallelMath::MakeFloatZero();
+ }
+ m_weightTotal = ParallelMath::MakeFloatZero();
+ m_minDist = ParallelMath::MakeFloat(FLT_MAX);
+ m_maxDist = ParallelMath::MakeFloat(-FLT_MAX);
+ }
+
+ void ContributePass(const MFloat *value, int pass, const MFloat &weight)
+ {
+ if (pass == 0)
+ ContributeCentroid(value, weight);
+ else if (pass == 1)
+ ContributeDirection(value, weight);
+ else if (pass == 2)
+ ContributeMinMax(value);
+ }
+
+ void FinishPass(int pass)
+ {
+ if (pass == 0)
+ FinishCentroid();
+ else if (pass == 1)
+ FinishDirection();
+ }
+
+ UnfinishedEndpoints<TVectorSize> GetEndpoints(const float channelWeights[TVectorSize]) const
+ {
+ MFloat unweightedBase[TVectorSize];
+ MFloat unweightedOffset[TVectorSize];
+
+ for (int ch = 0; ch < TVectorSize; ch++)
+ {
+ MFloat min = m_centroid[ch] + m_direction[ch] * m_minDist;
+ MFloat max = m_centroid[ch] + m_direction[ch] * m_maxDist;
+
+ float safeWeight = channelWeights[ch];
+ if (safeWeight == 0.f)
+ safeWeight = 1.0f;
+
+ unweightedBase[ch] = min / channelWeights[ch];
+ unweightedOffset[ch] = (max - min) / channelWeights[ch];
+ }
+
+ return UnfinishedEndpoints<TVectorSize>(unweightedBase, unweightedOffset);
+ }
+
+ private:
+ void ContributeCentroid(const MFloat *value, const MFloat &weight)
+ {
+ for (int ch = 0; ch < TVectorSize; ch++)
+ m_centroid[ch] = m_centroid[ch] + value[ch] * weight;
+ m_weightTotal = m_weightTotal + weight;
+ }
+
+ void FinishCentroid()
+ {
+ MFloat denom = m_weightTotal;
+ ParallelMath::MakeSafeDenominator(denom);
+
+ for (int ch = 0; ch < TVectorSize; ch++)
+ m_centroid[ch] = m_centroid[ch] / denom;
+ }
+
+ void ContributeDirection(const MFloat *value, const MFloat &weight)
+ {
+ MFloat diff[TVectorSize];
+ for (int ch = 0; ch < TVectorSize; ch++)
+ diff[ch] = value[ch] - m_centroid[ch];
+
+ m_covarianceMatrix.Add(diff, weight);
+ }
+
+ void FinishDirection()
+ {
+ MFloat approx[TVectorSize];
+ for (int ch = 0; ch < TVectorSize; ch++)
+ approx[ch] = ParallelMath::MakeFloat(1.0f);
+
+ for (int i = 0; i < TIterationCount; i++)
+ {
+ MFloat product[TVectorSize];
+ m_covarianceMatrix.Product(product, approx);
+
+ MFloat largestComponent = product[0];
+ for (int ch = 1; ch < TVectorSize; ch++)
+ largestComponent = ParallelMath::Max(largestComponent, product[ch]);
+
+ // product = largestComponent*newApprox
+ ParallelMath::MakeSafeDenominator(largestComponent);
+ for (int ch = 0; ch < TVectorSize; ch++)
+ approx[ch] = product[ch] / largestComponent;
+ }
+
+ // Normalize
+ MFloat approxLen = ParallelMath::MakeFloatZero();
+ for (int ch = 0; ch < TVectorSize; ch++)
+ approxLen = approxLen + approx[ch] * approx[ch];
+
+ approxLen = ParallelMath::Sqrt(approxLen);
+
+ ParallelMath::MakeSafeDenominator(approxLen);
+
+ for (int ch = 0; ch < TVectorSize; ch++)
+ m_direction[ch] = approx[ch] / approxLen;
+ }
+
+ void ContributeMinMax(const MFloat *value)
+ {
+ MFloat dist = ParallelMath::MakeFloatZero();
+ for (int ch = 0; ch < TVectorSize; ch++)
+ dist = dist + m_direction[ch] * (value[ch] - m_centroid[ch]);
+
+ m_minDist = ParallelMath::Min(m_minDist, dist);
+ m_maxDist = ParallelMath::Max(m_maxDist, dist);
+ }
+
+ ParallelMath::Float m_centroid[TVectorSize];
+ ParallelMath::Float m_direction[TVectorSize];
+ PackedCovarianceMatrix<TVectorSize> m_covarianceMatrix;
+ ParallelMath::Float m_weightTotal;
+
+ ParallelMath::Float m_minDist;
+ ParallelMath::Float m_maxDist;
+ };
+
+ static const ParallelMath::UInt16 g_weightReciprocals[] =
+ {
+ ParallelMath::MakeUInt16(0), // -1
+ ParallelMath::MakeUInt16(0), // 0
+ ParallelMath::MakeUInt16(32768), // 1
+ ParallelMath::MakeUInt16(16384), // 2
+ ParallelMath::MakeUInt16(10923), // 3
+ ParallelMath::MakeUInt16(8192), // 4
+ ParallelMath::MakeUInt16(6554), // 5
+ ParallelMath::MakeUInt16(5461), // 6
+ ParallelMath::MakeUInt16(4681), // 7
+ ParallelMath::MakeUInt16(4096), // 8
+ ParallelMath::MakeUInt16(3641), // 9
+ ParallelMath::MakeUInt16(3277), // 10
+ ParallelMath::MakeUInt16(2979), // 11
+ ParallelMath::MakeUInt16(2731), // 12
+ ParallelMath::MakeUInt16(2521), // 13
+ ParallelMath::MakeUInt16(2341), // 14
+ ParallelMath::MakeUInt16(2185), // 15
+ };
+
+ template<int TVectorSize>
+ class IndexSelector
+ {
+ public:
+ typedef ParallelMath::Float MFloat;
+ typedef ParallelMath::UInt16 MUInt16;
+ typedef ParallelMath::UInt15 MUInt15;
+ typedef ParallelMath::SInt16 MSInt16;
+ typedef ParallelMath::AInt16 MAInt16;
+ typedef ParallelMath::SInt32 MSInt32;
+ typedef ParallelMath::UInt31 MUInt31;
+
+ template<class TInterpolationEPType, class TColorEPType>
+ void Init(const float *channelWeights, const TInterpolationEPType interpolationEndPoints[2][TVectorSize], const TColorEPType colorSpaceEndpoints[2][TVectorSize], int range)
+ {
+ // In BC6H, the interpolation endpoints are higher-precision than the endpoints in color space.
+ // We need to select indexes using the color-space endpoints.
+
+ m_isUniform = true;
+ for (int ch = 1; ch < TVectorSize; ch++)
+ {
+ if (channelWeights[ch] != channelWeights[0])
+ m_isUniform = false;
+ }
+
+ // To work with channel weights, we need something where:
+ // pxDiff = px - ep[0]
+ // epDiff = ep[1] - ep[0]
+ //
+ // weightedEPDiff = epDiff * channelWeights
+ // normalizedWeightedAxis = weightedEPDiff / len(weightedEPDiff)
+ // normalizedIndex = dot(pxDiff * channelWeights, normalizedWeightedAxis) / len(weightedEPDiff)
+ // index = normalizedIndex * maxValue
+ //
+ // Equivalent to:
+ // axis = channelWeights * maxValue * epDiff * channelWeights / lenSquared(epDiff * channelWeights)
+ // index = dot(axis, pxDiff)
+
+ for (int ep = 0; ep < 2; ep++)
+ for (int ch = 0; ch < TVectorSize; ch++)
+ m_endPoint[ep][ch] = ParallelMath::LosslessCast<MAInt16>::Cast(interpolationEndPoints[ep][ch]);
+
+ m_range = range;
+ m_maxValue = static_cast<float>(range - 1);
+
+ MFloat epDiffWeighted[TVectorSize];
+ for (int ch = 0; ch < TVectorSize; ch++)
+ {
+ m_origin[ch] = ParallelMath::ToFloat(colorSpaceEndpoints[0][ch]);
+ MFloat opposingOriginCh = ParallelMath::ToFloat(colorSpaceEndpoints[1][ch]);
+ epDiffWeighted[ch] = (opposingOriginCh - m_origin[ch]) * channelWeights[ch];
+ }
+
+ MFloat lenSquared = epDiffWeighted[0] * epDiffWeighted[0];
+ for (int ch = 1; ch < TVectorSize; ch++)
+ lenSquared = lenSquared + epDiffWeighted[ch] * epDiffWeighted[ch];
+
+ ParallelMath::MakeSafeDenominator(lenSquared);
+
+ MFloat maxValueDividedByLengthSquared = ParallelMath::MakeFloat(m_maxValue) / lenSquared;
+
+ for (int ch = 0; ch < TVectorSize; ch++)
+ m_axis[ch] = epDiffWeighted[ch] * channelWeights[ch] * maxValueDividedByLengthSquared;
+ }
+
+ template<bool TSigned>
+ void Init(const float channelWeights[TVectorSize], const MUInt15 endPoints[2][TVectorSize], int range)
+ {
+ MAInt16 converted[2][TVectorSize];
+ for (int epi = 0; epi < 2; epi++)
+ for (int ch = 0; ch < TVectorSize; ch++)
+ converted[epi][ch] = ParallelMath::LosslessCast<MAInt16>::Cast(endPoints[epi][ch]);
+
+ Init<MUInt15, MUInt15>(channelWeights, endPoints, endPoints, range);
+ }
+
+ void ReconstructLDR_BC7(const MUInt15 &index, MUInt15* pixel, int numRealChannels)
+ {
+ MUInt15 weight = ParallelMath::LosslessCast<MUInt15>::Cast(ParallelMath::RightShift(ParallelMath::CompactMultiply(g_weightReciprocals[m_range], index) + 256, 9));
+
+ for (int ch = 0; ch < numRealChannels; ch++)
+ {
+ MUInt15 ep0f = ParallelMath::LosslessCast<MUInt15>::Cast(ParallelMath::CompactMultiply((ParallelMath::MakeUInt15(64) - weight), ParallelMath::LosslessCast<MUInt15>::Cast(m_endPoint[0][ch])));
+ MUInt15 ep1f = ParallelMath::LosslessCast<MUInt15>::Cast(ParallelMath::CompactMultiply(weight, ParallelMath::LosslessCast<MUInt15>::Cast(m_endPoint[1][ch])));
+ pixel[ch] = ParallelMath::LosslessCast<MUInt15>::Cast(ParallelMath::RightShift(ep0f + ep1f + ParallelMath::MakeUInt15(32), 6));
+ }
+ }
+
+ void ReconstructLDRPrecise(const MUInt15 &index, MUInt15* pixel, int numRealChannels)
+ {
+ MUInt15 weight = ParallelMath::LosslessCast<MUInt15>::Cast(ParallelMath::RightShift(ParallelMath::CompactMultiply(g_weightReciprocals[m_range], index) + 64, 7));
+
+ for (int ch = 0; ch < numRealChannels; ch++)
+ {
+ MUInt15 ep0f = ParallelMath::LosslessCast<MUInt15>::Cast(ParallelMath::CompactMultiply((ParallelMath::MakeUInt15(256) - weight), ParallelMath::LosslessCast<MUInt15>::Cast(m_endPoint[0][ch])));
+ MUInt15 ep1f = ParallelMath::LosslessCast<MUInt15>::Cast(ParallelMath::CompactMultiply(weight, ParallelMath::LosslessCast<MUInt15>::Cast(m_endPoint[1][ch])));
+ pixel[ch] = ParallelMath::LosslessCast<MUInt15>::Cast(ParallelMath::RightShift(ep0f + ep1f + ParallelMath::MakeUInt15(128), 8));
+ }
+ }
+
+ void ReconstructLDR_BC7(const MUInt15 &index, MUInt15* pixel)
+ {
+ ReconstructLDR_BC7(index, pixel, TVectorSize);
+ }
+
+ void ReconstructLDRPrecise(const MUInt15 &index, MUInt15* pixel)
+ {
+ ReconstructLDRPrecise(index, pixel, TVectorSize);
+ }
+
+ MUInt15 SelectIndexLDR(const MFloat* pixel, const ParallelMath::RoundTowardNearestForScope* rtn) const
+ {
+ MFloat dist = (pixel[0] - m_origin[0]) * m_axis[0];
+ for (int ch = 1; ch < TVectorSize; ch++)
+ dist = dist + (pixel[ch] - m_origin[ch]) * m_axis[ch];
+
+ return ParallelMath::RoundAndConvertToU15(ParallelMath::Clamp(dist, 0.0f, m_maxValue), rtn);
+ }
+
+ protected:
+ MAInt16 m_endPoint[2][TVectorSize];
+
+ private:
+ MFloat m_origin[TVectorSize];
+ MFloat m_axis[TVectorSize];
+ int m_range;
+ float m_maxValue;
+ bool m_isUniform;
+ };
+
+
+ template<int TVectorSize>
+ class IndexSelectorHDR : public IndexSelector<TVectorSize>
+ {
+ public:
+ typedef ParallelMath::UInt15 MUInt15;
+ typedef ParallelMath::UInt16 MUInt16;
+ typedef ParallelMath::UInt31 MUInt31;
+ typedef ParallelMath::SInt16 MSInt16;
+ typedef ParallelMath::SInt32 MSInt32;
+ typedef ParallelMath::Float MFloat;
+
+ private:
+
+ MUInt15 InvertSingle(const MUInt15& anIndex) const
+ {
+ MUInt15 inverted = m_maxValueMinusOne - anIndex;
+ return ParallelMath::Select(m_isInverted, inverted, anIndex);
+ }
+
+ void ReconstructHDRSignedUninverted(const MUInt15 &index, MSInt16* pixel) const
+ {
+ MUInt15 weight = ParallelMath::LosslessCast<MUInt15>::Cast(ParallelMath::RightShift(ParallelMath::CompactMultiply(g_weightReciprocals[m_range], index) + 256, 9));
+
+ for (int ch = 0; ch < TVectorSize; ch++)
+ {
+ MSInt16 ep0 = ParallelMath::LosslessCast<MSInt16>::Cast(this->m_endPoint[0][ch]);
+ MSInt16 ep1 = ParallelMath::LosslessCast<MSInt16>::Cast(this->m_endPoint[1][ch]);
+
+ MSInt32 pixel32 = ParallelMath::XMultiply((ParallelMath::MakeUInt15(64) - weight), ep0) + ParallelMath::XMultiply(weight, ep1);
+
+ pixel32 = ParallelMath::RightShift(pixel32 + ParallelMath::MakeSInt32(32), 6);
+
+ pixel[ch] = UnscaleHDRValueSigned(ParallelMath::ToSInt16(pixel32));
+ }
+ }
+
+ void ReconstructHDRUnsignedUninverted(const MUInt15 &index, MSInt16* pixel) const
+ {
+ MUInt15 weight = ParallelMath::LosslessCast<MUInt15>::Cast(ParallelMath::RightShift(ParallelMath::CompactMultiply(g_weightReciprocals[m_range], index) + 256, 9));
+
+ for (int ch = 0; ch < TVectorSize; ch++)
+ {
+ MUInt16 ep0 = ParallelMath::LosslessCast<MUInt16>::Cast(this->m_endPoint[0][ch]);
+ MUInt16 ep1 = ParallelMath::LosslessCast<MUInt16>::Cast(this->m_endPoint[1][ch]);
+
+ MUInt31 pixel31 = ParallelMath::XMultiply((ParallelMath::MakeUInt15(64) - weight), ep0) + ParallelMath::XMultiply(weight, ep1);
+
+ pixel31 = ParallelMath::RightShift(pixel31 + ParallelMath::MakeUInt31(32), 6);
+
+ pixel[ch] = ParallelMath::LosslessCast<MSInt16>::Cast(UnscaleHDRValueUnsigned(ParallelMath::ToUInt16(pixel31)));
+ }
+ }
+
+ MFloat ErrorForInterpolatorComponent(int index, int ch, const MFloat *pixel) const
+ {
+ MFloat diff = pixel[ch] - m_reconstructedInterpolators[index][ch];
+ return diff * diff;
+ }
+
+ MFloat ErrorForInterpolator(int index, const MFloat *pixel) const
+ {
+ MFloat error = ErrorForInterpolatorComponent(index, 0, pixel);
+ for (int ch = 1; ch < TVectorSize; ch++)
+ error = error + ErrorForInterpolatorComponent(index, ch, pixel);
+ return error;
+ }
+
+ public:
+
+ void InitHDR(int range, bool isSigned, bool fastIndexing, const float *channelWeights)
+ {
+ assert(range <= 16);
+
+ m_range = range;
+
+ m_isInverted = ParallelMath::MakeBoolInt16(false);
+ m_maxValueMinusOne = ParallelMath::MakeUInt15(static_cast<uint16_t>(range - 1));
+
+ if (!fastIndexing)
+ {
+ for (int i = 0; i < range; i++)
+ {
+ MSInt16 recon2CL[TVectorSize];
+
+ if (isSigned)
+ ReconstructHDRSignedUninverted(ParallelMath::MakeUInt15(static_cast<uint16_t>(i)), recon2CL);
+ else
+ ReconstructHDRUnsignedUninverted(ParallelMath::MakeUInt15(static_cast<uint16_t>(i)), recon2CL);
+
+ for (int ch = 0; ch < TVectorSize; ch++)
+ m_reconstructedInterpolators[i][ch] = ParallelMath::TwosCLHalfToFloat(recon2CL[ch]) * channelWeights[ch];
+ }
+ }
+ }
+
+ void ReconstructHDRSigned(const MUInt15 &index, MSInt16* pixel) const
+ {
+ ReconstructHDRSignedUninverted(InvertSingle(index), pixel);
+ }
+
+ void ReconstructHDRUnsigned(const MUInt15 &index, MSInt16* pixel) const
+ {
+ ReconstructHDRUnsignedUninverted(InvertSingle(index), pixel);
+ }
+
+ void ConditionalInvert(const ParallelMath::Int16CompFlag &invert)
+ {
+ m_isInverted = invert;
+ }
+
+ MUInt15 SelectIndexHDRSlow(const MFloat* pixel, const ParallelMath::RoundTowardNearestForScope*) const
+ {
+ MUInt15 index = ParallelMath::MakeUInt15(0);
+
+ MFloat bestError = ErrorForInterpolator(0, pixel);
+ for (int i = 1; i < m_range; i++)
+ {
+ MFloat error = ErrorForInterpolator(i, pixel);
+ ParallelMath::FloatCompFlag errorBetter = ParallelMath::Less(error, bestError);
+ ParallelMath::ConditionalSet(index, ParallelMath::FloatFlagToInt16(errorBetter), ParallelMath::MakeUInt15(static_cast<uint16_t>(i)));
+ bestError = ParallelMath::Min(bestError, error);
+ }
+
+ return InvertSingle(index);
+ }
+
+ MUInt15 SelectIndexHDRFast(const MFloat* pixel, const ParallelMath::RoundTowardNearestForScope* rtn) const
+ {
+ return InvertSingle(this->SelectIndexLDR(pixel, rtn));
+ }
+
+ private:
+ MFloat m_reconstructedInterpolators[16][TVectorSize];
+ ParallelMath::Int16CompFlag m_isInverted;
+ MUInt15 m_maxValueMinusOne;
+ int m_range;
+ };
+
+ // Solve for a, b where v = a*t + b
+ // This allows endpoints to be mapped to where T=0 and T=1
+ // Least squares from totals:
+ // a = (tv - t*v/w)/(tt - t*t/w)
+ // b = (v - a*t)/w
+ template<int TVectorSize>
+ class EndpointRefiner
+ {
+ public:
+ typedef ParallelMath::Float MFloat;
+ typedef ParallelMath::UInt16 MUInt16;
+ typedef ParallelMath::UInt15 MUInt15;
+ typedef ParallelMath::AInt16 MAInt16;
+ typedef ParallelMath::SInt16 MSInt16;
+ typedef ParallelMath::SInt32 MSInt32;
+
+ MFloat m_tv[TVectorSize];
+ MFloat m_v[TVectorSize];
+ MFloat m_tt;
+ MFloat m_t;
+ MFloat m_w;
+ int m_wu;
+
+ float m_rcpMaxIndex;
+ float m_channelWeights[TVectorSize];
+ float m_rcpChannelWeights[TVectorSize];
+
+ void Init(int indexRange, const float channelWeights[TVectorSize])
+ {
+ for (int ch = 0; ch < TVectorSize; ch++)
+ {
+ m_tv[ch] = ParallelMath::MakeFloatZero();
+ m_v[ch] = ParallelMath::MakeFloatZero();
+ }
+ m_tt = ParallelMath::MakeFloatZero();
+ m_t = ParallelMath::MakeFloatZero();
+ m_w = ParallelMath::MakeFloatZero();
+
+ m_rcpMaxIndex = 1.0f / static_cast<float>(indexRange - 1);
+
+ for (int ch = 0; ch < TVectorSize; ch++)
+ {
+ m_channelWeights[ch] = channelWeights[ch];
+ m_rcpChannelWeights[ch] = 1.0f;
+ if (m_channelWeights[ch] != 0.0f)
+ m_rcpChannelWeights[ch] = 1.0f / channelWeights[ch];
+ }
+
+ m_wu = 0;
+ }
+
+ void ContributePW(const MFloat *pwFloatPixel, const MUInt15 &index, const MFloat &weight)
+ {
+ MFloat t = ParallelMath::ToFloat(index) * m_rcpMaxIndex;
+
+ for (int ch = 0; ch < TVectorSize; ch++)
+ {
+ MFloat v = pwFloatPixel[ch] * weight;
+
+ m_tv[ch] = m_tv[ch] + t * v;
+ m_v[ch] = m_v[ch] + v;
+ }
+ m_tt = m_tt + weight * t * t;
+ m_t = m_t + weight * t;
+ m_w = m_w + weight;
+ }
+
+ void ContributeUnweightedPW(const MFloat *pwFloatPixel, const MUInt15 &index, int numRealChannels)
+ {
+ MFloat t = ParallelMath::ToFloat(index) * m_rcpMaxIndex;
+
+ for (int ch = 0; ch < numRealChannels; ch++)
+ {
+ MFloat v = pwFloatPixel[ch];
+
+ m_tv[ch] = m_tv[ch] + t * v;
+ m_v[ch] = m_v[ch] + v;
+ }
+ m_tt = m_tt + t * t;
+ m_t = m_t + t;
+ m_wu++;
+ }
+
+ void ContributeUnweightedPW(const MFloat *floatPixel, const MUInt15 &index)
+ {
+ ContributeUnweightedPW(floatPixel, index, TVectorSize);
+ }
+
+ void GetRefinedEndpoints(MFloat endPoint[2][TVectorSize])
+ {
+ // a = (tv - t*v/w)/(tt - t*t/w)
+ // b = (v - a*t)/w
+ MFloat w = m_w + ParallelMath::MakeFloat(static_cast<float>(m_wu));
+
+ ParallelMath::MakeSafeDenominator(w);
+ MFloat wRcp = ParallelMath::Reciprocal(w);
+
+ MFloat adenom = (m_tt * w - m_t * m_t) * wRcp;
+
+ ParallelMath::FloatCompFlag adenomZero = ParallelMath::Equal(adenom, ParallelMath::MakeFloatZero());
+ ParallelMath::ConditionalSet(adenom, adenomZero, ParallelMath::MakeFloat(1.0f));
+
+ for (int ch = 0; ch < TVectorSize; ch++)
+ {
+ /*
+ if (adenom == 0.0)
+ p1 = p2 = er.v / er.w;
+ else
+ {
+ float4 a = (er.tv - er.t*er.v / er.w) / adenom;
+ float4 b = (er.v - a * er.t) / er.w;
+ p1 = b;
+ p2 = a + b;
+ }
+ */
+
+ MFloat a = (m_tv[ch] - m_t * m_v[ch] * wRcp) / adenom;
+ MFloat b = (m_v[ch] - a * m_t) * wRcp;
+
+ MFloat p1 = b;
+ MFloat p2 = a + b;
+
+ ParallelMath::ConditionalSet(p1, adenomZero, (m_v[ch] * wRcp));
+ ParallelMath::ConditionalSet(p2, adenomZero, p1);
+
+ // Unweight
+ float inverseWeight = m_rcpChannelWeights[ch];
+
+ endPoint[0][ch] = p1 * inverseWeight;
+ endPoint[1][ch] = p2 * inverseWeight;
+ }
+ }
+
+ void GetRefinedEndpointsLDR(MUInt15 endPoint[2][TVectorSize], int numRealChannels, const ParallelMath::RoundTowardNearestForScope *roundingMode)
+ {
+ MFloat floatEndPoint[2][TVectorSize];
+ GetRefinedEndpoints(floatEndPoint);
+
+ for (int epi = 0; epi < 2; epi++)
+ for (int ch = 0; ch < TVectorSize; ch++)
+ endPoint[epi][ch] = ParallelMath::RoundAndConvertToU15(ParallelMath::Clamp(floatEndPoint[epi][ch], 0.0f, 255.0f), roundingMode);
+ }
+
+ void GetRefinedEndpointsLDR(MUInt15 endPoint[2][TVectorSize], const ParallelMath::RoundTowardNearestForScope *roundingMode)
+ {
+ GetRefinedEndpointsLDR(endPoint, TVectorSize, roundingMode);
+ }
+
+ void GetRefinedEndpointsHDR(MSInt16 endPoint[2][TVectorSize], bool isSigned, const ParallelMath::RoundTowardNearestForScope *roundingMode)
+ {
+ MFloat floatEndPoint[2][TVectorSize];
+ GetRefinedEndpoints(floatEndPoint);
+
+ for (int epi = 0; epi < 2; epi++)
+ {
+ for (int ch = 0; ch < TVectorSize; ch++)
+ {
+ MFloat f = floatEndPoint[epi][ch];
+ if (isSigned)
+ endPoint[epi][ch] = ParallelMath::LosslessCast<MSInt16>::Cast(ParallelMath::RoundAndConvertToS16(ParallelMath::Clamp(f, -31743.0f, 31743.0f), roundingMode));
+ else
+ endPoint[epi][ch] = ParallelMath::LosslessCast<MSInt16>::Cast(ParallelMath::RoundAndConvertToU15(ParallelMath::Clamp(f, 0.0f, 31743.0f), roundingMode));
+ }
+ }
+ }
+ };
+
+ template<int TVectorSize>
+ class AggregatedError
+ {
+ public:
+ typedef ParallelMath::UInt16 MUInt16;
+ typedef ParallelMath::UInt31 MUInt31;
+ typedef ParallelMath::Float MFloat;
+
+ AggregatedError()
+ {
+ for (int ch = 0; ch < TVectorSize; ch++)
+ m_errorUnweighted[ch] = ParallelMath::MakeUInt31(0);
+ }
+
+ void Add(const MUInt16 &channelErrorUnweighted, int ch)
+ {
+ m_errorUnweighted[ch] = m_errorUnweighted[ch] + ParallelMath::ToUInt31(channelErrorUnweighted);
+ }
+
+ MFloat Finalize(uint32_t flags, const float channelWeightsSq[TVectorSize]) const
+ {
+ if (flags & cvtt::Flags::Uniform)
+ {
+ MUInt31 total = m_errorUnweighted[0];
+ for (int ch = 1; ch < TVectorSize; ch++)
+ total = total + m_errorUnweighted[ch];
+ return ParallelMath::ToFloat(total);
+ }
+ else
+ {
+ MFloat total = ParallelMath::ToFloat(m_errorUnweighted[0]) * channelWeightsSq[0];
+ for (int ch = 1; ch < TVectorSize; ch++)
+ total = total + ParallelMath::ToFloat(m_errorUnweighted[ch]) * channelWeightsSq[ch];
+ return total;
+ }
+ }
+
+ private:
+ MUInt31 m_errorUnweighted[TVectorSize];
+ };
+
+ class BCCommon
+ {
+ public:
+ typedef ParallelMath::Float MFloat;
+ typedef ParallelMath::UInt16 MUInt16;
+ typedef ParallelMath::UInt15 MUInt15;
+ typedef ParallelMath::AInt16 MAInt16;
+ typedef ParallelMath::SInt16 MSInt16;
+ typedef ParallelMath::SInt32 MSInt32;
+
+ static int TweakRoundsForRange(int range)
+ {
+ if (range == 3)
+ return 3;
+ return 4;
+ }
+
+ template<int TVectorSize>
+ static void ComputeErrorLDR(uint32_t flags, const MUInt15 reconstructed[TVectorSize], const MUInt15 original[TVectorSize], int numRealChannels, AggregatedError<TVectorSize> &aggError)
+ {
+ for (int ch = 0; ch < numRealChannels; ch++)
+ aggError.Add(ParallelMath::SqDiffUInt8(reconstructed[ch], original[ch]), ch);
+ }
+
+ template<int TVectorSize>
+ static void ComputeErrorLDR(uint32_t flags, const MUInt15 reconstructed[TVectorSize], const MUInt15 original[TVectorSize], AggregatedError<TVectorSize> &aggError)
+ {
+ ComputeErrorLDR<TVectorSize>(flags, reconstructed, original, TVectorSize, aggError);
+ }
+
+ template<int TVectorSize>
+ static MFloat ComputeErrorLDRSimple(uint32_t flags, const MUInt15 reconstructed[TVectorSize], const MUInt15 original[TVectorSize], int numRealChannels, const float *channelWeightsSq)
+ {
+ AggregatedError<TVectorSize> aggError;
+ ComputeErrorLDR<TVectorSize>(flags, reconstructed, original, numRealChannels, aggError);
+ return aggError.Finalize(flags, channelWeightsSq);
+ }
+
+ template<int TVectorSize>
+ static MFloat ComputeErrorHDRFast(uint32_t flags, const MSInt16 reconstructed[TVectorSize], const MSInt16 original[TVectorSize], const float channelWeightsSq[TVectorSize])
+ {
+ MFloat error = ParallelMath::MakeFloatZero();
+ if (flags & Flags::Uniform)
+ {
+ for (int ch = 0; ch < TVectorSize; ch++)
+ error = error + ParallelMath::SqDiffSInt16(reconstructed[ch], original[ch]);
+ }
+ else
+ {
+ for (int ch = 0; ch < TVectorSize; ch++)
+ error = error + ParallelMath::SqDiffSInt16(reconstructed[ch], original[ch]) * ParallelMath::MakeFloat(channelWeightsSq[ch]);
+ }
+
+ return error;
+ }
+
+ template<int TVectorSize>
+ static MFloat ComputeErrorHDRSlow(uint32_t flags, const MSInt16 reconstructed[TVectorSize], const MSInt16 original[TVectorSize], const float channelWeightsSq[TVectorSize])
+ {
+ MFloat error = ParallelMath::MakeFloatZero();
+ if (flags & Flags::Uniform)
+ {
+ for (int ch = 0; ch < TVectorSize; ch++)
+ error = error + ParallelMath::SqDiff2CL(reconstructed[ch], original[ch]);
+ }
+ else
+ {
+ for (int ch = 0; ch < TVectorSize; ch++)
+ error = error + ParallelMath::SqDiff2CL(reconstructed[ch], original[ch]) * ParallelMath::MakeFloat(channelWeightsSq[ch]);
+ }
+
+ return error;
+ }
+
+ template<int TChannelCount>
+ static void PreWeightPixelsLDR(MFloat preWeightedPixels[16][TChannelCount], const MUInt15 pixels[16][TChannelCount], const float channelWeights[TChannelCount])
+ {
+ for (int px = 0; px < 16; px++)
+ {
+ for (int ch = 0; ch < TChannelCount; ch++)
+ preWeightedPixels[px][ch] = ParallelMath::ToFloat(pixels[px][ch]) * channelWeights[ch];
+ }
+ }
+
+ template<int TChannelCount>
+ static void PreWeightPixelsHDR(MFloat preWeightedPixels[16][TChannelCount], const MSInt16 pixels[16][TChannelCount], const float channelWeights[TChannelCount])
+ {
+ for (int px = 0; px < 16; px++)
+ {
+ for (int ch = 0; ch < TChannelCount; ch++)
+ preWeightedPixels[px][ch] = ParallelMath::ToFloat(pixels[px][ch]) * channelWeights[ch];
+ }
+ }
+ };
+
+ class BC7Computer
+ {
+ public:
+ static const int MaxTweakRounds = 4;
+
+ typedef ParallelMath::SInt16 MSInt16;
+ typedef ParallelMath::UInt15 MUInt15;
+ typedef ParallelMath::UInt16 MUInt16;
+ typedef ParallelMath::SInt32 MSInt32;
+ typedef ParallelMath::Float MFloat;
+
+ struct WorkInfo
+ {
+ MUInt15 m_mode;
+ MFloat m_error;
+ MUInt15 m_ep[3][2][4];
+ MUInt15 m_indexes[16];
+ MUInt15 m_indexes2[16];
+
+ union
+ {
+ MUInt15 m_partition;
+ struct IndexSelectorAndRotation
+ {
+ MUInt15 m_indexSelector;
+ MUInt15 m_rotation;
+ } m_isr;
+ } m_u;
+ };
+
+ static void TweakAlpha(const MUInt15 original[2], int tweak, int range, MUInt15 result[2])
+ {
+ ParallelMath::RoundTowardNearestForScope roundingMode;
+
+ float tf[2];
+ ComputeTweakFactors(tweak, range, tf);
+
+ MFloat base = ParallelMath::ToFloat(original[0]);
+ MFloat offs = ParallelMath::ToFloat(original[1]) - base;
+
+ result[0] = ParallelMath::RoundAndConvertToU15(ParallelMath::Clamp(base + offs * tf[0], 0.0f, 255.0f), &roundingMode);
+ result[1] = ParallelMath::RoundAndConvertToU15(ParallelMath::Clamp(base + offs * tf[1], 0.0f, 255.0f), &roundingMode);
+ }
+
+ static void Quantize(MUInt15* color, int bits, int channels, const ParallelMath::RoundTowardNearestForScope *roundingMode)
+ {
+ float maxColor = static_cast<float>((1 << bits) - 1);
+
+ for (int i = 0; i < channels; i++)
+ color[i] = ParallelMath::RoundAndConvertToU15(ParallelMath::Clamp(ParallelMath::ToFloat(color[i]) * ParallelMath::MakeFloat(1.0f / 255.0f) * maxColor, 0.f, 255.f), roundingMode);
+ }
+
+ static void QuantizeP(MUInt15* color, int bits, uint16_t p, int channels, const ParallelMath::RoundTowardNearestForScope *roundingMode)
+ {
+ uint16_t pShift = static_cast<uint16_t>(1 << (7 - bits));
+ MUInt15 pShiftV = ParallelMath::MakeUInt15(pShift);
+
+ float maxColorF = static_cast<float>(255 - (1 << (7 - bits)));
+
+ float maxQuantized = static_cast<float>((1 << bits) - 1);
+
+ for (int ch = 0; ch < channels; ch++)
+ {
+ MUInt15 clr = color[ch];
+ if (p)
+ clr = ParallelMath::Max(clr, pShiftV) - pShiftV;
+
+ MFloat rerangedColor = ParallelMath::ToFloat(clr) * maxQuantized / maxColorF;
+
+ clr = ParallelMath::RoundAndConvertToU15(ParallelMath::Clamp(rerangedColor, 0.0f, maxQuantized), roundingMode) << 1;
+ if (p)
+ clr = clr | ParallelMath::MakeUInt15(1);
+
+ color[ch] = clr;
+ }
+ }
+
+ static void Unquantize(MUInt15* color, int bits, int channels)
+ {
+ for (int ch = 0; ch < channels; ch++)
+ {
+ MUInt15 clr = color[ch];
+ clr = clr << (8 - bits);
+ color[ch] = clr | ParallelMath::RightShift(clr, bits);
+ }
+ }
+
+ static void CompressEndpoints0(MUInt15 ep[2][4], uint16_t p[2], const ParallelMath::RoundTowardNearestForScope *roundingMode)
+ {
+ for (int j = 0; j < 2; j++)
+ {
+ QuantizeP(ep[j], 4, p[j], 3, roundingMode);
+ Unquantize(ep[j], 5, 3);
+ ep[j][3] = ParallelMath::MakeUInt15(255);
+ }
+ }
+
+ static void CompressEndpoints1(MUInt15 ep[2][4], uint16_t p, const ParallelMath::RoundTowardNearestForScope *roundingMode)
+ {
+ for (int j = 0; j < 2; j++)
+ {
+ QuantizeP(ep[j], 6, p, 3, roundingMode);
+ Unquantize(ep[j], 7, 3);
+ ep[j][3] = ParallelMath::MakeUInt15(255);
+ }
+ }
+
+ static void CompressEndpoints2(MUInt15 ep[2][4], const ParallelMath::RoundTowardNearestForScope *roundingMode)
+ {
+ for (int j = 0; j < 2; j++)
+ {
+ Quantize(ep[j], 5, 3, roundingMode);
+ Unquantize(ep[j], 5, 3);
+ ep[j][3] = ParallelMath::MakeUInt15(255);
+ }
+ }
+
+ static void CompressEndpoints3(MUInt15 ep[2][4], uint16_t p[2], const ParallelMath::RoundTowardNearestForScope *roundingMode)
+ {
+ for (int j = 0; j < 2; j++)
+ {
+ QuantizeP(ep[j], 7, p[j], 3, roundingMode);
+ ep[j][3] = ParallelMath::MakeUInt15(255);
+ }
+ }
+
+ static void CompressEndpoints4(MUInt15 epRGB[2][3], MUInt15 epA[2], const ParallelMath::RoundTowardNearestForScope *roundingMode)
+ {
+ for (int j = 0; j < 2; j++)
+ {
+ Quantize(epRGB[j], 5, 3, roundingMode);
+ Unquantize(epRGB[j], 5, 3);
+
+ Quantize(epA + j, 6, 1, roundingMode);
+ Unquantize(epA + j, 6, 1);
+ }
+ }
+
+ static void CompressEndpoints5(MUInt15 epRGB[2][3], MUInt15 epA[2], const ParallelMath::RoundTowardNearestForScope *roundingMode)
+ {
+ for (int j = 0; j < 2; j++)
+ {
+ Quantize(epRGB[j], 7, 3, roundingMode);
+ Unquantize(epRGB[j], 7, 3);
+ }
+
+ // Alpha is full precision
+ (void)epA;
+ }
+
+ static void CompressEndpoints6(MUInt15 ep[2][4], uint16_t p[2], const ParallelMath::RoundTowardNearestForScope *roundingMode)
+ {
+ for (int j = 0; j < 2; j++)
+ QuantizeP(ep[j], 7, p[j], 4, roundingMode);
+ }
+
+ static void CompressEndpoints7(MUInt15 ep[2][4], uint16_t p[2], const ParallelMath::RoundTowardNearestForScope *roundingMode)
+ {
+ for (int j = 0; j < 2; j++)
+ {
+ QuantizeP(ep[j], 5, p[j], 4, roundingMode);
+ Unquantize(ep[j], 6, 4);
+ }
+ }
+
+ struct SinglePlaneTemporaries
+ {
+ UnfinishedEndpoints<3> unfinishedRGB[BC7Data::g_numShapesAll];
+ UnfinishedEndpoints<4> unfinishedRGBA[BC7Data::g_numShapes12];
+
+ MUInt15 fragmentBestIndexes[BC7Data::g_numFragments];
+ MUInt15 shapeBestEP[BC7Data::g_maxFragmentsPerMode][2][4];
+ MFloat shapeBestError[BC7Data::g_maxFragmentsPerMode];
+ };
+
+ static void TrySingleColorRGBAMultiTable(uint32_t flags, const MUInt15 pixels[16][4], const MFloat average[4], int numRealChannels, const uint8_t *fragmentStart, int shapeLength, const MFloat &staticAlphaError, const ParallelMath::Int16CompFlag punchThroughInvalid[4], MFloat& shapeBestError, MUInt15 shapeBestEP[2][4], MUInt15 *fragmentBestIndexes, const float *channelWeightsSq, const cvtt::Tables::BC7SC::Table*const* tables, int numTables, const ParallelMath::RoundTowardNearestForScope *rtn)
+ {
+ MFloat bestAverageError = ParallelMath::MakeFloat(FLT_MAX);
+
+ MUInt15 intAverage[4];
+ for (int ch = 0; ch < 4; ch++)
+ intAverage[ch] = ParallelMath::RoundAndConvertToU15(average[ch], rtn);
+
+ MUInt15 eps[2][4];
+ MUInt15 reconstructed[4];
+ MUInt15 index = ParallelMath::MakeUInt15(0);
+
+ for (int epi = 0; epi < 2; epi++)
+ {
+ for (int ch = 0; ch < 3; ch++)
+ eps[epi][ch] = ParallelMath::MakeUInt15(0);
+ eps[epi][3] = ParallelMath::MakeUInt15(255);
+ }
+
+ for (int ch = 0; ch < 3; ch++)
+ reconstructed[ch] = ParallelMath::MakeUInt15(0);
+ reconstructed[3] = ParallelMath::MakeUInt15(255);
+
+ // Depending on the target index and parity bits, there are multiple valid solid colors.
+ // We want to find the one closest to the actual average.
+ MFloat epsAverageDiff = ParallelMath::MakeFloat(FLT_MAX);
+ for (int t = 0; t < numTables; t++)
+ {
+ const cvtt::Tables::BC7SC::Table& table = *(tables[t]);
+
+ ParallelMath::Int16CompFlag pti = punchThroughInvalid[table.m_pBits];
+
+ MUInt15 candidateReconstructed[4];
+ MUInt15 candidateEPs[2][4];
+
+ for (int i = 0; i < ParallelMath::ParallelSize; i++)
+ {
+ for (int ch = 0; ch < numRealChannels; ch++)
+ {
+ ParallelMath::ScalarUInt16 avgValue = ParallelMath::Extract(intAverage[ch], i);
+ assert(avgValue >= 0 && avgValue <= 255);
+
+ const cvtt::Tables::BC7SC::TableEntry &entry = table.m_entries[avgValue];
+
+ ParallelMath::PutUInt15(candidateEPs[0][ch], i, entry.m_min);
+ ParallelMath::PutUInt15(candidateEPs[1][ch], i, entry.m_max);
+ ParallelMath::PutUInt15(candidateReconstructed[ch], i, entry.m_actualColor);
+ }
+ }
+
+ MFloat avgError = ParallelMath::MakeFloatZero();
+ for (int ch = 0; ch < numRealChannels; ch++)
+ {
+ MFloat delta = ParallelMath::ToFloat(candidateReconstructed[ch]) - average[ch];
+ avgError = avgError + delta * delta * channelWeightsSq[ch];
+ }
+
+ ParallelMath::Int16CompFlag better = ParallelMath::FloatFlagToInt16(ParallelMath::Less(avgError, bestAverageError));
+ better = ParallelMath::AndNot(pti, better); // Mask out punch-through invalidations
+
+ if (ParallelMath::AnySet(better))
+ {
+ ParallelMath::ConditionalSet(bestAverageError, ParallelMath::Int16FlagToFloat(better), avgError);
+
+ MUInt15 candidateIndex = ParallelMath::MakeUInt15(table.m_index);
+
+ ParallelMath::ConditionalSet(index, better, candidateIndex);
+
+ for (int ch = 0; ch < numRealChannels; ch++)
+ ParallelMath::ConditionalSet(reconstructed[ch], better, candidateReconstructed[ch]);
+
+ for (int epi = 0; epi < 2; epi++)
+ for (int ch = 0; ch < numRealChannels; ch++)
+ ParallelMath::ConditionalSet(eps[epi][ch], better, candidateEPs[epi][ch]);
+ }
+ }
+
+ AggregatedError<4> aggError;
+ for (int pxi = 0; pxi < shapeLength; pxi++)
+ {
+ int px = fragmentStart[pxi];
+
+ BCCommon::ComputeErrorLDR<4>(flags, reconstructed, pixels[px], numRealChannels, aggError);
+ }
+
+ MFloat error = aggError.Finalize(flags, channelWeightsSq) + staticAlphaError;
+
+ ParallelMath::Int16CompFlag better = ParallelMath::FloatFlagToInt16(ParallelMath::Less(error, shapeBestError));
+ if (ParallelMath::AnySet(better))
+ {
+ shapeBestError = ParallelMath::Min(shapeBestError, error);
+ for (int epi = 0; epi < 2; epi++)
+ {
+ for (int ch = 0; ch < numRealChannels; ch++)
+ ParallelMath::ConditionalSet(shapeBestEP[epi][ch], better, eps[epi][ch]);
+ }
+
+ for (int pxi = 0; pxi < shapeLength; pxi++)
+ ParallelMath::ConditionalSet(fragmentBestIndexes[pxi], better, index);
+ }
+ }
+
+
+ static void TrySinglePlane(uint32_t flags, const MUInt15 pixels[16][4], const MFloat floatPixels[16][4], const float channelWeights[4], int numTweakRounds, int numRefineRounds, WorkInfo& work, const ParallelMath::RoundTowardNearestForScope *rtn)
+ {
+ if (numRefineRounds < 1)
+ numRefineRounds = 1;
+
+ if (numTweakRounds < 1)
+ numTweakRounds = 1;
+ else if (numTweakRounds > MaxTweakRounds)
+ numTweakRounds = MaxTweakRounds;
+
+ float channelWeightsSq[4];
+
+ for (int ch = 0; ch < 4; ch++)
+ channelWeightsSq[ch] = channelWeights[ch] * channelWeights[ch];
+
+ SinglePlaneTemporaries temps;
+
+ MUInt15 maxAlpha = ParallelMath::MakeUInt15(0);
+ MUInt15 minAlpha = ParallelMath::MakeUInt15(255);
+ ParallelMath::Int16CompFlag isPunchThrough = ParallelMath::MakeBoolInt16(true);
+ for (int px = 0; px < 16; px++)
+ {
+ MUInt15 a = pixels[px][3];
+ maxAlpha = ParallelMath::Max(maxAlpha, a);
+ minAlpha = ParallelMath::Min(minAlpha, a);
+
+ isPunchThrough = (isPunchThrough & (ParallelMath::Equal(a, ParallelMath::MakeUInt15(0)) | ParallelMath::Equal(a, ParallelMath::MakeUInt15(255))));
+ }
+
+ ParallelMath::Int16CompFlag blockHasNonMaxAlpha = ParallelMath::Less(minAlpha, ParallelMath::MakeUInt15(255));
+ ParallelMath::Int16CompFlag blockHasNonZeroAlpha = ParallelMath::Less(ParallelMath::MakeUInt15(0), maxAlpha);
+
+ bool anyBlockHasAlpha = ParallelMath::AnySet(blockHasNonMaxAlpha);
+
+ // Try RGB modes if any block has a min alpha 251 or higher
+ bool allowRGBModes = ParallelMath::AnySet(ParallelMath::Less(ParallelMath::MakeUInt15(250), minAlpha));
+
+ // Try mode 7 if any block has alpha.
+ // Mode 7 is almost never selected for RGB blocks because mode 4 has very accurate 7.7.7.1 endpoints
+ // and its parity bit doesn't affect alpha, meaning mode 7 can only be better in extremely specific
+ // situations, and only by at most 1 unit of error per pixel.
+ bool allowMode7 = anyBlockHasAlpha;
+
+ MFloat preWeightedPixels[16][4];
+
+ BCCommon::PreWeightPixelsLDR<4>(preWeightedPixels, pixels, channelWeights);
+
+ const int *rgbInitialEPCollapseList = NULL;
+
+ // Get initial RGB endpoints
+ if (allowRGBModes)
+ {
+ const int *shapeList;
+ int numShapesToEvaluate;
+
+ if (flags & Flags::BC7_EnablePartitioning)
+ {
+ if (flags & Flags::BC7_Enable3Subsets)
+ {
+ shapeList = BC7Data::g_shapeListAll;
+ rgbInitialEPCollapseList = BC7Data::g_shapeListAll;
+ numShapesToEvaluate = BC7Data::g_numShapesAll;
+ }
+ else
+ {
+ shapeList = BC7Data::g_shapeList12;
+ rgbInitialEPCollapseList = BC7Data::g_shapeList12Collapse;
+ numShapesToEvaluate = BC7Data::g_numShapes12;
+ }
+ }
+ else
+ {
+ shapeList = BC7Data::g_shapeList1;
+ rgbInitialEPCollapseList = BC7Data::g_shapeList1Collapse;
+ numShapesToEvaluate = BC7Data::g_numShapes1;
+ }
+
+ for (int shapeIter = 0; shapeIter < numShapesToEvaluate; shapeIter++)
+ {
+ int shape = shapeList[shapeIter];
+
+ int shapeStart = BC7Data::g_shapeRanges[shape][0];
+ int shapeSize = BC7Data::g_shapeRanges[shape][1];
+
+ EndpointSelector<3, 8> epSelector;
+
+ for (int epPass = 0; epPass < NumEndpointSelectorPasses; epPass++)
+ {
+ for (int spx = 0; spx < shapeSize; spx++)
+ {
+ int px = BC7Data::g_fragments[shapeStart + spx];
+ epSelector.ContributePass(preWeightedPixels[px], epPass, ParallelMath::MakeFloat(1.0f));
+ }
+ epSelector.FinishPass(epPass);
+ }
+ temps.unfinishedRGB[shapeIter] = epSelector.GetEndpoints(channelWeights);
+ }
+ }
+
+ const int *rgbaInitialEPCollapseList = BC7Data::g_shapeList12Collapse;
+
+ // Get initial RGBA endpoints
+ {
+ const int *shapeList = BC7Data::g_shapeList12;
+ int numShapesToEvaluate = BC7Data::g_numShapes12;
+
+ for (int shapeIter = 0; shapeIter < numShapesToEvaluate; shapeIter++)
+ {
+ int shape = shapeList[shapeIter];
+
+ if (anyBlockHasAlpha || !allowRGBModes)
+ {
+ int shapeStart = BC7Data::g_shapeRanges[shape][0];
+ int shapeSize = BC7Data::g_shapeRanges[shape][1];
+
+ EndpointSelector<4, 8> epSelector;
+
+ for (int epPass = 0; epPass < NumEndpointSelectorPasses; epPass++)
+ {
+ for (int spx = 0; spx < shapeSize; spx++)
+ {
+ int px = BC7Data::g_fragments[shapeStart + spx];
+ epSelector.ContributePass(preWeightedPixels[px], epPass, ParallelMath::MakeFloat(1.0f));
+ }
+ epSelector.FinishPass(epPass);
+ }
+ temps.unfinishedRGBA[shapeIter] = epSelector.GetEndpoints(channelWeights);
+ }
+ else
+ {
+ temps.unfinishedRGBA[shapeIter] = temps.unfinishedRGB[rgbInitialEPCollapseList[shape]].ExpandTo<4>(255);
+ }
+ }
+ }
+
+ for (uint16_t mode = 0; mode <= 7; mode++)
+ {
+ if (!(flags & Flags::BC7_EnablePartitioning) && BC7Data::g_modes[mode].m_numSubsets != 1)
+ continue;
+
+ if (!(flags & Flags::BC7_Enable3Subsets) && BC7Data::g_modes[mode].m_numSubsets == 3)
+ continue;
+
+ if (mode == 4 || mode == 5)
+ continue;
+
+ if (mode < 4 && !allowRGBModes)
+ continue;
+
+ if (mode == 7 && !allowMode7)
+ continue;
+
+ bool isRGB = (mode < 4);
+
+ unsigned int numPartitions = 1 << BC7Data::g_modes[mode].m_partitionBits;
+ int numSubsets = BC7Data::g_modes[mode].m_numSubsets;
+ int indexPrec = BC7Data::g_modes[mode].m_indexBits;
+
+ int parityBitMax = 1;
+ if (BC7Data::g_modes[mode].m_pBitMode == BC7Data::PBitMode_PerEndpoint)
+ parityBitMax = 4;
+ else if (BC7Data::g_modes[mode].m_pBitMode == BC7Data::PBitMode_PerSubset)
+ parityBitMax = 2;
+
+ int numRealChannels = isRGB ? 3 : 4;
+
+ int numShapes;
+ const int *shapeList;
+ const int *shapeCollapseList;
+
+ if (numSubsets == 1)
+ {
+ numShapes = BC7Data::g_numShapes1;
+ shapeList = BC7Data::g_shapeList1;
+ shapeCollapseList = BC7Data::g_shapeList1Collapse;
+ }
+ else if (numSubsets == 2)
+ {
+ numShapes = BC7Data::g_numShapes2;
+ shapeList = BC7Data::g_shapeList2;
+ shapeCollapseList = BC7Data::g_shapeList2Collapse;
+ }
+ else
+ {
+ assert(numSubsets == 3);
+ if (numPartitions == 16)
+ {
+ numShapes = BC7Data::g_numShapes3Short;
+ shapeList = BC7Data::g_shapeList3Short;
+ shapeCollapseList = BC7Data::g_shapeList3ShortCollapse;
+ }
+ else
+ {
+ assert(numPartitions == 64);
+ numShapes = BC7Data::g_numShapes3;
+ shapeList = BC7Data::g_shapeList3;
+ shapeCollapseList = BC7Data::g_shapeList3Collapse;
+ }
+ }
+
+ for (int slot = 0; slot < BC7Data::g_maxFragmentsPerMode; slot++)
+ temps.shapeBestError[slot] = ParallelMath::MakeFloat(FLT_MAX);
+
+ for (int shapeIter = 0; shapeIter < numShapes; shapeIter++)
+ {
+ int shape = shapeList[shapeIter];
+ int shapeStart = BC7Data::g_shapeRanges[shape][0];
+ int shapeLength = BC7Data::g_shapeRanges[shape][1];
+ int shapeCollapsedEvalIndex = shapeCollapseList[shape];
+
+ AggregatedError<1> alphaAggError;
+ if (isRGB && anyBlockHasAlpha)
+ {
+ MUInt15 filledAlpha[1] = { ParallelMath::MakeUInt15(255) };
+
+ for (int pxi = 0; pxi < shapeLength; pxi++)
+ {
+ int px = BC7Data::g_fragments[shapeStart + pxi];
+ MUInt15 original[1] = { pixels[px][3] };
+ BCCommon::ComputeErrorLDR<1>(flags, filledAlpha, original, alphaAggError);
+ }
+ }
+
+ float alphaWeightsSq[1] = { channelWeightsSq[3] };
+ MFloat staticAlphaError = alphaAggError.Finalize(flags, alphaWeightsSq);
+
+ assert(shapeCollapsedEvalIndex >= 0);
+
+ MUInt15 tweakBaseEP[MaxTweakRounds][2][4];
+
+ for (int tweak = 0; tweak < numTweakRounds; tweak++)
+ {
+ if (isRGB)
+ {
+ temps.unfinishedRGB[rgbInitialEPCollapseList[shape]].FinishLDR(tweak, 1 << indexPrec, tweakBaseEP[tweak][0], tweakBaseEP[tweak][1]);
+ tweakBaseEP[tweak][0][3] = tweakBaseEP[tweak][1][3] = ParallelMath::MakeUInt15(255);
+ }
+ else
+ {
+ temps.unfinishedRGBA[rgbaInitialEPCollapseList[shape]].FinishLDR(tweak, 1 << indexPrec, tweakBaseEP[tweak][0], tweakBaseEP[tweak][1]);
+ }
+ }
+
+ ParallelMath::Int16CompFlag punchThroughInvalid[4];
+ for (int pIter = 0; pIter < parityBitMax; pIter++)
+ {
+ punchThroughInvalid[pIter] = ParallelMath::MakeBoolInt16(false);
+
+ if ((flags & Flags::BC7_RespectPunchThrough) && (mode == 6 || mode == 7))
+ {
+ // Modes 6 and 7 have parity bits that affect alpha
+ if (pIter == 0)
+ punchThroughInvalid[pIter] = (isPunchThrough & blockHasNonZeroAlpha);
+ else if (pIter == parityBitMax - 1)
+ punchThroughInvalid[pIter] = (isPunchThrough & blockHasNonMaxAlpha);
+ else
+ punchThroughInvalid[pIter] = isPunchThrough;
+ }
+ }
+
+ for (int pIter = 0; pIter < parityBitMax; pIter++)
+ {
+ if (ParallelMath::AllSet(punchThroughInvalid[pIter]))
+ continue;
+
+ bool needPunchThroughCheck = ParallelMath::AnySet(punchThroughInvalid[pIter]);
+
+ for (int tweak = 0; tweak < numTweakRounds; tweak++)
+ {
+ uint16_t p[2];
+ p[0] = (pIter & 1);
+ p[1] = ((pIter >> 1) & 1);
+
+ MUInt15 ep[2][4];
+
+ for (int epi = 0; epi < 2; epi++)
+ for (int ch = 0; ch < 4; ch++)
+ ep[epi][ch] = tweakBaseEP[tweak][epi][ch];
+
+ for (int refine = 0; refine < numRefineRounds; refine++)
+ {
+ switch (mode)
+ {
+ case 0:
+ CompressEndpoints0(ep, p, rtn);
+ break;
+ case 1:
+ CompressEndpoints1(ep, p[0], rtn);
+ break;
+ case 2:
+ CompressEndpoints2(ep, rtn);
+ break;
+ case 3:
+ CompressEndpoints3(ep, p, rtn);
+ break;
+ case 6:
+ CompressEndpoints6(ep, p, rtn);
+ break;
+ case 7:
+ CompressEndpoints7(ep, p, rtn);
+ break;
+ default:
+ assert(false);
+ break;
+ };
+
+ MFloat shapeError = ParallelMath::MakeFloatZero();
+
+ IndexSelector<4> indexSelector;
+ indexSelector.Init<false>(channelWeights, ep, 1 << indexPrec);
+
+ EndpointRefiner<4> epRefiner;
+ epRefiner.Init(1 << indexPrec, channelWeights);
+
+ MUInt15 indexes[16];
+
+ AggregatedError<4> aggError;
+ for (int pxi = 0; pxi < shapeLength; pxi++)
+ {
+ int px = BC7Data::g_fragments[shapeStart + pxi];
+
+ MUInt15 index;
+ MUInt15 reconstructed[4];
+
+ index = indexSelector.SelectIndexLDR(floatPixels[px], rtn);
+ indexSelector.ReconstructLDR_BC7(index, reconstructed, numRealChannels);
+
+ if (flags & cvtt::Flags::BC7_FastIndexing)
+ BCCommon::ComputeErrorLDR<4>(flags, reconstructed, pixels[px], numRealChannels, aggError);
+ else
+ {
+ MFloat error = BCCommon::ComputeErrorLDRSimple<4>(flags, reconstructed, pixels[px], numRealChannels, channelWeightsSq);
+
+ MUInt15 altIndexes[2];
+ altIndexes[0] = ParallelMath::Max(index, ParallelMath::MakeUInt15(1)) - ParallelMath::MakeUInt15(1);
+ altIndexes[1] = ParallelMath::Min(index + ParallelMath::MakeUInt15(1), ParallelMath::MakeUInt15(static_cast<uint16_t>((1 << indexPrec) - 1)));
+
+ for (int ii = 0; ii < 2; ii++)
+ {
+ indexSelector.ReconstructLDR_BC7(altIndexes[ii], reconstructed, numRealChannels);
+
+ MFloat altError = BCCommon::ComputeErrorLDRSimple<4>(flags, reconstructed, pixels[px], numRealChannels, channelWeightsSq);
+ ParallelMath::Int16CompFlag better = ParallelMath::FloatFlagToInt16(ParallelMath::Less(altError, error));
+ error = ParallelMath::Min(error, altError);
+ ParallelMath::ConditionalSet(index, better, altIndexes[ii]);
+ }
+
+ shapeError = shapeError + error;
+ }
+
+ if (refine != numRefineRounds - 1)
+ epRefiner.ContributeUnweightedPW(preWeightedPixels[px], index, numRealChannels);
+
+ indexes[pxi] = index;
+ }
+
+ if (flags & cvtt::Flags::BC7_FastIndexing)
+ shapeError = aggError.Finalize(flags, channelWeightsSq);
+
+ if (isRGB)
+ shapeError = shapeError + staticAlphaError;
+
+ ParallelMath::FloatCompFlag shapeErrorBetter;
+ ParallelMath::Int16CompFlag shapeErrorBetter16;
+
+ shapeErrorBetter = ParallelMath::Less(shapeError, temps.shapeBestError[shapeCollapsedEvalIndex]);
+ shapeErrorBetter16 = ParallelMath::FloatFlagToInt16(shapeErrorBetter);
+
+ if (ParallelMath::AnySet(shapeErrorBetter16))
+ {
+ bool punchThroughOK = true;
+ if (needPunchThroughCheck)
+ {
+ shapeErrorBetter16 = ParallelMath::AndNot(punchThroughInvalid[pIter], shapeErrorBetter16);
+ shapeErrorBetter = ParallelMath::Int16FlagToFloat(shapeErrorBetter16);
+
+ if (!ParallelMath::AnySet(shapeErrorBetter16))
+ punchThroughOK = false;
+ }
+
+ if (punchThroughOK)
+ {
+ ParallelMath::ConditionalSet(temps.shapeBestError[shapeCollapsedEvalIndex], shapeErrorBetter, shapeError);
+ for (int epi = 0; epi < 2; epi++)
+ for (int ch = 0; ch < numRealChannels; ch++)
+ ParallelMath::ConditionalSet(temps.shapeBestEP[shapeCollapsedEvalIndex][epi][ch], shapeErrorBetter16, ep[epi][ch]);
+
+ for (int pxi = 0; pxi < shapeLength; pxi++)
+ ParallelMath::ConditionalSet(temps.fragmentBestIndexes[shapeStart + pxi], shapeErrorBetter16, indexes[pxi]);
+ }
+ }
+
+ if (refine != numRefineRounds - 1)
+ epRefiner.GetRefinedEndpointsLDR(ep, numRealChannels, rtn);
+ } // refine
+ } // tweak
+ } // p
+
+ if (flags & cvtt::Flags::BC7_TrySingleColor)
+ {
+ MUInt15 total[4];
+ for (int ch = 0; ch < 4; ch++)
+ total[ch] = ParallelMath::MakeUInt15(0);
+
+ for (int pxi = 0; pxi < shapeLength; pxi++)
+ {
+ int px = BC7Data::g_fragments[shapeStart + pxi];
+ for (int ch = 0; ch < 4; ch++)
+ total[ch] = total[ch] + pixels[pxi][ch];
+ }
+
+ MFloat rcpShapeLength = ParallelMath::MakeFloat(1.0f / static_cast<float>(shapeLength));
+ MFloat average[4];
+ for (int ch = 0; ch < 4; ch++)
+ average[ch] = ParallelMath::ToFloat(total[ch]) * rcpShapeLength;
+
+ const uint8_t *fragment = BC7Data::g_fragments + shapeStart;
+ MFloat &shapeBestError = temps.shapeBestError[shapeCollapsedEvalIndex];
+ MUInt15(&shapeBestEP)[2][4] = temps.shapeBestEP[shapeCollapsedEvalIndex];
+ MUInt15 *fragmentBestIndexes = temps.fragmentBestIndexes + shapeStart;
+
+ const cvtt::Tables::BC7SC::Table **scTables = NULL;
+ int numSCTables = 0;
+
+ switch (mode)
+ {
+ case 0:
+ {
+ const cvtt::Tables::BC7SC::Table *tables[] =
+ {
+ &cvtt::Tables::BC7SC::g_mode0_p00_i1,
+ &cvtt::Tables::BC7SC::g_mode0_p00_i2,
+ &cvtt::Tables::BC7SC::g_mode0_p00_i3,
+ &cvtt::Tables::BC7SC::g_mode0_p01_i1,
+ &cvtt::Tables::BC7SC::g_mode0_p01_i2,
+ &cvtt::Tables::BC7SC::g_mode0_p01_i3,
+ &cvtt::Tables::BC7SC::g_mode0_p10_i1,
+ &cvtt::Tables::BC7SC::g_mode0_p10_i2,
+ &cvtt::Tables::BC7SC::g_mode0_p10_i3,
+ &cvtt::Tables::BC7SC::g_mode0_p11_i1,
+ &cvtt::Tables::BC7SC::g_mode0_p11_i2,
+ &cvtt::Tables::BC7SC::g_mode0_p11_i3,
+ };
+ scTables = tables;
+ numSCTables = sizeof(tables) / sizeof(tables[0]);
+ }
+ break;
+ case 1:
+ {
+ const cvtt::Tables::BC7SC::Table *tables[] =
+ {
+ &cvtt::Tables::BC7SC::g_mode1_p0_i1,
+ &cvtt::Tables::BC7SC::g_mode1_p0_i2,
+ &cvtt::Tables::BC7SC::g_mode1_p0_i3,
+ &cvtt::Tables::BC7SC::g_mode1_p1_i1,
+ &cvtt::Tables::BC7SC::g_mode1_p1_i2,
+ &cvtt::Tables::BC7SC::g_mode1_p1_i3,
+ };
+ scTables = tables;
+ numSCTables = sizeof(tables) / sizeof(tables[0]);
+ }
+ break;
+ case 2:
+ {
+ const cvtt::Tables::BC7SC::Table *tables[] =
+ {
+ &cvtt::Tables::BC7SC::g_mode2,
+ };
+ scTables = tables;
+ numSCTables = sizeof(tables) / sizeof(tables[0]);
+ }
+ break;
+ case 3:
+ {
+ const cvtt::Tables::BC7SC::Table *tables[] =
+ {
+ &cvtt::Tables::BC7SC::g_mode3_p0,
+ &cvtt::Tables::BC7SC::g_mode3_p1,
+ };
+ scTables = tables;
+ numSCTables = sizeof(tables) / sizeof(tables[0]);
+ }
+ break;
+ case 6:
+ {
+ const cvtt::Tables::BC7SC::Table *tables[] =
+ {
+ &cvtt::Tables::BC7SC::g_mode6_p0_i1,
+ &cvtt::Tables::BC7SC::g_mode6_p0_i2,
+ &cvtt::Tables::BC7SC::g_mode6_p0_i3,
+ &cvtt::Tables::BC7SC::g_mode6_p0_i4,
+ &cvtt::Tables::BC7SC::g_mode6_p0_i5,
+ &cvtt::Tables::BC7SC::g_mode6_p0_i6,
+ &cvtt::Tables::BC7SC::g_mode6_p0_i7,
+ &cvtt::Tables::BC7SC::g_mode6_p1_i1,
+ &cvtt::Tables::BC7SC::g_mode6_p1_i2,
+ &cvtt::Tables::BC7SC::g_mode6_p1_i3,
+ &cvtt::Tables::BC7SC::g_mode6_p1_i4,
+ &cvtt::Tables::BC7SC::g_mode6_p1_i5,
+ &cvtt::Tables::BC7SC::g_mode6_p1_i6,
+ &cvtt::Tables::BC7SC::g_mode6_p1_i7,
+ };
+ scTables = tables;
+ numSCTables = sizeof(tables) / sizeof(tables[0]);
+ }
+ break;
+ case 7:
+ {
+ const cvtt::Tables::BC7SC::Table *tables[] =
+ {
+ &cvtt::Tables::BC7SC::g_mode7_p00,
+ &cvtt::Tables::BC7SC::g_mode7_p01,
+ &cvtt::Tables::BC7SC::g_mode7_p10,
+ &cvtt::Tables::BC7SC::g_mode7_p11,
+ };
+ scTables = tables;
+ numSCTables = sizeof(tables) / sizeof(tables[0]);
+ }
+ break;
+ default:
+ assert(false);
+ break;
+ }
+
+ TrySingleColorRGBAMultiTable(flags, pixels, average, numRealChannels, fragment, shapeLength, staticAlphaError, punchThroughInvalid, shapeBestError, shapeBestEP, fragmentBestIndexes, channelWeightsSq, scTables, numSCTables, rtn);
+ }
+ } // shapeIter
+
+ for (uint16_t partition = 0; partition < numPartitions; partition++)
+ {
+ const int *partitionShapes;
+ if (numSubsets == 1)
+ partitionShapes = BC7Data::g_shapes1[partition];
+ else if (numSubsets == 2)
+ partitionShapes = BC7Data::g_shapes2[partition];
+ else
+ {
+ assert(numSubsets == 3);
+ partitionShapes = BC7Data::g_shapes3[partition];
+ }
+
+ MFloat totalError = ParallelMath::MakeFloatZero();
+ for (int subset = 0; subset < numSubsets; subset++)
+ totalError = totalError + temps.shapeBestError[shapeCollapseList[partitionShapes[subset]]];
+
+ ParallelMath::FloatCompFlag errorBetter = ParallelMath::Less(totalError, work.m_error);
+ ParallelMath::Int16CompFlag errorBetter16 = ParallelMath::FloatFlagToInt16(errorBetter);
+
+ if (ParallelMath::AnySet(errorBetter16))
+ {
+ for (int subset = 0; subset < numSubsets; subset++)
+ {
+ int shape = partitionShapes[subset];
+ int shapeStart = BC7Data::g_shapeRanges[shape][0];
+ int shapeLength = BC7Data::g_shapeRanges[shape][1];
+ int shapeCollapsedEvalIndex = shapeCollapseList[shape];
+
+ for (int epi = 0; epi < 2; epi++)
+ for (int ch = 0; ch < 4; ch++)
+ ParallelMath::ConditionalSet(work.m_ep[subset][epi][ch], errorBetter16, temps.shapeBestEP[shapeCollapsedEvalIndex][epi][ch]);
+
+ for (int pxi = 0; pxi < shapeLength; pxi++)
+ {
+ int px = BC7Data::g_fragments[shapeStart + pxi];
+ ParallelMath::ConditionalSet(work.m_indexes[px], errorBetter16, temps.fragmentBestIndexes[shapeStart + pxi]);
+ }
+ }
+
+ work.m_error = ParallelMath::Min(totalError, work.m_error);
+ ParallelMath::ConditionalSet(work.m_mode, errorBetter16, ParallelMath::MakeUInt15(mode));
+ ParallelMath::ConditionalSet(work.m_u.m_partition, errorBetter16, ParallelMath::MakeUInt15(partition));
+ }
+ }
+ }
+ }
+
+ static void TryDualPlane(uint32_t flags, const MUInt15 pixels[16][4], const MFloat floatPixels[16][4], const float channelWeights[4], int numTweakRounds, int numRefineRounds, WorkInfo& work, const ParallelMath::RoundTowardNearestForScope *rtn)
+ {
+ // TODO: These error calculations are not optimal for weight-by-alpha, but this routine needs to be mostly rewritten for that.
+ // The alpha/color solutions are co-dependent in that case, but a good way to solve it would probably be to
+ // solve the alpha channel first, then solve the RGB channels, which in turn breaks down into two cases:
+ // - Separate alpha channel, then weighted RGB
+ // - Alpha+2 other channels, then the independent channel
+
+ if (!(flags & Flags::BC7_EnableDualPlane))
+ return;
+
+ if (numRefineRounds < 1)
+ numRefineRounds = 1;
+
+ if (numTweakRounds < 1)
+ numTweakRounds = 1;
+ else if (numTweakRounds > MaxTweakRounds)
+ numTweakRounds = MaxTweakRounds;
+
+ float channelWeightsSq[4];
+ for (int ch = 0; ch < 4; ch++)
+ channelWeightsSq[ch] = channelWeights[ch] * channelWeights[ch];
+
+ for (uint16_t mode = 4; mode <= 5; mode++)
+ {
+ for (uint16_t rotation = 0; rotation < 4; rotation++)
+ {
+ int alphaChannel = (rotation + 3) & 3;
+ int redChannel = (rotation == 1) ? 3 : 0;
+ int greenChannel = (rotation == 2) ? 3 : 1;
+ int blueChannel = (rotation == 3) ? 3 : 2;
+
+ MUInt15 rotatedRGB[16][3];
+ MFloat floatRotatedRGB[16][3];
+
+ for (int px = 0; px < 16; px++)
+ {
+ rotatedRGB[px][0] = pixels[px][redChannel];
+ rotatedRGB[px][1] = pixels[px][greenChannel];
+ rotatedRGB[px][2] = pixels[px][blueChannel];
+
+ for (int ch = 0; ch < 3; ch++)
+ floatRotatedRGB[px][ch] = ParallelMath::ToFloat(rotatedRGB[px][ch]);
+ }
+
+ uint16_t maxIndexSelector = (mode == 4) ? 2 : 1;
+
+ float rotatedRGBWeights[3] = { channelWeights[redChannel], channelWeights[greenChannel], channelWeights[blueChannel] };
+ float rotatedRGBWeightsSq[3] = { channelWeightsSq[redChannel], channelWeightsSq[greenChannel], channelWeightsSq[blueChannel] };
+ float rotatedAlphaWeight[1] = { channelWeights[alphaChannel] };
+ float rotatedAlphaWeightSq[1] = { channelWeightsSq[alphaChannel] };
+
+ float uniformWeight[1] = { 1.0f }; // Since the alpha channel is independent, there's no need to bother with weights when doing refinement or selection, only error
+
+ MFloat preWeightedRotatedRGB[16][3];
+ BCCommon::PreWeightPixelsLDR<3>(preWeightedRotatedRGB, rotatedRGB, rotatedRGBWeights);
+
+ for (uint16_t indexSelector = 0; indexSelector < maxIndexSelector; indexSelector++)
+ {
+ EndpointSelector<3, 8> rgbSelector;
+
+ for (int epPass = 0; epPass < NumEndpointSelectorPasses; epPass++)
+ {
+ for (int px = 0; px < 16; px++)
+ rgbSelector.ContributePass(preWeightedRotatedRGB[px], epPass, ParallelMath::MakeFloat(1.0f));
+
+ rgbSelector.FinishPass(epPass);
+ }
+
+ MUInt15 alphaRange[2];
+
+ alphaRange[0] = alphaRange[1] = pixels[0][alphaChannel];
+ for (int px = 1; px < 16; px++)
+ {
+ alphaRange[0] = ParallelMath::Min(pixels[px][alphaChannel], alphaRange[0]);
+ alphaRange[1] = ParallelMath::Max(pixels[px][alphaChannel], alphaRange[1]);
+ }
+
+ int rgbPrec = 0;
+ int alphaPrec = 0;
+
+ if (mode == 4)
+ {
+ rgbPrec = indexSelector ? 3 : 2;
+ alphaPrec = indexSelector ? 2 : 3;
+ }
+ else
+ rgbPrec = alphaPrec = 2;
+
+ UnfinishedEndpoints<3> unfinishedRGB = rgbSelector.GetEndpoints(rotatedRGBWeights);
+
+ MFloat bestRGBError = ParallelMath::MakeFloat(FLT_MAX);
+ MFloat bestAlphaError = ParallelMath::MakeFloat(FLT_MAX);
+
+ MUInt15 bestRGBIndexes[16];
+ MUInt15 bestAlphaIndexes[16];
+ MUInt15 bestEP[2][4];
+
+ for (int px = 0; px < 16; px++)
+ bestRGBIndexes[px] = bestAlphaIndexes[px] = ParallelMath::MakeUInt15(0);
+
+ for (int tweak = 0; tweak < numTweakRounds; tweak++)
+ {
+ MUInt15 rgbEP[2][3];
+ MUInt15 alphaEP[2];
+
+ unfinishedRGB.FinishLDR(tweak, 1 << rgbPrec, rgbEP[0], rgbEP[1]);
+
+ TweakAlpha(alphaRange, tweak, 1 << alphaPrec, alphaEP);
+
+ for (int refine = 0; refine < numRefineRounds; refine++)
+ {
+ if (mode == 4)
+ CompressEndpoints4(rgbEP, alphaEP, rtn);
+ else
+ CompressEndpoints5(rgbEP, alphaEP, rtn);
+
+
+ IndexSelector<1> alphaIndexSelector;
+ IndexSelector<3> rgbIndexSelector;
+
+ {
+ MUInt15 alphaEPTemp[2][1] = { { alphaEP[0] },{ alphaEP[1] } };
+ alphaIndexSelector.Init<false>(uniformWeight, alphaEPTemp, 1 << alphaPrec);
+ }
+ rgbIndexSelector.Init<false>(rotatedRGBWeights, rgbEP, 1 << rgbPrec);
+
+ EndpointRefiner<3> rgbRefiner;
+ EndpointRefiner<1> alphaRefiner;
+
+ rgbRefiner.Init(1 << rgbPrec, rotatedRGBWeights);
+ alphaRefiner.Init(1 << alphaPrec, uniformWeight);
+
+ MFloat errorRGB = ParallelMath::MakeFloatZero();
+ MFloat errorA = ParallelMath::MakeFloatZero();
+
+ MUInt15 rgbIndexes[16];
+ MUInt15 alphaIndexes[16];
+
+ AggregatedError<3> rgbAggError;
+ AggregatedError<1> alphaAggError;
+
+ for (int px = 0; px < 16; px++)
+ {
+ MUInt15 rgbIndex = rgbIndexSelector.SelectIndexLDR(floatRotatedRGB[px], rtn);
+ MUInt15 alphaIndex = alphaIndexSelector.SelectIndexLDR(floatPixels[px] + alphaChannel, rtn);
+
+ MUInt15 reconstructedRGB[3];
+ MUInt15 reconstructedAlpha[1];
+
+ rgbIndexSelector.ReconstructLDR_BC7(rgbIndex, reconstructedRGB);
+ alphaIndexSelector.ReconstructLDR_BC7(alphaIndex, reconstructedAlpha);
+
+ if (flags & cvtt::Flags::BC7_FastIndexing)
+ {
+ BCCommon::ComputeErrorLDR<3>(flags, reconstructedRGB, rotatedRGB[px], rgbAggError);
+ BCCommon::ComputeErrorLDR<1>(flags, reconstructedAlpha, pixels[px] + alphaChannel, alphaAggError);
+ }
+ else
+ {
+ AggregatedError<3> baseRGBAggError;
+ AggregatedError<1> baseAlphaAggError;
+
+ BCCommon::ComputeErrorLDR<3>(flags, reconstructedRGB, rotatedRGB[px], baseRGBAggError);
+ BCCommon::ComputeErrorLDR<1>(flags, reconstructedAlpha, pixels[px] + alphaChannel, baseAlphaAggError);
+
+ MFloat rgbError = baseRGBAggError.Finalize(flags, rotatedRGBWeightsSq);
+ MFloat alphaError = baseAlphaAggError.Finalize(flags, rotatedAlphaWeightSq);
+
+ MUInt15 altRGBIndexes[2];
+ MUInt15 altAlphaIndexes[2];
+
+ altRGBIndexes[0] = ParallelMath::Max(rgbIndex, ParallelMath::MakeUInt15(1)) - ParallelMath::MakeUInt15(1);
+ altRGBIndexes[1] = ParallelMath::Min(rgbIndex + ParallelMath::MakeUInt15(1), ParallelMath::MakeUInt15(static_cast<uint16_t>((1 << rgbPrec) - 1)));
+
+ altAlphaIndexes[0] = ParallelMath::Max(alphaIndex, ParallelMath::MakeUInt15(1)) - ParallelMath::MakeUInt15(1);
+ altAlphaIndexes[1] = ParallelMath::Min(alphaIndex + ParallelMath::MakeUInt15(1), ParallelMath::MakeUInt15(static_cast<uint16_t>((1 << alphaPrec) - 1)));
+
+ for (int ii = 0; ii < 2; ii++)
+ {
+ rgbIndexSelector.ReconstructLDR_BC7(altRGBIndexes[ii], reconstructedRGB);
+ alphaIndexSelector.ReconstructLDR_BC7(altAlphaIndexes[ii], reconstructedAlpha);
+
+ AggregatedError<3> altRGBAggError;
+ AggregatedError<1> altAlphaAggError;
+
+ BCCommon::ComputeErrorLDR<3>(flags, reconstructedRGB, rotatedRGB[px], altRGBAggError);
+ BCCommon::ComputeErrorLDR<1>(flags, reconstructedAlpha, pixels[px] + alphaChannel, altAlphaAggError);
+
+ MFloat altRGBError = altRGBAggError.Finalize(flags, rotatedRGBWeightsSq);
+ MFloat altAlphaError = altAlphaAggError.Finalize(flags, rotatedAlphaWeightSq);
+
+ ParallelMath::Int16CompFlag rgbBetter = ParallelMath::FloatFlagToInt16(ParallelMath::Less(altRGBError, rgbError));
+ ParallelMath::Int16CompFlag alphaBetter = ParallelMath::FloatFlagToInt16(ParallelMath::Less(altAlphaError, alphaError));
+
+ rgbError = ParallelMath::Min(altRGBError, rgbError);
+ alphaError = ParallelMath::Min(altAlphaError, alphaError);
+
+ ParallelMath::ConditionalSet(rgbIndex, rgbBetter, altRGBIndexes[ii]);
+ ParallelMath::ConditionalSet(alphaIndex, alphaBetter, altAlphaIndexes[ii]);
+ }
+
+ errorRGB = errorRGB + rgbError;
+ errorA = errorA + alphaError;
+ }
+
+ if (refine != numRefineRounds - 1)
+ {
+ rgbRefiner.ContributeUnweightedPW(preWeightedRotatedRGB[px], rgbIndex);
+ alphaRefiner.ContributeUnweightedPW(floatPixels[px] + alphaChannel, alphaIndex);
+ }
+
+ if (flags & Flags::BC7_FastIndexing)
+ {
+ errorRGB = rgbAggError.Finalize(flags, rotatedRGBWeightsSq);
+ errorA = rgbAggError.Finalize(flags, rotatedAlphaWeightSq);
+ }
+
+ rgbIndexes[px] = rgbIndex;
+ alphaIndexes[px] = alphaIndex;
+ }
+
+ ParallelMath::FloatCompFlag rgbBetter = ParallelMath::Less(errorRGB, bestRGBError);
+ ParallelMath::FloatCompFlag alphaBetter = ParallelMath::Less(errorA, bestAlphaError);
+
+ ParallelMath::Int16CompFlag rgbBetterInt16 = ParallelMath::FloatFlagToInt16(rgbBetter);
+ ParallelMath::Int16CompFlag alphaBetterInt16 = ParallelMath::FloatFlagToInt16(alphaBetter);
+
+ if (ParallelMath::AnySet(rgbBetterInt16))
+ {
+ bestRGBError = ParallelMath::Min(errorRGB, bestRGBError);
+
+ for (int px = 0; px < 16; px++)
+ ParallelMath::ConditionalSet(bestRGBIndexes[px], rgbBetterInt16, rgbIndexes[px]);
+
+ for (int ep = 0; ep < 2; ep++)
+ {
+ for (int ch = 0; ch < 3; ch++)
+ ParallelMath::ConditionalSet(bestEP[ep][ch], rgbBetterInt16, rgbEP[ep][ch]);
+ }
+ }
+
+ if (ParallelMath::AnySet(alphaBetterInt16))
+ {
+ bestAlphaError = ParallelMath::Min(errorA, bestAlphaError);
+
+ for (int px = 0; px < 16; px++)
+ ParallelMath::ConditionalSet(bestAlphaIndexes[px], alphaBetterInt16, alphaIndexes[px]);
+
+ for (int ep = 0; ep < 2; ep++)
+ ParallelMath::ConditionalSet(bestEP[ep][3], alphaBetterInt16, alphaEP[ep]);
+ }
+
+ if (refine != numRefineRounds - 1)
+ {
+ rgbRefiner.GetRefinedEndpointsLDR(rgbEP, rtn);
+
+ MUInt15 alphaEPTemp[2][1];
+ alphaRefiner.GetRefinedEndpointsLDR(alphaEPTemp, rtn);
+
+ for (int i = 0; i < 2; i++)
+ alphaEP[i] = alphaEPTemp[i][0];
+ }
+ } // refine
+ } // tweak
+
+ MFloat combinedError = bestRGBError + bestAlphaError;
+
+ ParallelMath::FloatCompFlag errorBetter = ParallelMath::Less(combinedError, work.m_error);
+ ParallelMath::Int16CompFlag errorBetter16 = ParallelMath::FloatFlagToInt16(errorBetter);
+
+ work.m_error = ParallelMath::Min(combinedError, work.m_error);
+
+ ParallelMath::ConditionalSet(work.m_mode, errorBetter16, ParallelMath::MakeUInt15(mode));
+ ParallelMath::ConditionalSet(work.m_u.m_isr.m_rotation, errorBetter16, ParallelMath::MakeUInt15(rotation));
+ ParallelMath::ConditionalSet(work.m_u.m_isr.m_indexSelector, errorBetter16, ParallelMath::MakeUInt15(indexSelector));
+
+ for (int px = 0; px < 16; px++)
+ {
+ ParallelMath::ConditionalSet(work.m_indexes[px], errorBetter16, indexSelector ? bestAlphaIndexes[px] : bestRGBIndexes[px]);
+ ParallelMath::ConditionalSet(work.m_indexes2[px], errorBetter16, indexSelector ? bestRGBIndexes[px] : bestAlphaIndexes[px]);
+ }
+
+ for (int ep = 0; ep < 2; ep++)
+ for (int ch = 0; ch < 4; ch++)
+ ParallelMath::ConditionalSet(work.m_ep[0][ep][ch], errorBetter16, bestEP[ep][ch]);
+ }
+ }
+ }
+ }
+
+ template<class T>
+ static void Swap(T& a, T& b)
+ {
+ T temp = a;
+ a = b;
+ b = temp;
+ }
+
+ static void Pack(uint32_t flags, const PixelBlockU8* inputs, uint8_t* packedBlocks, const float channelWeights[4], int numTweakRounds, int numRefineRounds)
+ {
+ MUInt15 pixels[16][4];
+ MFloat floatPixels[16][4];
+
+ for (int px = 0; px < 16; px++)
+ {
+ for (int ch = 0; ch < 4; ch++)
+ ParallelMath::ConvertLDRInputs(inputs, px, ch, pixels[px][ch]);
+ }
+
+ for (int px = 0; px < 16; px++)
+ {
+ for (int ch = 0; ch < 4; ch++)
+ floatPixels[px][ch] = ParallelMath::ToFloat(pixels[px][ch]);
+ }
+
+ WorkInfo work;
+ memset(&work, 0, sizeof(work));
+
+ work.m_error = ParallelMath::MakeFloat(FLT_MAX);
+
+ {
+ ParallelMath::RoundTowardNearestForScope rtn;
+ TrySinglePlane(flags, pixels, floatPixels, channelWeights, numTweakRounds, numRefineRounds, work, &rtn);
+ TryDualPlane(flags, pixels, floatPixels, channelWeights, numTweakRounds, numRefineRounds, work, &rtn);
+ }
+
+ for (int block = 0; block < ParallelMath::ParallelSize; block++)
+ {
+ PackingVector pv;
+ pv.Init();
+
+ ParallelMath::ScalarUInt16 mode = ParallelMath::Extract(work.m_mode, block);
+ ParallelMath::ScalarUInt16 partition = ParallelMath::Extract(work.m_u.m_partition, block);
+ ParallelMath::ScalarUInt16 indexSelector = ParallelMath::Extract(work.m_u.m_isr.m_indexSelector, block);
+
+ const BC7Data::BC7ModeInfo& modeInfo = BC7Data::g_modes[mode];
+
+ ParallelMath::ScalarUInt16 indexes[16];
+ ParallelMath::ScalarUInt16 indexes2[16];
+ ParallelMath::ScalarUInt16 endPoints[3][2][4];
+
+ for (int i = 0; i < 16; i++)
+ {
+ indexes[i] = ParallelMath::Extract(work.m_indexes[i], block);
+ if (modeInfo.m_alphaMode == BC7Data::AlphaMode_Separate)
+ indexes2[i] = ParallelMath::Extract(work.m_indexes2[i], block);
+ }
+
+ for (int subset = 0; subset < 3; subset++)
+ {
+ for (int ep = 0; ep < 2; ep++)
+ {
+ for (int ch = 0; ch < 4; ch++)
+ endPoints[subset][ep][ch] = ParallelMath::Extract(work.m_ep[subset][ep][ch], block);
+ }
+ }
+
+ int fixups[3] = { 0, 0, 0 };
+
+ if (modeInfo.m_alphaMode == BC7Data::AlphaMode_Separate)
+ {
+ bool flipRGB = ((indexes[0] & (1 << (modeInfo.m_indexBits - 1))) != 0);
+ bool flipAlpha = ((indexes2[0] & (1 << (modeInfo.m_alphaIndexBits - 1))) != 0);
+
+ if (flipRGB)
+ {
+ uint16_t highIndex = (1 << modeInfo.m_indexBits) - 1;
+ for (int px = 0; px < 16; px++)
+ indexes[px] = highIndex - indexes[px];
+ }
+
+ if (flipAlpha)
+ {
+ uint16_t highIndex = (1 << modeInfo.m_alphaIndexBits) - 1;
+ for (int px = 0; px < 16; px++)
+ indexes2[px] = highIndex - indexes2[px];
+ }
+
+ if (indexSelector)
+ Swap(flipRGB, flipAlpha);
+
+ if (flipRGB)
+ {
+ for (int ch = 0; ch < 3; ch++)
+ Swap(endPoints[0][0][ch], endPoints[0][1][ch]);
+ }
+ if (flipAlpha)
+ Swap(endPoints[0][0][3], endPoints[0][1][3]);
+
+ }
+ else
+ {
+ if (modeInfo.m_numSubsets == 2)
+ fixups[1] = BC7Data::g_fixupIndexes2[partition];
+ else if (modeInfo.m_numSubsets == 3)
+ {
+ fixups[1] = BC7Data::g_fixupIndexes3[partition][0];
+ fixups[2] = BC7Data::g_fixupIndexes3[partition][1];
+ }
+
+ bool flip[3] = { false, false, false };
+ for (int subset = 0; subset < modeInfo.m_numSubsets; subset++)
+ flip[subset] = ((indexes[fixups[subset]] & (1 << (modeInfo.m_indexBits - 1))) != 0);
+
+ if (flip[0] || flip[1] || flip[2])
+ {
+ uint16_t highIndex = (1 << modeInfo.m_indexBits) - 1;
+ for (int px = 0; px < 16; px++)
+ {
+ int subset = 0;
+ if (modeInfo.m_numSubsets == 2)
+ subset = (BC7Data::g_partitionMap[partition] >> px) & 1;
+ else if (modeInfo.m_numSubsets == 3)
+ subset = (BC7Data::g_partitionMap2[partition] >> (px * 2)) & 3;
+
+ if (flip[subset])
+ indexes[px] = highIndex - indexes[px];
+ }
+
+ int maxCH = (modeInfo.m_alphaMode == BC7Data::AlphaMode_Combined) ? 4 : 3;
+ for (int subset = 0; subset < modeInfo.m_numSubsets; subset++)
+ {
+ if (flip[subset])
+ for (int ch = 0; ch < maxCH; ch++)
+ Swap(endPoints[subset][0][ch], endPoints[subset][1][ch]);
+ }
+ }
+ }
+
+ pv.Pack(static_cast<uint8_t>(1 << mode), mode + 1);
+
+ if (modeInfo.m_partitionBits)
+ pv.Pack(partition, modeInfo.m_partitionBits);
+
+ if (modeInfo.m_alphaMode == BC7Data::AlphaMode_Separate)
+ {
+ ParallelMath::ScalarUInt16 rotation = ParallelMath::Extract(work.m_u.m_isr.m_rotation, block);
+ pv.Pack(rotation, 2);
+ }
+
+ if (modeInfo.m_hasIndexSelector)
+ pv.Pack(indexSelector, 1);
+
+ // Encode RGB
+ for (int ch = 0; ch < 3; ch++)
+ {
+ for (int subset = 0; subset < modeInfo.m_numSubsets; subset++)
+ {
+ for (int ep = 0; ep < 2; ep++)
+ {
+ ParallelMath::ScalarUInt16 epPart = endPoints[subset][ep][ch];
+ epPart >>= (8 - modeInfo.m_rgbBits);
+
+ pv.Pack(epPart, modeInfo.m_rgbBits);
+ }
+ }
+ }
+
+ // Encode alpha
+ if (modeInfo.m_alphaMode != BC7Data::AlphaMode_None)
+ {
+ for (int subset = 0; subset < modeInfo.m_numSubsets; subset++)
+ {
+ for (int ep = 0; ep < 2; ep++)
+ {
+ ParallelMath::ScalarUInt16 epPart = endPoints[subset][ep][3];
+ epPart >>= (8 - modeInfo.m_alphaBits);
+
+ pv.Pack(epPart, modeInfo.m_alphaBits);
+ }
+ }
+ }
+
+ // Encode parity bits
+ if (modeInfo.m_pBitMode == BC7Data::PBitMode_PerSubset)
+ {
+ for (int subset = 0; subset < modeInfo.m_numSubsets; subset++)
+ {
+ ParallelMath::ScalarUInt16 epPart = endPoints[subset][0][0];
+ epPart >>= (7 - modeInfo.m_rgbBits);
+ epPart &= 1;
+
+ pv.Pack(epPart, 1);
+ }
+ }
+ else if (modeInfo.m_pBitMode == BC7Data::PBitMode_PerEndpoint)
+ {
+ for (int subset = 0; subset < modeInfo.m_numSubsets; subset++)
+ {
+ for (int ep = 0; ep < 2; ep++)
+ {
+ ParallelMath::ScalarUInt16 epPart = endPoints[subset][ep][0];
+ epPart >>= (7 - modeInfo.m_rgbBits);
+ epPart &= 1;
+
+ pv.Pack(epPart, 1);
+ }
+ }
+ }
+
+ // Encode indexes
+ for (int px = 0; px < 16; px++)
+ {
+ int bits = modeInfo.m_indexBits;
+ if ((px == 0) || (px == fixups[1]) || (px == fixups[2]))
+ bits--;
+
+ pv.Pack(indexes[px], bits);
+ }
+
+ // Encode secondary indexes
+ if (modeInfo.m_alphaMode == BC7Data::AlphaMode_Separate)
+ {
+ for (int px = 0; px < 16; px++)
+ {
+ int bits = modeInfo.m_alphaIndexBits;
+ if (px == 0)
+ bits--;
+
+ pv.Pack(indexes2[px], bits);
+ }
+ }
+
+ pv.Flush(packedBlocks);
+
+ packedBlocks += 16;
+ }
+ }
+
+ static void UnpackOne(PixelBlockU8 &output, const uint8_t* packedBlock)
+ {
+ UnpackingVector pv;
+ pv.Init(packedBlock);
+
+ int mode = 8;
+ for (int i = 0; i < 8; i++)
+ {
+ if (pv.Unpack(1) == 1)
+ {
+ mode = i;
+ break;
+ }
+ }
+
+ if (mode > 7)
+ {
+ for (int px = 0; px < 16; px++)
+ for (int ch = 0; ch < 4; ch++)
+ output.m_pixels[px][ch] = 0;
+
+ return;
+ }
+
+ const BC7Data::BC7ModeInfo &modeInfo = BC7Data::g_modes[mode];
+
+ int partition = 0;
+ if (modeInfo.m_partitionBits)
+ partition = pv.Unpack(modeInfo.m_partitionBits);
+
+ int rotation = 0;
+ if (modeInfo.m_alphaMode == BC7Data::AlphaMode_Separate)
+ rotation = pv.Unpack(2);
+
+ int indexSelector = 0;
+ if (modeInfo.m_hasIndexSelector)
+ indexSelector = pv.Unpack(1);
+
+ // Resolve fixups
+ int fixups[3] = { 0, 0, 0 };
+
+ if (modeInfo.m_alphaMode != BC7Data::AlphaMode_Separate)
+ {
+ if (modeInfo.m_numSubsets == 2)
+ fixups[1] = BC7Data::g_fixupIndexes2[partition];
+ else if (modeInfo.m_numSubsets == 3)
+ {
+ fixups[1] = BC7Data::g_fixupIndexes3[partition][0];
+ fixups[2] = BC7Data::g_fixupIndexes3[partition][1];
+ }
+ }
+
+ int endPoints[3][2][4];
+
+ // Decode RGB
+ for (int ch = 0; ch < 3; ch++)
+ {
+ for (int subset = 0; subset < modeInfo.m_numSubsets; subset++)
+ {
+ for (int ep = 0; ep < 2; ep++)
+ endPoints[subset][ep][ch] = (pv.Unpack(modeInfo.m_rgbBits) << (8 - modeInfo.m_rgbBits));
+ }
+ }
+
+ // Decode alpha
+ if (modeInfo.m_alphaMode != BC7Data::AlphaMode_None)
+ {
+ for (int subset = 0; subset < modeInfo.m_numSubsets; subset++)
+ {
+ for (int ep = 0; ep < 2; ep++)
+ endPoints[subset][ep][3] = (pv.Unpack(modeInfo.m_alphaBits) << (8 - modeInfo.m_alphaBits));
+ }
+ }
+ else
+ {
+ for (int subset = 0; subset < modeInfo.m_numSubsets; subset++)
+ {
+ for (int ep = 0; ep < 2; ep++)
+ endPoints[subset][ep][3] = 255;
+ }
+ }
+
+ int parityBits = 0;
+
+ // Decode parity bits
+ if (modeInfo.m_pBitMode == BC7Data::PBitMode_PerSubset)
+ {
+ for (int subset = 0; subset < modeInfo.m_numSubsets; subset++)
+ {
+ int p = pv.Unpack(1);
+
+ for (int ep = 0; ep < 2; ep++)
+ {
+ for (int ch = 0; ch < 3; ch++)
+ endPoints[subset][ep][ch] |= p << (7 - modeInfo.m_rgbBits);
+
+ if (modeInfo.m_alphaMode != BC7Data::AlphaMode_None)
+ endPoints[subset][ep][3] |= p << (7 - modeInfo.m_alphaBits);
+ }
+ }
+
+ parityBits = 1;
+ }
+ else if (modeInfo.m_pBitMode == BC7Data::PBitMode_PerEndpoint)
+ {
+ for (int subset = 0; subset < modeInfo.m_numSubsets; subset++)
+ {
+ for (int ep = 0; ep < 2; ep++)
+ {
+ int p = pv.Unpack(1);
+
+ for (int ch = 0; ch < 3; ch++)
+ endPoints[subset][ep][ch] |= p << (7 - modeInfo.m_rgbBits);
+
+ if (modeInfo.m_alphaMode != BC7Data::AlphaMode_None)
+ endPoints[subset][ep][3] |= p << (7 - modeInfo.m_alphaBits);
+ }
+ }
+
+ parityBits = 1;
+ }
+
+ // Fill endpoint bits
+ for (int subset = 0; subset < modeInfo.m_numSubsets; subset++)
+ {
+ for (int ep = 0; ep < 2; ep++)
+ {
+ for (int ch = 0; ch < 3; ch++)
+ endPoints[subset][ep][ch] |= (endPoints[subset][ep][ch] >> (modeInfo.m_rgbBits + parityBits));
+
+ if (modeInfo.m_alphaMode != BC7Data::AlphaMode_None)
+ endPoints[subset][ep][3] |= (endPoints[subset][ep][3] >> (modeInfo.m_alphaBits + parityBits));
+ }
+ }
+
+ int indexes[16];
+ int indexes2[16];
+
+ // Decode indexes
+ for (int px = 0; px < 16; px++)
+ {
+ int bits = modeInfo.m_indexBits;
+ if ((px == 0) || (px == fixups[1]) || (px == fixups[2]))
+ bits--;
+
+ indexes[px] = pv.Unpack(bits);
+ }
+
+ // Decode secondary indexes
+ if (modeInfo.m_alphaMode == BC7Data::AlphaMode_Separate)
+ {
+ for (int px = 0; px < 16; px++)
+ {
+ int bits = modeInfo.m_alphaIndexBits;
+ if (px == 0)
+ bits--;
+
+ indexes2[px] = pv.Unpack(bits);
+ }
+ }
+ else
+ {
+ for (int px = 0; px < 16; px++)
+ indexes2[px] = 0;
+ }
+
+ const int *alphaWeights = BC7Data::g_weightTables[modeInfo.m_alphaIndexBits];
+ const int *rgbWeights = BC7Data::g_weightTables[modeInfo.m_indexBits];
+
+ // Decode each pixel
+ for (int px = 0; px < 16; px++)
+ {
+ int rgbWeight = 0;
+ int alphaWeight = 0;
+
+ int rgbIndex = indexes[px];
+
+ rgbWeight = rgbWeights[indexes[px]];
+
+ if (modeInfo.m_alphaMode == BC7Data::AlphaMode_Combined)
+ alphaWeight = rgbWeight;
+ else if (modeInfo.m_alphaMode == BC7Data::AlphaMode_Separate)
+ alphaWeight = alphaWeights[indexes2[px]];
+
+ if (indexSelector == 1)
+ {
+ int temp = rgbWeight;
+ rgbWeight = alphaWeight;
+ alphaWeight = temp;
+ }
+
+ int pixel[4] = { 0, 0, 0, 255 };
+
+ int subset = 0;
+
+ if (modeInfo.m_numSubsets == 2)
+ subset = (BC7Data::g_partitionMap[partition] >> px) & 1;
+ else if (modeInfo.m_numSubsets == 3)
+ subset = (BC7Data::g_partitionMap2[partition] >> (px * 2)) & 3;
+
+ for (int ch = 0; ch < 3; ch++)
+ pixel[ch] = ((64 - rgbWeight) * endPoints[subset][0][ch] + rgbWeight * endPoints[subset][1][ch] + 32) >> 6;
+
+ if (modeInfo.m_alphaMode != BC7Data::AlphaMode_None)
+ pixel[3] = ((64 - alphaWeight) * endPoints[subset][0][3] + alphaWeight * endPoints[subset][1][3] + 32) >> 6;
+
+ if (rotation != 0)
+ {
+ int ch = rotation - 1;
+ int temp = pixel[ch];
+ pixel[ch] = pixel[3];
+ pixel[3] = temp;
+ }
+
+ for (int ch = 0; ch < 4; ch++)
+ output.m_pixels[px][ch] = static_cast<uint8_t>(pixel[ch]);
+ }
+ }
+ };
+
+ class BC6HComputer
+ {
+ public:
+ typedef ParallelMath::Float MFloat;
+ typedef ParallelMath::SInt16 MSInt16;
+ typedef ParallelMath::UInt16 MUInt16;
+ typedef ParallelMath::UInt15 MUInt15;
+ typedef ParallelMath::AInt16 MAInt16;
+ typedef ParallelMath::SInt32 MSInt32;
+ typedef ParallelMath::UInt31 MUInt31;
+
+ static const int MaxTweakRounds = 4;
+ static const int MaxRefineRounds = 3;
+
+ static MSInt16 QuantizeSingleEndpointElementSigned(const MSInt16 &elem2CL, int precision, const ParallelMath::RoundUpForScope* ru)
+ {
+ assert(ParallelMath::AllSet(ParallelMath::Less(elem2CL, ParallelMath::MakeSInt16(31744))));
+ assert(ParallelMath::AllSet(ParallelMath::Less(ParallelMath::MakeSInt16(-31744), elem2CL)));
+
+ // Expand to full range
+ ParallelMath::Int16CompFlag isNegative = ParallelMath::Less(elem2CL, ParallelMath::MakeSInt16(0));
+ MUInt15 absElem = ParallelMath::LosslessCast<MUInt15>::Cast(ParallelMath::Select(isNegative, ParallelMath::MakeSInt16(0) - elem2CL, elem2CL));
+
+ absElem = ParallelMath::RightShift(ParallelMath::RoundAndConvertToU15(ParallelMath::ToFloat(absElem) * 32.0f / 31.0f, ru), 16 - precision);
+
+ MSInt16 absElemS16 = ParallelMath::LosslessCast<MSInt16>::Cast(absElem);
+
+ return ParallelMath::Select(isNegative, ParallelMath::MakeSInt16(0) - absElemS16, absElemS16);
+ }
+
+ static MUInt15 QuantizeSingleEndpointElementUnsigned(const MUInt15 &elem, int precision, const ParallelMath::RoundUpForScope* ru)
+ {
+ MUInt16 expandedElem = ParallelMath::RoundAndConvertToU16(ParallelMath::Min(ParallelMath::ToFloat(elem) * 64.0f / 31.0f, ParallelMath::MakeFloat(65535.0f)), ru);
+ return ParallelMath::LosslessCast<MUInt15>::Cast(ParallelMath::RightShift(expandedElem, 16 - precision));
+ }
+
+ static void UnquantizeSingleEndpointElementSigned(const MSInt16 &comp, int precision, MSInt16 &outUnquantized, MSInt16 &outUnquantizedFinished2CL)
+ {
+ MSInt16 zero = ParallelMath::MakeSInt16(0);
+
+ ParallelMath::Int16CompFlag negative = ParallelMath::Less(comp, zero);
+ MUInt15 absComp = ParallelMath::LosslessCast<MUInt15>::Cast(ParallelMath::Select(negative, MSInt16(zero - comp), comp));
+
+ MSInt16 unq;
+ MUInt15 absUnq;
+
+ if (precision >= 16)
+ {
+ unq = comp;
+ absUnq = absComp;
+ }
+ else
+ {
+ MSInt16 maxCompMinusOne = ParallelMath::MakeSInt16(static_cast<int16_t>((1 << (precision - 1)) - 2));
+ ParallelMath::Int16CompFlag isZero = ParallelMath::Equal(comp, zero);
+ ParallelMath::Int16CompFlag isMax = ParallelMath::Less(maxCompMinusOne, comp);
+
+ absUnq = (absComp << (16 - precision)) + ParallelMath::MakeUInt15(static_cast<uint16_t>(0x4000 >> (precision - 1)));
+ ParallelMath::ConditionalSet(absUnq, isZero, ParallelMath::MakeUInt15(0));
+ ParallelMath::ConditionalSet(absUnq, isMax, ParallelMath::MakeUInt15(0x7fff));
+
+ unq = ParallelMath::ConditionalNegate(negative, ParallelMath::LosslessCast<MSInt16>::Cast(absUnq));
+ }
+
+ outUnquantized = unq;
+
+ MUInt15 funq = ParallelMath::ToUInt15(ParallelMath::RightShift(ParallelMath::XMultiply(absUnq, ParallelMath::MakeUInt15(31)), 5));
+
+ outUnquantizedFinished2CL = ParallelMath::ConditionalNegate(negative, ParallelMath::LosslessCast<MSInt16>::Cast(funq));
+ }
+
+ static void UnquantizeSingleEndpointElementUnsigned(const MUInt15 &comp, int precision, MUInt16 &outUnquantized, MUInt16 &outUnquantizedFinished)
+ {
+ MUInt16 unq = ParallelMath::LosslessCast<MUInt16>::Cast(comp);
+ if (precision < 15)
+ {
+ MUInt15 zero = ParallelMath::MakeUInt15(0);
+ MUInt15 maxCompMinusOne = ParallelMath::MakeUInt15(static_cast<uint16_t>((1 << precision) - 2));
+
+ ParallelMath::Int16CompFlag isZero = ParallelMath::Equal(comp, zero);
+ ParallelMath::Int16CompFlag isMax = ParallelMath::Less(maxCompMinusOne, comp);
+
+ unq = (ParallelMath::LosslessCast<MUInt16>::Cast(comp) << (16 - precision)) + ParallelMath::MakeUInt16(static_cast<uint16_t>(0x8000 >> precision));
+
+ ParallelMath::ConditionalSet(unq, isZero, ParallelMath::MakeUInt16(0));
+ ParallelMath::ConditionalSet(unq, isMax, ParallelMath::MakeUInt16(0xffff));
+ }
+
+ outUnquantized = unq;
+ outUnquantizedFinished = ParallelMath::ToUInt16(ParallelMath::RightShift(ParallelMath::XMultiply(unq, ParallelMath::MakeUInt15(31)), 6));
+ }
+
+ static void QuantizeEndpointsSigned(const MSInt16 endPoints[2][3], const MFloat floatPixelsColorSpace[16][3], const MFloat floatPixelsLinearWeighted[16][3], MAInt16 quantizedEndPoints[2][3], MUInt15 indexes[16], IndexSelectorHDR<3> &indexSelector, int fixupIndex, int precision, int indexRange, const float *channelWeights, bool fastIndexing, const ParallelMath::RoundTowardNearestForScope *rtn)
+ {
+ MSInt16 unquantizedEP[2][3];
+ MSInt16 finishedUnquantizedEP[2][3];
+
+ {
+ ParallelMath::RoundUpForScope ru;
+
+ for (int epi = 0; epi < 2; epi++)
+ {
+ for (int ch = 0; ch < 3; ch++)
+ {
+ MSInt16 qee = QuantizeSingleEndpointElementSigned(endPoints[epi][ch], precision, &ru);
+ UnquantizeSingleEndpointElementSigned(qee, precision, unquantizedEP[epi][ch], finishedUnquantizedEP[epi][ch]);
+ quantizedEndPoints[epi][ch] = ParallelMath::LosslessCast<MAInt16>::Cast(qee);
+ }
+ }
+ }
+
+ indexSelector.Init(channelWeights, unquantizedEP, finishedUnquantizedEP, indexRange);
+ indexSelector.InitHDR(indexRange, true, fastIndexing, channelWeights);
+
+ MUInt15 halfRangeMinusOne = ParallelMath::MakeUInt15(static_cast<uint16_t>(indexRange / 2) - 1);
+
+ MUInt15 index = fastIndexing ? indexSelector.SelectIndexHDRFast(floatPixelsColorSpace[fixupIndex], rtn) : indexSelector.SelectIndexHDRSlow(floatPixelsLinearWeighted[fixupIndex], rtn);
+
+ ParallelMath::Int16CompFlag invert = ParallelMath::Less(halfRangeMinusOne, index);
+
+ if (ParallelMath::AnySet(invert))
+ {
+ ParallelMath::ConditionalSet(index, invert, MUInt15(ParallelMath::MakeUInt15(static_cast<uint16_t>(indexRange - 1)) - index));
+
+ indexSelector.ConditionalInvert(invert);
+
+ for (int ch = 0; ch < 3; ch++)
+ {
+ MAInt16 firstEP = quantizedEndPoints[0][ch];
+ MAInt16 secondEP = quantizedEndPoints[1][ch];
+
+ quantizedEndPoints[0][ch] = ParallelMath::Select(invert, secondEP, firstEP);
+ quantizedEndPoints[1][ch] = ParallelMath::Select(invert, firstEP, secondEP);
+ }
+ }
+
+ indexes[fixupIndex] = index;
+ }
+
+ static void QuantizeEndpointsUnsigned(const MSInt16 endPoints[2][3], const MFloat floatPixelsColorSpace[16][3], const MFloat floatPixelsLinearWeighted[16][3], MAInt16 quantizedEndPoints[2][3], MUInt15 indexes[16], IndexSelectorHDR<3> &indexSelector, int fixupIndex, int precision, int indexRange, const float *channelWeights, bool fastIndexing, const ParallelMath::RoundTowardNearestForScope *rtn)
+ {
+ MUInt16 unquantizedEP[2][3];
+ MUInt16 finishedUnquantizedEP[2][3];
+
+ {
+ ParallelMath::RoundUpForScope ru;
+
+ for (int epi = 0; epi < 2; epi++)
+ {
+ for (int ch = 0; ch < 3; ch++)
+ {
+ MUInt15 qee = QuantizeSingleEndpointElementUnsigned(ParallelMath::LosslessCast<MUInt15>::Cast(endPoints[epi][ch]), precision, &ru);
+ UnquantizeSingleEndpointElementUnsigned(qee, precision, unquantizedEP[epi][ch], finishedUnquantizedEP[epi][ch]);
+ quantizedEndPoints[epi][ch] = ParallelMath::LosslessCast<MAInt16>::Cast(qee);
+ }
+ }
+ }
+
+ indexSelector.Init(channelWeights, unquantizedEP, finishedUnquantizedEP, indexRange);
+ indexSelector.InitHDR(indexRange, false, fastIndexing, channelWeights);
+
+ MUInt15 halfRangeMinusOne = ParallelMath::MakeUInt15(static_cast<uint16_t>(indexRange / 2) - 1);
+
+ MUInt15 index = fastIndexing ? indexSelector.SelectIndexHDRFast(floatPixelsColorSpace[fixupIndex], rtn) : indexSelector.SelectIndexHDRSlow(floatPixelsLinearWeighted[fixupIndex], rtn);
+
+ ParallelMath::Int16CompFlag invert = ParallelMath::Less(halfRangeMinusOne, index);
+
+ if (ParallelMath::AnySet(invert))
+ {
+ ParallelMath::ConditionalSet(index, invert, MUInt15(ParallelMath::MakeUInt15(static_cast<uint16_t>(indexRange - 1)) - index));
+
+ indexSelector.ConditionalInvert(invert);
+
+ for (int ch = 0; ch < 3; ch++)
+ {
+ MAInt16 firstEP = quantizedEndPoints[0][ch];
+ MAInt16 secondEP = quantizedEndPoints[1][ch];
+
+ quantizedEndPoints[0][ch] = ParallelMath::Select(invert, secondEP, firstEP);
+ quantizedEndPoints[1][ch] = ParallelMath::Select(invert, firstEP, secondEP);
+ }
+ }
+
+ indexes[fixupIndex] = index;
+ }
+
+ static void EvaluatePartitionedLegality(const MAInt16 ep0[2][3], const MAInt16 ep1[2][3], int aPrec, const int bPrec[3], bool isTransformed, MAInt16 outEncodedEPs[2][2][3], ParallelMath::Int16CompFlag& outIsLegal)
+ {
+ ParallelMath::Int16CompFlag allLegal = ParallelMath::MakeBoolInt16(true);
+
+ MAInt16 aSignificantMask = ParallelMath::MakeAInt16(static_cast<int16_t>((1 << aPrec) - 1));
+
+ for (int ch = 0; ch < 3; ch++)
+ {
+ outEncodedEPs[0][0][ch] = ep0[0][ch];
+ outEncodedEPs[0][1][ch] = ep0[1][ch];
+ outEncodedEPs[1][0][ch] = ep1[0][ch];
+ outEncodedEPs[1][1][ch] = ep1[1][ch];
+
+ if (isTransformed)
+ {
+ for (int subset = 0; subset < 2; subset++)
+ {
+ for (int epi = 0; epi < 2; epi++)
+ {
+ if (epi == 0 && subset == 0)
+ continue;
+
+ MAInt16 bReduced = (outEncodedEPs[subset][epi][ch] & aSignificantMask);
+
+ MSInt16 delta = ParallelMath::TruncateToPrecisionSigned(ParallelMath::LosslessCast<MSInt16>::Cast(ParallelMath::AbstractSubtract(outEncodedEPs[subset][epi][ch], outEncodedEPs[0][0][ch])), bPrec[ch]);
+
+ outEncodedEPs[subset][epi][ch] = ParallelMath::LosslessCast<MAInt16>::Cast(delta);
+
+ MAInt16 reconstructed = (ParallelMath::AbstractAdd(outEncodedEPs[subset][epi][ch], outEncodedEPs[0][0][ch]) & aSignificantMask);
+ allLegal = allLegal & ParallelMath::Equal(reconstructed, bReduced);
+ }
+ }
+ }
+
+ if (!ParallelMath::AnySet(allLegal))
+ break;
+ }
+
+ outIsLegal = allLegal;
+ }
+
+ static void EvaluateSingleLegality(const MAInt16 ep[2][3], int aPrec, const int bPrec[3], bool isTransformed, MAInt16 outEncodedEPs[2][3], ParallelMath::Int16CompFlag& outIsLegal)
+ {
+ ParallelMath::Int16CompFlag allLegal = ParallelMath::MakeBoolInt16(true);
+
+ MAInt16 aSignificantMask = ParallelMath::MakeAInt16(static_cast<int16_t>((1 << aPrec) - 1));
+
+ for (int ch = 0; ch < 3; ch++)
+ {
+ outEncodedEPs[0][ch] = ep[0][ch];
+ outEncodedEPs[1][ch] = ep[1][ch];
+
+ if (isTransformed)
+ {
+ MAInt16 bReduced = (outEncodedEPs[1][ch] & aSignificantMask);
+
+ MSInt16 delta = ParallelMath::TruncateToPrecisionSigned(ParallelMath::LosslessCast<MSInt16>::Cast(ParallelMath::AbstractSubtract(outEncodedEPs[1][ch], outEncodedEPs[0][ch])), bPrec[ch]);
+
+ outEncodedEPs[1][ch] = ParallelMath::LosslessCast<MAInt16>::Cast(delta);
+
+ MAInt16 reconstructed = (ParallelMath::AbstractAdd(outEncodedEPs[1][ch], outEncodedEPs[0][ch]) & aSignificantMask);
+ allLegal = allLegal & ParallelMath::Equal(reconstructed, bReduced);
+ }
+ }
+
+ outIsLegal = allLegal;
+ }
+
+ static void Pack(uint32_t flags, const PixelBlockF16* inputs, uint8_t* packedBlocks, const float channelWeights[4], bool isSigned, int numTweakRounds, int numRefineRounds)
+ {
+ if (numTweakRounds < 1)
+ numTweakRounds = 1;
+ else if (numTweakRounds > MaxTweakRounds)
+ numTweakRounds = MaxTweakRounds;
+
+ if (numRefineRounds < 1)
+ numRefineRounds = 1;
+ else if (numRefineRounds > MaxRefineRounds)
+ numRefineRounds = MaxRefineRounds;
+
+ bool fastIndexing = ((flags & cvtt::Flags::BC6H_FastIndexing) != 0);
+ float channelWeightsSq[3];
+
+ ParallelMath::RoundTowardNearestForScope rtn;
+
+ MSInt16 pixels[16][3];
+ MFloat floatPixels2CL[16][3];
+ MFloat floatPixelsLinearWeighted[16][3];
+
+ MSInt16 low15Bits = ParallelMath::MakeSInt16(32767);
+
+ for (int ch = 0; ch < 3; ch++)
+ channelWeightsSq[ch] = channelWeights[ch] * channelWeights[ch];
+
+ for (int px = 0; px < 16; px++)
+ {
+ for (int ch = 0; ch < 3; ch++)
+ {
+ MSInt16 pixelValue;
+ ParallelMath::ConvertHDRInputs(inputs, px, ch, pixelValue);
+
+ // Convert from sign+magnitude to 2CL
+ if (isSigned)
+ {
+ ParallelMath::Int16CompFlag negative = ParallelMath::Less(pixelValue, ParallelMath::MakeSInt16(0));
+ MSInt16 magnitude = (pixelValue & low15Bits);
+ ParallelMath::ConditionalSet(pixelValue, negative, ParallelMath::MakeSInt16(0) - magnitude);
+ pixelValue = ParallelMath::Max(pixelValue, ParallelMath::MakeSInt16(-31743));
+ }
+ else
+ pixelValue = ParallelMath::Max(pixelValue, ParallelMath::MakeSInt16(0));
+
+ pixelValue = ParallelMath::Min(pixelValue, ParallelMath::MakeSInt16(31743));
+
+ pixels[px][ch] = pixelValue;
+ floatPixels2CL[px][ch] = ParallelMath::ToFloat(pixelValue);
+ floatPixelsLinearWeighted[px][ch] = ParallelMath::TwosCLHalfToFloat(pixelValue) * channelWeights[ch];
+ }
+ }
+
+ MFloat preWeightedPixels[16][3];
+
+ BCCommon::PreWeightPixelsHDR<3>(preWeightedPixels, pixels, channelWeights);
+
+ MAInt16 bestEndPoints[2][2][3];
+ MUInt15 bestIndexes[16];
+ MFloat bestError = ParallelMath::MakeFloat(FLT_MAX);
+ MUInt15 bestMode = ParallelMath::MakeUInt15(0);
+ MUInt15 bestPartition = ParallelMath::MakeUInt15(0);
+
+ for (int px = 0; px < 16; px++)
+ bestIndexes[px] = ParallelMath::MakeUInt15(0);
+
+ for (int subset = 0; subset < 2; subset++)
+ for (int epi = 0; epi < 2; epi++)
+ for (int ch = 0; ch < 3; ch++)
+ bestEndPoints[subset][epi][ch] = ParallelMath::MakeAInt16(0);
+
+ UnfinishedEndpoints<3> partitionedUFEP[32][2];
+ UnfinishedEndpoints<3> singleUFEP;
+
+ // Generate UFEP for partitions
+ for (int p = 0; p < 32; p++)
+ {
+ int partitionMask = BC7Data::g_partitionMap[p];
+
+ EndpointSelector<3, 8> epSelectors[2];
+
+ for (int pass = 0; pass < NumEndpointSelectorPasses; pass++)
+ {
+ for (int px = 0; px < 16; px++)
+ {
+ int subset = (partitionMask >> px) & 1;
+ epSelectors[subset].ContributePass(preWeightedPixels[px], pass, ParallelMath::MakeFloat(1.0f));
+ }
+
+ for (int subset = 0; subset < 2; subset++)
+ epSelectors[subset].FinishPass(pass);
+ }
+
+ for (int subset = 0; subset < 2; subset++)
+ partitionedUFEP[p][subset] = epSelectors[subset].GetEndpoints(channelWeights);
+ }
+
+ // Generate UFEP for single
+ {
+ EndpointSelector<3, 8> epSelector;
+
+ for (int pass = 0; pass < NumEndpointSelectorPasses; pass++)
+ {
+ for (int px = 0; px < 16; px++)
+ epSelector.ContributePass(preWeightedPixels[px], pass, ParallelMath::MakeFloat(1.0f));
+
+ epSelector.FinishPass(pass);
+ }
+
+ singleUFEP = epSelector.GetEndpoints(channelWeights);
+ }
+
+ for (int partitionedInt = 0; partitionedInt < 2; partitionedInt++)
+ {
+ bool partitioned = (partitionedInt == 1);
+
+ for (int aPrec = BC7Data::g_maxHDRPrecision; aPrec >= 0; aPrec--)
+ {
+ if (!BC7Data::g_hdrModesExistForPrecision[partitionedInt][aPrec])
+ continue;
+
+ int numPartitions = partitioned ? 32 : 1;
+ int numSubsets = partitioned ? 2 : 1;
+ int indexBits = partitioned ? 3 : 4;
+ int indexRange = (1 << indexBits);
+
+ for (int p = 0; p < numPartitions; p++)
+ {
+ int partitionMask = partitioned ? BC7Data::g_partitionMap[p] : 0;
+
+ const int MaxMetaRounds = MaxTweakRounds * MaxRefineRounds;
+
+ MAInt16 metaEndPointsQuantized[MaxMetaRounds][2][2][3];
+ MUInt15 metaIndexes[MaxMetaRounds][16];
+ MFloat metaError[MaxMetaRounds][2];
+
+ bool roundValid[MaxMetaRounds][2];
+
+ for (int r = 0; r < MaxMetaRounds; r++)
+ for (int subset = 0; subset < 2; subset++)
+ roundValid[r][subset] = true;
+
+ for (int subset = 0; subset < numSubsets; subset++)
+ {
+ for (int tweak = 0; tweak < MaxTweakRounds; tweak++)
+ {
+ EndpointRefiner<3> refiners[2];
+
+ bool abortRemainingRefines = false;
+ for (int refinePass = 0; refinePass < MaxRefineRounds; refinePass++)
+ {
+ int metaRound = tweak * MaxRefineRounds + refinePass;
+
+ if (tweak >= numTweakRounds || refinePass >= numRefineRounds)
+ abortRemainingRefines = true;
+
+ if (abortRemainingRefines)
+ {
+ roundValid[metaRound][subset] = false;
+ continue;
+ }
+
+ MAInt16(&mrQuantizedEndPoints)[2][2][3] = metaEndPointsQuantized[metaRound];
+ MUInt15(&mrIndexes)[16] = metaIndexes[metaRound];
+
+ MSInt16 endPointsColorSpace[2][3];
+
+ if (refinePass == 0)
+ {
+ UnfinishedEndpoints<3> ufep = partitioned ? partitionedUFEP[p][subset] : singleUFEP;
+
+ if (isSigned)
+ ufep.FinishHDRSigned(tweak, indexRange, endPointsColorSpace[0], endPointsColorSpace[1], &rtn);
+ else
+ ufep.FinishHDRUnsigned(tweak, indexRange, endPointsColorSpace[0], endPointsColorSpace[1], &rtn);
+ }
+ else
+ refiners[subset].GetRefinedEndpointsHDR(endPointsColorSpace, isSigned, &rtn);
+
+ refiners[subset].Init(indexRange, channelWeights);
+
+ int fixupIndex = (subset == 0) ? 0 : BC7Data::g_fixupIndexes2[p];
+
+ IndexSelectorHDR<3> indexSelector;
+ if (isSigned)
+ QuantizeEndpointsSigned(endPointsColorSpace, floatPixels2CL, floatPixelsLinearWeighted, mrQuantizedEndPoints[subset], mrIndexes, indexSelector, fixupIndex, aPrec, indexRange, channelWeights, fastIndexing, &rtn);
+ else
+ QuantizeEndpointsUnsigned(endPointsColorSpace, floatPixels2CL, floatPixelsLinearWeighted, mrQuantizedEndPoints[subset], mrIndexes, indexSelector, fixupIndex, aPrec, indexRange, channelWeights, fastIndexing, &rtn);
+
+ if (metaRound > 0)
+ {
+ ParallelMath::Int16CompFlag anySame = ParallelMath::MakeBoolInt16(false);
+
+ for (int prevRound = 0; prevRound < metaRound; prevRound++)
+ {
+ MAInt16(&prevRoundEPs)[2][3] = metaEndPointsQuantized[prevRound][subset];
+
+ ParallelMath::Int16CompFlag same = ParallelMath::MakeBoolInt16(true);
+
+ for (int epi = 0; epi < 2; epi++)
+ for (int ch = 0; ch < 3; ch++)
+ same = (same & ParallelMath::Equal(prevRoundEPs[epi][ch], mrQuantizedEndPoints[subset][epi][ch]));
+
+ anySame = (anySame | same);
+ if (ParallelMath::AllSet(anySame))
+ break;
+ }
+
+ if (ParallelMath::AllSet(anySame))
+ {
+ roundValid[metaRound][subset] = false;
+ continue;
+ }
+ }
+
+ MFloat subsetError = ParallelMath::MakeFloatZero();
+
+ {
+ for (int px = 0; px < 16; px++)
+ {
+ if (subset != ((partitionMask >> px) & 1))
+ continue;
+
+ MUInt15 index;
+ if (px == fixupIndex)
+ index = mrIndexes[px];
+ else
+ {
+ index = fastIndexing ? indexSelector.SelectIndexHDRFast(floatPixels2CL[px], &rtn) : indexSelector.SelectIndexHDRSlow(floatPixelsLinearWeighted[px], &rtn);
+ mrIndexes[px] = index;
+ }
+
+ MSInt16 reconstructed[3];
+ if (isSigned)
+ indexSelector.ReconstructHDRSigned(mrIndexes[px], reconstructed);
+ else
+ indexSelector.ReconstructHDRUnsigned(mrIndexes[px], reconstructed);
+
+ subsetError = subsetError + (fastIndexing ? BCCommon::ComputeErrorHDRFast<3>(flags, reconstructed, pixels[px], channelWeightsSq) : BCCommon::ComputeErrorHDRSlow<3>(flags, reconstructed, pixels[px], channelWeightsSq));
+
+ if (refinePass != numRefineRounds - 1)
+ refiners[subset].ContributeUnweightedPW(preWeightedPixels[px], index);
+ }
+ }
+
+ metaError[metaRound][subset] = subsetError;
+ }
+ }
+ }
+
+ // Now we have a bunch of attempts, but not all of them will fit in the delta coding scheme
+ int numMeta1 = partitioned ? MaxMetaRounds : 1;
+ for (int meta0 = 0; meta0 < MaxMetaRounds; meta0++)
+ {
+ if (!roundValid[meta0][0])
+ continue;
+
+ for (int meta1 = 0; meta1 < numMeta1; meta1++)
+ {
+ MFloat combinedError = metaError[meta0][0];
+ if (partitioned)
+ {
+ if (!roundValid[meta1][1])
+ continue;
+
+ combinedError = combinedError + metaError[meta1][1];
+ }
+
+ ParallelMath::FloatCompFlag errorBetter = ParallelMath::Less(combinedError, bestError);
+ if (!ParallelMath::AnySet(errorBetter))
+ continue;
+
+ ParallelMath::Int16CompFlag needsCommit = ParallelMath::FloatFlagToInt16(errorBetter);
+
+ // Figure out if this is encodable
+ for (int mode = 0; mode < BC7Data::g_numHDRModes; mode++)
+ {
+ const BC7Data::BC6HModeInfo &modeInfo = BC7Data::g_hdrModes[mode];
+
+ if (modeInfo.m_partitioned != partitioned || modeInfo.m_aPrec != aPrec)
+ continue;
+
+ MAInt16 encodedEPs[2][2][3];
+ ParallelMath::Int16CompFlag isLegal;
+ if (partitioned)
+ EvaluatePartitionedLegality(metaEndPointsQuantized[meta0][0], metaEndPointsQuantized[meta1][1], modeInfo.m_aPrec, modeInfo.m_bPrec, modeInfo.m_transformed, encodedEPs, isLegal);
+ else
+ EvaluateSingleLegality(metaEndPointsQuantized[meta0][0], modeInfo.m_aPrec, modeInfo.m_bPrec, modeInfo.m_transformed, encodedEPs[0], isLegal);
+
+ ParallelMath::Int16CompFlag isLegalAndBetter = (ParallelMath::FloatFlagToInt16(errorBetter) & isLegal);
+ if (!ParallelMath::AnySet(isLegalAndBetter))
+ continue;
+
+ ParallelMath::FloatCompFlag isLegalAndBetterFloat = ParallelMath::Int16FlagToFloat(isLegalAndBetter);
+
+ ParallelMath::ConditionalSet(bestError, isLegalAndBetterFloat, combinedError);
+ ParallelMath::ConditionalSet(bestMode, isLegalAndBetter, ParallelMath::MakeUInt15(static_cast<uint16_t>(mode)));
+ ParallelMath::ConditionalSet(bestPartition, isLegalAndBetter, ParallelMath::MakeUInt15(static_cast<uint16_t>(p)));
+
+ for (int subset = 0; subset < numSubsets; subset++)
+ {
+ for (int epi = 0; epi < 2; epi++)
+ {
+ for (int ch = 0; ch < 3; ch++)
+ ParallelMath::ConditionalSet(bestEndPoints[subset][epi][ch], isLegalAndBetter, encodedEPs[subset][epi][ch]);
+ }
+ }
+
+ for (int px = 0; px < 16; px++)
+ {
+ int subset = ((partitionMask >> px) & 1);
+ if (subset == 0)
+ ParallelMath::ConditionalSet(bestIndexes[px], isLegalAndBetter, metaIndexes[meta0][px]);
+ else
+ ParallelMath::ConditionalSet(bestIndexes[px], isLegalAndBetter, metaIndexes[meta1][px]);
+ }
+
+ needsCommit = ParallelMath::AndNot(needsCommit, isLegalAndBetter);
+ if (!ParallelMath::AnySet(needsCommit))
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // At this point, everything should be set
+ for (int block = 0; block < ParallelMath::ParallelSize; block++)
+ {
+ ParallelMath::ScalarUInt16 mode = ParallelMath::Extract(bestMode, block);
+ ParallelMath::ScalarUInt16 partition = ParallelMath::Extract(bestPartition, block);
+ int32_t eps[2][2][3];
+ ParallelMath::ScalarUInt16 indexes[16];
+
+ const BC7Data::BC6HModeInfo& modeInfo = BC7Data::g_hdrModes[mode];
+
+ const BC6HData::ModeDescriptor* desc = BC6HData::g_modeDescriptors[mode];
+
+ const size_t headerBits = modeInfo.m_partitioned ? 82 : 65;
+
+ for (int subset = 0; subset < 2; subset++)
+ {
+ for (int epi = 0; epi < 2; epi++)
+ {
+ for (int ch = 0; ch < 3; ch++)
+ eps[subset][epi][ch] = ParallelMath::Extract(bestEndPoints[subset][epi][ch], block);
+ }
+ }
+
+ for (int px = 0; px < 16; px++)
+ indexes[px] = ParallelMath::Extract(bestIndexes[px], block);
+
+ uint16_t modeID = modeInfo.m_modeID;
+
+ PackingVector pv;
+ pv.Init();
+
+ for (size_t i = 0; i < headerBits; i++)
+ {
+ int32_t codedValue = 0;
+ switch (desc[i].m_eField)
+ {
+ case BC6HData::M: codedValue = modeID; break;
+ case BC6HData::D: codedValue = partition; break;
+ case BC6HData::RW: codedValue = eps[0][0][0]; break;
+ case BC6HData::RX: codedValue = eps[0][1][0]; break;
+ case BC6HData::RY: codedValue = eps[1][0][0]; break;
+ case BC6HData::RZ: codedValue = eps[1][1][0]; break;
+ case BC6HData::GW: codedValue = eps[0][0][1]; break;
+ case BC6HData::GX: codedValue = eps[0][1][1]; break;
+ case BC6HData::GY: codedValue = eps[1][0][1]; break;
+ case BC6HData::GZ: codedValue = eps[1][1][1]; break;
+ case BC6HData::BW: codedValue = eps[0][0][2]; break;
+ case BC6HData::BX: codedValue = eps[0][1][2]; break;
+ case BC6HData::BY: codedValue = eps[1][0][2]; break;
+ case BC6HData::BZ: codedValue = eps[1][1][2]; break;
+ default: assert(false); break;
+ }
+
+ pv.Pack(static_cast<uint16_t>((codedValue >> desc[i].m_uBit) & 1), 1);
+ }
+
+ int fixupIndex1 = 0;
+ int indexBits = 4;
+ if (modeInfo.m_partitioned)
+ {
+ fixupIndex1 = BC7Data::g_fixupIndexes2[partition];
+ indexBits = 3;
+ }
+
+ for (int px = 0; px < 16; px++)
+ {
+ ParallelMath::ScalarUInt16 index = ParallelMath::Extract(bestIndexes[px], block);
+ if (px == 0 || px == fixupIndex1)
+ pv.Pack(index, indexBits - 1);
+ else
+ pv.Pack(index, indexBits);
+ }
+
+ pv.Flush(packedBlocks + 16 * block);
+ }
+ }
+
+ static void SignExtendSingle(int &v, int bits)
+ {
+ if (v & (1 << (bits - 1)))
+ v |= -(1 << bits);
+ }
+
+ static void UnpackOne(PixelBlockF16 &output, const uint8_t *pBC, bool isSigned)
+ {
+ UnpackingVector pv;
+ pv.Init(pBC);
+
+ int numModeBits = 2;
+ int modeBits = pv.Unpack(2);
+ if (modeBits != 0 && modeBits != 1)
+ {
+ modeBits |= pv.Unpack(3) << 2;
+ numModeBits += 3;
+ }
+
+ int mode = -1;
+ for (int possibleMode = 0; possibleMode < BC7Data::g_numHDRModes; possibleMode++)
+ {
+ if (BC7Data::g_hdrModes[possibleMode].m_modeID == modeBits)
+ {
+ mode = possibleMode;
+ break;
+ }
+ }
+
+ if (mode < 0)
+ {
+ for (int px = 0; px < 16; px++)
+ {
+ for (int ch = 0; ch < 3; ch++)
+ output.m_pixels[px][ch] = 0;
+ output.m_pixels[px][3] = 0x3c00; // 1.0
+ }
+ return;
+ }
+
+ const BC7Data::BC6HModeInfo& modeInfo = BC7Data::g_hdrModes[mode];
+ const size_t headerBits = modeInfo.m_partitioned ? 82 : 65;
+ const BC6HData::ModeDescriptor* desc = BC6HData::g_modeDescriptors[mode];
+
+ int32_t partition = 0;
+ int32_t eps[2][2][3];
+
+ for (int subset = 0; subset < 2; subset++)
+ for (int epi = 0; epi < 2; epi++)
+ for (int ch = 0; ch < 3; ch++)
+ eps[subset][epi][ch] = 0;
+
+ for (size_t i = numModeBits; i < headerBits; i++)
+ {
+ int32_t *pCodedValue = NULL;
+
+ switch (desc[i].m_eField)
+ {
+ case BC6HData::D: pCodedValue = &partition; break;
+ case BC6HData::RW: pCodedValue = &eps[0][0][0]; break;
+ case BC6HData::RX: pCodedValue = &eps[0][1][0]; break;
+ case BC6HData::RY: pCodedValue = &eps[1][0][0]; break;
+ case BC6HData::RZ: pCodedValue = &eps[1][1][0]; break;
+ case BC6HData::GW: pCodedValue = &eps[0][0][1]; break;
+ case BC6HData::GX: pCodedValue = &eps[0][1][1]; break;
+ case BC6HData::GY: pCodedValue = &eps[1][0][1]; break;
+ case BC6HData::GZ: pCodedValue = &eps[1][1][1]; break;
+ case BC6HData::BW: pCodedValue = &eps[0][0][2]; break;
+ case BC6HData::BX: pCodedValue = &eps[0][1][2]; break;
+ case BC6HData::BY: pCodedValue = &eps[1][0][2]; break;
+ case BC6HData::BZ: pCodedValue = &eps[1][1][2]; break;
+ default: assert(false); break;
+ }
+
+ (*pCodedValue) |= pv.Unpack(1) << desc[i].m_uBit;
+ }
+
+
+ uint16_t modeID = modeInfo.m_modeID;
+
+ int fixupIndex1 = 0;
+ int indexBits = 4;
+ int numSubsets = 1;
+ if (modeInfo.m_partitioned)
+ {
+ fixupIndex1 = BC7Data::g_fixupIndexes2[partition];
+ indexBits = 3;
+ numSubsets = 2;
+ }
+
+ int indexes[16];
+ for (int px = 0; px < 16; px++)
+ {
+ if (px == 0 || px == fixupIndex1)
+ indexes[px] = pv.Unpack(indexBits - 1);
+ else
+ indexes[px] = pv.Unpack(indexBits);
+ }
+
+ if (modeInfo.m_partitioned)
+ {
+ for (int ch = 0; ch < 3; ch++)
+ {
+ if (isSigned)
+ SignExtendSingle(eps[0][0][ch], modeInfo.m_aPrec);
+ if (modeInfo.m_transformed || isSigned)
+ {
+ SignExtendSingle(eps[0][1][ch], modeInfo.m_bPrec[ch]);
+ SignExtendSingle(eps[1][0][ch], modeInfo.m_bPrec[ch]);
+ SignExtendSingle(eps[1][1][ch], modeInfo.m_bPrec[ch]);
+ }
+ }
+ }
+ else
+ {
+ for (int ch = 0; ch < 3; ch++)
+ {
+ if (isSigned)
+ SignExtendSingle(eps[0][0][ch], modeInfo.m_aPrec);
+ if (modeInfo.m_transformed || isSigned)
+ SignExtendSingle(eps[0][1][ch], modeInfo.m_bPrec[ch]);
+ }
+ }
+
+ int aPrec = modeInfo.m_aPrec;
+
+ if (modeInfo.m_transformed)
+ {
+ for (int ch = 0; ch < 3; ch++)
+ {
+ int wrapMask = (1 << aPrec) - 1;
+
+ eps[0][1][ch] = ((eps[0][0][ch] + eps[0][1][ch]) & wrapMask);
+ if (isSigned)
+ SignExtendSingle(eps[0][1][ch], aPrec);
+
+ if (modeInfo.m_partitioned)
+ {
+ eps[1][0][ch] = ((eps[0][0][ch] + eps[1][0][ch]) & wrapMask);
+ eps[1][1][ch] = ((eps[0][0][ch] + eps[1][1][ch]) & wrapMask);
+
+ if (isSigned)
+ {
+ SignExtendSingle(eps[1][0][ch], aPrec);
+ SignExtendSingle(eps[1][1][ch], aPrec);
+ }
+ }
+ }
+ }
+
+ // Unquantize endpoints
+ for (int subset = 0; subset < numSubsets; subset++)
+ {
+ for (int epi = 0; epi < 2; epi++)
+ {
+ for (int ch = 0; ch < 3; ch++)
+ {
+ int &v = eps[subset][epi][ch];
+
+ if (isSigned)
+ {
+ if (aPrec >= 16)
+ {
+ // Nothing
+ }
+ else
+ {
+ bool s = false;
+ int comp = v;
+ if (v < 0)
+ {
+ s = true;
+ comp = -comp;
+ }
+
+ int unq = 0;
+ if (comp == 0)
+ unq = 0;
+ else if (comp >= ((1 << (aPrec - 1)) - 1))
+ unq = 0x7fff;
+ else
+ unq = ((comp << 15) + 0x4000) >> (aPrec - 1);
+
+ if (s)
+ unq = -unq;
+
+ v = unq;
+ }
+ }
+ else
+ {
+ if (aPrec >= 15)
+ {
+ // Nothing
+ }
+ else if (v == 0)
+ {
+ // Nothing
+ }
+ else if (v == ((1 << aPrec) - 1))
+ v = 0xffff;
+ else
+ v = ((v << 16) + 0x8000) >> aPrec;
+ }
+ }
+ }
+ }
+
+ const int *weights = BC7Data::g_weightTables[indexBits];
+
+ for (int px = 0; px < 16; px++)
+ {
+ int subset = 0;
+ if (modeInfo.m_partitioned)
+ subset = (BC7Data::g_partitionMap[partition] >> px) & 1;
+
+ int w = weights[indexes[px]];
+ for (int ch = 0; ch < 3; ch++)
+ {
+ int comp = ((64 - w) * eps[subset][0][ch] + w * eps[subset][1][ch] + 32) >> 6;
+
+ if (isSigned)
+ {
+ if (comp < 0)
+ comp = -(((-comp) * 31) >> 5);
+ else
+ comp = (comp * 31) >> 5;
+
+ int s = 0;
+ if (comp < 0)
+ {
+ s = 0x8000;
+ comp = -comp;
+ }
+
+ output.m_pixels[px][ch] = static_cast<uint16_t>(s | comp);
+ }
+ else
+ {
+ comp = (comp * 31) >> 6;
+ output.m_pixels[px][ch] = static_cast<uint16_t>(comp);
+ }
+ }
+ output.m_pixels[px][3] = 0x3c00; // 1.0
+ }
+ }
+ };
+
+ namespace S3TCSingleColorTables
+ {
+ struct SingleColorTableEntry
+ {
+ uint8_t m_min;
+ uint8_t m_max;
+ uint8_t m_actualColor;
+ uint8_t m_span;
+ };
+
+ SingleColorTableEntry g_singleColor5_3[256] =
+ {
+ { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 8, 0, 2, 8 }, { 8, 0, 2, 8 }, { 0, 8, 5, 8 }, { 0, 8, 5, 8 }, { 0, 8, 5, 8 }, { 8, 8, 8, 0 },
+ { 8, 8, 8, 0 }, { 8, 8, 8, 0 }, { 16, 8, 10, 8 }, { 33, 0, 11, 33 }, { 8, 16, 13, 8 }, { 8, 16, 13, 8 }, { 8, 16, 13, 8 }, { 16, 16, 16, 0 },
+ { 16, 16, 16, 0 }, { 16, 16, 16, 0 }, { 24, 16, 18, 8 }, { 41, 8, 19, 33 }, { 16, 24, 21, 8 }, { 16, 24, 21, 8 }, { 0, 33, 22, 33 }, { 24, 24, 24, 0 },
+ { 24, 24, 24, 0 }, { 24, 24, 24, 0 }, { 33, 24, 27, 9 }, { 33, 24, 27, 9 }, { 33, 24, 27, 9 }, { 41, 24, 29, 17 }, { 24, 33, 30, 9 }, { 24, 33, 30, 9 },
+ { 16, 41, 32, 25 }, { 33, 33, 33, 0 }, { 33, 33, 33, 0 }, { 41, 33, 35, 8 }, { 41, 33, 35, 8 }, { 33, 41, 38, 8 }, { 33, 41, 38, 8 }, { 33, 41, 38, 8 },
+ { 24, 49, 40, 25 }, { 41, 41, 41, 0 }, { 41, 41, 41, 0 }, { 49, 41, 43, 8 }, { 66, 33, 44, 33 }, { 41, 49, 46, 8 }, { 41, 49, 46, 8 }, { 41, 49, 46, 8 },
+ { 49, 49, 49, 0 }, { 49, 49, 49, 0 }, { 49, 49, 49, 0 }, { 57, 49, 51, 8 }, { 74, 41, 52, 33 }, { 49, 57, 54, 8 }, { 49, 57, 54, 8 }, { 33, 66, 55, 33 },
+ { 57, 57, 57, 0 }, { 57, 57, 57, 0 }, { 57, 57, 57, 0 }, { 66, 57, 60, 9 }, { 66, 57, 60, 9 }, { 66, 57, 60, 9 }, { 74, 57, 62, 17 }, { 57, 66, 63, 9 },
+ { 57, 66, 63, 9 }, { 49, 74, 65, 25 }, { 66, 66, 66, 0 }, { 66, 66, 66, 0 }, { 74, 66, 68, 8 }, { 74, 66, 68, 8 }, { 66, 74, 71, 8 }, { 66, 74, 71, 8 },
+ { 66, 74, 71, 8 }, { 57, 82, 73, 25 }, { 74, 74, 74, 0 }, { 74, 74, 74, 0 }, { 82, 74, 76, 8 }, { 99, 66, 77, 33 }, { 74, 82, 79, 8 }, { 74, 82, 79, 8 },
+ { 74, 82, 79, 8 }, { 82, 82, 82, 0 }, { 82, 82, 82, 0 }, { 82, 82, 82, 0 }, { 90, 82, 84, 8 }, { 107, 74, 85, 33 }, { 82, 90, 87, 8 }, { 82, 90, 87, 8 },
+ { 66, 99, 88, 33 }, { 90, 90, 90, 0 }, { 90, 90, 90, 0 }, { 90, 90, 90, 0 }, { 99, 90, 93, 9 }, { 99, 90, 93, 9 }, { 99, 90, 93, 9 }, { 107, 90, 95, 17 },
+ { 90, 99, 96, 9 }, { 90, 99, 96, 9 }, { 82, 107, 98, 25 }, { 99, 99, 99, 0 }, { 99, 99, 99, 0 }, { 107, 99, 101, 8 }, { 107, 99, 101, 8 }, { 99, 107, 104, 8 },
+ { 99, 107, 104, 8 }, { 99, 107, 104, 8 }, { 90, 115, 106, 25 }, { 107, 107, 107, 0 }, { 107, 107, 107, 0 }, { 115, 107, 109, 8 }, { 132, 99, 110, 33 }, { 107, 115, 112, 8 },
+ { 107, 115, 112, 8 }, { 107, 115, 112, 8 }, { 115, 115, 115, 0 }, { 115, 115, 115, 0 }, { 115, 115, 115, 0 }, { 123, 115, 117, 8 }, { 140, 107, 118, 33 }, { 115, 123, 120, 8 },
+ { 115, 123, 120, 8 }, { 99, 132, 121, 33 }, { 123, 123, 123, 0 }, { 123, 123, 123, 0 }, { 123, 123, 123, 0 }, { 132, 123, 126, 9 }, { 132, 123, 126, 9 }, { 132, 123, 126, 9 },
+ { 140, 123, 128, 17 }, { 123, 132, 129, 9 }, { 123, 132, 129, 9 }, { 115, 140, 131, 25 }, { 132, 132, 132, 0 }, { 132, 132, 132, 0 }, { 140, 132, 134, 8 }, { 140, 132, 134, 8 },
+ { 132, 140, 137, 8 }, { 132, 140, 137, 8 }, { 132, 140, 137, 8 }, { 123, 148, 139, 25 }, { 140, 140, 140, 0 }, { 140, 140, 140, 0 }, { 148, 140, 142, 8 }, { 165, 132, 143, 33 },
+ { 140, 148, 145, 8 }, { 140, 148, 145, 8 }, { 140, 148, 145, 8 }, { 148, 148, 148, 0 }, { 148, 148, 148, 0 }, { 148, 148, 148, 0 }, { 156, 148, 150, 8 }, { 173, 140, 151, 33 },
+ { 148, 156, 153, 8 }, { 148, 156, 153, 8 }, { 132, 165, 154, 33 }, { 156, 156, 156, 0 }, { 156, 156, 156, 0 }, { 156, 156, 156, 0 }, { 165, 156, 159, 9 }, { 165, 156, 159, 9 },
+ { 165, 156, 159, 9 }, { 173, 156, 161, 17 }, { 156, 165, 162, 9 }, { 156, 165, 162, 9 }, { 148, 173, 164, 25 }, { 165, 165, 165, 0 }, { 165, 165, 165, 0 }, { 173, 165, 167, 8 },
+ { 173, 165, 167, 8 }, { 165, 173, 170, 8 }, { 165, 173, 170, 8 }, { 165, 173, 170, 8 }, { 156, 181, 172, 25 }, { 173, 173, 173, 0 }, { 173, 173, 173, 0 }, { 181, 173, 175, 8 },
+ { 198, 165, 176, 33 }, { 173, 181, 178, 8 }, { 173, 181, 178, 8 }, { 173, 181, 178, 8 }, { 181, 181, 181, 0 }, { 181, 181, 181, 0 }, { 181, 181, 181, 0 }, { 189, 181, 183, 8 },
+ { 206, 173, 184, 33 }, { 181, 189, 186, 8 }, { 181, 189, 186, 8 }, { 165, 198, 187, 33 }, { 189, 189, 189, 0 }, { 189, 189, 189, 0 }, { 189, 189, 189, 0 }, { 198, 189, 192, 9 },
+ { 198, 189, 192, 9 }, { 198, 189, 192, 9 }, { 206, 189, 194, 17 }, { 189, 198, 195, 9 }, { 189, 198, 195, 9 }, { 181, 206, 197, 25 }, { 198, 198, 198, 0 }, { 198, 198, 198, 0 },
+ { 206, 198, 200, 8 }, { 206, 198, 200, 8 }, { 198, 206, 203, 8 }, { 198, 206, 203, 8 }, { 198, 206, 203, 8 }, { 189, 214, 205, 25 }, { 206, 206, 206, 0 }, { 206, 206, 206, 0 },
+ { 214, 206, 208, 8 }, { 231, 198, 209, 33 }, { 206, 214, 211, 8 }, { 206, 214, 211, 8 }, { 206, 214, 211, 8 }, { 214, 214, 214, 0 }, { 214, 214, 214, 0 }, { 214, 214, 214, 0 },
+ { 222, 214, 216, 8 }, { 239, 206, 217, 33 }, { 214, 222, 219, 8 }, { 214, 222, 219, 8 }, { 198, 231, 220, 33 }, { 222, 222, 222, 0 }, { 222, 222, 222, 0 }, { 222, 222, 222, 0 },
+ { 231, 222, 225, 9 }, { 231, 222, 225, 9 }, { 231, 222, 225, 9 }, { 239, 222, 227, 17 }, { 222, 231, 228, 9 }, { 222, 231, 228, 9 }, { 214, 239, 230, 25 }, { 231, 231, 231, 0 },
+ { 231, 231, 231, 0 }, { 239, 231, 233, 8 }, { 239, 231, 233, 8 }, { 231, 239, 236, 8 }, { 231, 239, 236, 8 }, { 231, 239, 236, 8 }, { 222, 247, 238, 25 }, { 239, 239, 239, 0 },
+ { 239, 239, 239, 0 }, { 247, 239, 241, 8 }, { 247, 239, 241, 8 }, { 239, 247, 244, 8 }, { 239, 247, 244, 8 }, { 239, 247, 244, 8 }, { 247, 247, 247, 0 }, { 247, 247, 247, 0 },
+ { 247, 247, 247, 0 }, { 255, 247, 249, 8 }, { 255, 247, 249, 8 }, { 247, 255, 252, 8 }, { 247, 255, 252, 8 }, { 247, 255, 252, 8 }, { 255, 255, 255, 0 }, { 255, 255, 255, 0 },
+ };
+
+ SingleColorTableEntry g_singleColor6_3[256] =
+ {
+ { 0, 0, 0, 0 }, { 4, 0, 1, 4 }, { 0, 4, 2, 4 }, { 4, 4, 4, 0 }, { 4, 4, 4, 0 }, { 8, 4, 5, 4 }, { 4, 8, 6, 4 }, { 8, 8, 8, 0 },
+ { 8, 8, 8, 0 }, { 12, 8, 9, 4 }, { 8, 12, 10, 4 }, { 12, 12, 12, 0 }, { 12, 12, 12, 0 }, { 16, 12, 13, 4 }, { 12, 16, 14, 4 }, { 16, 16, 16, 0 },
+ { 16, 16, 16, 0 }, { 20, 16, 17, 4 }, { 16, 20, 18, 4 }, { 20, 20, 20, 0 }, { 20, 20, 20, 0 }, { 24, 20, 21, 4 }, { 20, 24, 22, 4 }, { 69, 0, 23, 69 },
+ { 24, 24, 24, 0 }, { 28, 24, 25, 4 }, { 24, 28, 26, 4 }, { 65, 8, 27, 57 }, { 28, 28, 28, 0 }, { 32, 28, 29, 4 }, { 28, 32, 30, 4 }, { 69, 12, 31, 57 },
+ { 32, 32, 32, 0 }, { 36, 32, 33, 4 }, { 32, 36, 34, 4 }, { 65, 20, 35, 45 }, { 36, 36, 36, 0 }, { 40, 36, 37, 4 }, { 36, 40, 38, 4 }, { 69, 24, 39, 45 },
+ { 40, 40, 40, 0 }, { 44, 40, 41, 4 }, { 40, 44, 42, 4 }, { 65, 32, 43, 33 }, { 44, 44, 44, 0 }, { 48, 44, 45, 4 }, { 44, 48, 46, 4 }, { 69, 36, 47, 33 },
+ { 48, 48, 48, 0 }, { 52, 48, 49, 4 }, { 48, 52, 50, 4 }, { 65, 44, 51, 21 }, { 52, 52, 52, 0 }, { 56, 52, 53, 4 }, { 52, 56, 54, 4 }, { 69, 48, 55, 21 },
+ { 56, 56, 56, 0 }, { 60, 56, 57, 4 }, { 56, 60, 58, 4 }, { 65, 56, 59, 9 }, { 60, 60, 60, 0 }, { 65, 60, 61, 5 }, { 56, 65, 62, 9 }, { 60, 65, 63, 5 },
+ { 56, 69, 64, 13 }, { 65, 65, 65, 0 }, { 69, 65, 66, 4 }, { 65, 69, 67, 4 }, { 60, 73, 68, 13 }, { 69, 69, 69, 0 }, { 73, 69, 70, 4 }, { 69, 73, 71, 4 },
+ { 56, 81, 72, 25 }, { 73, 73, 73, 0 }, { 77, 73, 74, 4 }, { 73, 77, 75, 4 }, { 60, 85, 76, 25 }, { 77, 77, 77, 0 }, { 81, 77, 78, 4 }, { 77, 81, 79, 4 },
+ { 56, 93, 80, 37 }, { 81, 81, 81, 0 }, { 85, 81, 82, 4 }, { 81, 85, 83, 4 }, { 60, 97, 84, 37 }, { 85, 85, 85, 0 }, { 89, 85, 86, 4 }, { 85, 89, 87, 4 },
+ { 56, 105, 88, 49 }, { 89, 89, 89, 0 }, { 93, 89, 90, 4 }, { 89, 93, 91, 4 }, { 60, 109, 92, 49 }, { 93, 93, 93, 0 }, { 97, 93, 94, 4 }, { 93, 97, 95, 4 },
+ { 134, 77, 96, 57 }, { 97, 97, 97, 0 }, { 101, 97, 98, 4 }, { 97, 101, 99, 4 }, { 130, 85, 100, 45 }, { 101, 101, 101, 0 }, { 105, 101, 102, 4 }, { 101, 105, 103, 4 },
+ { 134, 89, 104, 45 }, { 105, 105, 105, 0 }, { 109, 105, 106, 4 }, { 105, 109, 107, 4 }, { 130, 97, 108, 33 }, { 109, 109, 109, 0 }, { 113, 109, 110, 4 }, { 109, 113, 111, 4 },
+ { 134, 101, 112, 33 }, { 113, 113, 113, 0 }, { 117, 113, 114, 4 }, { 113, 117, 115, 4 }, { 130, 109, 116, 21 }, { 117, 117, 117, 0 }, { 121, 117, 118, 4 }, { 117, 121, 119, 4 },
+ { 134, 113, 120, 21 }, { 121, 121, 121, 0 }, { 125, 121, 122, 4 }, { 121, 125, 123, 4 }, { 130, 121, 124, 9 }, { 125, 125, 125, 0 }, { 130, 125, 126, 5 }, { 121, 130, 127, 9 },
+ { 125, 130, 128, 5 }, { 121, 134, 129, 13 }, { 130, 130, 130, 0 }, { 134, 130, 131, 4 }, { 130, 134, 132, 4 }, { 125, 138, 133, 13 }, { 134, 134, 134, 0 }, { 138, 134, 135, 4 },
+ { 134, 138, 136, 4 }, { 121, 146, 137, 25 }, { 138, 138, 138, 0 }, { 142, 138, 139, 4 }, { 138, 142, 140, 4 }, { 125, 150, 141, 25 }, { 142, 142, 142, 0 }, { 146, 142, 143, 4 },
+ { 142, 146, 144, 4 }, { 121, 158, 145, 37 }, { 146, 146, 146, 0 }, { 150, 146, 147, 4 }, { 146, 150, 148, 4 }, { 125, 162, 149, 37 }, { 150, 150, 150, 0 }, { 154, 150, 151, 4 },
+ { 150, 154, 152, 4 }, { 121, 170, 153, 49 }, { 154, 154, 154, 0 }, { 158, 154, 155, 4 }, { 154, 158, 156, 4 }, { 125, 174, 157, 49 }, { 158, 158, 158, 0 }, { 162, 158, 159, 4 },
+ { 158, 162, 160, 4 }, { 199, 142, 161, 57 }, { 162, 162, 162, 0 }, { 166, 162, 163, 4 }, { 162, 166, 164, 4 }, { 195, 150, 165, 45 }, { 166, 166, 166, 0 }, { 170, 166, 167, 4 },
+ { 166, 170, 168, 4 }, { 199, 154, 169, 45 }, { 170, 170, 170, 0 }, { 174, 170, 171, 4 }, { 170, 174, 172, 4 }, { 195, 162, 173, 33 }, { 174, 174, 174, 0 }, { 178, 174, 175, 4 },
+ { 174, 178, 176, 4 }, { 199, 166, 177, 33 }, { 178, 178, 178, 0 }, { 182, 178, 179, 4 }, { 178, 182, 180, 4 }, { 195, 174, 181, 21 }, { 182, 182, 182, 0 }, { 186, 182, 183, 4 },
+ { 182, 186, 184, 4 }, { 199, 178, 185, 21 }, { 186, 186, 186, 0 }, { 190, 186, 187, 4 }, { 186, 190, 188, 4 }, { 195, 186, 189, 9 }, { 190, 190, 190, 0 }, { 195, 190, 191, 5 },
+ { 186, 195, 192, 9 }, { 190, 195, 193, 5 }, { 186, 199, 194, 13 }, { 195, 195, 195, 0 }, { 199, 195, 196, 4 }, { 195, 199, 197, 4 }, { 190, 203, 198, 13 }, { 199, 199, 199, 0 },
+ { 203, 199, 200, 4 }, { 199, 203, 201, 4 }, { 186, 211, 202, 25 }, { 203, 203, 203, 0 }, { 207, 203, 204, 4 }, { 203, 207, 205, 4 }, { 190, 215, 206, 25 }, { 207, 207, 207, 0 },
+ { 211, 207, 208, 4 }, { 207, 211, 209, 4 }, { 186, 223, 210, 37 }, { 211, 211, 211, 0 }, { 215, 211, 212, 4 }, { 211, 215, 213, 4 }, { 190, 227, 214, 37 }, { 215, 215, 215, 0 },
+ { 219, 215, 216, 4 }, { 215, 219, 217, 4 }, { 186, 235, 218, 49 }, { 219, 219, 219, 0 }, { 223, 219, 220, 4 }, { 219, 223, 221, 4 }, { 190, 239, 222, 49 }, { 223, 223, 223, 0 },
+ { 227, 223, 224, 4 }, { 223, 227, 225, 4 }, { 186, 247, 226, 61 }, { 227, 227, 227, 0 }, { 231, 227, 228, 4 }, { 227, 231, 229, 4 }, { 190, 251, 230, 61 }, { 231, 231, 231, 0 },
+ { 235, 231, 232, 4 }, { 231, 235, 233, 4 }, { 235, 235, 235, 0 }, { 235, 235, 235, 0 }, { 239, 235, 236, 4 }, { 235, 239, 237, 4 }, { 239, 239, 239, 0 }, { 239, 239, 239, 0 },
+ { 243, 239, 240, 4 }, { 239, 243, 241, 4 }, { 243, 243, 243, 0 }, { 243, 243, 243, 0 }, { 247, 243, 244, 4 }, { 243, 247, 245, 4 }, { 247, 247, 247, 0 }, { 247, 247, 247, 0 },
+ { 251, 247, 248, 4 }, { 247, 251, 249, 4 }, { 251, 251, 251, 0 }, { 251, 251, 251, 0 }, { 255, 251, 252, 4 }, { 251, 255, 253, 4 }, { 255, 255, 255, 0 }, { 255, 255, 255, 0 },
+ };
+
+ SingleColorTableEntry g_singleColor5_2[256] =
+ {
+ { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 8, 4, 8 }, { 0, 8, 4, 8 }, { 0, 8, 4, 8 }, { 8, 8, 8, 0 }, { 8, 8, 8, 0 },
+ { 8, 8, 8, 0 }, { 8, 8, 8, 0 }, { 8, 8, 8, 0 }, { 8, 16, 12, 8 }, { 8, 16, 12, 8 }, { 8, 16, 12, 8 }, { 16, 16, 16, 0 }, { 16, 16, 16, 0 },
+ { 16, 16, 16, 0 }, { 16, 16, 16, 0 }, { 16, 16, 16, 0 }, { 16, 24, 20, 8 }, { 16, 24, 20, 8 }, { 16, 24, 20, 8 }, { 24, 24, 24, 0 }, { 24, 24, 24, 0 },
+ { 24, 24, 24, 0 }, { 24, 24, 24, 0 }, { 24, 24, 24, 0 }, { 24, 33, 28, 9 }, { 24, 33, 28, 9 }, { 24, 33, 28, 9 }, { 24, 33, 28, 9 }, { 24, 41, 32, 17 },
+ { 24, 41, 32, 17 }, { 33, 33, 33, 0 }, { 33, 33, 33, 0 }, { 24, 49, 36, 25 }, { 24, 49, 36, 25 }, { 33, 41, 37, 8 }, { 33, 41, 37, 8 }, { 24, 57, 40, 33 },
+ { 24, 57, 40, 33 }, { 41, 41, 41, 0 }, { 41, 41, 41, 0 }, { 41, 41, 41, 0 }, { 41, 49, 45, 8 }, { 41, 49, 45, 8 }, { 41, 49, 45, 8 }, { 49, 49, 49, 0 },
+ { 49, 49, 49, 0 }, { 49, 49, 49, 0 }, { 49, 49, 49, 0 }, { 49, 49, 49, 0 }, { 49, 57, 53, 8 }, { 49, 57, 53, 8 }, { 49, 57, 53, 8 }, { 57, 57, 57, 0 },
+ { 57, 57, 57, 0 }, { 57, 57, 57, 0 }, { 57, 57, 57, 0 }, { 57, 57, 57, 0 }, { 57, 66, 61, 9 }, { 57, 66, 61, 9 }, { 57, 66, 61, 9 }, { 57, 66, 61, 9 },
+ { 57, 74, 65, 17 }, { 57, 74, 65, 17 }, { 66, 66, 66, 0 }, { 66, 66, 66, 0 }, { 57, 82, 69, 25 }, { 57, 82, 69, 25 }, { 66, 74, 70, 8 }, { 66, 74, 70, 8 },
+ { 57, 90, 73, 33 }, { 57, 90, 73, 33 }, { 74, 74, 74, 0 }, { 74, 74, 74, 0 }, { 74, 74, 74, 0 }, { 74, 82, 78, 8 }, { 74, 82, 78, 8 }, { 74, 82, 78, 8 },
+ { 82, 82, 82, 0 }, { 82, 82, 82, 0 }, { 82, 82, 82, 0 }, { 82, 82, 82, 0 }, { 82, 82, 82, 0 }, { 82, 90, 86, 8 }, { 82, 90, 86, 8 }, { 82, 90, 86, 8 },
+ { 90, 90, 90, 0 }, { 90, 90, 90, 0 }, { 90, 90, 90, 0 }, { 90, 90, 90, 0 }, { 90, 90, 90, 0 }, { 90, 99, 94, 9 }, { 90, 99, 94, 9 }, { 90, 99, 94, 9 },
+ { 90, 99, 94, 9 }, { 90, 107, 98, 17 }, { 90, 107, 98, 17 }, { 99, 99, 99, 0 }, { 99, 99, 99, 0 }, { 90, 115, 102, 25 }, { 90, 115, 102, 25 }, { 99, 107, 103, 8 },
+ { 99, 107, 103, 8 }, { 90, 123, 106, 33 }, { 90, 123, 106, 33 }, { 107, 107, 107, 0 }, { 107, 107, 107, 0 }, { 107, 107, 107, 0 }, { 107, 115, 111, 8 }, { 107, 115, 111, 8 },
+ { 107, 115, 111, 8 }, { 115, 115, 115, 0 }, { 115, 115, 115, 0 }, { 115, 115, 115, 0 }, { 115, 115, 115, 0 }, { 115, 115, 115, 0 }, { 115, 123, 119, 8 }, { 115, 123, 119, 8 },
+ { 115, 123, 119, 8 }, { 123, 123, 123, 0 }, { 123, 123, 123, 0 }, { 123, 123, 123, 0 }, { 123, 123, 123, 0 }, { 123, 123, 123, 0 }, { 123, 132, 127, 9 }, { 123, 132, 127, 9 },
+ { 123, 132, 127, 9 }, { 123, 132, 127, 9 }, { 123, 140, 131, 17 }, { 123, 140, 131, 17 }, { 132, 132, 132, 0 }, { 132, 132, 132, 0 }, { 123, 148, 135, 25 }, { 123, 148, 135, 25 },
+ { 132, 140, 136, 8 }, { 132, 140, 136, 8 }, { 123, 156, 139, 33 }, { 123, 156, 139, 33 }, { 140, 140, 140, 0 }, { 140, 140, 140, 0 }, { 140, 140, 140, 0 }, { 140, 148, 144, 8 },
+ { 140, 148, 144, 8 }, { 140, 148, 144, 8 }, { 148, 148, 148, 0 }, { 148, 148, 148, 0 }, { 148, 148, 148, 0 }, { 148, 148, 148, 0 }, { 148, 148, 148, 0 }, { 148, 156, 152, 8 },
+ { 148, 156, 152, 8 }, { 148, 156, 152, 8 }, { 156, 156, 156, 0 }, { 156, 156, 156, 0 }, { 156, 156, 156, 0 }, { 156, 156, 156, 0 }, { 156, 156, 156, 0 }, { 156, 165, 160, 9 },
+ { 156, 165, 160, 9 }, { 156, 165, 160, 9 }, { 156, 165, 160, 9 }, { 156, 173, 164, 17 }, { 156, 173, 164, 17 }, { 165, 165, 165, 0 }, { 165, 165, 165, 0 }, { 156, 181, 168, 25 },
+ { 156, 181, 168, 25 }, { 165, 173, 169, 8 }, { 165, 173, 169, 8 }, { 156, 189, 172, 33 }, { 156, 189, 172, 33 }, { 173, 173, 173, 0 }, { 173, 173, 173, 0 }, { 173, 173, 173, 0 },
+ { 173, 181, 177, 8 }, { 173, 181, 177, 8 }, { 173, 181, 177, 8 }, { 181, 181, 181, 0 }, { 181, 181, 181, 0 }, { 181, 181, 181, 0 }, { 181, 181, 181, 0 }, { 181, 181, 181, 0 },
+ { 181, 189, 185, 8 }, { 181, 189, 185, 8 }, { 181, 189, 185, 8 }, { 189, 189, 189, 0 }, { 189, 189, 189, 0 }, { 189, 189, 189, 0 }, { 189, 189, 189, 0 }, { 189, 189, 189, 0 },
+ { 189, 198, 193, 9 }, { 189, 198, 193, 9 }, { 189, 198, 193, 9 }, { 189, 198, 193, 9 }, { 189, 206, 197, 17 }, { 189, 206, 197, 17 }, { 198, 198, 198, 0 }, { 198, 198, 198, 0 },
+ { 189, 214, 201, 25 }, { 189, 214, 201, 25 }, { 198, 206, 202, 8 }, { 198, 206, 202, 8 }, { 189, 222, 205, 33 }, { 189, 222, 205, 33 }, { 206, 206, 206, 0 }, { 206, 206, 206, 0 },
+ { 206, 206, 206, 0 }, { 206, 214, 210, 8 }, { 206, 214, 210, 8 }, { 206, 214, 210, 8 }, { 214, 214, 214, 0 }, { 214, 214, 214, 0 }, { 214, 214, 214, 0 }, { 214, 214, 214, 0 },
+ { 214, 214, 214, 0 }, { 214, 222, 218, 8 }, { 214, 222, 218, 8 }, { 214, 222, 218, 8 }, { 222, 222, 222, 0 }, { 222, 222, 222, 0 }, { 222, 222, 222, 0 }, { 222, 222, 222, 0 },
+ { 222, 222, 222, 0 }, { 222, 231, 226, 9 }, { 222, 231, 226, 9 }, { 222, 231, 226, 9 }, { 222, 231, 226, 9 }, { 222, 239, 230, 17 }, { 222, 239, 230, 17 }, { 231, 231, 231, 0 },
+ { 231, 231, 231, 0 }, { 222, 247, 234, 25 }, { 222, 247, 234, 25 }, { 231, 239, 235, 8 }, { 231, 239, 235, 8 }, { 222, 255, 238, 33 }, { 222, 255, 238, 33 }, { 239, 239, 239, 0 },
+ { 239, 239, 239, 0 }, { 239, 239, 239, 0 }, { 239, 247, 243, 8 }, { 239, 247, 243, 8 }, { 239, 247, 243, 8 }, { 247, 247, 247, 0 }, { 247, 247, 247, 0 }, { 247, 247, 247, 0 },
+ { 247, 247, 247, 0 }, { 247, 247, 247, 0 }, { 247, 255, 251, 8 }, { 247, 255, 251, 8 }, { 247, 255, 251, 8 }, { 255, 255, 255, 0 }, { 255, 255, 255, 0 }, { 255, 255, 255, 0 },
+ };
+
+ SingleColorTableEntry g_singleColor6_2[256] =
+ {
+ { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 4, 2, 4 }, { 4, 4, 4, 0 }, { 4, 4, 4, 0 }, { 4, 4, 4, 0 }, { 4, 8, 6, 4 }, { 8, 8, 8, 0 },
+ { 8, 8, 8, 0 }, { 8, 8, 8, 0 }, { 8, 12, 10, 4 }, { 12, 12, 12, 0 }, { 12, 12, 12, 0 }, { 12, 12, 12, 0 }, { 12, 16, 14, 4 }, { 16, 16, 16, 0 },
+ { 16, 16, 16, 0 }, { 16, 16, 16, 0 }, { 16, 20, 18, 4 }, { 20, 20, 20, 0 }, { 20, 20, 20, 0 }, { 20, 20, 20, 0 }, { 20, 24, 22, 4 }, { 24, 24, 24, 0 },
+ { 24, 24, 24, 0 }, { 24, 24, 24, 0 }, { 24, 28, 26, 4 }, { 28, 28, 28, 0 }, { 28, 28, 28, 0 }, { 28, 28, 28, 0 }, { 28, 32, 30, 4 }, { 32, 32, 32, 0 },
+ { 32, 32, 32, 0 }, { 32, 32, 32, 0 }, { 32, 36, 34, 4 }, { 36, 36, 36, 0 }, { 36, 36, 36, 0 }, { 36, 36, 36, 0 }, { 36, 40, 38, 4 }, { 40, 40, 40, 0 },
+ { 40, 40, 40, 0 }, { 40, 40, 40, 0 }, { 40, 44, 42, 4 }, { 44, 44, 44, 0 }, { 44, 44, 44, 0 }, { 44, 44, 44, 0 }, { 44, 48, 46, 4 }, { 48, 48, 48, 0 },
+ { 48, 48, 48, 0 }, { 48, 48, 48, 0 }, { 48, 52, 50, 4 }, { 52, 52, 52, 0 }, { 52, 52, 52, 0 }, { 52, 52, 52, 0 }, { 52, 56, 54, 4 }, { 56, 56, 56, 0 },
+ { 56, 56, 56, 0 }, { 56, 56, 56, 0 }, { 56, 60, 58, 4 }, { 60, 60, 60, 0 }, { 60, 60, 60, 0 }, { 60, 60, 60, 0 }, { 60, 65, 62, 5 }, { 60, 65, 62, 5 },
+ { 60, 69, 64, 9 }, { 65, 65, 65, 0 }, { 60, 73, 66, 13 }, { 65, 69, 67, 4 }, { 60, 77, 68, 17 }, { 69, 69, 69, 0 }, { 60, 81, 70, 21 }, { 69, 73, 71, 4 },
+ { 60, 85, 72, 25 }, { 73, 73, 73, 0 }, { 60, 89, 74, 29 }, { 73, 77, 75, 4 }, { 60, 93, 76, 33 }, { 77, 77, 77, 0 }, { 60, 97, 78, 37 }, { 77, 81, 79, 4 },
+ { 60, 101, 80, 41 }, { 81, 81, 81, 0 }, { 60, 105, 82, 45 }, { 81, 85, 83, 4 }, { 60, 109, 84, 49 }, { 85, 85, 85, 0 }, { 60, 113, 86, 53 }, { 85, 89, 87, 4 },
+ { 60, 117, 88, 57 }, { 89, 89, 89, 0 }, { 60, 121, 90, 61 }, { 89, 93, 91, 4 }, { 60, 125, 92, 65 }, { 93, 93, 93, 0 }, { 93, 93, 93, 0 }, { 93, 97, 95, 4 },
+ { 97, 97, 97, 0 }, { 97, 97, 97, 0 }, { 97, 97, 97, 0 }, { 97, 101, 99, 4 }, { 101, 101, 101, 0 }, { 101, 101, 101, 0 }, { 101, 101, 101, 0 }, { 101, 105, 103, 4 },
+ { 105, 105, 105, 0 }, { 105, 105, 105, 0 }, { 105, 105, 105, 0 }, { 105, 109, 107, 4 }, { 109, 109, 109, 0 }, { 109, 109, 109, 0 }, { 109, 109, 109, 0 }, { 109, 113, 111, 4 },
+ { 113, 113, 113, 0 }, { 113, 113, 113, 0 }, { 113, 113, 113, 0 }, { 113, 117, 115, 4 }, { 117, 117, 117, 0 }, { 117, 117, 117, 0 }, { 117, 117, 117, 0 }, { 117, 121, 119, 4 },
+ { 121, 121, 121, 0 }, { 121, 121, 121, 0 }, { 121, 121, 121, 0 }, { 121, 125, 123, 4 }, { 125, 125, 125, 0 }, { 125, 125, 125, 0 }, { 125, 125, 125, 0 }, { 125, 130, 127, 5 },
+ { 125, 130, 127, 5 }, { 125, 134, 129, 9 }, { 130, 130, 130, 0 }, { 125, 138, 131, 13 }, { 130, 134, 132, 4 }, { 125, 142, 133, 17 }, { 134, 134, 134, 0 }, { 125, 146, 135, 21 },
+ { 134, 138, 136, 4 }, { 125, 150, 137, 25 }, { 138, 138, 138, 0 }, { 125, 154, 139, 29 }, { 138, 142, 140, 4 }, { 125, 158, 141, 33 }, { 142, 142, 142, 0 }, { 125, 162, 143, 37 },
+ { 142, 146, 144, 4 }, { 125, 166, 145, 41 }, { 146, 146, 146, 0 }, { 125, 170, 147, 45 }, { 146, 150, 148, 4 }, { 125, 174, 149, 49 }, { 150, 150, 150, 0 }, { 125, 178, 151, 53 },
+ { 150, 154, 152, 4 }, { 125, 182, 153, 57 }, { 154, 154, 154, 0 }, { 125, 186, 155, 61 }, { 154, 158, 156, 4 }, { 125, 190, 157, 65 }, { 158, 158, 158, 0 }, { 158, 158, 158, 0 },
+ { 158, 162, 160, 4 }, { 162, 162, 162, 0 }, { 162, 162, 162, 0 }, { 162, 162, 162, 0 }, { 162, 166, 164, 4 }, { 166, 166, 166, 0 }, { 166, 166, 166, 0 }, { 166, 166, 166, 0 },
+ { 166, 170, 168, 4 }, { 170, 170, 170, 0 }, { 170, 170, 170, 0 }, { 170, 170, 170, 0 }, { 170, 174, 172, 4 }, { 174, 174, 174, 0 }, { 174, 174, 174, 0 }, { 174, 174, 174, 0 },
+ { 174, 178, 176, 4 }, { 178, 178, 178, 0 }, { 178, 178, 178, 0 }, { 178, 178, 178, 0 }, { 178, 182, 180, 4 }, { 182, 182, 182, 0 }, { 182, 182, 182, 0 }, { 182, 182, 182, 0 },
+ { 182, 186, 184, 4 }, { 186, 186, 186, 0 }, { 186, 186, 186, 0 }, { 186, 186, 186, 0 }, { 186, 190, 188, 4 }, { 190, 190, 190, 0 }, { 190, 190, 190, 0 }, { 190, 190, 190, 0 },
+ { 190, 195, 192, 5 }, { 190, 195, 192, 5 }, { 190, 199, 194, 9 }, { 195, 195, 195, 0 }, { 190, 203, 196, 13 }, { 195, 199, 197, 4 }, { 190, 207, 198, 17 }, { 199, 199, 199, 0 },
+ { 190, 211, 200, 21 }, { 199, 203, 201, 4 }, { 190, 215, 202, 25 }, { 203, 203, 203, 0 }, { 190, 219, 204, 29 }, { 203, 207, 205, 4 }, { 190, 223, 206, 33 }, { 207, 207, 207, 0 },
+ { 190, 227, 208, 37 }, { 207, 211, 209, 4 }, { 190, 231, 210, 41 }, { 211, 211, 211, 0 }, { 190, 235, 212, 45 }, { 211, 215, 213, 4 }, { 190, 239, 214, 49 }, { 215, 215, 215, 0 },
+ { 190, 243, 216, 53 }, { 215, 219, 217, 4 }, { 190, 247, 218, 57 }, { 219, 219, 219, 0 }, { 190, 251, 220, 61 }, { 219, 223, 221, 4 }, { 190, 255, 222, 65 }, { 223, 223, 223, 0 },
+ { 223, 223, 223, 0 }, { 223, 227, 225, 4 }, { 227, 227, 227, 0 }, { 227, 227, 227, 0 }, { 227, 227, 227, 0 }, { 227, 231, 229, 4 }, { 231, 231, 231, 0 }, { 231, 231, 231, 0 },
+ { 231, 231, 231, 0 }, { 231, 235, 233, 4 }, { 235, 235, 235, 0 }, { 235, 235, 235, 0 }, { 235, 235, 235, 0 }, { 235, 239, 237, 4 }, { 239, 239, 239, 0 }, { 239, 239, 239, 0 },
+ { 239, 239, 239, 0 }, { 239, 243, 241, 4 }, { 243, 243, 243, 0 }, { 243, 243, 243, 0 }, { 243, 243, 243, 0 }, { 243, 247, 245, 4 }, { 247, 247, 247, 0 }, { 247, 247, 247, 0 },
+ { 247, 247, 247, 0 }, { 247, 251, 249, 4 }, { 251, 251, 251, 0 }, { 251, 251, 251, 0 }, { 251, 251, 251, 0 }, { 251, 255, 253, 4 }, { 255, 255, 255, 0 }, { 255, 255, 255, 0 },
+ };
+
+ SingleColorTableEntry g_singleColor5_3_p[256] =
+ {
+ { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 8, 0, 2, 8 }, { 8, 0, 2, 8 }, { 0, 8, 5, 8 }, { 0, 8, 5, 8 }, { 0, 8, 5, 8 }, { 8, 8, 8, 0 },
+ { 8, 8, 8, 0 }, { 8, 8, 8, 0 }, { 16, 8, 10, 8 }, { 33, 0, 11, 33 }, { 8, 16, 13, 8 }, { 8, 16, 13, 8 }, { 8, 16, 13, 8 }, { 16, 16, 16, 0 },
+ { 16, 16, 16, 0 }, { 16, 16, 16, 0 }, { 24, 16, 18, 8 }, { 41, 8, 19, 33 }, { 16, 24, 21, 8 }, { 16, 24, 21, 8 }, { 0, 33, 22, 33 }, { 24, 24, 24, 0 },
+ { 24, 24, 24, 0 }, { 24, 24, 24, 0 }, { 33, 24, 27, 9 }, { 33, 24, 27, 9 }, { 33, 24, 27, 9 }, { 41, 24, 29, 17 }, { 24, 33, 30, 9 }, { 24, 33, 30, 9 },
+ { 16, 41, 32, 25 }, { 33, 33, 33, 0 }, { 33, 33, 33, 0 }, { 41, 33, 35, 8 }, { 41, 33, 35, 8 }, { 33, 41, 38, 8 }, { 33, 41, 38, 8 }, { 33, 41, 38, 8 },
+ { 24, 49, 40, 25 }, { 41, 41, 41, 0 }, { 41, 41, 41, 0 }, { 49, 41, 43, 8 }, { 66, 33, 44, 33 }, { 41, 49, 46, 8 }, { 41, 49, 46, 8 }, { 41, 49, 46, 8 },
+ { 49, 49, 49, 0 }, { 49, 49, 49, 0 }, { 49, 49, 49, 0 }, { 57, 49, 51, 8 }, { 74, 41, 52, 33 }, { 49, 57, 54, 8 }, { 49, 57, 54, 8 }, { 33, 66, 55, 33 },
+ { 57, 57, 57, 0 }, { 57, 57, 57, 0 }, { 57, 57, 57, 0 }, { 66, 57, 60, 9 }, { 66, 57, 60, 9 }, { 66, 57, 60, 9 }, { 74, 57, 62, 17 }, { 57, 66, 63, 9 },
+ { 57, 66, 63, 9 }, { 49, 74, 65, 25 }, { 66, 66, 66, 0 }, { 66, 66, 66, 0 }, { 74, 66, 68, 8 }, { 74, 66, 68, 8 }, { 66, 74, 71, 8 }, { 66, 74, 71, 8 },
+ { 66, 74, 71, 8 }, { 57, 82, 73, 25 }, { 74, 74, 74, 0 }, { 74, 74, 74, 0 }, { 82, 74, 76, 8 }, { 99, 66, 77, 33 }, { 74, 82, 79, 8 }, { 74, 82, 79, 8 },
+ { 74, 82, 79, 8 }, { 82, 82, 82, 0 }, { 82, 82, 82, 0 }, { 82, 82, 82, 0 }, { 90, 82, 84, 8 }, { 107, 74, 85, 33 }, { 82, 90, 87, 8 }, { 82, 90, 87, 8 },
+ { 66, 99, 88, 33 }, { 90, 90, 90, 0 }, { 90, 90, 90, 0 }, { 90, 90, 90, 0 }, { 99, 90, 93, 9 }, { 99, 90, 93, 9 }, { 99, 90, 93, 9 }, { 107, 90, 95, 17 },
+ { 90, 99, 96, 9 }, { 90, 99, 96, 9 }, { 82, 107, 98, 25 }, { 99, 99, 99, 0 }, { 99, 99, 99, 0 }, { 107, 99, 101, 8 }, { 107, 99, 101, 8 }, { 99, 107, 104, 8 },
+ { 99, 107, 104, 8 }, { 99, 107, 104, 8 }, { 90, 115, 106, 25 }, { 107, 107, 107, 0 }, { 107, 107, 107, 0 }, { 115, 107, 109, 8 }, { 132, 99, 110, 33 }, { 107, 115, 112, 8 },
+ { 107, 115, 112, 8 }, { 107, 115, 112, 8 }, { 115, 115, 115, 0 }, { 115, 115, 115, 0 }, { 115, 115, 115, 0 }, { 123, 115, 117, 8 }, { 140, 107, 118, 33 }, { 115, 123, 120, 8 },
+ { 115, 123, 120, 8 }, { 99, 132, 121, 33 }, { 123, 123, 123, 0 }, { 123, 123, 123, 0 }, { 123, 123, 123, 0 }, { 132, 123, 126, 9 }, { 132, 123, 126, 9 }, { 132, 123, 126, 9 },
+ { 140, 123, 128, 17 }, { 123, 132, 129, 9 }, { 123, 132, 129, 9 }, { 115, 140, 131, 25 }, { 132, 132, 132, 0 }, { 132, 132, 132, 0 }, { 140, 132, 134, 8 }, { 140, 132, 134, 8 },
+ { 132, 140, 137, 8 }, { 132, 140, 137, 8 }, { 132, 140, 137, 8 }, { 123, 148, 139, 25 }, { 140, 140, 140, 0 }, { 140, 140, 140, 0 }, { 148, 140, 142, 8 }, { 165, 132, 143, 33 },
+ { 140, 148, 145, 8 }, { 140, 148, 145, 8 }, { 140, 148, 145, 8 }, { 148, 148, 148, 0 }, { 148, 148, 148, 0 }, { 148, 148, 148, 0 }, { 156, 148, 150, 8 }, { 173, 140, 151, 33 },
+ { 148, 156, 153, 8 }, { 148, 156, 153, 8 }, { 132, 165, 154, 33 }, { 156, 156, 156, 0 }, { 156, 156, 156, 0 }, { 156, 156, 156, 0 }, { 165, 156, 159, 9 }, { 165, 156, 159, 9 },
+ { 165, 156, 159, 9 }, { 173, 156, 161, 17 }, { 156, 165, 162, 9 }, { 156, 165, 162, 9 }, { 148, 173, 164, 25 }, { 165, 165, 165, 0 }, { 165, 165, 165, 0 }, { 173, 165, 167, 8 },
+ { 173, 165, 167, 8 }, { 165, 173, 170, 8 }, { 165, 173, 170, 8 }, { 165, 173, 170, 8 }, { 156, 181, 172, 25 }, { 173, 173, 173, 0 }, { 173, 173, 173, 0 }, { 181, 173, 175, 8 },
+ { 198, 165, 176, 33 }, { 173, 181, 178, 8 }, { 173, 181, 178, 8 }, { 173, 181, 178, 8 }, { 181, 181, 181, 0 }, { 181, 181, 181, 0 }, { 181, 181, 181, 0 }, { 189, 181, 183, 8 },
+ { 206, 173, 184, 33 }, { 181, 189, 186, 8 }, { 181, 189, 186, 8 }, { 165, 198, 187, 33 }, { 189, 189, 189, 0 }, { 189, 189, 189, 0 }, { 189, 189, 189, 0 }, { 198, 189, 192, 9 },
+ { 198, 189, 192, 9 }, { 198, 189, 192, 9 }, { 206, 189, 194, 17 }, { 189, 198, 195, 9 }, { 189, 198, 195, 9 }, { 181, 206, 197, 25 }, { 198, 198, 198, 0 }, { 198, 198, 198, 0 },
+ { 206, 198, 200, 8 }, { 206, 198, 200, 8 }, { 198, 206, 203, 8 }, { 198, 206, 203, 8 }, { 198, 206, 203, 8 }, { 189, 214, 205, 25 }, { 206, 206, 206, 0 }, { 206, 206, 206, 0 },
+ { 214, 206, 208, 8 }, { 231, 198, 209, 33 }, { 206, 214, 211, 8 }, { 206, 214, 211, 8 }, { 206, 214, 211, 8 }, { 214, 214, 214, 0 }, { 214, 214, 214, 0 }, { 214, 214, 214, 0 },
+ { 222, 214, 216, 8 }, { 239, 206, 217, 33 }, { 214, 222, 219, 8 }, { 214, 222, 219, 8 }, { 198, 231, 220, 33 }, { 222, 222, 222, 0 }, { 222, 222, 222, 0 }, { 222, 222, 222, 0 },
+ { 231, 222, 225, 9 }, { 231, 222, 225, 9 }, { 231, 222, 225, 9 }, { 239, 222, 227, 17 }, { 222, 231, 228, 9 }, { 222, 231, 228, 9 }, { 214, 239, 230, 25 }, { 231, 231, 231, 0 },
+ { 231, 231, 231, 0 }, { 239, 231, 233, 8 }, { 239, 231, 233, 8 }, { 231, 239, 236, 8 }, { 231, 239, 236, 8 }, { 231, 239, 236, 8 }, { 222, 247, 238, 25 }, { 239, 239, 239, 0 },
+ { 239, 239, 239, 0 }, { 247, 239, 241, 8 }, { 247, 239, 241, 8 }, { 239, 247, 244, 8 }, { 239, 247, 244, 8 }, { 239, 247, 244, 8 }, { 247, 247, 247, 0 }, { 247, 247, 247, 0 },
+ { 247, 247, 247, 0 }, { 255, 247, 249, 8 }, { 255, 247, 249, 8 }, { 247, 255, 252, 8 }, { 247, 255, 252, 8 }, { 247, 255, 252, 8 }, { 255, 255, 255, 0 }, { 255, 255, 255, 0 },
+ };
+
+ SingleColorTableEntry g_singleColor6_3_p[256] =
+ {
+ { 0, 0, 0, 0 }, { 4, 0, 1, 4 }, { 0, 4, 2, 4 }, { 4, 4, 4, 0 }, { 4, 4, 4, 0 }, { 8, 4, 5, 4 }, { 4, 8, 6, 4 }, { 8, 8, 8, 0 },
+ { 8, 8, 8, 0 }, { 12, 8, 9, 4 }, { 8, 12, 10, 4 }, { 12, 12, 12, 0 }, { 12, 12, 12, 0 }, { 16, 12, 13, 4 }, { 12, 16, 14, 4 }, { 16, 16, 16, 0 },
+ { 16, 16, 16, 0 }, { 20, 16, 17, 4 }, { 16, 20, 18, 4 }, { 20, 20, 20, 0 }, { 20, 20, 20, 0 }, { 24, 20, 21, 4 }, { 20, 24, 22, 4 }, { 24, 24, 24, 0 },
+ { 24, 24, 24, 0 }, { 28, 24, 25, 4 }, { 24, 28, 26, 4 }, { 28, 28, 28, 0 }, { 28, 28, 28, 0 }, { 32, 28, 29, 4 }, { 28, 32, 30, 4 }, { 32, 32, 32, 0 },
+ { 32, 32, 32, 0 }, { 36, 32, 33, 4 }, { 32, 36, 34, 4 }, { 36, 36, 36, 0 }, { 36, 36, 36, 0 }, { 40, 36, 37, 4 }, { 36, 40, 38, 4 }, { 40, 40, 40, 0 },
+ { 40, 40, 40, 0 }, { 44, 40, 41, 4 }, { 40, 44, 42, 4 }, { 65, 32, 43, 33 }, { 44, 44, 44, 0 }, { 48, 44, 45, 4 }, { 44, 48, 46, 4 }, { 69, 36, 47, 33 },
+ { 48, 48, 48, 0 }, { 52, 48, 49, 4 }, { 48, 52, 50, 4 }, { 65, 44, 51, 21 }, { 52, 52, 52, 0 }, { 56, 52, 53, 4 }, { 52, 56, 54, 4 }, { 69, 48, 55, 21 },
+ { 56, 56, 56, 0 }, { 60, 56, 57, 4 }, { 56, 60, 58, 4 }, { 65, 56, 59, 9 }, { 60, 60, 60, 0 }, { 65, 60, 61, 5 }, { 56, 65, 62, 9 }, { 60, 65, 63, 5 },
+ { 56, 69, 64, 13 }, { 65, 65, 65, 0 }, { 69, 65, 66, 4 }, { 65, 69, 67, 4 }, { 60, 73, 68, 13 }, { 69, 69, 69, 0 }, { 73, 69, 70, 4 }, { 69, 73, 71, 4 },
+ { 56, 81, 72, 25 }, { 73, 73, 73, 0 }, { 77, 73, 74, 4 }, { 73, 77, 75, 4 }, { 60, 85, 76, 25 }, { 77, 77, 77, 0 }, { 81, 77, 78, 4 }, { 77, 81, 79, 4 },
+ { 81, 81, 81, 0 }, { 81, 81, 81, 0 }, { 85, 81, 82, 4 }, { 81, 85, 83, 4 }, { 85, 85, 85, 0 }, { 85, 85, 85, 0 }, { 89, 85, 86, 4 }, { 85, 89, 87, 4 },
+ { 89, 89, 89, 0 }, { 89, 89, 89, 0 }, { 93, 89, 90, 4 }, { 89, 93, 91, 4 }, { 93, 93, 93, 0 }, { 93, 93, 93, 0 }, { 97, 93, 94, 4 }, { 93, 97, 95, 4 },
+ { 97, 97, 97, 0 }, { 97, 97, 97, 0 }, { 101, 97, 98, 4 }, { 97, 101, 99, 4 }, { 101, 101, 101, 0 }, { 101, 101, 101, 0 }, { 105, 101, 102, 4 }, { 101, 105, 103, 4 },
+ { 105, 105, 105, 0 }, { 105, 105, 105, 0 }, { 109, 105, 106, 4 }, { 105, 109, 107, 4 }, { 130, 97, 108, 33 }, { 109, 109, 109, 0 }, { 113, 109, 110, 4 }, { 109, 113, 111, 4 },
+ { 134, 101, 112, 33 }, { 113, 113, 113, 0 }, { 117, 113, 114, 4 }, { 113, 117, 115, 4 }, { 130, 109, 116, 21 }, { 117, 117, 117, 0 }, { 121, 117, 118, 4 }, { 117, 121, 119, 4 },
+ { 134, 113, 120, 21 }, { 121, 121, 121, 0 }, { 125, 121, 122, 4 }, { 121, 125, 123, 4 }, { 130, 121, 124, 9 }, { 125, 125, 125, 0 }, { 130, 125, 126, 5 }, { 121, 130, 127, 9 },
+ { 125, 130, 128, 5 }, { 121, 134, 129, 13 }, { 130, 130, 130, 0 }, { 134, 130, 131, 4 }, { 130, 134, 132, 4 }, { 125, 138, 133, 13 }, { 134, 134, 134, 0 }, { 138, 134, 135, 4 },
+ { 134, 138, 136, 4 }, { 121, 146, 137, 25 }, { 138, 138, 138, 0 }, { 142, 138, 139, 4 }, { 138, 142, 140, 4 }, { 125, 150, 141, 25 }, { 142, 142, 142, 0 }, { 146, 142, 143, 4 },
+ { 142, 146, 144, 4 }, { 146, 146, 146, 0 }, { 146, 146, 146, 0 }, { 150, 146, 147, 4 }, { 146, 150, 148, 4 }, { 150, 150, 150, 0 }, { 150, 150, 150, 0 }, { 154, 150, 151, 4 },
+ { 150, 154, 152, 4 }, { 154, 154, 154, 0 }, { 154, 154, 154, 0 }, { 158, 154, 155, 4 }, { 154, 158, 156, 4 }, { 158, 158, 158, 0 }, { 158, 158, 158, 0 }, { 162, 158, 159, 4 },
+ { 158, 162, 160, 4 }, { 162, 162, 162, 0 }, { 162, 162, 162, 0 }, { 166, 162, 163, 4 }, { 162, 166, 164, 4 }, { 166, 166, 166, 0 }, { 166, 166, 166, 0 }, { 170, 166, 167, 4 },
+ { 166, 170, 168, 4 }, { 170, 170, 170, 0 }, { 170, 170, 170, 0 }, { 174, 170, 171, 4 }, { 170, 174, 172, 4 }, { 195, 162, 173, 33 }, { 174, 174, 174, 0 }, { 178, 174, 175, 4 },
+ { 174, 178, 176, 4 }, { 199, 166, 177, 33 }, { 178, 178, 178, 0 }, { 182, 178, 179, 4 }, { 178, 182, 180, 4 }, { 195, 174, 181, 21 }, { 182, 182, 182, 0 }, { 186, 182, 183, 4 },
+ { 182, 186, 184, 4 }, { 199, 178, 185, 21 }, { 186, 186, 186, 0 }, { 190, 186, 187, 4 }, { 186, 190, 188, 4 }, { 195, 186, 189, 9 }, { 190, 190, 190, 0 }, { 195, 190, 191, 5 },
+ { 186, 195, 192, 9 }, { 190, 195, 193, 5 }, { 186, 199, 194, 13 }, { 195, 195, 195, 0 }, { 199, 195, 196, 4 }, { 195, 199, 197, 4 }, { 190, 203, 198, 13 }, { 199, 199, 199, 0 },
+ { 203, 199, 200, 4 }, { 199, 203, 201, 4 }, { 186, 211, 202, 25 }, { 203, 203, 203, 0 }, { 207, 203, 204, 4 }, { 203, 207, 205, 4 }, { 190, 215, 206, 25 }, { 207, 207, 207, 0 },
+ { 211, 207, 208, 4 }, { 207, 211, 209, 4 }, { 211, 211, 211, 0 }, { 211, 211, 211, 0 }, { 215, 211, 212, 4 }, { 211, 215, 213, 4 }, { 215, 215, 215, 0 }, { 215, 215, 215, 0 },
+ { 219, 215, 216, 4 }, { 215, 219, 217, 4 }, { 219, 219, 219, 0 }, { 219, 219, 219, 0 }, { 223, 219, 220, 4 }, { 219, 223, 221, 4 }, { 223, 223, 223, 0 }, { 223, 223, 223, 0 },
+ { 227, 223, 224, 4 }, { 223, 227, 225, 4 }, { 227, 227, 227, 0 }, { 227, 227, 227, 0 }, { 231, 227, 228, 4 }, { 227, 231, 229, 4 }, { 231, 231, 231, 0 }, { 231, 231, 231, 0 },
+ { 235, 231, 232, 4 }, { 231, 235, 233, 4 }, { 235, 235, 235, 0 }, { 235, 235, 235, 0 }, { 239, 235, 236, 4 }, { 235, 239, 237, 4 }, { 239, 239, 239, 0 }, { 239, 239, 239, 0 },
+ { 243, 239, 240, 4 }, { 239, 243, 241, 4 }, { 243, 243, 243, 0 }, { 243, 243, 243, 0 }, { 247, 243, 244, 4 }, { 243, 247, 245, 4 }, { 247, 247, 247, 0 }, { 247, 247, 247, 0 },
+ { 251, 247, 248, 4 }, { 247, 251, 249, 4 }, { 251, 251, 251, 0 }, { 251, 251, 251, 0 }, { 255, 251, 252, 4 }, { 251, 255, 253, 4 }, { 255, 255, 255, 0 }, { 255, 255, 255, 0 },
+ };
+
+ SingleColorTableEntry g_singleColor5_2_p[256] =
+ {
+ { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 8, 4, 8 }, { 0, 8, 4, 8 }, { 0, 8, 4, 8 }, { 8, 8, 8, 0 }, { 8, 8, 8, 0 },
+ { 8, 8, 8, 0 }, { 8, 8, 8, 0 }, { 8, 8, 8, 0 }, { 8, 16, 12, 8 }, { 8, 16, 12, 8 }, { 8, 16, 12, 8 }, { 16, 16, 16, 0 }, { 16, 16, 16, 0 },
+ { 16, 16, 16, 0 }, { 16, 16, 16, 0 }, { 16, 16, 16, 0 }, { 16, 24, 20, 8 }, { 16, 24, 20, 8 }, { 16, 24, 20, 8 }, { 24, 24, 24, 0 }, { 24, 24, 24, 0 },
+ { 24, 24, 24, 0 }, { 24, 24, 24, 0 }, { 24, 24, 24, 0 }, { 24, 33, 28, 9 }, { 24, 33, 28, 9 }, { 24, 33, 28, 9 }, { 24, 33, 28, 9 }, { 24, 41, 32, 17 },
+ { 24, 41, 32, 17 }, { 33, 33, 33, 0 }, { 33, 33, 33, 0 }, { 24, 49, 36, 25 }, { 24, 49, 36, 25 }, { 33, 41, 37, 8 }, { 33, 41, 37, 8 }, { 24, 57, 40, 33 },
+ { 24, 57, 40, 33 }, { 41, 41, 41, 0 }, { 41, 41, 41, 0 }, { 41, 41, 41, 0 }, { 41, 49, 45, 8 }, { 41, 49, 45, 8 }, { 41, 49, 45, 8 }, { 49, 49, 49, 0 },
+ { 49, 49, 49, 0 }, { 49, 49, 49, 0 }, { 49, 49, 49, 0 }, { 49, 49, 49, 0 }, { 49, 57, 53, 8 }, { 49, 57, 53, 8 }, { 49, 57, 53, 8 }, { 57, 57, 57, 0 },
+ { 57, 57, 57, 0 }, { 57, 57, 57, 0 }, { 57, 57, 57, 0 }, { 57, 57, 57, 0 }, { 57, 66, 61, 9 }, { 57, 66, 61, 9 }, { 57, 66, 61, 9 }, { 57, 66, 61, 9 },
+ { 57, 74, 65, 17 }, { 57, 74, 65, 17 }, { 66, 66, 66, 0 }, { 66, 66, 66, 0 }, { 57, 82, 69, 25 }, { 57, 82, 69, 25 }, { 66, 74, 70, 8 }, { 66, 74, 70, 8 },
+ { 57, 90, 73, 33 }, { 57, 90, 73, 33 }, { 74, 74, 74, 0 }, { 74, 74, 74, 0 }, { 74, 74, 74, 0 }, { 74, 82, 78, 8 }, { 74, 82, 78, 8 }, { 74, 82, 78, 8 },
+ { 82, 82, 82, 0 }, { 82, 82, 82, 0 }, { 82, 82, 82, 0 }, { 82, 82, 82, 0 }, { 82, 82, 82, 0 }, { 82, 90, 86, 8 }, { 82, 90, 86, 8 }, { 82, 90, 86, 8 },
+ { 90, 90, 90, 0 }, { 90, 90, 90, 0 }, { 90, 90, 90, 0 }, { 90, 90, 90, 0 }, { 90, 90, 90, 0 }, { 90, 99, 94, 9 }, { 90, 99, 94, 9 }, { 90, 99, 94, 9 },
+ { 90, 99, 94, 9 }, { 90, 107, 98, 17 }, { 90, 107, 98, 17 }, { 99, 99, 99, 0 }, { 99, 99, 99, 0 }, { 90, 115, 102, 25 }, { 90, 115, 102, 25 }, { 99, 107, 103, 8 },
+ { 99, 107, 103, 8 }, { 90, 123, 106, 33 }, { 90, 123, 106, 33 }, { 107, 107, 107, 0 }, { 107, 107, 107, 0 }, { 107, 107, 107, 0 }, { 107, 115, 111, 8 }, { 107, 115, 111, 8 },
+ { 107, 115, 111, 8 }, { 115, 115, 115, 0 }, { 115, 115, 115, 0 }, { 115, 115, 115, 0 }, { 115, 115, 115, 0 }, { 115, 115, 115, 0 }, { 115, 123, 119, 8 }, { 115, 123, 119, 8 },
+ { 115, 123, 119, 8 }, { 123, 123, 123, 0 }, { 123, 123, 123, 0 }, { 123, 123, 123, 0 }, { 123, 123, 123, 0 }, { 123, 123, 123, 0 }, { 123, 132, 127, 9 }, { 123, 132, 127, 9 },
+ { 123, 132, 127, 9 }, { 123, 132, 127, 9 }, { 123, 140, 131, 17 }, { 123, 140, 131, 17 }, { 132, 132, 132, 0 }, { 132, 132, 132, 0 }, { 123, 148, 135, 25 }, { 123, 148, 135, 25 },
+ { 132, 140, 136, 8 }, { 132, 140, 136, 8 }, { 123, 156, 139, 33 }, { 123, 156, 139, 33 }, { 140, 140, 140, 0 }, { 140, 140, 140, 0 }, { 140, 140, 140, 0 }, { 140, 148, 144, 8 },
+ { 140, 148, 144, 8 }, { 140, 148, 144, 8 }, { 148, 148, 148, 0 }, { 148, 148, 148, 0 }, { 148, 148, 148, 0 }, { 148, 148, 148, 0 }, { 148, 148, 148, 0 }, { 148, 156, 152, 8 },
+ { 148, 156, 152, 8 }, { 148, 156, 152, 8 }, { 156, 156, 156, 0 }, { 156, 156, 156, 0 }, { 156, 156, 156, 0 }, { 156, 156, 156, 0 }, { 156, 156, 156, 0 }, { 156, 165, 160, 9 },
+ { 156, 165, 160, 9 }, { 156, 165, 160, 9 }, { 156, 165, 160, 9 }, { 156, 173, 164, 17 }, { 156, 173, 164, 17 }, { 165, 165, 165, 0 }, { 165, 165, 165, 0 }, { 156, 181, 168, 25 },
+ { 156, 181, 168, 25 }, { 165, 173, 169, 8 }, { 165, 173, 169, 8 }, { 156, 189, 172, 33 }, { 156, 189, 172, 33 }, { 173, 173, 173, 0 }, { 173, 173, 173, 0 }, { 173, 173, 173, 0 },
+ { 173, 181, 177, 8 }, { 173, 181, 177, 8 }, { 173, 181, 177, 8 }, { 181, 181, 181, 0 }, { 181, 181, 181, 0 }, { 181, 181, 181, 0 }, { 181, 181, 181, 0 }, { 181, 181, 181, 0 },
+ { 181, 189, 185, 8 }, { 181, 189, 185, 8 }, { 181, 189, 185, 8 }, { 189, 189, 189, 0 }, { 189, 189, 189, 0 }, { 189, 189, 189, 0 }, { 189, 189, 189, 0 }, { 189, 189, 189, 0 },
+ { 189, 198, 193, 9 }, { 189, 198, 193, 9 }, { 189, 198, 193, 9 }, { 189, 198, 193, 9 }, { 189, 206, 197, 17 }, { 189, 206, 197, 17 }, { 198, 198, 198, 0 }, { 198, 198, 198, 0 },
+ { 189, 214, 201, 25 }, { 189, 214, 201, 25 }, { 198, 206, 202, 8 }, { 198, 206, 202, 8 }, { 189, 222, 205, 33 }, { 189, 222, 205, 33 }, { 206, 206, 206, 0 }, { 206, 206, 206, 0 },
+ { 206, 206, 206, 0 }, { 206, 214, 210, 8 }, { 206, 214, 210, 8 }, { 206, 214, 210, 8 }, { 214, 214, 214, 0 }, { 214, 214, 214, 0 }, { 214, 214, 214, 0 }, { 214, 214, 214, 0 },
+ { 214, 214, 214, 0 }, { 214, 222, 218, 8 }, { 214, 222, 218, 8 }, { 214, 222, 218, 8 }, { 222, 222, 222, 0 }, { 222, 222, 222, 0 }, { 222, 222, 222, 0 }, { 222, 222, 222, 0 },
+ { 222, 222, 222, 0 }, { 222, 231, 226, 9 }, { 222, 231, 226, 9 }, { 222, 231, 226, 9 }, { 222, 231, 226, 9 }, { 222, 239, 230, 17 }, { 222, 239, 230, 17 }, { 231, 231, 231, 0 },
+ { 231, 231, 231, 0 }, { 222, 247, 234, 25 }, { 222, 247, 234, 25 }, { 231, 239, 235, 8 }, { 231, 239, 235, 8 }, { 222, 255, 238, 33 }, { 222, 255, 238, 33 }, { 239, 239, 239, 0 },
+ { 239, 239, 239, 0 }, { 239, 239, 239, 0 }, { 239, 247, 243, 8 }, { 239, 247, 243, 8 }, { 239, 247, 243, 8 }, { 247, 247, 247, 0 }, { 247, 247, 247, 0 }, { 247, 247, 247, 0 },
+ { 247, 247, 247, 0 }, { 247, 247, 247, 0 }, { 247, 255, 251, 8 }, { 247, 255, 251, 8 }, { 247, 255, 251, 8 }, { 255, 255, 255, 0 }, { 255, 255, 255, 0 }, { 255, 255, 255, 0 },
+ };
+
+ SingleColorTableEntry g_singleColor6_2_p[256] =
+ {
+ { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 4, 2, 4 }, { 4, 4, 4, 0 }, { 4, 4, 4, 0 }, { 4, 4, 4, 0 }, { 4, 8, 6, 4 }, { 8, 8, 8, 0 },
+ { 8, 8, 8, 0 }, { 8, 8, 8, 0 }, { 8, 12, 10, 4 }, { 12, 12, 12, 0 }, { 12, 12, 12, 0 }, { 12, 12, 12, 0 }, { 12, 16, 14, 4 }, { 16, 16, 16, 0 },
+ { 16, 16, 16, 0 }, { 16, 16, 16, 0 }, { 16, 20, 18, 4 }, { 20, 20, 20, 0 }, { 20, 20, 20, 0 }, { 20, 20, 20, 0 }, { 20, 24, 22, 4 }, { 24, 24, 24, 0 },
+ { 24, 24, 24, 0 }, { 24, 24, 24, 0 }, { 24, 28, 26, 4 }, { 28, 28, 28, 0 }, { 28, 28, 28, 0 }, { 28, 28, 28, 0 }, { 28, 32, 30, 4 }, { 32, 32, 32, 0 },
+ { 32, 32, 32, 0 }, { 32, 32, 32, 0 }, { 32, 36, 34, 4 }, { 36, 36, 36, 0 }, { 36, 36, 36, 0 }, { 36, 36, 36, 0 }, { 36, 40, 38, 4 }, { 40, 40, 40, 0 },
+ { 40, 40, 40, 0 }, { 40, 40, 40, 0 }, { 40, 44, 42, 4 }, { 44, 44, 44, 0 }, { 44, 44, 44, 0 }, { 44, 44, 44, 0 }, { 44, 48, 46, 4 }, { 48, 48, 48, 0 },
+ { 48, 48, 48, 0 }, { 48, 48, 48, 0 }, { 48, 52, 50, 4 }, { 52, 52, 52, 0 }, { 52, 52, 52, 0 }, { 52, 52, 52, 0 }, { 52, 56, 54, 4 }, { 56, 56, 56, 0 },
+ { 56, 56, 56, 0 }, { 56, 56, 56, 0 }, { 56, 60, 58, 4 }, { 60, 60, 60, 0 }, { 60, 60, 60, 0 }, { 60, 60, 60, 0 }, { 60, 65, 62, 5 }, { 60, 65, 62, 5 },
+ { 60, 69, 64, 9 }, { 65, 65, 65, 0 }, { 60, 73, 66, 13 }, { 65, 69, 67, 4 }, { 60, 77, 68, 17 }, { 69, 69, 69, 0 }, { 60, 81, 70, 21 }, { 69, 73, 71, 4 },
+ { 60, 85, 72, 25 }, { 73, 73, 73, 0 }, { 60, 89, 74, 29 }, { 73, 77, 75, 4 }, { 60, 93, 76, 33 }, { 77, 77, 77, 0 }, { 77, 77, 77, 0 }, { 77, 81, 79, 4 },
+ { 81, 81, 81, 0 }, { 81, 81, 81, 0 }, { 81, 81, 81, 0 }, { 81, 85, 83, 4 }, { 85, 85, 85, 0 }, { 85, 85, 85, 0 }, { 85, 85, 85, 0 }, { 85, 89, 87, 4 },
+ { 89, 89, 89, 0 }, { 89, 89, 89, 0 }, { 89, 89, 89, 0 }, { 89, 93, 91, 4 }, { 93, 93, 93, 0 }, { 93, 93, 93, 0 }, { 93, 93, 93, 0 }, { 93, 97, 95, 4 },
+ { 97, 97, 97, 0 }, { 97, 97, 97, 0 }, { 97, 97, 97, 0 }, { 97, 101, 99, 4 }, { 101, 101, 101, 0 }, { 101, 101, 101, 0 }, { 101, 101, 101, 0 }, { 101, 105, 103, 4 },
+ { 105, 105, 105, 0 }, { 105, 105, 105, 0 }, { 105, 105, 105, 0 }, { 105, 109, 107, 4 }, { 109, 109, 109, 0 }, { 109, 109, 109, 0 }, { 109, 109, 109, 0 }, { 109, 113, 111, 4 },
+ { 113, 113, 113, 0 }, { 113, 113, 113, 0 }, { 113, 113, 113, 0 }, { 113, 117, 115, 4 }, { 117, 117, 117, 0 }, { 117, 117, 117, 0 }, { 117, 117, 117, 0 }, { 117, 121, 119, 4 },
+ { 121, 121, 121, 0 }, { 121, 121, 121, 0 }, { 121, 121, 121, 0 }, { 121, 125, 123, 4 }, { 125, 125, 125, 0 }, { 125, 125, 125, 0 }, { 125, 125, 125, 0 }, { 125, 130, 127, 5 },
+ { 125, 130, 127, 5 }, { 125, 134, 129, 9 }, { 130, 130, 130, 0 }, { 125, 138, 131, 13 }, { 130, 134, 132, 4 }, { 125, 142, 133, 17 }, { 134, 134, 134, 0 }, { 125, 146, 135, 21 },
+ { 134, 138, 136, 4 }, { 125, 150, 137, 25 }, { 138, 138, 138, 0 }, { 125, 154, 139, 29 }, { 138, 142, 140, 4 }, { 125, 158, 141, 33 }, { 142, 142, 142, 0 }, { 142, 142, 142, 0 },
+ { 142, 146, 144, 4 }, { 146, 146, 146, 0 }, { 146, 146, 146, 0 }, { 146, 146, 146, 0 }, { 146, 150, 148, 4 }, { 150, 150, 150, 0 }, { 150, 150, 150, 0 }, { 150, 150, 150, 0 },
+ { 150, 154, 152, 4 }, { 154, 154, 154, 0 }, { 154, 154, 154, 0 }, { 154, 154, 154, 0 }, { 154, 158, 156, 4 }, { 158, 158, 158, 0 }, { 158, 158, 158, 0 }, { 158, 158, 158, 0 },
+ { 158, 162, 160, 4 }, { 162, 162, 162, 0 }, { 162, 162, 162, 0 }, { 162, 162, 162, 0 }, { 162, 166, 164, 4 }, { 166, 166, 166, 0 }, { 166, 166, 166, 0 }, { 166, 166, 166, 0 },
+ { 166, 170, 168, 4 }, { 170, 170, 170, 0 }, { 170, 170, 170, 0 }, { 170, 170, 170, 0 }, { 170, 174, 172, 4 }, { 174, 174, 174, 0 }, { 174, 174, 174, 0 }, { 174, 174, 174, 0 },
+ { 174, 178, 176, 4 }, { 178, 178, 178, 0 }, { 178, 178, 178, 0 }, { 178, 178, 178, 0 }, { 178, 182, 180, 4 }, { 182, 182, 182, 0 }, { 182, 182, 182, 0 }, { 182, 182, 182, 0 },
+ { 182, 186, 184, 4 }, { 186, 186, 186, 0 }, { 186, 186, 186, 0 }, { 186, 186, 186, 0 }, { 186, 190, 188, 4 }, { 190, 190, 190, 0 }, { 190, 190, 190, 0 }, { 190, 190, 190, 0 },
+ { 190, 195, 192, 5 }, { 190, 195, 192, 5 }, { 190, 199, 194, 9 }, { 195, 195, 195, 0 }, { 190, 203, 196, 13 }, { 195, 199, 197, 4 }, { 190, 207, 198, 17 }, { 199, 199, 199, 0 },
+ { 190, 211, 200, 21 }, { 199, 203, 201, 4 }, { 190, 215, 202, 25 }, { 203, 203, 203, 0 }, { 190, 219, 204, 29 }, { 203, 207, 205, 4 }, { 190, 223, 206, 33 }, { 207, 207, 207, 0 },
+ { 207, 207, 207, 0 }, { 207, 211, 209, 4 }, { 211, 211, 211, 0 }, { 211, 211, 211, 0 }, { 211, 211, 211, 0 }, { 211, 215, 213, 4 }, { 215, 215, 215, 0 }, { 215, 215, 215, 0 },
+ { 215, 215, 215, 0 }, { 215, 219, 217, 4 }, { 219, 219, 219, 0 }, { 219, 219, 219, 0 }, { 219, 219, 219, 0 }, { 219, 223, 221, 4 }, { 223, 223, 223, 0 }, { 223, 223, 223, 0 },
+ { 223, 223, 223, 0 }, { 223, 227, 225, 4 }, { 227, 227, 227, 0 }, { 227, 227, 227, 0 }, { 227, 227, 227, 0 }, { 227, 231, 229, 4 }, { 231, 231, 231, 0 }, { 231, 231, 231, 0 },
+ { 231, 231, 231, 0 }, { 231, 235, 233, 4 }, { 235, 235, 235, 0 }, { 235, 235, 235, 0 }, { 235, 235, 235, 0 }, { 235, 239, 237, 4 }, { 239, 239, 239, 0 }, { 239, 239, 239, 0 },
+ { 239, 239, 239, 0 }, { 239, 243, 241, 4 }, { 243, 243, 243, 0 }, { 243, 243, 243, 0 }, { 243, 243, 243, 0 }, { 243, 247, 245, 4 }, { 247, 247, 247, 0 }, { 247, 247, 247, 0 },
+ { 247, 247, 247, 0 }, { 247, 251, 249, 4 }, { 251, 251, 251, 0 }, { 251, 251, 251, 0 }, { 251, 251, 251, 0 }, { 251, 255, 253, 4 }, { 255, 255, 255, 0 }, { 255, 255, 255, 0 },
+ };
+ }
+
+ class S3TCComputer
+ {
+ public:
+ typedef ParallelMath::Float MFloat;
+ typedef ParallelMath::SInt16 MSInt16;
+ typedef ParallelMath::UInt15 MUInt15;
+ typedef ParallelMath::UInt16 MUInt16;
+ typedef ParallelMath::SInt32 MSInt32;
+
+ static void Init(MFloat& error)
+ {
+ error = ParallelMath::MakeFloat(FLT_MAX);
+ }
+
+ static void QuantizeTo6Bits(MUInt15& v)
+ {
+ MUInt15 reduced = ParallelMath::LosslessCast<MUInt15>::Cast(ParallelMath::RightShift(ParallelMath::CompactMultiply(v, ParallelMath::MakeUInt15(253)) + ParallelMath::MakeUInt16(512), 10));
+ v = (reduced << 2) | ParallelMath::RightShift(reduced, 4);
+ }
+
+ static void QuantizeTo5Bits(MUInt15& v)
+ {
+ MUInt15 reduced = ParallelMath::LosslessCast<MUInt15>::Cast(ParallelMath::RightShift(ParallelMath::CompactMultiply(v, ParallelMath::MakeUInt15(249)) + ParallelMath::MakeUInt16(1024), 11));
+ v = (reduced << 3) | ParallelMath::RightShift(reduced, 2);
+ }
+
+ static void QuantizeTo565(MUInt15 endPoint[3])
+ {
+ QuantizeTo5Bits(endPoint[0]);
+ QuantizeTo6Bits(endPoint[1]);
+ QuantizeTo5Bits(endPoint[2]);
+ }
+
+ static MFloat ParanoidFactorForSpan(const MSInt16& span)
+ {
+ return ParallelMath::Abs(ParallelMath::ToFloat(span)) * 0.03f;
+ }
+
+ static MFloat ParanoidDiff(const MUInt15& a, const MUInt15& b, const MFloat& d)
+ {
+ MFloat absDiff = ParallelMath::Abs(ParallelMath::ToFloat(ParallelMath::LosslessCast<MSInt16>::Cast(a) - ParallelMath::LosslessCast<MSInt16>::Cast(b)));
+ absDiff = absDiff + d;
+ return absDiff * absDiff;
+ }
+
+ static void TestSingleColor(uint32_t flags, const MUInt15 pixels[16][4], const MFloat floatPixels[16][4], int range, const float* channelWeights,
+ MFloat &bestError, MUInt15 bestEndpoints[2][3], MUInt15 bestIndexes[16], MUInt15 &bestRange, const ParallelMath::RoundTowardNearestForScope *rtn)
+ {
+ float channelWeightsSq[3];
+
+ for (int ch = 0; ch < 3; ch++)
+ channelWeightsSq[ch] = channelWeights[ch] * channelWeights[ch];
+
+ MUInt15 totals[3] = { ParallelMath::MakeUInt15(0), ParallelMath::MakeUInt15(0), ParallelMath::MakeUInt15(0) };
+
+ for (int px = 0; px < 16; px++)
+ {
+ for (int ch = 0; ch < 3; ch++)
+ totals[ch] = totals[ch] + pixels[px][ch];
+ }
+
+ MUInt15 average[3];
+ for (int ch = 0; ch < 3; ch++)
+ average[ch] = ParallelMath::RightShift(totals[ch] + ParallelMath::MakeUInt15(8), 4);
+
+ const S3TCSingleColorTables::SingleColorTableEntry* rbTable = NULL;
+ const S3TCSingleColorTables::SingleColorTableEntry* gTable = NULL;
+ if (flags & cvtt::Flags::S3TC_Paranoid)
+ {
+ if (range == 4)
+ {
+ rbTable = S3TCSingleColorTables::g_singleColor5_3_p;
+ gTable = S3TCSingleColorTables::g_singleColor6_3_p;
+ }
+ else
+ {
+ assert(range == 3);
+ rbTable = S3TCSingleColorTables::g_singleColor5_2_p;
+ gTable = S3TCSingleColorTables::g_singleColor6_2_p;
+ }
+ }
+ else
+ {
+ if (range == 4)
+ {
+ rbTable = S3TCSingleColorTables::g_singleColor5_3;
+ gTable = S3TCSingleColorTables::g_singleColor6_3;
+ }
+ else
+ {
+ assert(range == 3);
+ rbTable = S3TCSingleColorTables::g_singleColor5_2;
+ gTable = S3TCSingleColorTables::g_singleColor6_2;
+ }
+ }
+
+ MUInt15 interpolated[3];
+ MUInt15 eps[2][3];
+ MSInt16 spans[3];
+ for (int i = 0; i < ParallelMath::ParallelSize; i++)
+ {
+ for (int ch = 0; ch < 3; ch++)
+ {
+ uint16_t avg = ParallelMath::Extract(average[ch], i);
+ const S3TCSingleColorTables::SingleColorTableEntry& tableEntry = ((ch == 1) ? gTable[avg] : rbTable[avg]);
+ ParallelMath::PutUInt15(eps[0][ch], i, tableEntry.m_min);
+ ParallelMath::PutUInt15(eps[1][ch], i, tableEntry.m_max);
+ ParallelMath::PutUInt15(interpolated[ch], i, tableEntry.m_actualColor);
+ ParallelMath::PutSInt16(spans[ch], i, tableEntry.m_span);
+ }
+ }
+
+ MFloat error = ParallelMath::MakeFloatZero();
+ if (flags & cvtt::Flags::S3TC_Paranoid)
+ {
+ MFloat spanParanoidFactors[3];
+ for (int ch = 0; ch < 3; ch++)
+ spanParanoidFactors[ch] = ParanoidFactorForSpan(spans[ch]);
+
+ for (int px = 0; px < 16; px++)
+ {
+ for (int ch = 0; ch < 3; ch++)
+ error = error + ParanoidDiff(interpolated[ch], pixels[px][ch], spanParanoidFactors[ch]) * channelWeightsSq[ch];
+ }
+ }
+ else
+ {
+ for (int px = 0; px < 16; px++)
+ {
+ for (int ch = 0; ch < 3; ch++)
+ error = error + ParallelMath::ToFloat(ParallelMath::SqDiffUInt8(interpolated[ch], pixels[px][ch])) * channelWeightsSq[ch];
+ }
+ }
+
+ ParallelMath::FloatCompFlag better = ParallelMath::Less(error, bestError);
+ ParallelMath::Int16CompFlag better16 = ParallelMath::FloatFlagToInt16(better);
+
+ if (ParallelMath::AnySet(better16))
+ {
+ bestError = ParallelMath::Min(bestError, error);
+ for (int epi = 0; epi < 2; epi++)
+ for (int ch = 0; ch < 3; ch++)
+ ParallelMath::ConditionalSet(bestEndpoints[epi][ch], better16, eps[epi][ch]);
+
+ MUInt15 vindexes = ParallelMath::MakeUInt15(1);
+ for (int px = 0; px < 16; px++)
+ ParallelMath::ConditionalSet(bestIndexes[px], better16, vindexes);
+
+ ParallelMath::ConditionalSet(bestRange, better16, ParallelMath::MakeUInt15(range));
+ }
+ }
+
+ static void TestEndpoints(uint32_t flags, const MUInt15 pixels[16][4], const MFloat floatPixels[16][4], const MFloat preWeightedPixels[16][4], const MUInt15 unquantizedEndPoints[2][3], int range, const float* channelWeights,
+ MFloat &bestError, MUInt15 bestEndpoints[2][3], MUInt15 bestIndexes[16], MUInt15 &bestRange, EndpointRefiner<3> *refiner, const ParallelMath::RoundTowardNearestForScope *rtn)
+ {
+ float channelWeightsSq[3];
+
+ for (int ch = 0; ch < 3; ch++)
+ channelWeightsSq[ch] = channelWeights[ch] * channelWeights[ch];
+
+ MUInt15 endPoints[2][3];
+
+ for (int ep = 0; ep < 2; ep++)
+ for (int ch = 0; ch < 3; ch++)
+ endPoints[ep][ch] = unquantizedEndPoints[ep][ch];
+
+ QuantizeTo565(endPoints[0]);
+ QuantizeTo565(endPoints[1]);
+
+ IndexSelector<3> selector;
+ selector.Init<false>(channelWeights, endPoints, range);
+
+ MUInt15 indexes[16];
+
+ MFloat paranoidFactors[3];
+ for (int ch = 0; ch < 3; ch++)
+ paranoidFactors[ch] = ParanoidFactorForSpan(ParallelMath::LosslessCast<MSInt16>::Cast(endPoints[0][ch]) - ParallelMath::LosslessCast<MSInt16>::Cast(endPoints[1][ch]));
+
+ MFloat error = ParallelMath::MakeFloatZero();
+ AggregatedError<3> aggError;
+ for (int px = 0; px < 16; px++)
+ {
+ MUInt15 index = selector.SelectIndexLDR(floatPixels[px], rtn);
+ indexes[px] = index;
+
+ if (refiner)
+ refiner->ContributeUnweightedPW(preWeightedPixels[px], index);
+
+ MUInt15 reconstructed[3];
+ selector.ReconstructLDRPrecise(index, reconstructed);
+
+ if (flags & Flags::S3TC_Paranoid)
+ {
+ for (int ch = 0; ch < 3; ch++)
+ error = error + ParanoidDiff(reconstructed[ch], pixels[px][ch], paranoidFactors[ch]) * channelWeightsSq[ch];
+ }
+ else
+ BCCommon::ComputeErrorLDR<3>(flags, reconstructed, pixels[px], aggError);
+ }
+
+ if (!(flags & Flags::S3TC_Paranoid))
+ error = aggError.Finalize(flags, channelWeightsSq);
+
+ ParallelMath::FloatCompFlag better = ParallelMath::Less(error, bestError);
+
+ if (ParallelMath::AnySet(better))
+ {
+ ParallelMath::Int16CompFlag betterInt16 = ParallelMath::FloatFlagToInt16(better);
+
+ ParallelMath::ConditionalSet(bestError, better, error);
+
+ for (int ep = 0; ep < 2; ep++)
+ for (int ch = 0; ch < 3; ch++)
+ ParallelMath::ConditionalSet(bestEndpoints[ep][ch], betterInt16, endPoints[ep][ch]);
+
+ for (int px = 0; px < 16; px++)
+ ParallelMath::ConditionalSet(bestIndexes[px], betterInt16, indexes[px]);
+
+ ParallelMath::ConditionalSet(bestRange, betterInt16, ParallelMath::MakeUInt15(static_cast<uint16_t>(range)));
+ }
+ }
+
+ static void TestCounts(uint32_t flags, const int *counts, int nCounts, const MUInt15 &numElements, const MUInt15 pixels[16][4], const MFloat floatPixels[16][4], const MFloat preWeightedPixels[16][4], bool alphaTest,
+ const MFloat floatSortedInputs[16][4], const MFloat preWeightedFloatSortedInputs[16][4], const float *channelWeights, MFloat &bestError, MUInt15 bestEndpoints[2][3], MUInt15 bestIndexes[16], MUInt15 &bestRange,
+ const ParallelMath::RoundTowardNearestForScope* rtn)
+ {
+ UNREFERENCED_PARAMETER(alphaTest);
+ UNREFERENCED_PARAMETER(flags);
+
+ EndpointRefiner<3> refiner;
+
+ refiner.Init(nCounts, channelWeights);
+
+ bool escape = false;
+ int e = 0;
+ for (int i = 0; i < nCounts; i++)
+ {
+ for (int n = 0; n < counts[i]; n++)
+ {
+ ParallelMath::Int16CompFlag valid = ParallelMath::Less(ParallelMath::MakeUInt15(static_cast<uint16_t>(n)), numElements);
+ if (!ParallelMath::AnySet(valid))
+ {
+ escape = true;
+ break;
+ }
+
+ if (ParallelMath::AllSet(valid))
+ refiner.ContributeUnweightedPW(preWeightedFloatSortedInputs[e++], ParallelMath::MakeUInt15(static_cast<uint16_t>(i)));
+ else
+ {
+ MFloat weight = ParallelMath::Select(ParallelMath::Int16FlagToFloat(valid), ParallelMath::MakeFloat(1.0f), ParallelMath::MakeFloat(0.0f));
+ refiner.ContributePW(preWeightedFloatSortedInputs[e++], ParallelMath::MakeUInt15(static_cast<uint16_t>(i)), weight);
+ }
+ }
+
+ if (escape)
+ break;
+ }
+
+ MUInt15 endPoints[2][3];
+ refiner.GetRefinedEndpointsLDR(endPoints, rtn);
+
+ TestEndpoints(flags, pixels, floatPixels, preWeightedPixels, endPoints, nCounts, channelWeights, bestError, bestEndpoints, bestIndexes, bestRange, NULL, rtn);
+ }
+
+ static void PackExplicitAlpha(uint32_t flags, const PixelBlockU8* inputs, int inputChannel, uint8_t* packedBlocks, size_t packedBlockStride)
+ {
+ UNREFERENCED_PARAMETER(flags);
+ ParallelMath::RoundTowardNearestForScope rtn;
+
+ float weights[1] = { 1.0f };
+
+ MUInt15 pixels[16];
+ MFloat floatPixels[16];
+
+ for (int px = 0; px < 16; px++)
+ {
+ ParallelMath::ConvertLDRInputs(inputs, px, inputChannel, pixels[px]);
+ floatPixels[px] = ParallelMath::ToFloat(pixels[px]);
+ }
+
+ MUInt15 ep[2][1] = { { ParallelMath::MakeUInt15(0) },{ ParallelMath::MakeUInt15(255) } };
+
+ IndexSelector<1> selector;
+ selector.Init<false>(weights, ep, 16);
+
+ MUInt15 indexes[16];
+
+ for (int px = 0; px < 16; px++)
+ indexes[px] = selector.SelectIndexLDR(&floatPixels[px], &rtn);
+
+ for (int block = 0; block < ParallelMath::ParallelSize; block++)
+ {
+ for (int px = 0; px < 16; px += 8)
+ {
+ int index0 = ParallelMath::Extract(indexes[px], block);
+ int index1 = ParallelMath::Extract(indexes[px], block);
+
+ packedBlocks[px / 2] = static_cast<uint8_t>(index0 | (index1 << 4));
+ }
+
+ packedBlocks += packedBlockStride;
+ }
+ }
+
+ static void PackInterpolatedAlpha(uint32_t flags, const PixelBlockU8* inputs, int inputChannel, uint8_t* packedBlocks, size_t packedBlockStride, bool isSigned, int maxTweakRounds, int numRefineRounds)
+ {
+ if (maxTweakRounds < 1)
+ maxTweakRounds = 1;
+
+ if (numRefineRounds < 1)
+ numRefineRounds = 1;
+
+ ParallelMath::RoundTowardNearestForScope rtn;
+
+ float oneWeight[1] = { 1.0f };
+
+ MUInt15 pixels[16];
+ MFloat floatPixels[16];
+
+ MUInt15 highTerminal = isSigned ? ParallelMath::MakeUInt15(254) : ParallelMath::MakeUInt15(255);
+ MUInt15 highTerminalMinusOne = highTerminal - ParallelMath::MakeUInt15(1);
+
+ for (int px = 0; px < 16; px++)
+ {
+ ParallelMath::ConvertLDRInputs(inputs, px, inputChannel, pixels[px]);
+
+ if (isSigned)
+ pixels[px] = ParallelMath::Min(pixels[px], highTerminal);
+
+ floatPixels[px] = ParallelMath::ToFloat(pixels[px]);
+ }
+
+ MUInt15 sortedPixels[16];
+ for (int px = 0; px < 16; px++)
+ sortedPixels[px] = pixels[px];
+
+ for (int sortEnd = 15; sortEnd > 0; sortEnd--)
+ {
+ for (int sortOffset = 0; sortOffset < sortEnd; sortOffset++)
+ {
+ MUInt15 a = sortedPixels[sortOffset];
+ MUInt15 b = sortedPixels[sortOffset + 1];
+
+ sortedPixels[sortOffset] = ParallelMath::Min(a, b);
+ sortedPixels[sortOffset + 1] = ParallelMath::Max(a, b);
+ }
+ }
+
+ MUInt15 zero = ParallelMath::MakeUInt15(0);
+ MUInt15 one = ParallelMath::MakeUInt15(1);
+
+ MUInt15 bestIsFullRange = zero;
+ MFloat bestError = ParallelMath::MakeFloat(FLT_MAX);
+ MUInt15 bestEP[2] = { zero, zero };
+ MUInt15 bestIndexes[16] = {
+ zero, zero, zero, zero,
+ zero, zero, zero, zero,
+ zero, zero, zero, zero,
+ zero, zero, zero, zero
+ };
+
+ // Full-precision
+ {
+ MUInt15 minEP = sortedPixels[0];
+ MUInt15 maxEP = sortedPixels[15];
+
+ MFloat base[1] = { ParallelMath::ToFloat(minEP) };
+ MFloat offset[1] = { ParallelMath::ToFloat(maxEP - minEP) };
+
+ UnfinishedEndpoints<1> ufep = UnfinishedEndpoints<1>(base, offset);
+
+ int numTweakRounds = BCCommon::TweakRoundsForRange(8);
+ if (numTweakRounds > maxTweakRounds)
+ numTweakRounds = maxTweakRounds;
+
+ for (int tweak = 0; tweak < numTweakRounds; tweak++)
+ {
+ MUInt15 ep[2][1];
+
+ ufep.FinishLDR(tweak, 8, ep[0], ep[1]);
+
+ for (int refinePass = 0; refinePass < numRefineRounds; refinePass++)
+ {
+ EndpointRefiner<1> refiner;
+ refiner.Init(8, oneWeight);
+
+ if (isSigned)
+ for (int epi = 0; epi < 2; epi++)
+ ep[epi][0] = ParallelMath::Min(ep[epi][0], highTerminal);
+
+ IndexSelector<1> indexSelector;
+ indexSelector.Init<false>(oneWeight, ep, 8);
+
+ MUInt15 indexes[16];
+
+ AggregatedError<1> aggError;
+ for (int px = 0; px < 16; px++)
+ {
+ MUInt15 index = indexSelector.SelectIndexLDR(&floatPixels[px], &rtn);
+
+ MUInt15 reconstructedPixel;
+
+ indexSelector.ReconstructLDRPrecise(index, &reconstructedPixel);
+ BCCommon::ComputeErrorLDR<1>(flags, &reconstructedPixel, &pixels[px], aggError);
+
+ if (refinePass != numRefineRounds - 1)
+ refiner.ContributeUnweightedPW(&floatPixels[px], index);
+
+ indexes[px] = index;
+ }
+ MFloat error = aggError.Finalize(flags | Flags::Uniform, oneWeight);
+
+ ParallelMath::FloatCompFlag errorBetter = ParallelMath::Less(error, bestError);
+ ParallelMath::Int16CompFlag errorBetter16 = ParallelMath::FloatFlagToInt16(errorBetter);
+
+ if (ParallelMath::AnySet(errorBetter16))
+ {
+ bestError = ParallelMath::Min(error, bestError);
+ ParallelMath::ConditionalSet(bestIsFullRange, errorBetter16, one);
+ for (int px = 0; px < 16; px++)
+ ParallelMath::ConditionalSet(bestIndexes[px], errorBetter16, indexes[px]);
+
+ for (int epi = 0; epi < 2; epi++)
+ ParallelMath::ConditionalSet(bestEP[epi], errorBetter16, ep[epi][0]);
+ }
+
+ if (refinePass != numRefineRounds - 1)
+ refiner.GetRefinedEndpointsLDR(ep, &rtn);
+ }
+ }
+ }
+
+ // Reduced precision with special endpoints
+ {
+ MUInt15 bestHeuristicMin = sortedPixels[0];
+ MUInt15 bestHeuristicMax = sortedPixels[15];
+
+ ParallelMath::Int16CompFlag canTryClipping;
+
+ // In reduced precision, we want try putting endpoints at the reserved indexes at the ends.
+ // The heuristic we use is to assign indexes to the end as long as they aren't off by more than half of the index range.
+ // This will usually not find anything, but it's cheap to check.
+
+ {
+ MUInt15 largestPossibleRange = bestHeuristicMax - bestHeuristicMin; // Max: 255
+ MUInt15 lowestPossibleClearance = ParallelMath::Min(bestHeuristicMin, static_cast<MUInt15>(highTerminal - bestHeuristicMax));
+
+ MUInt15 lowestPossibleClearanceTimes10 = (lowestPossibleClearance << 2) + (lowestPossibleClearance << 4);
+ canTryClipping = ParallelMath::LessOrEqual(lowestPossibleClearanceTimes10, largestPossibleRange);
+ }
+
+ if (ParallelMath::AnySet(canTryClipping))
+ {
+ MUInt15 lowClearances[16];
+ MUInt15 highClearances[16];
+ MUInt15 bestSkipCount = ParallelMath::MakeUInt15(0);
+
+ lowClearances[0] = highClearances[0] = ParallelMath::MakeUInt15(0);
+
+ for (int px = 1; px < 16; px++)
+ {
+ lowClearances[px] = sortedPixels[px - 1];
+ highClearances[px] = highTerminal - sortedPixels[16 - px];
+ }
+
+ for (uint16_t firstIndex = 0; firstIndex < 16; firstIndex++)
+ {
+ uint16_t numSkippedLow = firstIndex;
+
+ MUInt15 lowClearance = lowClearances[firstIndex];
+
+ for (uint16_t lastIndex = firstIndex; lastIndex < 16; lastIndex++)
+ {
+ uint16_t numSkippedHigh = 15 - lastIndex;
+ uint16_t numSkipped = numSkippedLow + numSkippedHigh;
+
+ MUInt15 numSkippedV = ParallelMath::MakeUInt15(numSkipped);
+
+ ParallelMath::Int16CompFlag areMoreSkipped = ParallelMath::Less(bestSkipCount, numSkippedV);
+
+ if (!ParallelMath::AnySet(areMoreSkipped))
+ continue;
+
+ MUInt15 clearance = ParallelMath::Max(highClearances[numSkippedHigh], lowClearance);
+ MUInt15 clearanceTimes10 = (clearance << 2) + (clearance << 4);
+
+ MUInt15 range = sortedPixels[lastIndex] - sortedPixels[firstIndex];
+
+ ParallelMath::Int16CompFlag isBetter = (areMoreSkipped & ParallelMath::LessOrEqual(clearanceTimes10, range));
+ ParallelMath::ConditionalSet(bestHeuristicMin, isBetter, sortedPixels[firstIndex]);
+ ParallelMath::ConditionalSet(bestHeuristicMax, isBetter, sortedPixels[lastIndex]);
+ }
+ }
+ }
+
+ MUInt15 bestSimpleMin = one;
+ MUInt15 bestSimpleMax = highTerminalMinusOne;
+
+ for (int px = 0; px < 16; px++)
+ {
+ ParallelMath::ConditionalSet(bestSimpleMin, ParallelMath::Less(zero, sortedPixels[15 - px]), sortedPixels[15 - px]);
+ ParallelMath::ConditionalSet(bestSimpleMax, ParallelMath::Less(sortedPixels[px], highTerminal), sortedPixels[px]);
+ }
+
+ MUInt15 minEPs[2] = { bestSimpleMin, bestHeuristicMin };
+ MUInt15 maxEPs[2] = { bestSimpleMax, bestHeuristicMax };
+
+ int minEPRange = 2;
+ if (ParallelMath::AllSet(ParallelMath::Equal(minEPs[0], minEPs[1])))
+ minEPRange = 1;
+
+ int maxEPRange = 2;
+ if (ParallelMath::AllSet(ParallelMath::Equal(maxEPs[0], maxEPs[1])))
+ maxEPRange = 1;
+
+ for (int minEPIndex = 0; minEPIndex < minEPRange; minEPIndex++)
+ {
+ for (int maxEPIndex = 0; maxEPIndex < maxEPRange; maxEPIndex++)
+ {
+ MFloat base[1] = { ParallelMath::ToFloat(minEPs[minEPIndex]) };
+ MFloat offset[1] = { ParallelMath::ToFloat(maxEPs[maxEPIndex] - minEPs[minEPIndex]) };
+
+ UnfinishedEndpoints<1> ufep = UnfinishedEndpoints<1>(base, offset);
+
+ int numTweakRounds = BCCommon::TweakRoundsForRange(6);
+ if (numTweakRounds > maxTweakRounds)
+ numTweakRounds = maxTweakRounds;
+
+ for (int tweak = 0; tweak < numTweakRounds; tweak++)
+ {
+ MUInt15 ep[2][1];
+
+ ufep.FinishLDR(tweak, 8, ep[0], ep[1]);
+
+ for (int refinePass = 0; refinePass < numRefineRounds; refinePass++)
+ {
+ EndpointRefiner<1> refiner;
+ refiner.Init(6, oneWeight);
+
+ if (isSigned)
+ for (int epi = 0; epi < 2; epi++)
+ ep[epi][0] = ParallelMath::Min(ep[epi][0], highTerminal);
+
+ IndexSelector<1> indexSelector;
+ indexSelector.Init<false>(oneWeight, ep, 6);
+
+ MUInt15 indexes[16];
+ MFloat error = ParallelMath::MakeFloatZero();
+
+ for (int px = 0; px < 16; px++)
+ {
+ MUInt15 selectedIndex = indexSelector.SelectIndexLDR(&floatPixels[px], &rtn);
+
+ MUInt15 reconstructedPixel;
+
+ indexSelector.ReconstructLDRPrecise(selectedIndex, &reconstructedPixel);
+
+ MFloat zeroError = BCCommon::ComputeErrorLDRSimple<1>(flags | Flags::Uniform, &zero, &pixels[px], 1, oneWeight);
+ MFloat highTerminalError = BCCommon::ComputeErrorLDRSimple<1>(flags | Flags::Uniform, &highTerminal, &pixels[px], 1, oneWeight);
+ MFloat selectedIndexError = BCCommon::ComputeErrorLDRSimple<1>(flags | Flags::Uniform, &reconstructedPixel, &pixels[px], 1, oneWeight);
+
+ MFloat bestPixelError = zeroError;
+ MUInt15 index = ParallelMath::MakeUInt15(6);
+
+ ParallelMath::ConditionalSet(index, ParallelMath::FloatFlagToInt16(ParallelMath::Less(highTerminalError, bestPixelError)), ParallelMath::MakeUInt15(7));
+ bestPixelError = ParallelMath::Min(bestPixelError, highTerminalError);
+
+ ParallelMath::FloatCompFlag selectedIndexBetter = ParallelMath::Less(selectedIndexError, bestPixelError);
+
+ if (ParallelMath::AllSet(selectedIndexBetter))
+ {
+ if (refinePass != numRefineRounds - 1)
+ refiner.ContributeUnweightedPW(&floatPixels[px], selectedIndex);
+ }
+ else
+ {
+ MFloat refineWeight = ParallelMath::Select(selectedIndexBetter, ParallelMath::MakeFloat(1.0f), ParallelMath::MakeFloatZero());
+
+ if (refinePass != numRefineRounds - 1)
+ refiner.ContributePW(&floatPixels[px], selectedIndex, refineWeight);
+ }
+
+ ParallelMath::ConditionalSet(index, ParallelMath::FloatFlagToInt16(selectedIndexBetter), selectedIndex);
+ bestPixelError = ParallelMath::Min(bestPixelError, selectedIndexError);
+
+ error = error + bestPixelError;
+
+ indexes[px] = index;
+ }
+
+ ParallelMath::FloatCompFlag errorBetter = ParallelMath::Less(error, bestError);
+ ParallelMath::Int16CompFlag errorBetter16 = ParallelMath::FloatFlagToInt16(errorBetter);
+
+ if (ParallelMath::AnySet(errorBetter16))
+ {
+ bestError = ParallelMath::Min(error, bestError);
+ ParallelMath::ConditionalSet(bestIsFullRange, errorBetter16, zero);
+ for (int px = 0; px < 16; px++)
+ ParallelMath::ConditionalSet(bestIndexes[px], errorBetter16, indexes[px]);
+
+ for (int epi = 0; epi < 2; epi++)
+ ParallelMath::ConditionalSet(bestEP[epi], errorBetter16, ep[epi][0]);
+ }
+
+ if (refinePass != numRefineRounds - 1)
+ refiner.GetRefinedEndpointsLDR(ep, &rtn);
+ }
+ }
+ }
+ }
+ }
+
+ for (int block = 0; block < ParallelMath::ParallelSize; block++)
+ {
+ int ep0 = ParallelMath::Extract(bestEP[0], block);
+ int ep1 = ParallelMath::Extract(bestEP[1], block);
+ int isFullRange = ParallelMath::Extract(bestIsFullRange, block);
+
+ if (isSigned)
+ {
+ ep0 -= 127;
+ ep1 -= 127;
+
+ assert(ep0 >= -127 && ep0 <= 127);
+ assert(ep1 >= -127 && ep1 <= 127);
+ }
+
+
+ bool swapEndpoints = (isFullRange != 0) != (ep0 > ep1);
+
+ if (swapEndpoints)
+ std::swap(ep0, ep1);
+
+ uint16_t dumpBits = 0;
+ int dumpBitsOffset = 0;
+ int dumpByteOffset = 2;
+ packedBlocks[0] = static_cast<uint8_t>(ep0 & 0xff);
+ packedBlocks[1] = static_cast<uint8_t>(ep1 & 0xff);
+
+ int maxValue = (isFullRange != 0) ? 7 : 5;
+
+ for (int px = 0; px < 16; px++)
+ {
+ int index = ParallelMath::Extract(bestIndexes[px], block);
+
+ if (swapEndpoints && index <= maxValue)
+ index = maxValue - index;
+
+ if (index != 0)
+ {
+ if (index == maxValue)
+ index = 1;
+ else if (index < maxValue)
+ index++;
+ }
+
+ assert(index >= 0 && index < 8);
+
+ dumpBits |= static_cast<uint16_t>(index << dumpBitsOffset);
+ dumpBitsOffset += 3;
+
+ if (dumpBitsOffset >= 8)
+ {
+ assert(dumpByteOffset < 8);
+ packedBlocks[dumpByteOffset] = static_cast<uint8_t>(dumpBits & 0xff);
+ dumpBits >>= 8;
+ dumpBitsOffset -= 8;
+ dumpByteOffset++;
+ }
+ }
+
+ assert(dumpBitsOffset == 0);
+ assert(dumpByteOffset == 8);
+
+ packedBlocks += packedBlockStride;
+ }
+ }
+
+ static void PackRGB(uint32_t flags, const PixelBlockU8* inputs, uint8_t* packedBlocks, size_t packedBlockStride, const float channelWeights[4], bool alphaTest, float alphaThreshold, bool exhaustive, int maxTweakRounds, int numRefineRounds)
+ {
+ ParallelMath::RoundTowardNearestForScope rtn;
+
+ if (numRefineRounds < 1)
+ numRefineRounds = 1;
+
+ if (maxTweakRounds < 1)
+ maxTweakRounds = 1;
+
+ EndpointSelector<3, 8> endpointSelector;
+
+ MUInt15 pixels[16][4];
+ MFloat floatPixels[16][4];
+
+ MFloat preWeightedPixels[16][4];
+
+ for (int px = 0; px < 16; px++)
+ {
+ for (int ch = 0; ch < 4; ch++)
+ ParallelMath::ConvertLDRInputs(inputs, px, ch, pixels[px][ch]);
+ }
+
+ for (int px = 0; px < 16; px++)
+ {
+ for (int ch = 0; ch < 4; ch++)
+ floatPixels[px][ch] = ParallelMath::ToFloat(pixels[px][ch]);
+ }
+
+ if (alphaTest)
+ {
+ MUInt15 threshold = ParallelMath::MakeUInt15(static_cast<uint16_t>(floor(alphaThreshold * 255.0f + 0.5f)));
+
+ for (int px = 0; px < 16; px++)
+ {
+ ParallelMath::Int16CompFlag belowThreshold = ParallelMath::Less(pixels[px][3], threshold);
+ pixels[px][3] = ParallelMath::Select(belowThreshold, ParallelMath::MakeUInt15(0), ParallelMath::MakeUInt15(255));
+ }
+ }
+
+ BCCommon::PreWeightPixelsLDR<4>(preWeightedPixels, pixels, channelWeights);
+
+ MUInt15 minAlpha = ParallelMath::MakeUInt15(255);
+
+ for (int px = 0; px < 16; px++)
+ minAlpha = ParallelMath::Min(minAlpha, pixels[px][3]);
+
+ MFloat pixelWeights[16];
+ for (int px = 0; px < 16; px++)
+ {
+ pixelWeights[px] = ParallelMath::MakeFloat(1.0f);
+ if (alphaTest)
+ {
+ ParallelMath::Int16CompFlag isTransparent = ParallelMath::Less(pixels[px][3], ParallelMath::MakeUInt15(255));
+
+ ParallelMath::ConditionalSet(pixelWeights[px], ParallelMath::Int16FlagToFloat(isTransparent), ParallelMath::MakeFloatZero());
+ }
+ }
+
+ for (int pass = 0; pass < NumEndpointSelectorPasses; pass++)
+ {
+ for (int px = 0; px < 16; px++)
+ endpointSelector.ContributePass(preWeightedPixels[px], pass, pixelWeights[px]);
+
+ endpointSelector.FinishPass(pass);
+ }
+
+ UnfinishedEndpoints<3> ufep = endpointSelector.GetEndpoints(channelWeights);
+
+ MUInt15 bestEndpoints[2][3];
+ MUInt15 bestIndexes[16];
+ MUInt15 bestRange = ParallelMath::MakeUInt15(0);
+ MFloat bestError = ParallelMath::MakeFloat(FLT_MAX);
+
+ for (int px = 0; px < 16; px++)
+ bestIndexes[px] = ParallelMath::MakeUInt15(0);
+
+ for (int ep = 0; ep < 2; ep++)
+ for (int ch = 0; ch < 3; ch++)
+ bestEndpoints[ep][ch] = ParallelMath::MakeUInt15(0);
+
+ if (exhaustive)
+ {
+ MSInt16 sortBins[16];
+
+ {
+ // Compute an 11-bit index, change it to signed, stuff it in the high bits of the sort bins,
+ // and pack the original indexes into the low bits.
+
+ MUInt15 sortEP[2][3];
+ ufep.FinishLDR(0, 11, sortEP[0], sortEP[1]);
+
+ IndexSelector<3> sortSelector;
+ sortSelector.Init<false>(channelWeights, sortEP, 1 << 11);
+
+ for (int16_t px = 0; px < 16; px++)
+ {
+ MSInt16 sortBin = ParallelMath::LosslessCast<MSInt16>::Cast(sortSelector.SelectIndexLDR(floatPixels[px], &rtn) << 4);
+
+ if (alphaTest)
+ {
+ ParallelMath::Int16CompFlag isTransparent = ParallelMath::Less(pixels[px][3], ParallelMath::MakeUInt15(255));
+
+ ParallelMath::ConditionalSet(sortBin, isTransparent, ParallelMath::MakeSInt16(-16)); // 0xfff0
+ }
+
+ sortBin = sortBin + ParallelMath::MakeSInt16(px);
+
+ sortBins[px] = sortBin;
+ }
+ }
+
+ // Sort bins
+ for (int sortEnd = 1; sortEnd < 16; sortEnd++)
+ {
+ for (int sortLoc = sortEnd; sortLoc > 0; sortLoc--)
+ {
+ MSInt16 a = sortBins[sortLoc];
+ MSInt16 b = sortBins[sortLoc - 1];
+
+ sortBins[sortLoc] = ParallelMath::Max(a, b);
+ sortBins[sortLoc - 1] = ParallelMath::Min(a, b);
+ }
+ }
+
+ MUInt15 firstElement = ParallelMath::MakeUInt15(0);
+ for (uint16_t e = 0; e < 16; e++)
+ {
+ ParallelMath::Int16CompFlag isInvalid = ParallelMath::Less(sortBins[e], ParallelMath::MakeSInt16(0));
+ ParallelMath::ConditionalSet(firstElement, isInvalid, ParallelMath::MakeUInt15(e + 1));
+ if (!ParallelMath::AnySet(isInvalid))
+ break;
+ }
+
+ MUInt15 numElements = ParallelMath::MakeUInt15(16) - firstElement;
+
+ MUInt15 sortedInputs[16][4];
+ MFloat floatSortedInputs[16][4];
+ MFloat pwFloatSortedInputs[16][4];
+
+ for (int e = 0; e < 16; e++)
+ {
+ for (int ch = 0; ch < 4; ch++)
+ sortedInputs[e][ch] = ParallelMath::MakeUInt15(0);
+ }
+
+ for (int block = 0; block < ParallelMath::ParallelSize; block++)
+ {
+ for (int e = ParallelMath::Extract(firstElement, block); e < 16; e++)
+ {
+ ParallelMath::ScalarUInt16 sortBin = ParallelMath::Extract(sortBins[e], block);
+ int originalIndex = (sortBin & 15);
+
+ for (int ch = 0; ch < 4; ch++)
+ ParallelMath::PutUInt15(sortedInputs[15 - e][ch], block, ParallelMath::Extract(pixels[originalIndex][ch], block));
+ }
+ }
+
+ for (int e = 0; e < 16; e++)
+ {
+ for (int ch = 0; ch < 4; ch++)
+ {
+ MFloat f = ParallelMath::ToFloat(sortedInputs[e][ch]);
+ floatSortedInputs[e][ch] = f;
+ pwFloatSortedInputs[e][ch] = f * channelWeights[ch];
+ }
+ }
+
+ for (int n0 = 0; n0 <= 15; n0++)
+ {
+ int remainingFor1 = 16 - n0;
+ if (remainingFor1 == 16)
+ remainingFor1 = 15;
+
+ for (int n1 = 0; n1 <= remainingFor1; n1++)
+ {
+ int remainingFor2 = 16 - n1 - n0;
+ if (remainingFor2 == 16)
+ remainingFor2 = 15;
+
+ for (int n2 = 0; n2 <= remainingFor2; n2++)
+ {
+ int n3 = 16 - n2 - n1 - n0;
+
+ if (n3 == 16)
+ continue;
+
+ int counts[4] = { n0, n1, n2, n3 };
+
+ TestCounts(flags, counts, 4, numElements, pixels, floatPixels, preWeightedPixels, alphaTest, floatSortedInputs, pwFloatSortedInputs, channelWeights, bestError, bestEndpoints, bestIndexes, bestRange, &rtn);
+ }
+ }
+ }
+
+ TestSingleColor(flags, pixels, floatPixels, 4, channelWeights, bestError, bestEndpoints, bestIndexes, bestRange, &rtn);
+
+ if (alphaTest)
+ {
+ for (int n0 = 0; n0 <= 15; n0++)
+ {
+ int remainingFor1 = 16 - n0;
+ if (remainingFor1 == 16)
+ remainingFor1 = 15;
+
+ for (int n1 = 0; n1 <= remainingFor1; n1++)
+ {
+ int n2 = 16 - n1 - n0;
+
+ if (n2 == 16)
+ continue;
+
+ int counts[3] = { n0, n1, n2 };
+
+ TestCounts(flags, counts, 3, numElements, pixels, floatPixels, preWeightedPixels, alphaTest, floatSortedInputs, pwFloatSortedInputs, channelWeights, bestError, bestEndpoints, bestIndexes, bestRange, &rtn);
+ }
+ }
+
+ TestSingleColor(flags, pixels, floatPixels, 3, channelWeights, bestError, bestEndpoints, bestIndexes, bestRange, &rtn);
+ }
+ }
+ else
+ {
+ int minRange = alphaTest ? 3 : 4;
+
+ for (int range = minRange; range <= 4; range++)
+ {
+ int tweakRounds = BCCommon::TweakRoundsForRange(range);
+ if (tweakRounds > maxTweakRounds)
+ tweakRounds = maxTweakRounds;
+
+ for (int tweak = 0; tweak < tweakRounds; tweak++)
+ {
+ MUInt15 endPoints[2][3];
+
+ ufep.FinishLDR(tweak, range, endPoints[0], endPoints[1]);
+
+ for (int refine = 0; refine < numRefineRounds; refine++)
+ {
+ EndpointRefiner<3> refiner;
+ refiner.Init(range, channelWeights);
+
+ TestEndpoints(flags, pixels, floatPixels, preWeightedPixels, endPoints, range, channelWeights, bestError, bestEndpoints, bestIndexes, bestRange, &refiner, &rtn);
+
+ if (refine != numRefineRounds - 1)
+ refiner.GetRefinedEndpointsLDR(endPoints, &rtn);
+ }
+ }
+ }
+ }
+
+ for (int block = 0; block < ParallelMath::ParallelSize; block++)
+ {
+ ParallelMath::ScalarUInt16 range = ParallelMath::Extract(bestRange, block);
+ assert(range == 3 || range == 4);
+
+ ParallelMath::ScalarUInt16 compressedEP[2];
+ for (int ep = 0; ep < 2; ep++)
+ {
+ ParallelMath::ScalarUInt16 endPoint[3];
+ for (int ch = 0; ch < 3; ch++)
+ endPoint[ch] = ParallelMath::Extract(bestEndpoints[ep][ch], block);
+
+ int compressed = (endPoint[0] & 0xf8) << 8;
+ compressed |= (endPoint[1] & 0xfc) << 3;
+ compressed |= (endPoint[2] & 0xf8) >> 3;
+
+ compressedEP[ep] = static_cast<ParallelMath::ScalarUInt16>(compressed);
+ }
+
+ int indexOrder[4];
+
+ if (range == 4)
+ {
+ if (compressedEP[0] == compressedEP[1])
+ {
+ indexOrder[0] = 0;
+ indexOrder[1] = 0;
+ indexOrder[2] = 0;
+ indexOrder[3] = 0;
+ }
+ else if (compressedEP[0] < compressedEP[1])
+ {
+ std::swap(compressedEP[0], compressedEP[1]);
+ indexOrder[0] = 1;
+ indexOrder[1] = 3;
+ indexOrder[2] = 2;
+ indexOrder[3] = 0;
+ }
+ else
+ {
+ indexOrder[0] = 0;
+ indexOrder[1] = 2;
+ indexOrder[2] = 3;
+ indexOrder[3] = 1;
+ }
+ }
+ else
+ {
+ assert(range == 3);
+
+ if (compressedEP[0] > compressedEP[1])
+ {
+ std::swap(compressedEP[0], compressedEP[1]);
+ indexOrder[0] = 1;
+ indexOrder[1] = 2;
+ indexOrder[2] = 0;
+ }
+ else
+ {
+ indexOrder[0] = 0;
+ indexOrder[1] = 2;
+ indexOrder[2] = 1;
+ }
+ indexOrder[3] = 3;
+ }
+
+ packedBlocks[0] = static_cast<uint8_t>(compressedEP[0] & 0xff);
+ packedBlocks[1] = static_cast<uint8_t>((compressedEP[0] >> 8) & 0xff);
+ packedBlocks[2] = static_cast<uint8_t>(compressedEP[1] & 0xff);
+ packedBlocks[3] = static_cast<uint8_t>((compressedEP[1] >> 8) & 0xff);
+
+ for (int i = 0; i < 16; i += 4)
+ {
+ int packedIndexes = 0;
+ for (int subi = 0; subi < 4; subi++)
+ {
+ ParallelMath::ScalarUInt16 index = ParallelMath::Extract(bestIndexes[i + subi], block);
+ packedIndexes |= (indexOrder[index] << (subi * 2));
+ }
+
+ packedBlocks[4 + i / 4] = static_cast<uint8_t>(packedIndexes);
+ }
+
+ packedBlocks += packedBlockStride;
+ }
+ }
+ };
+
+ // Signed input blocks are converted into unsigned space, with the maximum value being 254
+ void BiasSignedInput(PixelBlockU8 inputNormalized[ParallelMath::ParallelSize], const PixelBlockS8 inputSigned[ParallelMath::ParallelSize])
+ {
+ for (size_t block = 0; block < ParallelMath::ParallelSize; block++)
+ {
+ const PixelBlockS8& inputSignedBlock = inputSigned[block];
+ PixelBlockU8& inputNormalizedBlock = inputNormalized[block];
+
+ for (size_t px = 0; px < 16; px++)
+ {
+ for (size_t ch = 0; ch < 4; ch++)
+ inputNormalizedBlock.m_pixels[px][ch] = static_cast<uint8_t>(std::max<int>(inputSignedBlock.m_pixels[px][ch], -127) + 127);
+ }
+ }
+ }
+
+ void FillWeights(const Options &options, float channelWeights[4])
+ {
+ if (options.flags & Flags::Uniform)
+ channelWeights[0] = channelWeights[1] = channelWeights[2] = channelWeights[3] = 1.0f;
+ else
+ {
+ channelWeights[0] = options.redWeight;
+ channelWeights[1] = options.greenWeight;
+ channelWeights[2] = options.blueWeight;
+ channelWeights[3] = options.alphaWeight;
+ }
+ }
+ }
+
+ namespace Kernels
+ {
+ void EncodeBC7(uint8_t *pBC, const PixelBlockU8 *pBlocks, const cvtt::Options &options)
+ {
+ assert(pBlocks);
+ assert(pBC);
+
+ float channelWeights[4];
+ Internal::FillWeights(options, channelWeights);
+
+ for (size_t blockBase = 0; blockBase < cvtt::NumParallelBlocks; blockBase += ParallelMath::ParallelSize)
+ {
+ Internal::BC7Computer::Pack(options.flags, pBlocks + blockBase, pBC, channelWeights, options.seedPoints, options.refineRoundsBC7);
+ pBC += ParallelMath::ParallelSize * 16;
+ }
+ }
+
+ void EncodeBC6HU(uint8_t *pBC, const PixelBlockF16 *pBlocks, const cvtt::Options &options)
+ {
+ assert(pBlocks);
+ assert(pBC);
+
+ float channelWeights[4];
+ Internal::FillWeights(options, channelWeights);
+
+ for (size_t blockBase = 0; blockBase < cvtt::NumParallelBlocks; blockBase += ParallelMath::ParallelSize)
+ {
+ Internal::BC6HComputer::Pack(options.flags, pBlocks + blockBase, pBC, channelWeights, false, options.seedPoints, options.refineRoundsBC6H);
+ pBC += ParallelMath::ParallelSize * 16;
+ }
+ }
+
+ void EncodeBC6HS(uint8_t *pBC, const PixelBlockF16 *pBlocks, const cvtt::Options &options)
+ {
+ assert(pBlocks);
+ assert(pBC);
+
+ float channelWeights[4];
+ Internal::FillWeights(options, channelWeights);
+
+ for (size_t blockBase = 0; blockBase < cvtt::NumParallelBlocks; blockBase += ParallelMath::ParallelSize)
+ {
+ Internal::BC6HComputer::Pack(options.flags, pBlocks + blockBase, pBC, channelWeights, true, options.seedPoints, options.refineRoundsBC6H);
+ pBC += ParallelMath::ParallelSize * 16;
+ }
+ }
+
+ void EncodeBC1(uint8_t *pBC, const PixelBlockU8 *pBlocks, const cvtt::Options &options)
+ {
+ assert(pBlocks);
+ assert(pBC);
+
+ float channelWeights[4];
+ Internal::FillWeights(options, channelWeights);
+
+ for (size_t blockBase = 0; blockBase < cvtt::NumParallelBlocks; blockBase += ParallelMath::ParallelSize)
+ {
+ Internal::S3TCComputer::PackRGB(options.flags, pBlocks + blockBase, pBC, 8, channelWeights, true, options.threshold, (options.flags & Flags::S3TC_Exhaustive) != 0, options.seedPoints, options.refineRoundsS3TC);
+ pBC += ParallelMath::ParallelSize * 8;
+ }
+ }
+
+ void EncodeBC2(uint8_t *pBC, const PixelBlockU8 *pBlocks, const Options &options)
+ {
+ assert(pBlocks);
+ assert(pBC);
+
+ float channelWeights[4];
+ Internal::FillWeights(options, channelWeights);
+
+ for (size_t blockBase = 0; blockBase < NumParallelBlocks; blockBase += ParallelMath::ParallelSize)
+ {
+ Internal::S3TCComputer::PackRGB(options.flags, pBlocks + blockBase, pBC + 8, 16, channelWeights, false, 1.0f, (options.flags & Flags::S3TC_Exhaustive) != 0, options.seedPoints, options.refineRoundsS3TC);
+ Internal::S3TCComputer::PackExplicitAlpha(options.flags, pBlocks + blockBase, 3, pBC, 16);
+ pBC += ParallelMath::ParallelSize * 16;
+ }
+ }
+
+ void EncodeBC3(uint8_t *pBC, const PixelBlockU8 *pBlocks, const Options &options)
+ {
+ assert(pBlocks);
+ assert(pBC);
+
+ float channelWeights[4];
+ Internal::FillWeights(options, channelWeights);
+
+ for (size_t blockBase = 0; blockBase < NumParallelBlocks; blockBase += ParallelMath::ParallelSize)
+ {
+ Internal::S3TCComputer::PackRGB(options.flags, pBlocks + blockBase, pBC + 8, 16, channelWeights, false, 1.0f, (options.flags & Flags::S3TC_Exhaustive) != 0, options.seedPoints, options.refineRoundsS3TC);
+ Internal::S3TCComputer::PackInterpolatedAlpha(options.flags, pBlocks + blockBase, 3, pBC, 16, false, options.seedPoints, options.refineRoundsIIC);
+ pBC += ParallelMath::ParallelSize * 16;
+ }
+ }
+
+ void EncodeBC4U(uint8_t *pBC, const PixelBlockU8 *pBlocks, const Options &options)
+ {
+ assert(pBlocks);
+ assert(pBC);
+
+ float channelWeights[4];
+ Internal::FillWeights(options, channelWeights);
+
+ for (size_t blockBase = 0; blockBase < NumParallelBlocks; blockBase += ParallelMath::ParallelSize)
+ {
+ Internal::S3TCComputer::PackInterpolatedAlpha(options.flags, pBlocks + blockBase, 0, pBC, 8, false, options.seedPoints, options.refineRoundsIIC);
+ pBC += ParallelMath::ParallelSize * 8;
+ }
+ }
+
+ void EncodeBC4S(uint8_t *pBC, const PixelBlockS8 *pBlocks, const Options &options)
+ {
+ assert(pBlocks);
+ assert(pBC);
+
+ float channelWeights[4];
+ Internal::FillWeights(options, channelWeights);
+
+ for (size_t blockBase = 0; blockBase < NumParallelBlocks; blockBase += ParallelMath::ParallelSize)
+ {
+ PixelBlockU8 inputBlocks[ParallelMath::ParallelSize];
+ Internal::BiasSignedInput(inputBlocks, pBlocks + blockBase);
+
+ Internal::S3TCComputer::PackInterpolatedAlpha(options.flags, inputBlocks, 0, pBC, 8, true, options.seedPoints, options.refineRoundsIIC);
+ pBC += ParallelMath::ParallelSize * 8;
+ }
+ }
+
+ void EncodeBC5U(uint8_t *pBC, const PixelBlockU8 *pBlocks, const Options &options)
+ {
+ assert(pBlocks);
+ assert(pBC);
+
+ float channelWeights[4];
+ Internal::FillWeights(options, channelWeights);
+
+ for (size_t blockBase = 0; blockBase < NumParallelBlocks; blockBase += ParallelMath::ParallelSize)
+ {
+ Internal::S3TCComputer::PackInterpolatedAlpha(options.flags, pBlocks + blockBase, 0, pBC, 16, false, options.seedPoints, options.refineRoundsIIC);
+ Internal::S3TCComputer::PackInterpolatedAlpha(options.flags, pBlocks + blockBase, 1, pBC + 8, 16, false, options.seedPoints, options.refineRoundsIIC);
+ pBC += ParallelMath::ParallelSize * 16;
+ }
+ }
+
+ void EncodeBC5S(uint8_t *pBC, const PixelBlockS8 *pBlocks, const Options &options)
+ {
+ assert(pBlocks);
+ assert(pBC);
+
+ float channelWeights[4];
+ Internal::FillWeights(options, channelWeights);
+
+ for (size_t blockBase = 0; blockBase < NumParallelBlocks; blockBase += ParallelMath::ParallelSize)
+ {
+ PixelBlockU8 inputBlocks[ParallelMath::ParallelSize];
+ Internal::BiasSignedInput(inputBlocks, pBlocks + blockBase);
+
+ Internal::S3TCComputer::PackInterpolatedAlpha(options.flags, inputBlocks, 0, pBC, 16, true, options.seedPoints, options.refineRoundsIIC);
+ Internal::S3TCComputer::PackInterpolatedAlpha(options.flags, inputBlocks, 1, pBC + 8, 16, true, options.seedPoints, options.refineRoundsIIC);
+ pBC += ParallelMath::ParallelSize * 16;
+ }
+ }
+
+ void DecodeBC7(PixelBlockU8 *pBlocks, const uint8_t *pBC)
+ {
+ assert(pBlocks);
+ assert(pBC);
+
+ for (size_t blockBase = 0; blockBase < cvtt::NumParallelBlocks; blockBase++)
+ {
+ Internal::BC7Computer::UnpackOne(pBlocks[blockBase], pBC);
+ pBC += 16;
+ }
+ }
+
+ void DecodeBC6HU(PixelBlockF16 *pBlocks, const uint8_t *pBC)
+ {
+ assert(pBlocks);
+ assert(pBC);
+
+ for (size_t blockBase = 0; blockBase < cvtt::NumParallelBlocks; blockBase++)
+ {
+ Internal::BC6HComputer::UnpackOne(pBlocks[blockBase], pBC, false);
+ pBC += 16;
+ }
+ }
+
+ void DecodeBC6HS(PixelBlockF16 *pBlocks, const uint8_t *pBC)
+ {
+ assert(pBlocks);
+ assert(pBC);
+
+ for (size_t blockBase = 0; blockBase < cvtt::NumParallelBlocks; blockBase++)
+ {
+ Internal::BC6HComputer::UnpackOne(pBlocks[blockBase], pBC, true);
+ pBC += 16;
+ }
+ }
+ }
+}
diff --git a/thirdparty/cvtt/ConvectionKernels.h b/thirdparty/cvtt/ConvectionKernels.h
new file mode 100644
index 0000000000..fb5ca130f9
--- /dev/null
+++ b/thirdparty/cvtt/ConvectionKernels.h
@@ -0,0 +1,145 @@
+/*
+Convection Texture Tools
+Copyright (c) 2018 Eric Lasota
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject
+to the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+#pragma once
+#ifndef __CVTT_CONVECTION_KERNELS__
+#define __CVTT_CONVECTION_KERNELS__
+
+#include <stdint.h>
+
+namespace cvtt
+{
+ namespace Flags
+ {
+ // Enable partitioned modes in BC7 encoding (slower, better quality)
+ const uint32_t BC7_EnablePartitioning = 0x001;
+
+ // Enable 3-partition modes in BC7 encoding (slower, better quality, requires BC7_EnablePartitioning)
+ const uint32_t BC7_Enable3Subsets = 0x002;
+
+ // Enable dual-plane modes in BC7 encoding (slower, better quality)
+ const uint32_t BC7_EnableDualPlane = 0x004;
+
+ // Use fast indexing in BC7 encoding (about 2x faster, slightly worse quality)
+ const uint32_t BC7_FastIndexing = 0x008;
+
+ // Try precomputed single-color lookups where applicable (slightly slower, small quality increase on specific blocks)
+ const uint32_t BC7_TrySingleColor = 0x010;
+
+ // Don't allow non-zero or non-max alpha values in blocks that only contain one or the other
+ const uint32_t BC7_RespectPunchThrough = 0x020;
+
+ // Use fast indexing in HDR formats (faster, worse quality)
+ const uint32_t BC6H_FastIndexing = 0x040;
+
+ // Exhaustive search RGB orderings when encoding BC1-BC3 (much slower, better quality)
+ const uint32_t S3TC_Exhaustive = 0x080;
+
+ // Penalize distant endpoints, improving quality on inaccurate GPU decoders
+ const uint32_t S3TC_Paranoid = 0x100;
+
+ // Uniform color channel importance
+ const uint32_t Uniform = 0x200;
+
+ // Misc useful default flag combinations
+ const uint32_t Fastest = (BC6H_FastIndexing | S3TC_Paranoid);
+ const uint32_t Faster = (BC7_EnableDualPlane | BC6H_FastIndexing | S3TC_Paranoid);
+ const uint32_t Fast = (BC7_EnablePartitioning | BC7_EnableDualPlane | BC7_FastIndexing | S3TC_Paranoid);
+ const uint32_t Default = (BC7_EnablePartitioning | BC7_EnableDualPlane | BC7_Enable3Subsets | BC7_FastIndexing | S3TC_Paranoid);
+ const uint32_t Better = (BC7_EnablePartitioning | BC7_EnableDualPlane | BC7_Enable3Subsets | S3TC_Paranoid | S3TC_Exhaustive);
+ const uint32_t Ultra = (BC7_EnablePartitioning | BC7_EnableDualPlane | BC7_Enable3Subsets | BC7_TrySingleColor | S3TC_Paranoid | S3TC_Exhaustive);
+ }
+
+ const unsigned int NumParallelBlocks = 8;
+
+ struct Options
+ {
+ uint32_t flags; // Bitmask of cvtt::Flags values
+ float threshold; // Alpha test threshold for BC1
+ float redWeight; // Red channel importance
+ float greenWeight; // Green channel importance
+ float blueWeight; // Blue channel importance
+ float alphaWeight; // Alpha channel importance
+
+ int refineRoundsBC7; // Number of refine rounds for BC7
+ int refineRoundsBC6H; // Number of refine rounds for BC6H (max 3)
+ int refineRoundsIIC; // Number of refine rounds for independent interpolated channels (BC3 alpha, BC4, BC5)
+ int refineRoundsS3TC; // Number of refine rounds for S3TC RGB
+
+ int seedPoints; // Number of seed points (min 1, max 4)
+
+ Options()
+ : flags(Flags::Default)
+ , threshold(0.5f)
+ , redWeight(0.2125f / 0.7154f)
+ , greenWeight(1.0f)
+ , blueWeight(0.0721f / 0.7154f)
+ , alphaWeight(1.0f)
+ , refineRoundsBC7(2)
+ , refineRoundsBC6H(3)
+ , refineRoundsIIC(8)
+ , refineRoundsS3TC(2)
+ , seedPoints(4)
+ {
+ }
+ };
+
+ // RGBA input block for unsigned 8-bit formats
+ struct PixelBlockU8
+ {
+ uint8_t m_pixels[16][4];
+ };
+
+ // RGBA input block for signed 8-bit formats
+ struct PixelBlockS8
+ {
+ int8_t m_pixels[16][4];
+ };
+
+ // RGBA input block for half-precision float formats (bit-cast to int16_t)
+ struct PixelBlockF16
+ {
+ int16_t m_pixels[16][4];
+ };
+
+ namespace Kernels
+ {
+ // NOTE: All functions accept and output NumParallelBlocks blocks at once
+ void EncodeBC1(uint8_t *pBC, const PixelBlockU8 *pBlocks, const Options &options);
+ void EncodeBC2(uint8_t *pBC, const PixelBlockU8 *pBlocks, const Options &options);
+ void EncodeBC3(uint8_t *pBC, const PixelBlockU8 *pBlocks, const Options &options);
+ void EncodeBC4U(uint8_t *pBC, const PixelBlockU8 *pBlocks, const Options &options);
+ void EncodeBC4S(uint8_t *pBC, const PixelBlockS8 *pBlocks, const Options &options);
+ void EncodeBC5U(uint8_t *pBC, const PixelBlockU8 *pBlocks, const Options &options);
+ void EncodeBC5S(uint8_t *pBC, const PixelBlockS8 *pBlocks, const Options &options);
+ void EncodeBC6HU(uint8_t *pBC, const PixelBlockF16 *pBlocks, const Options &options);
+ void EncodeBC6HS(uint8_t *pBC, const PixelBlockF16 *pBlocks, const Options &options);
+ void EncodeBC7(uint8_t *pBC, const PixelBlockU8 *pBlocks, const Options &options);
+
+ void DecodeBC6HU(PixelBlockF16 *pBlocks, const uint8_t *pBC);
+ void DecodeBC6HS(PixelBlockF16 *pBlocks, const uint8_t *pBC);
+ void DecodeBC7(PixelBlockU8 *pBlocks, const uint8_t *pBC);
+ }
+}
+
+#endif
diff --git a/thirdparty/cvtt/ConvectionKernels_BC7_SingleColor.h b/thirdparty/cvtt/ConvectionKernels_BC7_SingleColor.h
new file mode 100644
index 0000000000..b5564c0dab
--- /dev/null
+++ b/thirdparty/cvtt/ConvectionKernels_BC7_SingleColor.h
@@ -0,0 +1,1940 @@
+#pragma once
+#include <stdint.h>
+
+namespace cvtt { namespace Tables { namespace BC7SC {
+
+struct TableEntry
+{
+ uint8_t m_min;
+ uint8_t m_max;
+ uint8_t m_actualColor;
+};
+
+struct Table
+{
+ uint8_t m_index;
+ uint8_t m_pBits;
+ TableEntry m_entries[256];
+};
+
+Table g_mode0_p00_i1=
+{
+ 1,
+ 0,
+ {
+ { 0, 0, 0 }, { 0, 0, 0 }, { 0, 16, 2 }, { 0, 16, 2 }, { 0, 33, 5 }, { 0, 33, 5 }, { 0, 33, 5 }, { 0, 49, 7 },
+ { 0, 49, 7 }, { 0, 66, 9 }, { 0, 66, 9 }, { 0, 82, 12 }, { 0, 82, 12 }, { 0, 82, 12 }, { 0, 99, 14 }, { 0, 99, 14 },
+ { 0, 115, 16 }, { 0, 115, 16 }, { 16, 33, 18 }, { 0, 132, 19 }, { 0, 132, 19 }, { 0, 148, 21 }, { 0, 148, 21 }, { 0, 165, 23 },
+ { 0, 165, 23 }, { 0, 181, 25 }, { 0, 181, 25 }, { 0, 198, 28 }, { 0, 198, 28 }, { 0, 198, 28 }, { 0, 214, 30 }, { 33, 16, 31 },
+ { 0, 231, 32 }, { 33, 33, 33 }, { 0, 247, 35 }, { 0, 247, 35 }, { 0, 247, 35 }, { 16, 165, 37 }, { 33, 66, 38 }, { 16, 181, 39 },
+ { 33, 82, 40 }, { 16, 198, 42 }, { 16, 198, 42 }, { 16, 198, 42 }, { 16, 214, 44 }, { 33, 115, 45 }, { 16, 231, 46 }, { 33, 132, 47 },
+ { 16, 247, 48 }, { 33, 148, 49 }, { 33, 148, 49 }, { 49, 66, 51 }, { 33, 165, 52 }, { 33, 165, 52 }, { 33, 181, 54 }, { 33, 181, 54 },
+ { 33, 198, 56 }, { 66, 0, 57 }, { 33, 214, 58 }, { 66, 16, 59 }, { 33, 231, 61 }, { 33, 231, 61 }, { 33, 231, 61 }, { 33, 247, 63 },
+ { 66, 49, 64 }, { 49, 165, 65 }, { 66, 66, 66 }, { 49, 181, 68 }, { 49, 181, 68 }, { 49, 181, 68 }, { 49, 198, 70 }, { 66, 99, 71 },
+ { 49, 214, 72 }, { 66, 115, 73 }, { 49, 231, 75 }, { 49, 231, 75 }, { 49, 231, 75 }, { 49, 247, 77 }, { 66, 148, 78 }, { 66, 148, 78 },
+ { 66, 165, 80 }, { 66, 165, 80 }, { 66, 181, 82 }, { 66, 181, 82 }, { 82, 99, 84 }, { 66, 198, 85 }, { 66, 198, 85 }, { 66, 214, 87 },
+ { 66, 214, 87 }, { 66, 231, 89 }, { 99, 33, 90 }, { 66, 247, 91 }, { 99, 49, 92 }, { 82, 165, 94 }, { 82, 165, 94 }, { 82, 165, 94 },
+ { 82, 181, 96 }, { 99, 82, 97 }, { 82, 198, 98 }, { 99, 99, 99 }, { 82, 214, 101 }, { 82, 214, 101 }, { 82, 214, 101 }, { 82, 231, 103 },
+ { 99, 132, 104 }, { 82, 247, 105 }, { 99, 148, 106 }, { 99, 148, 106 }, { 99, 165, 108 }, { 99, 165, 108 }, { 115, 82, 110 }, { 99, 181, 111 },
+ { 99, 181, 111 }, { 99, 198, 113 }, { 99, 198, 113 }, { 99, 214, 115 }, { 132, 16, 116 }, { 115, 132, 117 }, { 99, 231, 118 }, { 99, 231, 118 },
+ { 99, 247, 120 }, { 99, 247, 120 }, { 115, 165, 122 }, { 132, 66, 123 }, { 115, 181, 124 }, { 132, 82, 125 }, { 115, 198, 127 }, { 115, 198, 127 },
+ { 115, 198, 127 }, { 115, 214, 129 }, { 132, 115, 130 }, { 115, 231, 131 }, { 132, 132, 132 }, { 115, 247, 134 }, { 115, 247, 134 }, { 115, 247, 134 },
+ { 148, 66, 136 }, { 132, 165, 137 }, { 132, 165, 137 }, { 132, 181, 139 }, { 132, 181, 139 }, { 132, 198, 141 }, { 165, 0, 142 }, { 148, 115, 143 },
+ { 132, 214, 144 }, { 132, 214, 144 }, { 132, 231, 146 }, { 132, 231, 146 }, { 132, 247, 148 }, { 165, 49, 149 }, { 148, 165, 150 }, { 165, 66, 151 },
+ { 148, 181, 153 }, { 148, 181, 153 }, { 148, 181, 153 }, { 148, 198, 155 }, { 165, 99, 156 }, { 148, 214, 157 }, { 165, 115, 158 }, { 148, 231, 160 },
+ { 148, 231, 160 }, { 148, 231, 160 }, { 148, 247, 162 }, { 165, 148, 163 }, { 165, 148, 163 }, { 165, 165, 165 }, { 165, 165, 165 }, { 165, 181, 167 },
+ { 165, 181, 167 }, { 181, 99, 169 }, { 165, 198, 170 }, { 165, 198, 170 }, { 165, 214, 172 }, { 165, 214, 172 }, { 165, 231, 174 }, { 198, 33, 175 },
+ { 181, 148, 176 }, { 165, 247, 177 }, { 165, 247, 177 }, { 181, 165, 179 }, { 181, 165, 179 }, { 181, 181, 181 }, { 198, 82, 182 }, { 181, 198, 183 },
+ { 198, 99, 184 }, { 181, 214, 186 }, { 181, 214, 186 }, { 181, 214, 186 }, { 181, 231, 188 }, { 198, 132, 189 }, { 181, 247, 190 }, { 198, 148, 191 },
+ { 198, 148, 191 }, { 198, 165, 193 }, { 198, 165, 193 }, { 214, 82, 195 }, { 198, 181, 196 }, { 198, 181, 196 }, { 198, 198, 198 }, { 231, 0, 199 },
+ { 198, 214, 200 }, { 231, 16, 201 }, { 214, 132, 202 }, { 198, 231, 203 }, { 198, 231, 203 }, { 198, 247, 205 }, { 198, 247, 205 }, { 214, 165, 207 },
+ { 231, 66, 208 }, { 214, 181, 209 }, { 231, 82, 210 }, { 214, 198, 212 }, { 214, 198, 212 }, { 214, 198, 212 }, { 214, 214, 214 }, { 231, 115, 215 },
+ { 214, 231, 216 }, { 231, 132, 217 }, { 214, 247, 219 }, { 214, 247, 219 }, { 214, 247, 219 }, { 231, 165, 222 }, { 231, 165, 222 }, { 231, 165, 222 },
+ { 231, 181, 224 }, { 231, 181, 224 }, { 231, 198, 226 }, { 231, 198, 226 }, { 247, 115, 228 }, { 231, 214, 229 }, { 231, 214, 229 }, { 231, 231, 231 },
+ { 231, 231, 231 }, { 231, 247, 233 }, { 231, 247, 233 }, { 247, 165, 235 }, { 247, 165, 235 }, { 247, 181, 238 }, { 247, 181, 238 }, { 247, 181, 238 },
+ { 247, 198, 240 }, { 247, 198, 240 }, { 247, 214, 242 }, { 247, 214, 242 }, { 247, 231, 245 }, { 247, 231, 245 }, { 247, 231, 245 }, { 247, 247, 247 },
+ { 247, 247, 247 }, { 247, 247, 247 }, { 247, 247, 247 }, { 247, 247, 247 }, { 247, 247, 247 }, { 247, 247, 247 }, { 247, 247, 247 }, { 247, 247, 247 },
+ }
+};
+
+Table g_mode0_p00_i2=
+{
+ 2,
+ 0,
+ {
+ { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 16, 5 }, { 0, 16, 5 }, { 0, 16, 5 }, { 0, 16, 5 }, { 0, 16, 5 },
+ { 0, 33, 9 }, { 0, 33, 9 }, { 0, 33, 9 }, { 16, 0, 12 }, { 16, 0, 12 }, { 0, 49, 14 }, { 0, 49, 14 }, { 0, 49, 14 },
+ { 16, 16, 16 }, { 16, 16, 16 }, { 0, 66, 19 }, { 0, 66, 19 }, { 0, 66, 19 }, { 16, 33, 21 }, { 0, 82, 23 }, { 0, 82, 23 },
+ { 33, 0, 24 }, { 16, 49, 25 }, { 16, 49, 25 }, { 0, 99, 28 }, { 0, 99, 28 }, { 0, 99, 28 }, { 16, 66, 30 }, { 0, 115, 32 },
+ { 0, 115, 32 }, { 33, 33, 33 }, { 16, 82, 35 }, { 16, 82, 35 }, { 0, 132, 37 }, { 0, 132, 37 }, { 33, 49, 38 }, { 16, 99, 39 },
+ { 49, 16, 40 }, { 0, 148, 42 }, { 0, 148, 42 }, { 0, 148, 42 }, { 16, 115, 44 }, { 49, 33, 45 }, { 0, 165, 46 }, { 33, 82, 47 },
+ { 16, 132, 49 }, { 16, 132, 49 }, { 0, 181, 51 }, { 0, 181, 51 }, { 33, 99, 52 }, { 16, 148, 53 }, { 49, 66, 54 }, { 0, 198, 56 },
+ { 0, 198, 56 }, { 66, 33, 57 }, { 16, 165, 58 }, { 82, 0, 59 }, { 0, 214, 60 }, { 33, 132, 61 }, { 16, 181, 62 }, { 49, 99, 63 },
+ { 0, 231, 65 }, { 0, 231, 65 }, { 66, 66, 66 }, { 16, 198, 67 }, { 49, 115, 68 }, { 0, 247, 69 }, { 33, 165, 70 }, { 66, 82, 71 },
+ { 16, 214, 72 }, { 82, 49, 73 }, { 33, 181, 75 }, { 33, 181, 75 }, { 16, 231, 76 }, { 49, 148, 77 }, { 82, 66, 78 }, { 33, 198, 79 },
+ { 66, 115, 80 }, { 16, 247, 81 }, { 49, 165, 82 }, { 115, 0, 83 }, { 33, 214, 84 }, { 66, 132, 85 }, { 49, 181, 86 }, { 82, 99, 87 },
+ { 33, 231, 89 }, { 33, 231, 89 }, { 99, 66, 90 }, { 49, 198, 91 }, { 115, 33, 92 }, { 33, 247, 93 }, { 66, 165, 94 }, { 49, 214, 95 },
+ { 82, 132, 96 }, { 66, 181, 98 }, { 66, 181, 98 }, { 99, 99, 99 }, { 49, 231, 100 }, { 82, 148, 101 }, { 66, 198, 103 }, { 66, 198, 103 },
+ { 99, 115, 104 }, { 49, 247, 105 }, { 115, 82, 106 }, { 66, 214, 108 }, { 66, 214, 108 }, { 132, 49, 109 }, { 82, 181, 110 }, { 115, 99, 111 },
+ { 66, 231, 112 }, { 99, 148, 113 }, { 82, 198, 115 }, { 82, 198, 115 }, { 148, 33, 116 }, { 66, 247, 117 }, { 99, 165, 118 }, { 82, 214, 119 },
+ { 115, 132, 120 }, { 99, 181, 122 }, { 99, 181, 122 }, { 132, 99, 123 }, { 82, 231, 124 }, { 148, 66, 125 }, { 99, 198, 127 }, { 99, 198, 127 },
+ { 82, 247, 128 }, { 115, 165, 129 }, { 181, 0, 130 }, { 99, 214, 131 }, { 132, 132, 132 }, { 115, 181, 134 }, { 115, 181, 134 }, { 181, 16, 135 },
+ { 99, 231, 136 }, { 132, 148, 137 }, { 115, 198, 138 }, { 148, 115, 139 }, { 99, 247, 141 }, { 99, 247, 141 }, { 165, 82, 142 }, { 115, 214, 143 },
+ { 148, 132, 144 }, { 132, 181, 146 }, { 132, 181, 146 }, { 198, 16, 147 }, { 115, 231, 148 }, { 181, 66, 149 }, { 132, 198, 151 }, { 132, 198, 151 },
+ { 115, 247, 152 }, { 148, 165, 153 }, { 214, 0, 154 }, { 132, 214, 155 }, { 165, 132, 156 }, { 148, 181, 157 }, { 181, 99, 158 }, { 132, 231, 160 },
+ { 132, 231, 160 }, { 198, 66, 161 }, { 148, 198, 162 }, { 214, 33, 163 }, { 132, 247, 164 }, { 165, 165, 165 }, { 231, 0, 166 }, { 148, 214, 167 },
+ { 214, 49, 168 }, { 165, 181, 170 }, { 165, 181, 170 }, { 148, 231, 171 }, { 181, 148, 172 }, { 165, 198, 174 }, { 165, 198, 174 }, { 198, 115, 175 },
+ { 148, 247, 176 }, { 181, 165, 177 }, { 247, 0, 178 }, { 165, 214, 179 }, { 231, 49, 180 }, { 181, 181, 181 }, { 214, 99, 182 }, { 165, 231, 184 },
+ { 165, 231, 184 }, { 231, 66, 185 }, { 181, 198, 186 }, { 247, 33, 187 }, { 165, 247, 188 }, { 198, 165, 189 }, { 181, 214, 190 }, { 214, 132, 191 },
+ { 198, 181, 193 }, { 198, 181, 193 }, { 231, 99, 194 }, { 181, 231, 195 }, { 247, 66, 196 }, { 198, 198, 198 }, { 198, 198, 198 }, { 181, 247, 200 },
+ { 181, 247, 200 }, { 247, 82, 201 }, { 198, 214, 203 }, { 198, 214, 203 }, { 198, 214, 203 }, { 214, 181, 205 }, { 198, 231, 207 }, { 198, 231, 207 },
+ { 231, 148, 208 }, { 214, 198, 210 }, { 214, 198, 210 }, { 198, 247, 212 }, { 198, 247, 212 }, { 198, 247, 212 }, { 214, 214, 214 }, { 247, 132, 215 },
+ { 231, 181, 217 }, { 231, 181, 217 }, { 214, 231, 219 }, { 214, 231, 219 }, { 214, 231, 219 }, { 231, 198, 222 }, { 231, 198, 222 }, { 214, 247, 223 },
+ { 247, 165, 224 }, { 231, 214, 226 }, { 231, 214, 226 }, { 231, 214, 226 }, { 247, 181, 228 }, { 247, 181, 228 }, { 231, 231, 231 }, { 231, 231, 231 },
+ { 231, 231, 231 }, { 247, 198, 233 }, { 247, 198, 233 }, { 231, 247, 236 }, { 231, 247, 236 }, { 231, 247, 236 }, { 247, 214, 238 }, { 247, 214, 238 },
+ { 247, 214, 238 }, { 247, 231, 243 }, { 247, 231, 243 }, { 247, 231, 243 }, { 247, 231, 243 }, { 247, 231, 243 }, { 247, 247, 247 }, { 247, 247, 247 },
+ { 247, 247, 247 }, { 247, 247, 247 }, { 247, 247, 247 }, { 247, 247, 247 }, { 247, 247, 247 }, { 247, 247, 247 }, { 247, 247, 247 }, { 247, 247, 247 },
+ }
+};
+
+Table g_mode0_p00_i3=
+{
+ 3,
+ 0,
+ {
+ { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 16, 7 }, { 0, 16, 7 }, { 0, 16, 7 }, { 0, 16, 7 },
+ { 0, 16, 7 }, { 16, 0, 9 }, { 16, 0, 9 }, { 16, 0, 9 }, { 0, 33, 14 }, { 0, 33, 14 }, { 0, 33, 14 }, { 0, 33, 14 },
+ { 16, 16, 16 }, { 16, 16, 16 }, { 33, 0, 19 }, { 33, 0, 19 }, { 0, 49, 21 }, { 0, 49, 21 }, { 0, 49, 21 }, { 16, 33, 23 },
+ { 16, 33, 23 }, { 33, 16, 26 }, { 33, 16, 26 }, { 0, 66, 28 }, { 0, 66, 28 }, { 0, 66, 28 }, { 16, 49, 30 }, { 16, 49, 30 },
+ { 33, 33, 33 }, { 33, 33, 33 }, { 0, 82, 35 }, { 0, 82, 35 }, { 0, 82, 35 }, { 16, 66, 37 }, { 66, 0, 38 }, { 33, 49, 40 },
+ { 33, 49, 40 }, { 0, 99, 42 }, { 0, 99, 42 }, { 0, 99, 42 }, { 16, 82, 44 }, { 66, 16, 45 }, { 33, 66, 47 }, { 33, 66, 47 },
+ { 0, 115, 49 }, { 0, 115, 49 }, { 0, 115, 49 }, { 16, 99, 51 }, { 66, 33, 52 }, { 33, 82, 54 }, { 33, 82, 54 }, { 0, 132, 56 },
+ { 0, 132, 56 }, { 99, 0, 57 }, { 16, 115, 58 }, { 66, 49, 59 }, { 33, 99, 61 }, { 33, 99, 61 }, { 0, 148, 62 }, { 49, 82, 63 },
+ { 99, 16, 64 }, { 16, 132, 65 }, { 66, 66, 66 }, { 33, 115, 68 }, { 33, 115, 68 }, { 0, 165, 70 }, { 0, 165, 70 }, { 99, 33, 71 },
+ { 16, 148, 72 }, { 66, 82, 73 }, { 33, 132, 75 }, { 33, 132, 75 }, { 0, 181, 76 }, { 49, 115, 77 }, { 99, 49, 78 }, { 16, 165, 79 },
+ { 66, 99, 80 }, { 33, 148, 82 }, { 33, 148, 82 }, { 132, 16, 83 }, { 0, 198, 84 }, { 99, 66, 85 }, { 16, 181, 86 }, { 66, 115, 87 },
+ { 33, 165, 89 }, { 33, 165, 89 }, { 0, 214, 90 }, { 49, 148, 91 }, { 99, 82, 92 }, { 16, 198, 93 }, { 66, 132, 94 }, { 33, 181, 95 },
+ { 82, 115, 96 }, { 0, 231, 97 }, { 49, 165, 98 }, { 99, 99, 99 }, { 16, 214, 100 }, { 66, 148, 101 }, { 165, 16, 102 }, { 33, 198, 103 },
+ { 0, 247, 104 }, { 49, 181, 105 }, { 99, 115, 106 }, { 16, 231, 107 }, { 66, 165, 108 }, { 33, 214, 109 }, { 82, 148, 110 }, { 132, 82, 111 },
+ { 49, 198, 112 }, { 16, 247, 113 }, { 198, 0, 114 }, { 66, 181, 115 }, { 165, 49, 116 }, { 33, 231, 117 }, { 132, 99, 118 }, { 49, 214, 119 },
+ { 99, 148, 120 }, { 198, 16, 121 }, { 66, 198, 122 }, { 33, 247, 123 }, { 82, 181, 124 }, { 132, 115, 125 }, { 49, 231, 126 }, { 99, 165, 127 },
+ { 66, 214, 128 }, { 115, 148, 129 }, { 165, 82, 130 }, { 82, 198, 131 }, { 132, 132, 132 }, { 49, 247, 133 }, { 99, 181, 134 }, { 198, 49, 135 },
+ { 66, 231, 136 }, { 165, 99, 137 }, { 82, 214, 138 }, { 132, 148, 139 }, { 231, 16, 140 }, { 99, 198, 141 }, { 66, 247, 142 }, { 115, 181, 143 },
+ { 165, 115, 144 }, { 82, 231, 145 }, { 132, 165, 146 }, { 231, 33, 147 }, { 99, 214, 148 }, { 198, 82, 149 }, { 115, 198, 150 }, { 165, 132, 151 },
+ { 82, 247, 152 }, { 132, 181, 153 }, { 231, 49, 154 }, { 99, 231, 155 }, { 198, 99, 156 }, { 115, 214, 157 }, { 165, 148, 158 }, { 132, 198, 160 },
+ { 132, 198, 160 }, { 99, 247, 161 }, { 148, 181, 162 }, { 198, 115, 163 }, { 115, 231, 164 }, { 165, 165, 165 }, { 132, 214, 167 }, { 132, 214, 167 },
+ { 231, 82, 168 }, { 148, 198, 169 }, { 198, 132, 170 }, { 115, 247, 171 }, { 165, 181, 172 }, { 132, 231, 174 }, { 132, 231, 174 }, { 231, 99, 175 },
+ { 148, 214, 176 }, { 198, 148, 177 }, { 165, 198, 179 }, { 165, 198, 179 }, { 132, 247, 181 }, { 132, 247, 181 }, { 231, 115, 182 }, { 148, 231, 183 },
+ { 198, 165, 184 }, { 247, 99, 185 }, { 165, 214, 186 }, { 165, 214, 186 }, { 181, 198, 188 }, { 231, 132, 189 }, { 148, 247, 190 }, { 198, 181, 191 },
+ { 165, 231, 193 }, { 165, 231, 193 }, { 165, 231, 193 }, { 181, 214, 195 }, { 231, 148, 196 }, { 198, 198, 198 }, { 198, 198, 198 }, { 165, 247, 200 },
+ { 165, 247, 200 }, { 165, 247, 200 }, { 181, 231, 202 }, { 231, 165, 203 }, { 198, 214, 205 }, { 198, 214, 205 }, { 198, 214, 205 }, { 214, 198, 207 },
+ { 181, 247, 209 }, { 181, 247, 209 }, { 231, 181, 210 }, { 198, 231, 212 }, { 198, 231, 212 }, { 198, 231, 212 }, { 214, 214, 214 }, { 214, 214, 214 },
+ { 231, 198, 217 }, { 231, 198, 217 }, { 198, 247, 219 }, { 198, 247, 219 }, { 198, 247, 219 }, { 214, 231, 221 }, { 214, 231, 221 }, { 231, 214, 224 },
+ { 231, 214, 224 }, { 231, 214, 224 }, { 247, 198, 226 }, { 214, 247, 228 }, { 214, 247, 228 }, { 214, 247, 228 }, { 231, 231, 231 }, { 231, 231, 231 },
+ { 231, 231, 231 }, { 247, 214, 233 }, { 247, 214, 233 }, { 247, 214, 233 }, { 231, 247, 238 }, { 231, 247, 238 }, { 231, 247, 238 }, { 231, 247, 238 },
+ { 247, 231, 240 }, { 247, 231, 240 }, { 247, 231, 240 }, { 247, 231, 240 }, { 247, 247, 247 }, { 247, 247, 247 }, { 247, 247, 247 }, { 247, 247, 247 },
+ { 247, 247, 247 }, { 247, 247, 247 }, { 247, 247, 247 }, { 247, 247, 247 }, { 247, 247, 247 }, { 247, 247, 247 }, { 247, 247, 247 }, { 247, 247, 247 },
+ }
+};
+
+Table g_mode0_p01_i1=
+{
+ 1,
+ 2,
+ {
+ { 0, 8, 1 }, { 0, 8, 1 }, { 0, 8, 1 }, { 0, 24, 3 }, { 0, 24, 3 }, { 0, 41, 6 }, { 0, 41, 6 }, { 0, 41, 6 },
+ { 0, 57, 8 }, { 0, 57, 8 }, { 0, 74, 10 }, { 0, 74, 10 }, { 0, 90, 13 }, { 0, 90, 13 }, { 0, 90, 13 }, { 0, 107, 15 },
+ { 0, 107, 15 }, { 0, 123, 17 }, { 0, 123, 17 }, { 0, 140, 20 }, { 0, 140, 20 }, { 0, 140, 20 }, { 0, 156, 22 }, { 0, 156, 22 },
+ { 0, 173, 24 }, { 0, 173, 24 }, { 16, 90, 26 }, { 0, 189, 27 }, { 0, 189, 27 }, { 0, 206, 29 }, { 0, 206, 29 }, { 0, 222, 31 },
+ { 33, 24, 32 }, { 16, 140, 33 }, { 0, 239, 34 }, { 0, 239, 34 }, { 0, 255, 36 }, { 0, 255, 36 }, { 16, 173, 38 }, { 33, 74, 39 },
+ { 16, 189, 40 }, { 33, 90, 41 }, { 16, 206, 43 }, { 16, 206, 43 }, { 16, 206, 43 }, { 16, 222, 45 }, { 33, 123, 46 }, { 16, 239, 47 },
+ { 33, 140, 48 }, { 16, 255, 50 }, { 16, 255, 50 }, { 16, 255, 50 }, { 33, 173, 53 }, { 33, 173, 53 }, { 33, 173, 53 }, { 33, 189, 55 },
+ { 33, 189, 55 }, { 33, 206, 57 }, { 66, 8, 58 }, { 49, 123, 59 }, { 33, 222, 60 }, { 33, 222, 60 }, { 33, 239, 62 }, { 33, 239, 62 },
+ { 33, 255, 64 }, { 66, 57, 65 }, { 49, 173, 66 }, { 66, 74, 67 }, { 49, 189, 69 }, { 49, 189, 69 }, { 49, 189, 69 }, { 49, 206, 71 },
+ { 66, 107, 72 }, { 49, 222, 73 }, { 66, 123, 74 }, { 49, 239, 76 }, { 49, 239, 76 }, { 49, 239, 76 }, { 49, 255, 78 }, { 66, 156, 79 },
+ { 66, 156, 79 }, { 66, 173, 81 }, { 66, 173, 81 }, { 66, 189, 83 }, { 66, 189, 83 }, { 66, 206, 86 }, { 66, 206, 86 }, { 66, 206, 86 },
+ { 66, 222, 88 }, { 66, 222, 88 }, { 66, 239, 90 }, { 99, 41, 91 }, { 82, 156, 92 }, { 66, 255, 93 }, { 66, 255, 93 }, { 82, 173, 95 },
+ { 82, 173, 95 }, { 82, 189, 97 }, { 99, 90, 98 }, { 82, 206, 99 }, { 99, 107, 100 }, { 82, 222, 102 }, { 82, 222, 102 }, { 82, 222, 102 },
+ { 82, 239, 104 }, { 99, 140, 105 }, { 82, 255, 106 }, { 99, 156, 107 }, { 99, 156, 107 }, { 99, 173, 109 }, { 99, 173, 109 }, { 115, 90, 111 },
+ { 99, 189, 112 }, { 99, 189, 112 }, { 99, 206, 114 }, { 132, 8, 115 }, { 99, 222, 116 }, { 132, 24, 117 }, { 99, 239, 119 }, { 99, 239, 119 },
+ { 99, 239, 119 }, { 99, 255, 121 }, { 99, 255, 121 }, { 115, 173, 123 }, { 132, 74, 124 }, { 115, 189, 125 }, { 132, 90, 126 }, { 115, 206, 128 },
+ { 115, 206, 128 }, { 115, 206, 128 }, { 115, 222, 130 }, { 132, 123, 131 }, { 115, 239, 132 }, { 132, 140, 133 }, { 115, 255, 135 }, { 115, 255, 135 },
+ { 115, 255, 135 }, { 132, 173, 138 }, { 132, 173, 138 }, { 132, 173, 138 }, { 132, 189, 140 }, { 132, 189, 140 }, { 132, 206, 142 }, { 165, 8, 143 },
+ { 148, 123, 144 }, { 132, 222, 145 }, { 132, 222, 145 }, { 132, 239, 147 }, { 165, 41, 148 }, { 132, 255, 149 }, { 165, 57, 150 }, { 148, 173, 152 },
+ { 148, 173, 152 }, { 148, 173, 152 }, { 148, 189, 154 }, { 148, 189, 154 }, { 148, 206, 156 }, { 165, 107, 157 }, { 148, 222, 158 }, { 165, 123, 159 },
+ { 148, 239, 161 }, { 148, 239, 161 }, { 148, 239, 161 }, { 148, 255, 163 }, { 165, 156, 164 }, { 165, 156, 164 }, { 165, 173, 166 }, { 165, 173, 166 },
+ { 165, 189, 168 }, { 165, 189, 168 }, { 165, 206, 171 }, { 165, 206, 171 }, { 165, 206, 171 }, { 165, 222, 173 }, { 198, 24, 174 }, { 165, 239, 175 },
+ { 198, 41, 176 }, { 181, 156, 177 }, { 165, 255, 178 }, { 165, 255, 178 }, { 181, 173, 180 }, { 198, 74, 181 }, { 181, 189, 182 }, { 198, 90, 183 },
+ { 181, 206, 185 }, { 181, 206, 185 }, { 181, 206, 185 }, { 181, 222, 187 }, { 181, 222, 187 }, { 181, 239, 189 }, { 198, 140, 190 }, { 181, 255, 191 },
+ { 198, 156, 192 }, { 198, 156, 192 }, { 198, 173, 194 }, { 198, 173, 194 }, { 198, 189, 197 }, { 198, 189, 197 }, { 198, 189, 197 }, { 198, 206, 199 },
+ { 231, 8, 200 }, { 198, 222, 201 }, { 231, 24, 202 }, { 198, 239, 204 }, { 198, 239, 204 }, { 198, 239, 204 }, { 198, 255, 206 }, { 231, 57, 207 },
+ { 214, 173, 208 }, { 231, 74, 209 }, { 214, 189, 210 }, { 231, 90, 211 }, { 214, 206, 213 }, { 214, 206, 213 }, { 231, 107, 214 }, { 214, 222, 215 },
+ { 231, 123, 216 }, { 214, 239, 218 }, { 214, 239, 218 }, { 214, 239, 218 }, { 214, 255, 220 }, { 214, 255, 220 }, { 231, 173, 223 }, { 231, 173, 223 },
+ { 231, 173, 223 }, { 231, 189, 225 }, { 231, 189, 225 }, { 231, 206, 227 }, { 231, 206, 227 }, { 231, 222, 230 }, { 231, 222, 230 }, { 231, 222, 230 },
+ { 231, 239, 232 }, { 231, 239, 232 }, { 231, 255, 234 }, { 231, 255, 234 }, { 247, 173, 237 }, { 247, 173, 237 }, { 247, 173, 237 }, { 247, 189, 239 },
+ { 247, 189, 239 }, { 247, 206, 241 }, { 247, 206, 241 }, { 247, 222, 243 }, { 247, 222, 243 }, { 247, 239, 246 }, { 247, 239, 246 }, { 247, 239, 246 },
+ { 247, 255, 248 }, { 247, 255, 248 }, { 247, 255, 248 }, { 247, 255, 248 }, { 247, 255, 248 }, { 247, 255, 248 }, { 247, 255, 248 }, { 247, 255, 248 },
+ }
+};
+
+Table g_mode0_p01_i2=
+{
+ 2,
+ 2,
+ {
+ { 0, 8, 2 }, { 0, 8, 2 }, { 0, 8, 2 }, { 0, 8, 2 }, { 0, 8, 2 }, { 0, 24, 7 }, { 0, 24, 7 }, { 0, 24, 7 },
+ { 0, 24, 7 }, { 0, 24, 7 }, { 0, 41, 12 }, { 0, 41, 12 }, { 0, 41, 12 }, { 0, 41, 12 }, { 16, 8, 14 }, { 0, 57, 16 },
+ { 0, 57, 16 }, { 0, 57, 16 }, { 16, 24, 18 }, { 16, 24, 18 }, { 0, 74, 21 }, { 0, 74, 21 }, { 0, 74, 21 }, { 16, 41, 23 },
+ { 0, 90, 25 }, { 0, 90, 25 }, { 33, 8, 26 }, { 16, 57, 28 }, { 16, 57, 28 }, { 0, 107, 30 }, { 0, 107, 30 }, { 0, 107, 30 },
+ { 16, 74, 32 }, { 16, 74, 32 }, { 0, 123, 35 }, { 0, 123, 35 }, { 0, 123, 35 }, { 16, 90, 37 }, { 0, 140, 39 }, { 0, 140, 39 },
+ { 33, 57, 40 }, { 16, 107, 42 }, { 16, 107, 42 }, { 0, 156, 44 }, { 0, 156, 44 }, { 33, 74, 45 }, { 16, 123, 46 }, { 49, 41, 47 },
+ { 0, 173, 49 }, { 0, 173, 49 }, { 66, 8, 50 }, { 16, 140, 51 }, { 0, 189, 53 }, { 0, 189, 53 }, { 33, 107, 54 }, { 16, 156, 55 },
+ { 49, 74, 56 }, { 0, 206, 58 }, { 0, 206, 58 }, { 66, 41, 59 }, { 16, 173, 60 }, { 49, 90, 61 }, { 0, 222, 62 }, { 33, 140, 63 },
+ { 16, 189, 65 }, { 16, 189, 65 }, { 82, 24, 66 }, { 0, 239, 67 }, { 33, 156, 68 }, { 16, 206, 69 }, { 49, 123, 70 }, { 0, 255, 72 },
+ { 0, 255, 72 }, { 66, 90, 73 }, { 16, 222, 74 }, { 49, 140, 75 }, { 33, 189, 77 }, { 33, 189, 77 }, { 66, 107, 78 }, { 16, 239, 79 },
+ { 82, 74, 80 }, { 33, 206, 82 }, { 33, 206, 82 }, { 16, 255, 83 }, { 49, 173, 84 }, { 115, 8, 85 }, { 33, 222, 86 }, { 66, 140, 87 },
+ { 49, 189, 88 }, { 82, 107, 89 }, { 33, 239, 91 }, { 33, 239, 91 }, { 99, 74, 92 }, { 49, 206, 93 }, { 82, 123, 94 }, { 33, 255, 95 },
+ { 66, 173, 96 }, { 132, 8, 97 }, { 49, 222, 98 }, { 115, 57, 99 }, { 66, 189, 101 }, { 66, 189, 101 }, { 49, 239, 102 }, { 82, 156, 103 },
+ { 66, 206, 105 }, { 66, 206, 105 }, { 99, 123, 106 }, { 49, 255, 107 }, { 82, 173, 108 }, { 148, 8, 109 }, { 66, 222, 110 }, { 99, 140, 111 },
+ { 82, 189, 112 }, { 115, 107, 113 }, { 66, 239, 115 }, { 66, 239, 115 }, { 132, 74, 116 }, { 82, 206, 117 }, { 148, 41, 118 }, { 66, 255, 119 },
+ { 99, 173, 120 }, { 82, 222, 121 }, { 115, 140, 122 }, { 99, 189, 124 }, { 99, 189, 124 }, { 132, 107, 125 }, { 82, 239, 126 }, { 115, 156, 127 },
+ { 99, 206, 129 }, { 99, 206, 129 }, { 165, 41, 130 }, { 82, 255, 131 }, { 148, 90, 132 }, { 99, 222, 134 }, { 99, 222, 134 }, { 165, 57, 135 },
+ { 115, 189, 136 }, { 181, 24, 137 }, { 99, 239, 138 }, { 132, 156, 139 }, { 115, 206, 141 }, { 115, 206, 141 }, { 181, 41, 142 }, { 99, 255, 143 },
+ { 132, 173, 144 }, { 115, 222, 145 }, { 148, 140, 146 }, { 132, 189, 148 }, { 132, 189, 148 }, { 165, 107, 149 }, { 115, 239, 150 }, { 181, 74, 151 },
+ { 132, 206, 153 }, { 132, 206, 153 }, { 115, 255, 154 }, { 148, 173, 155 }, { 214, 8, 156 }, { 132, 222, 157 }, { 165, 140, 158 }, { 148, 189, 160 },
+ { 148, 189, 160 }, { 214, 24, 161 }, { 132, 239, 162 }, { 198, 74, 163 }, { 148, 206, 164 }, { 181, 123, 165 }, { 132, 255, 167 }, { 132, 255, 167 },
+ { 198, 90, 168 }, { 148, 222, 169 }, { 214, 57, 170 }, { 165, 189, 172 }, { 165, 189, 172 }, { 231, 24, 173 }, { 148, 239, 174 }, { 214, 74, 175 },
+ { 165, 206, 177 }, { 165, 206, 177 }, { 148, 255, 178 }, { 181, 173, 179 }, { 247, 8, 180 }, { 165, 222, 181 }, { 198, 140, 182 }, { 181, 189, 183 },
+ { 214, 107, 184 }, { 165, 239, 186 }, { 165, 239, 186 }, { 231, 74, 187 }, { 181, 206, 188 }, { 247, 41, 189 }, { 165, 255, 190 }, { 198, 173, 191 },
+ { 181, 222, 193 }, { 181, 222, 193 }, { 247, 57, 194 }, { 198, 189, 195 }, { 231, 107, 196 }, { 181, 239, 197 }, { 214, 156, 198 }, { 198, 206, 200 },
+ { 198, 206, 200 }, { 231, 123, 201 }, { 181, 255, 202 }, { 247, 90, 203 }, { 198, 222, 205 }, { 198, 222, 205 }, { 198, 222, 205 }, { 214, 189, 207 },
+ { 247, 107, 208 }, { 198, 239, 210 }, { 198, 239, 210 }, { 198, 239, 210 }, { 214, 206, 212 }, { 198, 255, 214 }, { 198, 255, 214 }, { 231, 173, 215 },
+ { 214, 222, 216 }, { 247, 140, 217 }, { 231, 189, 219 }, { 231, 189, 219 }, { 214, 239, 221 }, { 214, 239, 221 }, { 214, 239, 221 }, { 231, 206, 224 },
+ { 231, 206, 224 }, { 214, 255, 226 }, { 214, 255, 226 }, { 214, 255, 226 }, { 231, 222, 228 }, { 231, 222, 228 }, { 247, 189, 231 }, { 247, 189, 231 },
+ { 231, 239, 233 }, { 231, 239, 233 }, { 231, 239, 233 }, { 247, 206, 235 }, { 247, 206, 235 }, { 231, 255, 238 }, { 231, 255, 238 }, { 231, 255, 238 },
+ { 247, 222, 240 }, { 247, 222, 240 }, { 247, 222, 240 }, { 247, 239, 245 }, { 247, 239, 245 }, { 247, 239, 245 }, { 247, 239, 245 }, { 247, 239, 245 },
+ { 247, 255, 249 }, { 247, 255, 249 }, { 247, 255, 249 }, { 247, 255, 249 }, { 247, 255, 249 }, { 247, 255, 249 }, { 247, 255, 249 }, { 247, 255, 249 },
+ }
+};
+
+Table g_mode0_p01_i3=
+{
+ 3,
+ 2,
+ {
+ { 0, 8, 3 }, { 0, 8, 3 }, { 0, 8, 3 }, { 0, 8, 3 }, { 0, 8, 3 }, { 0, 8, 3 }, { 0, 8, 3 }, { 0, 24, 10 },
+ { 0, 24, 10 }, { 0, 24, 10 }, { 0, 24, 10 }, { 0, 24, 10 }, { 16, 8, 13 }, { 16, 8, 13 }, { 16, 8, 13 }, { 0, 41, 17 },
+ { 0, 41, 17 }, { 0, 41, 17 }, { 0, 41, 17 }, { 16, 24, 19 }, { 16, 24, 19 }, { 33, 8, 22 }, { 33, 8, 22 }, { 0, 57, 24 },
+ { 0, 57, 24 }, { 0, 57, 24 }, { 16, 41, 27 }, { 16, 41, 27 }, { 16, 41, 27 }, { 33, 24, 29 }, { 0, 74, 31 }, { 0, 74, 31 },
+ { 49, 8, 32 }, { 16, 57, 33 }, { 16, 57, 33 }, { 33, 41, 36 }, { 33, 41, 36 }, { 0, 90, 38 }, { 0, 90, 38 }, { 0, 90, 38 },
+ { 16, 74, 40 }, { 16, 74, 40 }, { 66, 8, 42 }, { 33, 57, 43 }, { 0, 107, 45 }, { 0, 107, 45 }, { 49, 41, 46 }, { 16, 90, 47 },
+ { 66, 24, 48 }, { 33, 74, 50 }, { 33, 74, 50 }, { 82, 8, 51 }, { 0, 123, 52 }, { 0, 123, 52 }, { 16, 107, 54 }, { 66, 41, 55 },
+ { 33, 90, 57 }, { 33, 90, 57 }, { 82, 24, 58 }, { 0, 140, 59 }, { 49, 74, 60 }, { 16, 123, 61 }, { 66, 57, 62 }, { 33, 107, 64 },
+ { 33, 107, 64 }, { 82, 41, 65 }, { 0, 156, 66 }, { 99, 24, 67 }, { 16, 140, 68 }, { 66, 74, 69 }, { 115, 8, 70 }, { 33, 123, 71 },
+ { 0, 173, 73 }, { 0, 173, 73 }, { 0, 173, 73 }, { 16, 156, 75 }, { 66, 90, 76 }, { 115, 24, 77 }, { 33, 140, 78 }, { 82, 74, 79 },
+ { 0, 189, 80 }, { 99, 57, 81 }, { 16, 173, 82 }, { 66, 107, 83 }, { 115, 41, 84 }, { 33, 156, 85 }, { 132, 24, 86 }, { 0, 206, 87 },
+ { 99, 74, 88 }, { 16, 189, 89 }, { 66, 123, 90 }, { 115, 57, 91 }, { 33, 173, 92 }, { 82, 107, 93 }, { 0, 222, 94 }, { 99, 90, 95 },
+ { 16, 206, 96 }, { 66, 140, 97 }, { 115, 74, 98 }, { 33, 189, 99 }, { 132, 57, 100 }, { 0, 239, 101 }, { 99, 107, 102 }, { 16, 222, 103 },
+ { 66, 156, 104 }, { 33, 206, 106 }, { 33, 206, 106 }, { 0, 255, 108 }, { 0, 255, 108 }, { 99, 123, 109 }, { 16, 239, 110 }, { 66, 173, 111 },
+ { 115, 107, 112 }, { 33, 222, 113 }, { 132, 90, 114 }, { 49, 206, 115 }, { 99, 140, 116 }, { 16, 255, 117 }, { 66, 189, 118 }, { 165, 57, 119 },
+ { 33, 239, 120 }, { 132, 107, 121 }, { 49, 222, 122 }, { 99, 156, 123 }, { 148, 90, 124 }, { 66, 206, 125 }, { 115, 140, 126 }, { 33, 255, 127 },
+ { 132, 123, 128 }, { 49, 239, 129 }, { 99, 173, 130 }, { 148, 107, 131 }, { 66, 222, 132 }, { 165, 90, 133 }, { 82, 206, 134 }, { 132, 140, 135 },
+ { 49, 255, 136 }, { 99, 189, 137 }, { 66, 239, 139 }, { 66, 239, 139 }, { 66, 239, 139 }, { 82, 222, 141 }, { 132, 156, 142 }, { 181, 90, 143 },
+ { 99, 206, 144 }, { 148, 140, 145 }, { 66, 255, 146 }, { 165, 123, 147 }, { 82, 239, 148 }, { 132, 173, 149 }, { 181, 107, 150 }, { 99, 222, 151 },
+ { 198, 90, 152 }, { 115, 206, 153 }, { 165, 140, 154 }, { 82, 255, 155 }, { 132, 189, 156 }, { 181, 123, 157 }, { 99, 239, 158 }, { 148, 173, 159 },
+ { 115, 222, 160 }, { 165, 156, 161 }, { 214, 90, 162 }, { 132, 206, 163 }, { 181, 140, 164 }, { 99, 255, 165 }, { 198, 123, 166 }, { 115, 239, 167 },
+ { 165, 173, 168 }, { 214, 107, 169 }, { 132, 222, 170 }, { 132, 222, 170 }, { 148, 206, 172 }, { 115, 255, 174 }, { 115, 255, 174 }, { 165, 189, 175 },
+ { 214, 123, 176 }, { 132, 239, 177 }, { 181, 173, 178 }, { 148, 222, 179 }, { 198, 156, 180 }, { 247, 90, 181 }, { 165, 206, 182 }, { 214, 140, 183 },
+ { 132, 255, 184 }, { 231, 123, 185 }, { 148, 239, 186 }, { 198, 173, 187 }, { 247, 107, 188 }, { 165, 222, 189 }, { 214, 156, 190 }, { 181, 206, 192 },
+ { 181, 206, 192 }, { 148, 255, 193 }, { 198, 189, 194 }, { 247, 123, 195 }, { 165, 239, 196 }, { 214, 173, 197 }, { 181, 222, 198 }, { 231, 156, 199 },
+ { 198, 206, 201 }, { 198, 206, 201 }, { 247, 140, 202 }, { 165, 255, 203 }, { 165, 255, 203 }, { 181, 239, 205 }, { 181, 239, 205 }, { 231, 173, 207 },
+ { 198, 222, 208 }, { 247, 156, 209 }, { 214, 206, 211 }, { 214, 206, 211 }, { 181, 255, 212 }, { 231, 189, 213 }, { 198, 239, 215 }, { 198, 239, 215 },
+ { 247, 173, 216 }, { 214, 222, 217 }, { 214, 222, 217 }, { 231, 206, 220 }, { 231, 206, 220 }, { 198, 255, 222 }, { 198, 255, 222 }, { 247, 189, 223 },
+ { 214, 239, 225 }, { 214, 239, 225 }, { 214, 239, 225 }, { 231, 222, 227 }, { 231, 222, 227 }, { 247, 206, 230 }, { 247, 206, 230 }, { 214, 255, 231 },
+ { 214, 255, 231 }, { 231, 239, 234 }, { 231, 239, 234 }, { 231, 239, 234 }, { 247, 222, 236 }, { 247, 222, 236 }, { 247, 222, 236 }, { 231, 255, 241 },
+ { 231, 255, 241 }, { 231, 255, 241 }, { 231, 255, 241 }, { 247, 239, 244 }, { 247, 239, 244 }, { 247, 239, 244 }, { 247, 239, 244 }, { 247, 239, 244 },
+ { 247, 255, 250 }, { 247, 255, 250 }, { 247, 255, 250 }, { 247, 255, 250 }, { 247, 255, 250 }, { 247, 255, 250 }, { 247, 255, 250 }, { 247, 255, 250 },
+ }
+};
+
+Table g_mode0_p10_i1=
+{
+ 1,
+ 1,
+ {
+ { 8, 0, 7 }, { 8, 0, 7 }, { 8, 0, 7 }, { 8, 0, 7 }, { 8, 0, 7 }, { 8, 0, 7 }, { 8, 0, 7 }, { 8, 0, 7 },
+ { 8, 0, 7 }, { 8, 16, 9 }, { 8, 16, 9 }, { 8, 33, 12 }, { 8, 33, 12 }, { 8, 33, 12 }, { 8, 49, 14 }, { 8, 49, 14 },
+ { 8, 66, 16 }, { 8, 66, 16 }, { 8, 82, 18 }, { 8, 82, 18 }, { 8, 99, 21 }, { 8, 99, 21 }, { 8, 99, 21 }, { 8, 115, 23 },
+ { 8, 115, 23 }, { 8, 132, 25 }, { 8, 132, 25 }, { 8, 148, 28 }, { 8, 148, 28 }, { 8, 148, 28 }, { 8, 165, 30 }, { 8, 165, 30 },
+ { 8, 181, 32 }, { 8, 181, 32 }, { 8, 198, 35 }, { 8, 198, 35 }, { 8, 198, 35 }, { 8, 214, 37 }, { 8, 214, 37 }, { 8, 231, 39 },
+ { 41, 33, 40 }, { 24, 148, 41 }, { 8, 247, 42 }, { 8, 247, 42 }, { 24, 165, 44 }, { 41, 66, 45 }, { 24, 181, 46 }, { 41, 82, 47 },
+ { 24, 198, 48 }, { 41, 99, 49 }, { 24, 214, 51 }, { 24, 214, 51 }, { 24, 214, 51 }, { 24, 231, 53 }, { 41, 132, 54 }, { 24, 247, 55 },
+ { 41, 148, 56 }, { 41, 148, 56 }, { 41, 165, 58 }, { 41, 165, 58 }, { 41, 181, 61 }, { 41, 181, 61 }, { 41, 181, 61 }, { 41, 198, 63 },
+ { 74, 0, 64 }, { 41, 214, 65 }, { 74, 16, 66 }, { 41, 231, 68 }, { 41, 231, 68 }, { 41, 231, 68 }, { 41, 247, 70 }, { 41, 247, 70 },
+ { 57, 165, 72 }, { 74, 66, 73 }, { 57, 181, 74 }, { 74, 82, 75 }, { 57, 198, 77 }, { 57, 198, 77 }, { 74, 99, 78 }, { 57, 214, 79 },
+ { 74, 115, 80 }, { 57, 231, 81 }, { 74, 132, 82 }, { 57, 247, 84 }, { 57, 247, 84 }, { 57, 247, 84 }, { 74, 165, 87 }, { 74, 165, 87 },
+ { 74, 165, 87 }, { 74, 181, 89 }, { 74, 181, 89 }, { 74, 198, 91 }, { 107, 0, 92 }, { 74, 214, 94 }, { 74, 214, 94 }, { 74, 214, 94 },
+ { 74, 231, 96 }, { 107, 33, 97 }, { 74, 247, 98 }, { 107, 49, 99 }, { 90, 165, 101 }, { 90, 165, 101 }, { 90, 165, 101 }, { 90, 181, 103 },
+ { 90, 181, 103 }, { 90, 198, 105 }, { 107, 99, 106 }, { 90, 214, 107 }, { 107, 115, 108 }, { 90, 231, 110 }, { 90, 231, 110 }, { 107, 132, 111 },
+ { 90, 247, 112 }, { 107, 148, 113 }, { 107, 148, 113 }, { 107, 165, 115 }, { 107, 165, 115 }, { 107, 181, 117 }, { 107, 181, 117 }, { 107, 198, 120 },
+ { 107, 198, 120 }, { 107, 198, 120 }, { 107, 214, 122 }, { 140, 16, 123 }, { 107, 231, 124 }, { 140, 33, 125 }, { 107, 247, 127 }, { 107, 247, 127 },
+ { 107, 247, 127 }, { 123, 165, 129 }, { 140, 66, 130 }, { 123, 181, 131 }, { 140, 82, 132 }, { 123, 198, 134 }, { 123, 198, 134 }, { 123, 198, 134 },
+ { 123, 214, 136 }, { 123, 214, 136 }, { 123, 231, 138 }, { 140, 132, 139 }, { 123, 247, 140 }, { 140, 148, 141 }, { 140, 148, 141 }, { 156, 66, 143 },
+ { 140, 165, 144 }, { 140, 165, 144 }, { 140, 181, 146 }, { 140, 181, 146 }, { 140, 198, 148 }, { 173, 0, 149 }, { 140, 214, 150 }, { 173, 16, 151 },
+ { 140, 231, 153 }, { 140, 231, 153 }, { 140, 231, 153 }, { 140, 247, 155 }, { 173, 49, 156 }, { 156, 165, 157 }, { 173, 66, 158 }, { 156, 181, 160 },
+ { 156, 181, 160 }, { 156, 181, 160 }, { 156, 198, 162 }, { 173, 99, 163 }, { 156, 214, 164 }, { 173, 115, 165 }, { 156, 231, 167 }, { 156, 231, 167 },
+ { 156, 231, 167 }, { 156, 247, 169 }, { 156, 247, 169 }, { 173, 165, 172 }, { 173, 165, 172 }, { 173, 165, 172 }, { 173, 181, 174 }, { 173, 181, 174 },
+ { 189, 99, 176 }, { 173, 198, 177 }, { 173, 198, 177 }, { 173, 214, 179 }, { 173, 214, 179 }, { 173, 231, 181 }, { 206, 33, 182 }, { 173, 247, 183 },
+ { 206, 49, 184 }, { 189, 165, 186 }, { 189, 165, 186 }, { 189, 165, 186 }, { 189, 181, 188 }, { 206, 82, 189 }, { 189, 198, 190 }, { 206, 99, 191 },
+ { 189, 214, 193 }, { 189, 214, 193 }, { 189, 214, 193 }, { 189, 231, 195 }, { 206, 132, 196 }, { 189, 247, 197 }, { 206, 148, 198 }, { 206, 148, 198 },
+ { 206, 165, 200 }, { 206, 165, 200 }, { 206, 181, 202 }, { 206, 181, 202 }, { 206, 198, 205 }, { 206, 198, 205 }, { 206, 198, 205 }, { 206, 214, 207 },
+ { 239, 16, 208 }, { 222, 132, 209 }, { 206, 231, 210 }, { 206, 231, 210 }, { 206, 247, 212 }, { 206, 247, 212 }, { 222, 165, 214 }, { 239, 66, 215 },
+ { 222, 181, 216 }, { 239, 82, 217 }, { 222, 198, 219 }, { 222, 198, 219 }, { 222, 198, 219 }, { 222, 214, 221 }, { 239, 115, 222 }, { 222, 231, 223 },
+ { 239, 132, 224 }, { 222, 247, 226 }, { 222, 247, 226 }, { 222, 247, 226 }, { 255, 66, 228 }, { 239, 165, 229 }, { 239, 165, 229 }, { 239, 181, 231 },
+ { 239, 181, 231 }, { 239, 198, 233 }, { 239, 198, 233 }, { 239, 214, 235 }, { 239, 214, 235 }, { 239, 231, 238 }, { 239, 231, 238 }, { 239, 231, 238 },
+ { 239, 247, 240 }, { 239, 247, 240 }, { 255, 165, 242 }, { 255, 165, 242 }, { 255, 181, 245 }, { 255, 181, 245 }, { 255, 181, 245 }, { 255, 198, 247 },
+ { 255, 198, 247 }, { 255, 214, 249 }, { 255, 214, 249 }, { 255, 231, 252 }, { 255, 231, 252 }, { 255, 231, 252 }, { 255, 247, 254 }, { 255, 247, 254 },
+ }
+};
+
+Table g_mode0_p10_i2=
+{
+ 2,
+ 1,
+ {
+ { 8, 0, 6 }, { 8, 0, 6 }, { 8, 0, 6 }, { 8, 0, 6 }, { 8, 0, 6 }, { 8, 0, 6 }, { 8, 0, 6 }, { 8, 0, 6 },
+ { 8, 0, 6 }, { 8, 16, 10 }, { 8, 16, 10 }, { 8, 16, 10 }, { 8, 16, 10 }, { 8, 33, 15 }, { 8, 33, 15 }, { 8, 33, 15 },
+ { 8, 33, 15 }, { 24, 0, 17 }, { 24, 0, 17 }, { 8, 49, 20 }, { 8, 49, 20 }, { 8, 49, 20 }, { 24, 16, 22 }, { 8, 66, 24 },
+ { 8, 66, 24 }, { 8, 66, 24 }, { 24, 33, 27 }, { 24, 33, 27 }, { 8, 82, 29 }, { 8, 82, 29 }, { 8, 82, 29 }, { 24, 49, 31 },
+ { 24, 49, 31 }, { 8, 99, 34 }, { 8, 99, 34 }, { 8, 99, 34 }, { 24, 66, 36 }, { 8, 115, 38 }, { 8, 115, 38 }, { 41, 33, 39 },
+ { 24, 82, 40 }, { 57, 0, 41 }, { 8, 132, 43 }, { 8, 132, 43 }, { 8, 132, 43 }, { 24, 99, 45 }, { 8, 148, 47 }, { 8, 148, 47 },
+ { 41, 66, 48 }, { 24, 115, 50 }, { 24, 115, 50 }, { 8, 165, 52 }, { 8, 165, 52 }, { 41, 82, 53 }, { 24, 132, 54 }, { 57, 49, 55 },
+ { 8, 181, 57 }, { 8, 181, 57 }, { 74, 16, 58 }, { 24, 148, 59 }, { 57, 66, 60 }, { 8, 198, 61 }, { 41, 115, 62 }, { 24, 165, 64 },
+ { 24, 165, 64 }, { 90, 0, 65 }, { 8, 214, 66 }, { 41, 132, 67 }, { 24, 181, 68 }, { 57, 99, 69 }, { 8, 231, 71 }, { 8, 231, 71 },
+ { 74, 66, 72 }, { 24, 198, 73 }, { 90, 33, 74 }, { 8, 247, 75 }, { 41, 165, 76 }, { 24, 214, 77 }, { 57, 132, 78 }, { 41, 181, 80 },
+ { 41, 181, 80 }, { 74, 99, 81 }, { 24, 231, 82 }, { 57, 148, 83 }, { 41, 198, 85 }, { 41, 198, 85 }, { 74, 115, 86 }, { 24, 247, 87 },
+ { 90, 82, 88 }, { 41, 214, 90 }, { 41, 214, 90 }, { 107, 49, 91 }, { 57, 181, 92 }, { 90, 99, 93 }, { 41, 231, 94 }, { 74, 148, 95 },
+ { 57, 198, 97 }, { 57, 198, 97 }, { 123, 33, 98 }, { 41, 247, 99 }, { 74, 165, 100 }, { 57, 214, 101 }, { 90, 132, 102 }, { 74, 181, 104 },
+ { 74, 181, 104 }, { 107, 99, 105 }, { 57, 231, 106 }, { 123, 66, 107 }, { 74, 198, 109 }, { 74, 198, 109 }, { 57, 247, 110 }, { 90, 165, 111 },
+ { 156, 0, 112 }, { 74, 214, 113 }, { 107, 132, 114 }, { 90, 181, 116 }, { 90, 181, 116 }, { 156, 16, 117 }, { 74, 231, 118 }, { 107, 148, 119 },
+ { 90, 198, 120 }, { 123, 115, 121 }, { 74, 247, 123 }, { 74, 247, 123 }, { 140, 82, 124 }, { 90, 214, 125 }, { 123, 132, 126 }, { 107, 181, 128 },
+ { 107, 181, 128 }, { 173, 16, 129 }, { 90, 231, 130 }, { 156, 66, 131 }, { 107, 198, 133 }, { 107, 198, 133 }, { 90, 247, 134 }, { 123, 165, 135 },
+ { 189, 0, 136 }, { 107, 214, 137 }, { 140, 132, 138 }, { 123, 181, 139 }, { 156, 99, 140 }, { 107, 231, 142 }, { 107, 231, 142 }, { 173, 66, 143 },
+ { 123, 198, 144 }, { 189, 33, 145 }, { 107, 247, 146 }, { 140, 165, 147 }, { 206, 0, 148 }, { 123, 214, 149 }, { 189, 49, 150 }, { 140, 181, 152 },
+ { 140, 181, 152 }, { 123, 231, 153 }, { 156, 148, 154 }, { 140, 198, 156 }, { 140, 198, 156 }, { 173, 115, 157 }, { 123, 247, 158 }, { 156, 165, 159 },
+ { 222, 0, 160 }, { 140, 214, 161 }, { 206, 49, 162 }, { 156, 181, 163 }, { 189, 99, 164 }, { 140, 231, 166 }, { 140, 231, 166 }, { 206, 66, 167 },
+ { 156, 198, 168 }, { 222, 33, 169 }, { 140, 247, 170 }, { 173, 165, 171 }, { 156, 214, 172 }, { 189, 132, 173 }, { 173, 181, 175 }, { 173, 181, 175 },
+ { 206, 99, 176 }, { 156, 231, 177 }, { 222, 66, 178 }, { 173, 198, 180 }, { 173, 198, 180 }, { 239, 33, 181 }, { 156, 247, 182 }, { 222, 82, 183 },
+ { 173, 214, 185 }, { 173, 214, 185 }, { 239, 49, 186 }, { 189, 181, 187 }, { 255, 16, 188 }, { 173, 231, 189 }, { 206, 148, 190 }, { 189, 198, 192 },
+ { 189, 198, 192 }, { 255, 33, 193 }, { 173, 247, 194 }, { 239, 82, 195 }, { 189, 214, 196 }, { 222, 132, 197 }, { 206, 181, 199 }, { 206, 181, 199 },
+ { 239, 99, 200 }, { 189, 231, 201 }, { 255, 66, 202 }, { 206, 198, 204 }, { 206, 198, 204 }, { 189, 247, 205 }, { 222, 165, 206 }, { 206, 214, 208 },
+ { 206, 214, 208 }, { 239, 132, 209 }, { 222, 181, 210 }, { 255, 99, 211 }, { 206, 231, 213 }, { 206, 231, 213 }, { 206, 231, 213 }, { 222, 198, 215 },
+ { 255, 115, 216 }, { 206, 247, 218 }, { 206, 247, 218 }, { 206, 247, 218 }, { 222, 214, 220 }, { 222, 214, 220 }, { 239, 181, 223 }, { 239, 181, 223 },
+ { 222, 231, 225 }, { 222, 231, 225 }, { 222, 231, 225 }, { 239, 198, 227 }, { 222, 247, 229 }, { 222, 247, 229 }, { 255, 165, 230 }, { 239, 214, 232 },
+ { 239, 214, 232 }, { 239, 214, 232 }, { 255, 181, 234 }, { 255, 181, 234 }, { 239, 231, 237 }, { 239, 231, 237 }, { 239, 231, 237 }, { 255, 198, 239 },
+ { 239, 247, 241 }, { 239, 247, 241 }, { 239, 247, 241 }, { 255, 214, 243 }, { 255, 214, 243 }, { 255, 214, 243 }, { 255, 231, 248 }, { 255, 231, 248 },
+ { 255, 231, 248 }, { 255, 231, 248 }, { 255, 231, 248 }, { 255, 247, 253 }, { 255, 247, 253 }, { 255, 247, 253 }, { 255, 247, 253 }, { 255, 247, 253 },
+ }
+};
+
+Table g_mode0_p10_i3=
+{
+ 3,
+ 3,
+ {
+ { 8, 8, 8 }, { 8, 8, 8 }, { 8, 8, 8 }, { 8, 8, 8 }, { 8, 8, 8 }, { 8, 8, 8 }, { 8, 8, 8 }, { 8, 8, 8 },
+ { 8, 8, 8 }, { 8, 8, 8 }, { 8, 8, 8 }, { 8, 8, 8 }, { 8, 24, 15 }, { 8, 24, 15 }, { 8, 24, 15 }, { 8, 24, 15 },
+ { 8, 24, 15 }, { 24, 8, 17 }, { 24, 8, 17 }, { 24, 8, 17 }, { 8, 41, 22 }, { 8, 41, 22 }, { 8, 41, 22 }, { 8, 41, 22 },
+ { 24, 24, 24 }, { 24, 24, 24 }, { 41, 8, 27 }, { 41, 8, 27 }, { 8, 57, 29 }, { 8, 57, 29 }, { 8, 57, 29 }, { 24, 41, 31 },
+ { 24, 41, 31 }, { 41, 24, 34 }, { 41, 24, 34 }, { 8, 74, 36 }, { 8, 74, 36 }, { 8, 74, 36 }, { 24, 57, 38 }, { 24, 57, 38 },
+ { 41, 41, 41 }, { 41, 41, 41 }, { 8, 90, 43 }, { 8, 90, 43 }, { 8, 90, 43 }, { 24, 74, 45 }, { 74, 8, 46 }, { 41, 57, 48 },
+ { 41, 57, 48 }, { 8, 107, 50 }, { 8, 107, 50 }, { 8, 107, 50 }, { 24, 90, 52 }, { 74, 24, 53 }, { 41, 74, 55 }, { 41, 74, 55 },
+ { 8, 123, 57 }, { 8, 123, 57 }, { 8, 123, 57 }, { 24, 107, 59 }, { 74, 41, 60 }, { 41, 90, 62 }, { 41, 90, 62 }, { 8, 140, 64 },
+ { 8, 140, 64 }, { 107, 8, 65 }, { 24, 123, 66 }, { 74, 57, 67 }, { 41, 107, 69 }, { 41, 107, 69 }, { 8, 156, 70 }, { 57, 90, 71 },
+ { 107, 24, 72 }, { 24, 140, 73 }, { 74, 74, 74 }, { 41, 123, 76 }, { 41, 123, 76 }, { 8, 173, 78 }, { 8, 173, 78 }, { 107, 41, 79 },
+ { 24, 156, 80 }, { 74, 90, 81 }, { 41, 140, 83 }, { 41, 140, 83 }, { 8, 189, 84 }, { 57, 123, 85 }, { 107, 57, 86 }, { 24, 173, 87 },
+ { 74, 107, 88 }, { 41, 156, 90 }, { 41, 156, 90 }, { 140, 24, 91 }, { 8, 206, 92 }, { 107, 74, 93 }, { 24, 189, 94 }, { 74, 123, 95 },
+ { 41, 173, 97 }, { 41, 173, 97 }, { 8, 222, 98 }, { 57, 156, 99 }, { 107, 90, 100 }, { 24, 206, 101 }, { 74, 140, 102 }, { 41, 189, 103 },
+ { 90, 123, 104 }, { 8, 239, 105 }, { 57, 173, 106 }, { 107, 107, 107 }, { 24, 222, 108 }, { 74, 156, 109 }, { 173, 24, 110 }, { 41, 206, 111 },
+ { 8, 255, 112 }, { 57, 189, 113 }, { 107, 123, 114 }, { 24, 239, 115 }, { 74, 173, 116 }, { 41, 222, 117 }, { 90, 156, 118 }, { 140, 90, 119 },
+ { 57, 206, 120 }, { 24, 255, 121 }, { 206, 8, 122 }, { 74, 189, 123 }, { 173, 57, 124 }, { 41, 239, 125 }, { 140, 107, 126 }, { 57, 222, 127 },
+ { 107, 156, 128 }, { 206, 24, 129 }, { 74, 206, 130 }, { 41, 255, 131 }, { 90, 189, 132 }, { 140, 123, 133 }, { 57, 239, 134 }, { 107, 173, 135 },
+ { 74, 222, 136 }, { 123, 156, 137 }, { 173, 90, 138 }, { 90, 206, 139 }, { 140, 140, 140 }, { 57, 255, 141 }, { 107, 189, 142 }, { 206, 57, 143 },
+ { 74, 239, 144 }, { 173, 107, 145 }, { 90, 222, 146 }, { 140, 156, 147 }, { 239, 24, 148 }, { 107, 206, 149 }, { 74, 255, 150 }, { 123, 189, 151 },
+ { 173, 123, 152 }, { 90, 239, 153 }, { 140, 173, 154 }, { 239, 41, 155 }, { 107, 222, 156 }, { 206, 90, 157 }, { 123, 206, 158 }, { 173, 140, 159 },
+ { 90, 255, 160 }, { 140, 189, 161 }, { 239, 57, 162 }, { 107, 239, 163 }, { 206, 107, 164 }, { 123, 222, 165 }, { 173, 156, 166 }, { 140, 206, 168 },
+ { 140, 206, 168 }, { 107, 255, 169 }, { 156, 189, 170 }, { 206, 123, 171 }, { 123, 239, 172 }, { 173, 173, 173 }, { 140, 222, 175 }, { 140, 222, 175 },
+ { 239, 90, 176 }, { 156, 206, 177 }, { 206, 140, 178 }, { 123, 255, 179 }, { 173, 189, 180 }, { 140, 239, 182 }, { 140, 239, 182 }, { 239, 107, 183 },
+ { 156, 222, 184 }, { 206, 156, 185 }, { 173, 206, 187 }, { 173, 206, 187 }, { 140, 255, 189 }, { 140, 255, 189 }, { 239, 123, 190 }, { 156, 239, 191 },
+ { 206, 173, 192 }, { 255, 107, 193 }, { 173, 222, 194 }, { 173, 222, 194 }, { 189, 206, 196 }, { 239, 140, 197 }, { 156, 255, 198 }, { 206, 189, 199 },
+ { 173, 239, 201 }, { 173, 239, 201 }, { 173, 239, 201 }, { 189, 222, 203 }, { 239, 156, 204 }, { 206, 206, 206 }, { 206, 206, 206 }, { 173, 255, 208 },
+ { 173, 255, 208 }, { 173, 255, 208 }, { 189, 239, 210 }, { 239, 173, 211 }, { 206, 222, 213 }, { 206, 222, 213 }, { 206, 222, 213 }, { 222, 206, 215 },
+ { 189, 255, 217 }, { 189, 255, 217 }, { 239, 189, 218 }, { 206, 239, 220 }, { 206, 239, 220 }, { 206, 239, 220 }, { 222, 222, 222 }, { 222, 222, 222 },
+ { 239, 206, 225 }, { 239, 206, 225 }, { 206, 255, 227 }, { 206, 255, 227 }, { 206, 255, 227 }, { 222, 239, 229 }, { 222, 239, 229 }, { 239, 222, 232 },
+ { 239, 222, 232 }, { 239, 222, 232 }, { 255, 206, 234 }, { 222, 255, 236 }, { 222, 255, 236 }, { 222, 255, 236 }, { 239, 239, 239 }, { 239, 239, 239 },
+ { 239, 239, 239 }, { 255, 222, 241 }, { 255, 222, 241 }, { 255, 222, 241 }, { 239, 255, 246 }, { 239, 255, 246 }, { 239, 255, 246 }, { 239, 255, 246 },
+ { 255, 239, 248 }, { 255, 239, 248 }, { 255, 239, 248 }, { 255, 239, 248 }, { 255, 255, 255 }, { 255, 255, 255 }, { 255, 255, 255 }, { 255, 255, 255 },
+ }
+};
+
+Table g_mode0_p11_i1=
+{
+ 1,
+ 3,
+ {
+ { 8, 8, 8 }, { 8, 8, 8 }, { 8, 8, 8 }, { 8, 8, 8 }, { 8, 8, 8 }, { 8, 8, 8 }, { 8, 8, 8 }, { 8, 8, 8 },
+ { 8, 8, 8 }, { 8, 8, 8 }, { 8, 24, 10 }, { 8, 24, 10 }, { 8, 41, 13 }, { 8, 41, 13 }, { 8, 41, 13 }, { 8, 57, 15 },
+ { 8, 57, 15 }, { 8, 74, 17 }, { 8, 74, 17 }, { 8, 90, 20 }, { 8, 90, 20 }, { 8, 90, 20 }, { 8, 107, 22 }, { 8, 107, 22 },
+ { 8, 123, 24 }, { 8, 123, 24 }, { 24, 41, 26 }, { 8, 140, 27 }, { 8, 140, 27 }, { 8, 156, 29 }, { 8, 156, 29 }, { 8, 173, 31 },
+ { 8, 173, 31 }, { 8, 189, 33 }, { 8, 189, 33 }, { 8, 206, 36 }, { 8, 206, 36 }, { 8, 206, 36 }, { 8, 222, 38 }, { 41, 24, 39 },
+ { 8, 239, 40 }, { 41, 41, 41 }, { 8, 255, 43 }, { 8, 255, 43 }, { 8, 255, 43 }, { 24, 173, 45 }, { 41, 74, 46 }, { 24, 189, 47 },
+ { 41, 90, 48 }, { 24, 206, 50 }, { 24, 206, 50 }, { 24, 206, 50 }, { 24, 222, 52 }, { 41, 123, 53 }, { 24, 239, 54 }, { 41, 140, 55 },
+ { 24, 255, 56 }, { 41, 156, 57 }, { 41, 156, 57 }, { 57, 74, 59 }, { 41, 173, 60 }, { 41, 173, 60 }, { 41, 189, 62 }, { 41, 189, 62 },
+ { 41, 206, 64 }, { 74, 8, 65 }, { 41, 222, 66 }, { 74, 24, 67 }, { 41, 239, 69 }, { 41, 239, 69 }, { 41, 239, 69 }, { 41, 255, 71 },
+ { 74, 57, 72 }, { 57, 173, 73 }, { 74, 74, 74 }, { 57, 189, 76 }, { 57, 189, 76 }, { 57, 189, 76 }, { 57, 206, 78 }, { 74, 107, 79 },
+ { 57, 222, 80 }, { 74, 123, 81 }, { 57, 239, 83 }, { 57, 239, 83 }, { 57, 239, 83 }, { 57, 255, 85 }, { 74, 156, 86 }, { 74, 156, 86 },
+ { 74, 173, 88 }, { 74, 173, 88 }, { 74, 189, 90 }, { 74, 189, 90 }, { 90, 107, 92 }, { 74, 206, 93 }, { 74, 206, 93 }, { 74, 222, 95 },
+ { 74, 222, 95 }, { 74, 239, 97 }, { 107, 41, 98 }, { 74, 255, 99 }, { 107, 57, 100 }, { 90, 173, 102 }, { 90, 173, 102 }, { 90, 173, 102 },
+ { 90, 189, 104 }, { 107, 90, 105 }, { 90, 206, 106 }, { 107, 107, 107 }, { 90, 222, 109 }, { 90, 222, 109 }, { 90, 222, 109 }, { 90, 239, 111 },
+ { 107, 140, 112 }, { 90, 255, 113 }, { 107, 156, 114 }, { 107, 156, 114 }, { 107, 173, 116 }, { 107, 173, 116 }, { 123, 90, 118 }, { 107, 189, 119 },
+ { 107, 189, 119 }, { 107, 206, 121 }, { 107, 206, 121 }, { 107, 222, 123 }, { 140, 24, 124 }, { 123, 140, 125 }, { 107, 239, 126 }, { 107, 239, 126 },
+ { 107, 255, 128 }, { 107, 255, 128 }, { 123, 173, 130 }, { 140, 74, 131 }, { 123, 189, 132 }, { 140, 90, 133 }, { 123, 206, 135 }, { 123, 206, 135 },
+ { 123, 206, 135 }, { 123, 222, 137 }, { 140, 123, 138 }, { 123, 239, 139 }, { 140, 140, 140 }, { 123, 255, 142 }, { 123, 255, 142 }, { 123, 255, 142 },
+ { 156, 74, 144 }, { 140, 173, 145 }, { 140, 173, 145 }, { 140, 189, 147 }, { 140, 189, 147 }, { 140, 206, 149 }, { 173, 8, 150 }, { 156, 123, 151 },
+ { 140, 222, 152 }, { 140, 222, 152 }, { 140, 239, 154 }, { 140, 239, 154 }, { 140, 255, 156 }, { 173, 57, 157 }, { 156, 173, 158 }, { 173, 74, 159 },
+ { 156, 189, 161 }, { 156, 189, 161 }, { 156, 189, 161 }, { 156, 206, 163 }, { 173, 107, 164 }, { 156, 222, 165 }, { 173, 123, 166 }, { 156, 239, 168 },
+ { 156, 239, 168 }, { 156, 239, 168 }, { 156, 255, 170 }, { 173, 156, 171 }, { 173, 156, 171 }, { 173, 173, 173 }, { 173, 173, 173 }, { 173, 189, 175 },
+ { 173, 189, 175 }, { 189, 107, 177 }, { 173, 206, 178 }, { 173, 206, 178 }, { 173, 222, 180 }, { 173, 222, 180 }, { 173, 239, 182 }, { 206, 41, 183 },
+ { 189, 156, 184 }, { 173, 255, 185 }, { 173, 255, 185 }, { 189, 173, 187 }, { 189, 173, 187 }, { 189, 189, 189 }, { 206, 90, 190 }, { 189, 206, 191 },
+ { 206, 107, 192 }, { 189, 222, 194 }, { 189, 222, 194 }, { 189, 222, 194 }, { 189, 239, 196 }, { 206, 140, 197 }, { 189, 255, 198 }, { 206, 156, 199 },
+ { 206, 156, 199 }, { 206, 173, 201 }, { 206, 173, 201 }, { 222, 90, 203 }, { 206, 189, 204 }, { 206, 189, 204 }, { 206, 206, 206 }, { 239, 8, 207 },
+ { 206, 222, 208 }, { 239, 24, 209 }, { 222, 140, 210 }, { 206, 239, 211 }, { 206, 239, 211 }, { 206, 255, 213 }, { 206, 255, 213 }, { 222, 173, 215 },
+ { 239, 74, 216 }, { 222, 189, 217 }, { 239, 90, 218 }, { 222, 206, 220 }, { 222, 206, 220 }, { 222, 206, 220 }, { 222, 222, 222 }, { 239, 123, 223 },
+ { 222, 239, 224 }, { 239, 140, 225 }, { 222, 255, 227 }, { 222, 255, 227 }, { 222, 255, 227 }, { 239, 173, 230 }, { 239, 173, 230 }, { 239, 173, 230 },
+ { 239, 189, 232 }, { 239, 189, 232 }, { 239, 206, 234 }, { 239, 206, 234 }, { 255, 123, 236 }, { 239, 222, 237 }, { 239, 222, 237 }, { 239, 239, 239 },
+ { 239, 239, 239 }, { 239, 255, 241 }, { 239, 255, 241 }, { 255, 173, 243 }, { 255, 173, 243 }, { 255, 189, 246 }, { 255, 189, 246 }, { 255, 189, 246 },
+ { 255, 206, 248 }, { 255, 206, 248 }, { 255, 222, 250 }, { 255, 222, 250 }, { 255, 239, 253 }, { 255, 239, 253 }, { 255, 239, 253 }, { 255, 255, 255 },
+ }
+};
+
+Table g_mode0_p11_i2=
+{
+ 2,
+ 3,
+ {
+ { 8, 8, 8 }, { 8, 8, 8 }, { 8, 8, 8 }, { 8, 8, 8 }, { 8, 8, 8 }, { 8, 8, 8 }, { 8, 8, 8 }, { 8, 8, 8 },
+ { 8, 8, 8 }, { 8, 8, 8 }, { 8, 8, 8 }, { 8, 24, 13 }, { 8, 24, 13 }, { 8, 24, 13 }, { 8, 24, 13 }, { 8, 24, 13 },
+ { 8, 41, 17 }, { 8, 41, 17 }, { 8, 41, 17 }, { 24, 8, 20 }, { 24, 8, 20 }, { 8, 57, 22 }, { 8, 57, 22 }, { 8, 57, 22 },
+ { 24, 24, 24 }, { 24, 24, 24 }, { 8, 74, 27 }, { 8, 74, 27 }, { 8, 74, 27 }, { 24, 41, 29 }, { 8, 90, 31 }, { 8, 90, 31 },
+ { 41, 8, 32 }, { 24, 57, 33 }, { 24, 57, 33 }, { 8, 107, 36 }, { 8, 107, 36 }, { 8, 107, 36 }, { 24, 74, 38 }, { 8, 123, 40 },
+ { 8, 123, 40 }, { 41, 41, 41 }, { 24, 90, 43 }, { 24, 90, 43 }, { 8, 140, 45 }, { 8, 140, 45 }, { 41, 57, 46 }, { 24, 107, 47 },
+ { 57, 24, 48 }, { 8, 156, 50 }, { 8, 156, 50 }, { 8, 156, 50 }, { 24, 123, 52 }, { 57, 41, 53 }, { 8, 173, 54 }, { 41, 90, 55 },
+ { 24, 140, 57 }, { 24, 140, 57 }, { 8, 189, 59 }, { 8, 189, 59 }, { 41, 107, 60 }, { 24, 156, 61 }, { 57, 74, 62 }, { 8, 206, 64 },
+ { 8, 206, 64 }, { 74, 41, 65 }, { 24, 173, 66 }, { 90, 8, 67 }, { 8, 222, 68 }, { 41, 140, 69 }, { 24, 189, 70 }, { 57, 107, 71 },
+ { 8, 239, 73 }, { 8, 239, 73 }, { 74, 74, 74 }, { 24, 206, 75 }, { 57, 123, 76 }, { 8, 255, 77 }, { 41, 173, 78 }, { 74, 90, 79 },
+ { 24, 222, 80 }, { 90, 57, 81 }, { 41, 189, 83 }, { 41, 189, 83 }, { 24, 239, 84 }, { 57, 156, 85 }, { 90, 74, 86 }, { 41, 206, 87 },
+ { 74, 123, 88 }, { 24, 255, 89 }, { 57, 173, 90 }, { 123, 8, 91 }, { 41, 222, 92 }, { 74, 140, 93 }, { 57, 189, 94 }, { 90, 107, 95 },
+ { 41, 239, 97 }, { 41, 239, 97 }, { 107, 74, 98 }, { 57, 206, 99 }, { 123, 41, 100 }, { 41, 255, 101 }, { 74, 173, 102 }, { 57, 222, 103 },
+ { 90, 140, 104 }, { 74, 189, 106 }, { 74, 189, 106 }, { 107, 107, 107 }, { 57, 239, 108 }, { 90, 156, 109 }, { 74, 206, 111 }, { 74, 206, 111 },
+ { 107, 123, 112 }, { 57, 255, 113 }, { 123, 90, 114 }, { 74, 222, 116 }, { 74, 222, 116 }, { 140, 57, 117 }, { 90, 189, 118 }, { 123, 107, 119 },
+ { 74, 239, 120 }, { 107, 156, 121 }, { 90, 206, 123 }, { 90, 206, 123 }, { 156, 41, 124 }, { 74, 255, 125 }, { 107, 173, 126 }, { 90, 222, 127 },
+ { 123, 140, 128 }, { 107, 189, 130 }, { 107, 189, 130 }, { 140, 107, 131 }, { 90, 239, 132 }, { 156, 74, 133 }, { 107, 206, 135 }, { 107, 206, 135 },
+ { 90, 255, 136 }, { 123, 173, 137 }, { 189, 8, 138 }, { 107, 222, 139 }, { 140, 140, 140 }, { 123, 189, 142 }, { 123, 189, 142 }, { 189, 24, 143 },
+ { 107, 239, 144 }, { 140, 156, 145 }, { 123, 206, 146 }, { 156, 123, 147 }, { 107, 255, 149 }, { 107, 255, 149 }, { 173, 90, 150 }, { 123, 222, 151 },
+ { 156, 140, 152 }, { 140, 189, 154 }, { 140, 189, 154 }, { 206, 24, 155 }, { 123, 239, 156 }, { 189, 74, 157 }, { 140, 206, 159 }, { 140, 206, 159 },
+ { 123, 255, 160 }, { 156, 173, 161 }, { 222, 8, 162 }, { 140, 222, 163 }, { 173, 140, 164 }, { 156, 189, 165 }, { 189, 107, 166 }, { 140, 239, 168 },
+ { 140, 239, 168 }, { 206, 74, 169 }, { 156, 206, 170 }, { 222, 41, 171 }, { 140, 255, 172 }, { 173, 173, 173 }, { 239, 8, 174 }, { 156, 222, 175 },
+ { 222, 57, 176 }, { 173, 189, 178 }, { 173, 189, 178 }, { 156, 239, 179 }, { 189, 156, 180 }, { 173, 206, 182 }, { 173, 206, 182 }, { 206, 123, 183 },
+ { 156, 255, 184 }, { 189, 173, 185 }, { 255, 8, 186 }, { 173, 222, 187 }, { 239, 57, 188 }, { 189, 189, 189 }, { 222, 107, 190 }, { 173, 239, 192 },
+ { 173, 239, 192 }, { 239, 74, 193 }, { 189, 206, 194 }, { 255, 41, 195 }, { 173, 255, 196 }, { 206, 173, 197 }, { 189, 222, 198 }, { 222, 140, 199 },
+ { 206, 189, 201 }, { 206, 189, 201 }, { 239, 107, 202 }, { 189, 239, 203 }, { 255, 74, 204 }, { 206, 206, 206 }, { 206, 206, 206 }, { 189, 255, 208 },
+ { 189, 255, 208 }, { 255, 90, 209 }, { 206, 222, 211 }, { 206, 222, 211 }, { 206, 222, 211 }, { 222, 189, 213 }, { 206, 239, 215 }, { 206, 239, 215 },
+ { 239, 156, 216 }, { 222, 206, 218 }, { 222, 206, 218 }, { 206, 255, 220 }, { 206, 255, 220 }, { 206, 255, 220 }, { 222, 222, 222 }, { 255, 140, 223 },
+ { 239, 189, 225 }, { 239, 189, 225 }, { 222, 239, 227 }, { 222, 239, 227 }, { 222, 239, 227 }, { 239, 206, 230 }, { 239, 206, 230 }, { 222, 255, 231 },
+ { 255, 173, 232 }, { 239, 222, 234 }, { 239, 222, 234 }, { 239, 222, 234 }, { 255, 189, 236 }, { 255, 189, 236 }, { 239, 239, 239 }, { 239, 239, 239 },
+ { 239, 239, 239 }, { 255, 206, 241 }, { 255, 206, 241 }, { 239, 255, 244 }, { 239, 255, 244 }, { 239, 255, 244 }, { 255, 222, 246 }, { 255, 222, 246 },
+ { 255, 222, 246 }, { 255, 239, 251 }, { 255, 239, 251 }, { 255, 239, 251 }, { 255, 239, 251 }, { 255, 239, 251 }, { 255, 255, 255 }, { 255, 255, 255 },
+ }
+};
+
+Table g_mode0_p11_i3=
+{
+ 3,
+ 3,
+ {
+ { 8, 8, 8 }, { 8, 8, 8 }, { 8, 8, 8 }, { 8, 8, 8 }, { 8, 8, 8 }, { 8, 8, 8 }, { 8, 8, 8 }, { 8, 8, 8 },
+ { 8, 8, 8 }, { 8, 8, 8 }, { 8, 8, 8 }, { 8, 8, 8 }, { 8, 24, 15 }, { 8, 24, 15 }, { 8, 24, 15 }, { 8, 24, 15 },
+ { 8, 24, 15 }, { 24, 8, 17 }, { 24, 8, 17 }, { 24, 8, 17 }, { 8, 41, 22 }, { 8, 41, 22 }, { 8, 41, 22 }, { 8, 41, 22 },
+ { 24, 24, 24 }, { 24, 24, 24 }, { 41, 8, 27 }, { 41, 8, 27 }, { 8, 57, 29 }, { 8, 57, 29 }, { 8, 57, 29 }, { 24, 41, 31 },
+ { 24, 41, 31 }, { 41, 24, 34 }, { 41, 24, 34 }, { 8, 74, 36 }, { 8, 74, 36 }, { 8, 74, 36 }, { 24, 57, 38 }, { 24, 57, 38 },
+ { 41, 41, 41 }, { 41, 41, 41 }, { 8, 90, 43 }, { 8, 90, 43 }, { 8, 90, 43 }, { 24, 74, 45 }, { 74, 8, 46 }, { 41, 57, 48 },
+ { 41, 57, 48 }, { 8, 107, 50 }, { 8, 107, 50 }, { 8, 107, 50 }, { 24, 90, 52 }, { 74, 24, 53 }, { 41, 74, 55 }, { 41, 74, 55 },
+ { 8, 123, 57 }, { 8, 123, 57 }, { 8, 123, 57 }, { 24, 107, 59 }, { 74, 41, 60 }, { 41, 90, 62 }, { 41, 90, 62 }, { 8, 140, 64 },
+ { 8, 140, 64 }, { 107, 8, 65 }, { 24, 123, 66 }, { 74, 57, 67 }, { 41, 107, 69 }, { 41, 107, 69 }, { 8, 156, 70 }, { 57, 90, 71 },
+ { 107, 24, 72 }, { 24, 140, 73 }, { 74, 74, 74 }, { 41, 123, 76 }, { 41, 123, 76 }, { 8, 173, 78 }, { 8, 173, 78 }, { 107, 41, 79 },
+ { 24, 156, 80 }, { 74, 90, 81 }, { 41, 140, 83 }, { 41, 140, 83 }, { 8, 189, 84 }, { 57, 123, 85 }, { 107, 57, 86 }, { 24, 173, 87 },
+ { 74, 107, 88 }, { 41, 156, 90 }, { 41, 156, 90 }, { 140, 24, 91 }, { 8, 206, 92 }, { 107, 74, 93 }, { 24, 189, 94 }, { 74, 123, 95 },
+ { 41, 173, 97 }, { 41, 173, 97 }, { 8, 222, 98 }, { 57, 156, 99 }, { 107, 90, 100 }, { 24, 206, 101 }, { 74, 140, 102 }, { 41, 189, 103 },
+ { 90, 123, 104 }, { 8, 239, 105 }, { 57, 173, 106 }, { 107, 107, 107 }, { 24, 222, 108 }, { 74, 156, 109 }, { 173, 24, 110 }, { 41, 206, 111 },
+ { 8, 255, 112 }, { 57, 189, 113 }, { 107, 123, 114 }, { 24, 239, 115 }, { 74, 173, 116 }, { 41, 222, 117 }, { 90, 156, 118 }, { 140, 90, 119 },
+ { 57, 206, 120 }, { 24, 255, 121 }, { 206, 8, 122 }, { 74, 189, 123 }, { 173, 57, 124 }, { 41, 239, 125 }, { 140, 107, 126 }, { 57, 222, 127 },
+ { 107, 156, 128 }, { 206, 24, 129 }, { 74, 206, 130 }, { 41, 255, 131 }, { 90, 189, 132 }, { 140, 123, 133 }, { 57, 239, 134 }, { 107, 173, 135 },
+ { 74, 222, 136 }, { 123, 156, 137 }, { 173, 90, 138 }, { 90, 206, 139 }, { 140, 140, 140 }, { 57, 255, 141 }, { 107, 189, 142 }, { 206, 57, 143 },
+ { 74, 239, 144 }, { 173, 107, 145 }, { 90, 222, 146 }, { 140, 156, 147 }, { 239, 24, 148 }, { 107, 206, 149 }, { 74, 255, 150 }, { 123, 189, 151 },
+ { 173, 123, 152 }, { 90, 239, 153 }, { 140, 173, 154 }, { 239, 41, 155 }, { 107, 222, 156 }, { 206, 90, 157 }, { 123, 206, 158 }, { 173, 140, 159 },
+ { 90, 255, 160 }, { 140, 189, 161 }, { 239, 57, 162 }, { 107, 239, 163 }, { 206, 107, 164 }, { 123, 222, 165 }, { 173, 156, 166 }, { 140, 206, 168 },
+ { 140, 206, 168 }, { 107, 255, 169 }, { 156, 189, 170 }, { 206, 123, 171 }, { 123, 239, 172 }, { 173, 173, 173 }, { 140, 222, 175 }, { 140, 222, 175 },
+ { 239, 90, 176 }, { 156, 206, 177 }, { 206, 140, 178 }, { 123, 255, 179 }, { 173, 189, 180 }, { 140, 239, 182 }, { 140, 239, 182 }, { 239, 107, 183 },
+ { 156, 222, 184 }, { 206, 156, 185 }, { 173, 206, 187 }, { 173, 206, 187 }, { 140, 255, 189 }, { 140, 255, 189 }, { 239, 123, 190 }, { 156, 239, 191 },
+ { 206, 173, 192 }, { 255, 107, 193 }, { 173, 222, 194 }, { 173, 222, 194 }, { 189, 206, 196 }, { 239, 140, 197 }, { 156, 255, 198 }, { 206, 189, 199 },
+ { 173, 239, 201 }, { 173, 239, 201 }, { 173, 239, 201 }, { 189, 222, 203 }, { 239, 156, 204 }, { 206, 206, 206 }, { 206, 206, 206 }, { 173, 255, 208 },
+ { 173, 255, 208 }, { 173, 255, 208 }, { 189, 239, 210 }, { 239, 173, 211 }, { 206, 222, 213 }, { 206, 222, 213 }, { 206, 222, 213 }, { 222, 206, 215 },
+ { 189, 255, 217 }, { 189, 255, 217 }, { 239, 189, 218 }, { 206, 239, 220 }, { 206, 239, 220 }, { 206, 239, 220 }, { 222, 222, 222 }, { 222, 222, 222 },
+ { 239, 206, 225 }, { 239, 206, 225 }, { 206, 255, 227 }, { 206, 255, 227 }, { 206, 255, 227 }, { 222, 239, 229 }, { 222, 239, 229 }, { 239, 222, 232 },
+ { 239, 222, 232 }, { 239, 222, 232 }, { 255, 206, 234 }, { 222, 255, 236 }, { 222, 255, 236 }, { 222, 255, 236 }, { 239, 239, 239 }, { 239, 239, 239 },
+ { 239, 239, 239 }, { 255, 222, 241 }, { 255, 222, 241 }, { 255, 222, 241 }, { 239, 255, 246 }, { 239, 255, 246 }, { 239, 255, 246 }, { 239, 255, 246 },
+ { 255, 239, 248 }, { 255, 239, 248 }, { 255, 239, 248 }, { 255, 239, 248 }, { 255, 255, 255 }, { 255, 255, 255 }, { 255, 255, 255 }, { 255, 255, 255 },
+ }
+};
+
+Table g_mode1_p0_i1=
+{
+ 1,
+ 0,
+ {
+ { 0, 0, 0 }, { 0, 4, 1 }, { 0, 12, 2 }, { 0, 20, 3 }, { 0, 28, 4 }, { 0, 32, 5 }, { 0, 40, 6 }, { 0, 48, 7 },
+ { 0, 56, 8 }, { 0, 64, 9 }, { 0, 68, 10 }, { 0, 76, 11 }, { 0, 84, 12 }, { 0, 92, 13 }, { 0, 96, 14 }, { 0, 104, 15 },
+ { 0, 112, 16 }, { 0, 120, 17 }, { 0, 129, 18 }, { 0, 133, 19 }, { 0, 141, 20 }, { 0, 149, 21 }, { 0, 153, 22 }, { 0, 161, 23 },
+ { 0, 169, 24 }, { 0, 177, 25 }, { 0, 185, 26 }, { 0, 189, 27 }, { 0, 197, 28 }, { 0, 205, 29 }, { 0, 213, 30 }, { 0, 217, 31 },
+ { 0, 225, 32 }, { 0, 233, 33 }, { 0, 241, 34 }, { 0, 249, 35 }, { 0, 253, 36 }, { 4, 237, 37 }, { 4, 245, 38 }, { 4, 253, 39 },
+ { 8, 233, 40 }, { 8, 241, 41 }, { 8, 249, 42 }, { 12, 229, 43 }, { 12, 237, 44 }, { 12, 245, 45 }, { 12, 253, 46 }, { 16, 233, 47 },
+ { 16, 241, 48 }, { 16, 249, 49 }, { 20, 233, 50 }, { 20, 237, 51 }, { 20, 245, 52 }, { 20, 253, 53 }, { 24, 237, 54 }, { 24, 241, 55 },
+ { 24, 249, 56 }, { 28, 233, 57 }, { 28, 241, 58 }, { 28, 245, 59 }, { 28, 253, 60 }, { 32, 237, 61 }, { 32, 245, 62 }, { 32, 249, 63 },
+ { 36, 233, 64 }, { 36, 241, 65 }, { 36, 249, 66 }, { 36, 253, 67 }, { 40, 237, 68 }, { 40, 245, 69 }, { 40, 253, 70 }, { 44, 233, 71 },
+ { 44, 241, 72 }, { 44, 249, 73 }, { 48, 233, 74 }, { 48, 237, 75 }, { 48, 245, 76 }, { 48, 253, 77 }, { 52, 237, 78 }, { 52, 241, 79 },
+ { 52, 249, 80 }, { 56, 233, 81 }, { 56, 241, 82 }, { 56, 245, 83 }, { 56, 253, 84 }, { 60, 237, 85 }, { 60, 245, 86 }, { 60, 249, 87 },
+ { 64, 233, 88 }, { 64, 241, 89 }, { 64, 249, 90 }, { 64, 253, 91 }, { 68, 237, 92 }, { 68, 245, 93 }, { 68, 253, 94 }, { 72, 233, 95 },
+ { 72, 241, 96 }, { 72, 249, 97 }, { 76, 229, 98 }, { 76, 237, 99 }, { 76, 245, 100 }, { 76, 253, 101 }, { 80, 233, 102 }, { 80, 241, 103 },
+ { 80, 249, 104 }, { 84, 233, 105 }, { 84, 237, 106 }, { 84, 245, 107 }, { 84, 253, 108 }, { 88, 237, 109 }, { 88, 241, 110 }, { 88, 249, 111 },
+ { 92, 233, 112 }, { 92, 241, 113 }, { 92, 245, 114 }, { 92, 253, 115 }, { 96, 237, 116 }, { 96, 245, 117 }, { 96, 249, 118 }, { 100, 233, 119 },
+ { 100, 241, 120 }, { 100, 249, 121 }, { 100, 253, 122 }, { 104, 237, 123 }, { 104, 245, 124 }, { 104, 253, 125 }, { 108, 233, 126 }, { 108, 241, 127 },
+ { 108, 249, 128 }, { 112, 233, 129 }, { 112, 237, 130 }, { 112, 245, 131 }, { 112, 253, 132 }, { 116, 237, 133 }, { 116, 241, 134 }, { 116, 249, 135 },
+ { 120, 233, 136 }, { 120, 241, 137 }, { 120, 245, 138 }, { 120, 253, 139 }, { 124, 237, 140 }, { 124, 245, 141 }, { 124, 249, 142 }, { 129, 225, 143 },
+ { 129, 233, 144 }, { 129, 241, 145 }, { 129, 249, 146 }, { 133, 229, 147 }, { 133, 237, 148 }, { 133, 245, 149 }, { 133, 253, 150 }, { 137, 233, 151 },
+ { 137, 241, 152 }, { 137, 249, 153 }, { 141, 233, 154 }, { 141, 237, 155 }, { 141, 245, 156 }, { 141, 253, 157 }, { 145, 237, 158 }, { 145, 241, 159 },
+ { 145, 249, 160 }, { 149, 233, 161 }, { 149, 241, 162 }, { 149, 245, 163 }, { 149, 253, 164 }, { 153, 237, 165 }, { 153, 245, 166 }, { 153, 249, 167 },
+ { 157, 233, 168 }, { 157, 241, 169 }, { 157, 249, 170 }, { 157, 253, 171 }, { 161, 237, 172 }, { 161, 245, 173 }, { 161, 253, 174 }, { 165, 233, 175 },
+ { 165, 241, 176 }, { 165, 249, 177 }, { 169, 233, 178 }, { 169, 237, 179 }, { 169, 245, 180 }, { 169, 253, 181 }, { 173, 237, 182 }, { 173, 241, 183 },
+ { 173, 249, 184 }, { 177, 233, 185 }, { 177, 241, 186 }, { 177, 245, 187 }, { 177, 253, 188 }, { 181, 237, 189 }, { 181, 245, 190 }, { 181, 249, 191 },
+ { 185, 233, 192 }, { 185, 241, 193 }, { 185, 249, 194 }, { 185, 253, 195 }, { 189, 237, 196 }, { 189, 245, 197 }, { 189, 253, 198 }, { 193, 233, 199 },
+ { 193, 241, 200 }, { 193, 249, 201 }, { 197, 229, 202 }, { 197, 237, 203 }, { 197, 245, 204 }, { 197, 253, 205 }, { 201, 233, 206 }, { 201, 241, 207 },
+ { 201, 249, 208 }, { 205, 233, 209 }, { 205, 237, 210 }, { 205, 245, 211 }, { 205, 253, 212 }, { 209, 237, 213 }, { 209, 241, 214 }, { 209, 249, 215 },
+ { 213, 233, 216 }, { 213, 241, 217 }, { 213, 245, 218 }, { 213, 253, 219 }, { 217, 237, 220 }, { 217, 245, 221 }, { 217, 249, 222 }, { 221, 233, 223 },
+ { 221, 241, 224 }, { 221, 249, 225 }, { 221, 253, 226 }, { 225, 237, 227 }, { 225, 245, 228 }, { 225, 253, 229 }, { 229, 233, 230 }, { 229, 241, 231 },
+ { 229, 249, 232 }, { 233, 233, 233 }, { 233, 237, 234 }, { 233, 245, 235 }, { 233, 253, 236 }, { 237, 237, 237 }, { 237, 241, 238 }, { 237, 249, 239 },
+ { 241, 233, 240 }, { 241, 241, 241 }, { 241, 245, 242 }, { 241, 253, 243 }, { 245, 237, 244 }, { 245, 245, 245 }, { 245, 249, 246 }, { 249, 233, 247 },
+ { 249, 241, 248 }, { 249, 249, 249 }, { 249, 253, 250 }, { 253, 237, 251 }, { 253, 245, 252 }, { 253, 253, 253 }, { 253, 253, 253 }, { 253, 253, 253 },
+ }
+};
+
+Table g_mode1_p0_i2=
+{
+ 2,
+ 0,
+ {
+ { 0, 0, 0 }, { 0, 4, 1 }, { 0, 8, 2 }, { 0, 12, 3 }, { 4, 4, 4 }, { 0, 16, 5 }, { 0, 20, 6 }, { 0, 24, 7 },
+ { 0, 28, 8 }, { 0, 32, 9 }, { 0, 36, 10 }, { 0, 40, 11 }, { 0, 44, 12 }, { 4, 36, 13 }, { 0, 48, 14 }, { 0, 52, 15 },
+ { 0, 56, 16 }, { 0, 60, 17 }, { 0, 64, 18 }, { 0, 68, 19 }, { 0, 72, 20 }, { 0, 76, 21 }, { 4, 68, 22 }, { 0, 80, 23 },
+ { 0, 84, 24 }, { 0, 88, 25 }, { 0, 92, 26 }, { 0, 96, 27 }, { 0, 100, 28 }, { 0, 104, 29 }, { 0, 108, 30 }, { 4, 100, 31 },
+ { 0, 112, 32 }, { 0, 116, 33 }, { 0, 120, 34 }, { 0, 124, 35 }, { 0, 129, 36 }, { 0, 133, 37 }, { 4, 124, 38 }, { 0, 137, 39 },
+ { 0, 141, 40 }, { 0, 145, 41 }, { 0, 149, 42 }, { 0, 153, 43 }, { 0, 157, 44 }, { 0, 161, 45 }, { 0, 165, 46 }, { 4, 157, 47 },
+ { 0, 169, 48 }, { 0, 173, 49 }, { 0, 177, 50 }, { 0, 181, 51 }, { 0, 185, 52 }, { 0, 189, 53 }, { 0, 193, 54 }, { 0, 197, 55 },
+ { 4, 189, 56 }, { 0, 201, 57 }, { 0, 205, 58 }, { 0, 209, 59 }, { 0, 213, 60 }, { 0, 217, 61 }, { 0, 221, 62 }, { 0, 225, 63 },
+ { 0, 229, 64 }, { 4, 221, 65 }, { 0, 233, 66 }, { 0, 237, 67 }, { 0, 241, 68 }, { 0, 245, 69 }, { 0, 249, 70 }, { 0, 253, 71 },
+ { 4, 245, 72 }, { 4, 249, 73 }, { 4, 253, 74 }, { 8, 245, 75 }, { 8, 249, 76 }, { 8, 253, 77 }, { 12, 245, 78 }, { 12, 249, 79 },
+ { 12, 253, 80 }, { 20, 237, 81 }, { 16, 249, 82 }, { 16, 253, 83 }, { 20, 249, 84 }, { 24, 241, 85 }, { 20, 253, 86 }, { 24, 249, 87 },
+ { 24, 253, 88 }, { 28, 245, 89 }, { 28, 249, 90 }, { 28, 253, 91 }, { 32, 245, 92 }, { 32, 249, 93 }, { 32, 253, 94 }, { 36, 245, 95 },
+ { 36, 249, 96 }, { 36, 253, 97 }, { 40, 245, 98 }, { 40, 249, 99 }, { 40, 253, 100 }, { 44, 245, 101 }, { 44, 249, 102 }, { 44, 253, 103 },
+ { 52, 237, 104 }, { 48, 249, 105 }, { 48, 253, 106 }, { 52, 249, 107 }, { 56, 241, 108 }, { 52, 253, 109 }, { 56, 249, 110 }, { 56, 253, 111 },
+ { 60, 245, 112 }, { 60, 249, 113 }, { 60, 253, 114 }, { 64, 245, 115 }, { 64, 249, 116 }, { 64, 253, 117 }, { 68, 245, 118 }, { 68, 249, 119 },
+ { 68, 253, 120 }, { 72, 245, 121 }, { 72, 249, 122 }, { 72, 253, 123 }, { 76, 245, 124 }, { 76, 249, 125 }, { 76, 253, 126 }, { 84, 237, 127 },
+ { 80, 249, 128 }, { 80, 253, 129 }, { 84, 249, 130 }, { 88, 241, 131 }, { 84, 253, 132 }, { 88, 249, 133 }, { 88, 253, 134 }, { 92, 245, 135 },
+ { 92, 249, 136 }, { 92, 253, 137 }, { 96, 245, 138 }, { 96, 249, 139 }, { 96, 253, 140 }, { 100, 245, 141 }, { 100, 249, 142 }, { 100, 253, 143 },
+ { 104, 245, 144 }, { 104, 249, 145 }, { 104, 253, 146 }, { 108, 245, 147 }, { 108, 249, 148 }, { 108, 253, 149 }, { 116, 237, 150 }, { 112, 249, 151 },
+ { 112, 253, 152 }, { 116, 249, 153 }, { 120, 241, 154 }, { 116, 253, 155 }, { 120, 249, 156 }, { 120, 253, 157 }, { 124, 245, 158 }, { 124, 249, 159 },
+ { 124, 253, 160 }, { 129, 241, 161 }, { 129, 245, 162 }, { 129, 249, 163 }, { 129, 253, 164 }, { 133, 245, 165 }, { 133, 249, 166 }, { 133, 253, 167 },
+ { 141, 237, 168 }, { 137, 249, 169 }, { 137, 253, 170 }, { 141, 249, 171 }, { 145, 241, 172 }, { 141, 253, 173 }, { 145, 249, 174 }, { 145, 253, 175 },
+ { 149, 245, 176 }, { 149, 249, 177 }, { 149, 253, 178 }, { 153, 245, 179 }, { 153, 249, 180 }, { 153, 253, 181 }, { 157, 245, 182 }, { 157, 249, 183 },
+ { 157, 253, 184 }, { 161, 245, 185 }, { 161, 249, 186 }, { 161, 253, 187 }, { 165, 245, 188 }, { 165, 249, 189 }, { 165, 253, 190 }, { 173, 237, 191 },
+ { 169, 249, 192 }, { 169, 253, 193 }, { 173, 249, 194 }, { 177, 241, 195 }, { 173, 253, 196 }, { 177, 249, 197 }, { 177, 253, 198 }, { 181, 245, 199 },
+ { 181, 249, 200 }, { 181, 253, 201 }, { 185, 245, 202 }, { 185, 249, 203 }, { 185, 253, 204 }, { 189, 245, 205 }, { 189, 249, 206 }, { 189, 253, 207 },
+ { 193, 245, 208 }, { 193, 249, 209 }, { 193, 253, 210 }, { 197, 245, 211 }, { 197, 249, 212 }, { 197, 253, 213 }, { 205, 237, 214 }, { 201, 249, 215 },
+ { 201, 253, 216 }, { 205, 249, 217 }, { 209, 241, 218 }, { 205, 253, 219 }, { 209, 249, 220 }, { 209, 253, 221 }, { 213, 245, 222 }, { 213, 249, 223 },
+ { 213, 253, 224 }, { 217, 245, 225 }, { 217, 249, 226 }, { 217, 253, 227 }, { 221, 245, 228 }, { 221, 249, 229 }, { 221, 253, 230 }, { 225, 245, 231 },
+ { 225, 249, 232 }, { 225, 253, 233 }, { 229, 245, 234 }, { 229, 249, 235 }, { 229, 253, 236 }, { 237, 237, 237 }, { 233, 249, 238 }, { 233, 253, 239 },
+ { 237, 249, 240 }, { 241, 241, 241 }, { 237, 253, 242 }, { 241, 249, 243 }, { 241, 253, 244 }, { 245, 245, 245 }, { 245, 249, 246 }, { 245, 253, 247 },
+ { 249, 245, 248 }, { 249, 249, 249 }, { 249, 253, 250 }, { 253, 245, 251 }, { 253, 249, 252 }, { 253, 253, 253 }, { 253, 253, 253 }, { 253, 253, 253 },
+ }
+};
+
+Table g_mode1_p0_i3=
+{
+ 3,
+ 0,
+ {
+ { 0, 0, 0 }, { 0, 0, 0 }, { 0, 4, 2 }, { 0, 8, 3 }, { 4, 4, 4 }, { 0, 12, 5 }, { 4, 8, 6 }, { 0, 16, 7 },
+ { 0, 20, 8 }, { 4, 16, 9 }, { 0, 24, 10 }, { 4, 20, 11 }, { 0, 28, 12 }, { 8, 20, 13 }, { 0, 32, 14 }, { 0, 36, 15 },
+ { 4, 32, 16 }, { 0, 40, 17 }, { 4, 36, 18 }, { 0, 44, 19 }, { 0, 48, 20 }, { 4, 44, 21 }, { 0, 52, 22 }, { 4, 48, 23 },
+ { 0, 56, 24 }, { 0, 60, 25 }, { 4, 56, 26 }, { 0, 64, 27 }, { 4, 60, 28 }, { 0, 68, 29 }, { 0, 72, 30 }, { 4, 68, 31 },
+ { 0, 76, 32 }, { 4, 72, 33 }, { 0, 80, 34 }, { 0, 84, 35 }, { 4, 80, 36 }, { 0, 88, 37 }, { 4, 84, 38 }, { 0, 92, 39 },
+ { 8, 84, 40 }, { 0, 96, 41 }, { 0, 100, 42 }, { 4, 96, 43 }, { 0, 104, 44 }, { 4, 100, 45 }, { 0, 108, 46 }, { 0, 112, 47 },
+ { 4, 108, 48 }, { 0, 116, 49 }, { 4, 112, 50 }, { 0, 120, 51 }, { 0, 124, 52 }, { 4, 120, 53 }, { 0, 129, 54 }, { 4, 124, 55 },
+ { 0, 133, 56 }, { 4, 129, 57 }, { 0, 137, 58 }, { 0, 141, 59 }, { 4, 137, 60 }, { 0, 145, 61 }, { 4, 141, 62 }, { 0, 149, 63 },
+ { 8, 141, 64 }, { 0, 153, 65 }, { 0, 157, 66 }, { 4, 153, 67 }, { 0, 161, 68 }, { 4, 157, 69 }, { 0, 165, 70 }, { 0, 169, 71 },
+ { 4, 165, 72 }, { 0, 173, 73 }, { 4, 169, 74 }, { 0, 177, 75 }, { 0, 181, 76 }, { 4, 177, 77 }, { 0, 185, 78 }, { 4, 181, 79 },
+ { 0, 189, 80 }, { 0, 193, 81 }, { 4, 189, 82 }, { 0, 197, 83 }, { 4, 193, 84 }, { 0, 201, 85 }, { 0, 205, 86 }, { 4, 201, 87 },
+ { 0, 209, 88 }, { 4, 205, 89 }, { 0, 213, 90 }, { 8, 205, 91 }, { 0, 217, 92 }, { 0, 221, 93 }, { 4, 217, 94 }, { 0, 225, 95 },
+ { 4, 221, 96 }, { 0, 229, 97 }, { 0, 233, 98 }, { 4, 229, 99 }, { 0, 237, 100 }, { 4, 233, 101 }, { 0, 241, 102 }, { 0, 245, 103 },
+ { 4, 241, 104 }, { 0, 249, 105 }, { 4, 245, 106 }, { 0, 253, 107 }, { 8, 245, 108 }, { 4, 253, 109 }, { 8, 249, 110 }, { 8, 253, 111 },
+ { 12, 249, 112 }, { 16, 245, 113 }, { 12, 253, 114 }, { 20, 245, 115 }, { 16, 253, 116 }, { 20, 249, 117 }, { 20, 253, 118 }, { 24, 249, 119 },
+ { 28, 245, 120 }, { 24, 253, 121 }, { 32, 245, 122 }, { 28, 253, 123 }, { 32, 249, 124 }, { 32, 253, 125 }, { 36, 249, 126 }, { 44, 241, 127 },
+ { 36, 253, 128 }, { 44, 245, 129 }, { 40, 253, 130 }, { 48, 245, 131 }, { 44, 253, 132 }, { 48, 249, 133 }, { 48, 253, 134 }, { 52, 249, 135 },
+ { 56, 245, 136 }, { 52, 253, 137 }, { 60, 245, 138 }, { 56, 253, 139 }, { 60, 249, 140 }, { 60, 253, 141 }, { 64, 249, 142 }, { 68, 245, 143 },
+ { 64, 253, 144 }, { 72, 245, 145 }, { 68, 253, 146 }, { 72, 249, 147 }, { 72, 253, 148 }, { 76, 249, 149 }, { 80, 245, 150 }, { 76, 253, 151 },
+ { 84, 245, 152 }, { 80, 253, 153 }, { 84, 249, 154 }, { 84, 253, 155 }, { 88, 249, 156 }, { 92, 245, 157 }, { 88, 253, 158 }, { 96, 245, 159 },
+ { 92, 253, 160 }, { 96, 249, 161 }, { 96, 253, 162 }, { 100, 249, 163 }, { 108, 241, 164 }, { 100, 253, 165 }, { 108, 245, 166 }, { 104, 253, 167 },
+ { 112, 245, 168 }, { 108, 253, 169 }, { 112, 249, 170 }, { 112, 253, 171 }, { 116, 249, 172 }, { 120, 245, 173 }, { 116, 253, 174 }, { 124, 245, 175 },
+ { 120, 253, 176 }, { 124, 249, 177 }, { 124, 253, 178 }, { 133, 241, 179 }, { 129, 249, 180 }, { 129, 253, 181 }, { 133, 249, 182 }, { 137, 245, 183 },
+ { 133, 253, 184 }, { 141, 245, 185 }, { 137, 253, 186 }, { 141, 249, 187 }, { 141, 253, 188 }, { 145, 249, 189 }, { 149, 245, 190 }, { 145, 253, 191 },
+ { 153, 245, 192 }, { 149, 253, 193 }, { 153, 249, 194 }, { 153, 253, 195 }, { 157, 249, 196 }, { 165, 241, 197 }, { 157, 253, 198 }, { 165, 245, 199 },
+ { 161, 253, 200 }, { 169, 245, 201 }, { 165, 253, 202 }, { 169, 249, 203 }, { 169, 253, 204 }, { 173, 249, 205 }, { 177, 245, 206 }, { 173, 253, 207 },
+ { 181, 245, 208 }, { 177, 253, 209 }, { 181, 249, 210 }, { 181, 253, 211 }, { 185, 249, 212 }, { 189, 245, 213 }, { 185, 253, 214 }, { 193, 245, 215 },
+ { 189, 253, 216 }, { 193, 249, 217 }, { 193, 253, 218 }, { 197, 249, 219 }, { 201, 245, 220 }, { 197, 253, 221 }, { 205, 245, 222 }, { 201, 253, 223 },
+ { 205, 249, 224 }, { 205, 253, 225 }, { 209, 249, 226 }, { 213, 245, 227 }, { 209, 253, 228 }, { 217, 245, 229 }, { 213, 253, 230 }, { 217, 249, 231 },
+ { 217, 253, 232 }, { 221, 249, 233 }, { 229, 241, 234 }, { 221, 253, 235 }, { 229, 245, 236 }, { 225, 253, 237 }, { 233, 245, 238 }, { 229, 253, 239 },
+ { 233, 249, 240 }, { 233, 253, 241 }, { 237, 249, 242 }, { 241, 245, 243 }, { 237, 253, 244 }, { 245, 245, 245 }, { 241, 253, 246 }, { 245, 249, 247 },
+ { 245, 253, 248 }, { 249, 249, 249 }, { 253, 245, 250 }, { 249, 253, 251 }, { 249, 253, 251 }, { 253, 253, 253 }, { 253, 253, 253 }, { 253, 253, 253 },
+ }
+};
+
+Table g_mode1_p1_i1=
+{
+ 1,
+ 1,
+ {
+ { 2, 2, 2 }, { 2, 2, 2 }, { 2, 2, 2 }, { 2, 6, 3 }, { 2, 14, 4 }, { 2, 22, 5 }, { 2, 30, 6 }, { 2, 34, 7 },
+ { 2, 42, 8 }, { 2, 50, 9 }, { 2, 58, 10 }, { 2, 66, 11 }, { 2, 70, 12 }, { 2, 78, 13 }, { 2, 86, 14 }, { 2, 94, 15 },
+ { 2, 98, 16 }, { 2, 106, 17 }, { 2, 114, 18 }, { 2, 122, 19 }, { 2, 131, 20 }, { 2, 135, 21 }, { 2, 143, 22 }, { 2, 151, 23 },
+ { 2, 155, 24 }, { 2, 163, 25 }, { 2, 171, 26 }, { 2, 179, 27 }, { 2, 187, 28 }, { 2, 191, 29 }, { 2, 199, 30 }, { 2, 207, 31 },
+ { 2, 215, 32 }, { 2, 219, 33 }, { 2, 227, 34 }, { 2, 235, 35 }, { 2, 243, 36 }, { 2, 251, 37 }, { 2, 255, 38 }, { 6, 239, 39 },
+ { 6, 247, 40 }, { 6, 255, 41 }, { 10, 235, 42 }, { 10, 243, 43 }, { 10, 251, 44 }, { 14, 231, 45 }, { 14, 239, 46 }, { 14, 247, 47 },
+ { 14, 255, 48 }, { 18, 235, 49 }, { 18, 243, 50 }, { 18, 251, 51 }, { 22, 235, 52 }, { 22, 239, 53 }, { 22, 247, 54 }, { 22, 255, 55 },
+ { 26, 239, 56 }, { 26, 243, 57 }, { 26, 251, 58 }, { 30, 235, 59 }, { 30, 243, 60 }, { 30, 247, 61 }, { 30, 255, 62 }, { 34, 239, 63 },
+ { 34, 247, 64 }, { 34, 251, 65 }, { 38, 235, 66 }, { 38, 243, 67 }, { 38, 251, 68 }, { 38, 255, 69 }, { 42, 239, 70 }, { 42, 247, 71 },
+ { 42, 255, 72 }, { 46, 235, 73 }, { 46, 243, 74 }, { 46, 251, 75 }, { 50, 235, 76 }, { 50, 239, 77 }, { 50, 247, 78 }, { 50, 255, 79 },
+ { 54, 239, 80 }, { 54, 243, 81 }, { 54, 251, 82 }, { 58, 235, 83 }, { 58, 243, 84 }, { 58, 247, 85 }, { 58, 255, 86 }, { 62, 239, 87 },
+ { 62, 247, 88 }, { 62, 251, 89 }, { 66, 235, 90 }, { 66, 243, 91 }, { 66, 251, 92 }, { 66, 255, 93 }, { 70, 239, 94 }, { 70, 247, 95 },
+ { 70, 255, 96 }, { 74, 235, 97 }, { 74, 243, 98 }, { 74, 251, 99 }, { 78, 231, 100 }, { 78, 239, 101 }, { 78, 247, 102 }, { 78, 255, 103 },
+ { 82, 235, 104 }, { 82, 243, 105 }, { 82, 251, 106 }, { 86, 235, 107 }, { 86, 239, 108 }, { 86, 247, 109 }, { 86, 255, 110 }, { 90, 239, 111 },
+ { 90, 243, 112 }, { 90, 251, 113 }, { 94, 235, 114 }, { 94, 243, 115 }, { 94, 247, 116 }, { 94, 255, 117 }, { 98, 239, 118 }, { 98, 247, 119 },
+ { 98, 251, 120 }, { 102, 235, 121 }, { 102, 243, 122 }, { 102, 251, 123 }, { 102, 255, 124 }, { 106, 239, 125 }, { 106, 247, 126 }, { 106, 255, 127 },
+ { 110, 235, 128 }, { 110, 243, 129 }, { 110, 251, 130 }, { 114, 235, 131 }, { 114, 239, 132 }, { 114, 247, 133 }, { 114, 255, 134 }, { 118, 239, 135 },
+ { 118, 243, 136 }, { 118, 251, 137 }, { 122, 235, 138 }, { 122, 243, 139 }, { 122, 247, 140 }, { 122, 255, 141 }, { 126, 239, 142 }, { 126, 247, 143 },
+ { 126, 251, 144 }, { 131, 227, 145 }, { 131, 235, 146 }, { 131, 243, 147 }, { 131, 251, 148 }, { 135, 231, 149 }, { 135, 239, 150 }, { 135, 247, 151 },
+ { 135, 255, 152 }, { 139, 235, 153 }, { 139, 243, 154 }, { 139, 251, 155 }, { 143, 235, 156 }, { 143, 239, 157 }, { 143, 247, 158 }, { 143, 255, 159 },
+ { 147, 239, 160 }, { 147, 243, 161 }, { 147, 251, 162 }, { 151, 235, 163 }, { 151, 243, 164 }, { 151, 247, 165 }, { 151, 255, 166 }, { 155, 239, 167 },
+ { 155, 247, 168 }, { 155, 251, 169 }, { 159, 235, 170 }, { 159, 243, 171 }, { 159, 251, 172 }, { 159, 255, 173 }, { 163, 239, 174 }, { 163, 247, 175 },
+ { 163, 255, 176 }, { 167, 235, 177 }, { 167, 243, 178 }, { 167, 251, 179 }, { 171, 235, 180 }, { 171, 239, 181 }, { 171, 247, 182 }, { 171, 255, 183 },
+ { 175, 239, 184 }, { 175, 243, 185 }, { 175, 251, 186 }, { 179, 235, 187 }, { 179, 243, 188 }, { 179, 247, 189 }, { 179, 255, 190 }, { 183, 239, 191 },
+ { 183, 247, 192 }, { 183, 251, 193 }, { 187, 235, 194 }, { 187, 243, 195 }, { 187, 251, 196 }, { 187, 255, 197 }, { 191, 239, 198 }, { 191, 247, 199 },
+ { 191, 255, 200 }, { 195, 235, 201 }, { 195, 243, 202 }, { 195, 251, 203 }, { 199, 231, 204 }, { 199, 239, 205 }, { 199, 247, 206 }, { 199, 255, 207 },
+ { 203, 235, 208 }, { 203, 243, 209 }, { 203, 251, 210 }, { 207, 235, 211 }, { 207, 239, 212 }, { 207, 247, 213 }, { 207, 255, 214 }, { 211, 239, 215 },
+ { 211, 243, 216 }, { 211, 251, 217 }, { 215, 235, 218 }, { 215, 243, 219 }, { 215, 247, 220 }, { 215, 255, 221 }, { 219, 239, 222 }, { 219, 247, 223 },
+ { 219, 251, 224 }, { 223, 235, 225 }, { 223, 243, 226 }, { 223, 251, 227 }, { 223, 255, 228 }, { 227, 239, 229 }, { 227, 247, 230 }, { 227, 255, 231 },
+ { 231, 235, 232 }, { 231, 243, 233 }, { 231, 251, 234 }, { 235, 235, 235 }, { 235, 239, 236 }, { 235, 247, 237 }, { 235, 255, 238 }, { 239, 239, 239 },
+ { 239, 243, 240 }, { 239, 251, 241 }, { 243, 235, 242 }, { 243, 243, 243 }, { 243, 247, 244 }, { 243, 255, 245 }, { 247, 239, 246 }, { 247, 247, 247 },
+ { 247, 251, 248 }, { 251, 235, 249 }, { 251, 243, 250 }, { 251, 251, 251 }, { 251, 255, 252 }, { 255, 239, 253 }, { 255, 247, 254 }, { 255, 255, 255 },
+ }
+};
+
+Table g_mode1_p1_i2=
+{
+ 2,
+ 1,
+ {
+ { 2, 2, 2 }, { 2, 2, 2 }, { 2, 2, 2 }, { 2, 6, 3 }, { 2, 10, 4 }, { 2, 14, 5 }, { 6, 6, 6 }, { 2, 18, 7 },
+ { 2, 22, 8 }, { 2, 26, 9 }, { 2, 30, 10 }, { 2, 34, 11 }, { 2, 38, 12 }, { 2, 42, 13 }, { 2, 46, 14 }, { 6, 38, 15 },
+ { 2, 50, 16 }, { 2, 54, 17 }, { 2, 58, 18 }, { 2, 62, 19 }, { 2, 66, 20 }, { 2, 70, 21 }, { 2, 74, 22 }, { 2, 78, 23 },
+ { 6, 70, 24 }, { 2, 82, 25 }, { 2, 86, 26 }, { 2, 90, 27 }, { 2, 94, 28 }, { 2, 98, 29 }, { 2, 102, 30 }, { 2, 106, 31 },
+ { 2, 110, 32 }, { 6, 102, 33 }, { 2, 114, 34 }, { 2, 118, 35 }, { 2, 122, 36 }, { 2, 126, 37 }, { 2, 131, 38 }, { 2, 135, 39 },
+ { 6, 126, 40 }, { 2, 139, 41 }, { 2, 143, 42 }, { 2, 147, 43 }, { 2, 151, 44 }, { 2, 155, 45 }, { 2, 159, 46 }, { 2, 163, 47 },
+ { 2, 167, 48 }, { 6, 159, 49 }, { 2, 171, 50 }, { 2, 175, 51 }, { 2, 179, 52 }, { 2, 183, 53 }, { 2, 187, 54 }, { 2, 191, 55 },
+ { 2, 195, 56 }, { 2, 199, 57 }, { 6, 191, 58 }, { 2, 203, 59 }, { 2, 207, 60 }, { 2, 211, 61 }, { 2, 215, 62 }, { 2, 219, 63 },
+ { 2, 223, 64 }, { 2, 227, 65 }, { 2, 231, 66 }, { 6, 223, 67 }, { 2, 235, 68 }, { 2, 239, 69 }, { 2, 243, 70 }, { 2, 247, 71 },
+ { 2, 251, 72 }, { 2, 255, 73 }, { 6, 247, 74 }, { 6, 251, 75 }, { 6, 255, 76 }, { 10, 247, 77 }, { 10, 251, 78 }, { 10, 255, 79 },
+ { 14, 247, 80 }, { 14, 251, 81 }, { 14, 255, 82 }, { 22, 239, 83 }, { 18, 251, 84 }, { 18, 255, 85 }, { 22, 251, 86 }, { 26, 243, 87 },
+ { 22, 255, 88 }, { 26, 251, 89 }, { 26, 255, 90 }, { 30, 247, 91 }, { 30, 251, 92 }, { 30, 255, 93 }, { 34, 247, 94 }, { 34, 251, 95 },
+ { 34, 255, 96 }, { 38, 247, 97 }, { 38, 251, 98 }, { 38, 255, 99 }, { 42, 247, 100 }, { 42, 251, 101 }, { 42, 255, 102 }, { 46, 247, 103 },
+ { 46, 251, 104 }, { 46, 255, 105 }, { 54, 239, 106 }, { 50, 251, 107 }, { 50, 255, 108 }, { 54, 251, 109 }, { 58, 243, 110 }, { 54, 255, 111 },
+ { 58, 251, 112 }, { 58, 255, 113 }, { 62, 247, 114 }, { 62, 251, 115 }, { 62, 255, 116 }, { 66, 247, 117 }, { 66, 251, 118 }, { 66, 255, 119 },
+ { 70, 247, 120 }, { 70, 251, 121 }, { 70, 255, 122 }, { 74, 247, 123 }, { 74, 251, 124 }, { 74, 255, 125 }, { 78, 247, 126 }, { 78, 251, 127 },
+ { 78, 255, 128 }, { 86, 239, 129 }, { 82, 251, 130 }, { 82, 255, 131 }, { 86, 251, 132 }, { 90, 243, 133 }, { 86, 255, 134 }, { 90, 251, 135 },
+ { 90, 255, 136 }, { 94, 247, 137 }, { 94, 251, 138 }, { 94, 255, 139 }, { 98, 247, 140 }, { 98, 251, 141 }, { 98, 255, 142 }, { 102, 247, 143 },
+ { 102, 251, 144 }, { 102, 255, 145 }, { 106, 247, 146 }, { 106, 251, 147 }, { 106, 255, 148 }, { 110, 247, 149 }, { 110, 251, 150 }, { 110, 255, 151 },
+ { 118, 239, 152 }, { 114, 251, 153 }, { 114, 255, 154 }, { 118, 251, 155 }, { 122, 243, 156 }, { 118, 255, 157 }, { 122, 251, 158 }, { 122, 255, 159 },
+ { 126, 247, 160 }, { 126, 251, 161 }, { 126, 255, 162 }, { 131, 243, 163 }, { 131, 247, 164 }, { 131, 251, 165 }, { 131, 255, 166 }, { 135, 247, 167 },
+ { 135, 251, 168 }, { 135, 255, 169 }, { 143, 239, 170 }, { 139, 251, 171 }, { 139, 255, 172 }, { 143, 251, 173 }, { 147, 243, 174 }, { 143, 255, 175 },
+ { 147, 251, 176 }, { 147, 255, 177 }, { 151, 247, 178 }, { 151, 251, 179 }, { 151, 255, 180 }, { 155, 247, 181 }, { 155, 251, 182 }, { 155, 255, 183 },
+ { 159, 247, 184 }, { 159, 251, 185 }, { 159, 255, 186 }, { 163, 247, 187 }, { 163, 251, 188 }, { 163, 255, 189 }, { 167, 247, 190 }, { 167, 251, 191 },
+ { 167, 255, 192 }, { 175, 239, 193 }, { 171, 251, 194 }, { 171, 255, 195 }, { 175, 251, 196 }, { 179, 243, 197 }, { 175, 255, 198 }, { 179, 251, 199 },
+ { 179, 255, 200 }, { 183, 247, 201 }, { 183, 251, 202 }, { 183, 255, 203 }, { 187, 247, 204 }, { 187, 251, 205 }, { 187, 255, 206 }, { 191, 247, 207 },
+ { 191, 251, 208 }, { 191, 255, 209 }, { 195, 247, 210 }, { 195, 251, 211 }, { 195, 255, 212 }, { 199, 247, 213 }, { 199, 251, 214 }, { 199, 255, 215 },
+ { 207, 239, 216 }, { 203, 251, 217 }, { 203, 255, 218 }, { 207, 251, 219 }, { 211, 243, 220 }, { 207, 255, 221 }, { 211, 251, 222 }, { 211, 255, 223 },
+ { 215, 247, 224 }, { 215, 251, 225 }, { 215, 255, 226 }, { 219, 247, 227 }, { 219, 251, 228 }, { 219, 255, 229 }, { 223, 247, 230 }, { 223, 251, 231 },
+ { 223, 255, 232 }, { 227, 247, 233 }, { 227, 251, 234 }, { 227, 255, 235 }, { 231, 247, 236 }, { 231, 251, 237 }, { 231, 255, 238 }, { 239, 239, 239 },
+ { 235, 251, 240 }, { 235, 255, 241 }, { 239, 251, 242 }, { 243, 243, 243 }, { 239, 255, 244 }, { 243, 251, 245 }, { 243, 255, 246 }, { 247, 247, 247 },
+ { 247, 251, 248 }, { 247, 255, 249 }, { 251, 247, 250 }, { 251, 251, 251 }, { 251, 255, 252 }, { 255, 247, 253 }, { 255, 251, 254 }, { 255, 255, 255 },
+ }
+};
+
+Table g_mode1_p1_i3=
+{
+ 3,
+ 1,
+ {
+ { 2, 2, 2 }, { 2, 2, 2 }, { 2, 2, 2 }, { 2, 2, 2 }, { 2, 6, 4 }, { 2, 10, 5 }, { 6, 6, 6 }, { 2, 14, 7 },
+ { 6, 10, 8 }, { 2, 18, 9 }, { 2, 22, 10 }, { 6, 18, 11 }, { 2, 26, 12 }, { 6, 22, 13 }, { 2, 30, 14 }, { 10, 22, 15 },
+ { 2, 34, 16 }, { 2, 38, 17 }, { 6, 34, 18 }, { 2, 42, 19 }, { 6, 38, 20 }, { 2, 46, 21 }, { 2, 50, 22 }, { 6, 46, 23 },
+ { 2, 54, 24 }, { 6, 50, 25 }, { 2, 58, 26 }, { 2, 62, 27 }, { 6, 58, 28 }, { 2, 66, 29 }, { 6, 62, 30 }, { 2, 70, 31 },
+ { 2, 74, 32 }, { 6, 70, 33 }, { 2, 78, 34 }, { 6, 74, 35 }, { 2, 82, 36 }, { 2, 86, 37 }, { 6, 82, 38 }, { 2, 90, 39 },
+ { 6, 86, 40 }, { 2, 94, 41 }, { 10, 86, 42 }, { 2, 98, 43 }, { 2, 102, 44 }, { 6, 98, 45 }, { 2, 106, 46 }, { 6, 102, 47 },
+ { 2, 110, 48 }, { 2, 114, 49 }, { 6, 110, 50 }, { 2, 118, 51 }, { 6, 114, 52 }, { 2, 122, 53 }, { 2, 126, 54 }, { 6, 122, 55 },
+ { 2, 131, 56 }, { 6, 126, 57 }, { 2, 135, 58 }, { 6, 131, 59 }, { 2, 139, 60 }, { 2, 143, 61 }, { 6, 139, 62 }, { 2, 147, 63 },
+ { 6, 143, 64 }, { 2, 151, 65 }, { 10, 143, 66 }, { 2, 155, 67 }, { 2, 159, 68 }, { 6, 155, 69 }, { 2, 163, 70 }, { 6, 159, 71 },
+ { 2, 167, 72 }, { 2, 171, 73 }, { 6, 167, 74 }, { 2, 175, 75 }, { 6, 171, 76 }, { 2, 179, 77 }, { 2, 183, 78 }, { 6, 179, 79 },
+ { 2, 187, 80 }, { 6, 183, 81 }, { 2, 191, 82 }, { 2, 195, 83 }, { 6, 191, 84 }, { 2, 199, 85 }, { 6, 195, 86 }, { 2, 203, 87 },
+ { 2, 207, 88 }, { 6, 203, 89 }, { 2, 211, 90 }, { 6, 207, 91 }, { 2, 215, 92 }, { 10, 207, 93 }, { 2, 219, 94 }, { 2, 223, 95 },
+ { 6, 219, 96 }, { 2, 227, 97 }, { 6, 223, 98 }, { 2, 231, 99 }, { 2, 235, 100 }, { 6, 231, 101 }, { 2, 239, 102 }, { 6, 235, 103 },
+ { 2, 243, 104 }, { 2, 247, 105 }, { 6, 243, 106 }, { 2, 251, 107 }, { 6, 247, 108 }, { 2, 255, 109 }, { 10, 247, 110 }, { 6, 255, 111 },
+ { 10, 251, 112 }, { 10, 255, 113 }, { 14, 251, 114 }, { 18, 247, 115 }, { 14, 255, 116 }, { 22, 247, 117 }, { 18, 255, 118 }, { 22, 251, 119 },
+ { 22, 255, 120 }, { 26, 251, 121 }, { 30, 247, 122 }, { 26, 255, 123 }, { 34, 247, 124 }, { 30, 255, 125 }, { 34, 251, 126 }, { 34, 255, 127 },
+ { 38, 251, 128 }, { 46, 243, 129 }, { 38, 255, 130 }, { 46, 247, 131 }, { 42, 255, 132 }, { 50, 247, 133 }, { 46, 255, 134 }, { 50, 251, 135 },
+ { 50, 255, 136 }, { 54, 251, 137 }, { 58, 247, 138 }, { 54, 255, 139 }, { 62, 247, 140 }, { 58, 255, 141 }, { 62, 251, 142 }, { 62, 255, 143 },
+ { 66, 251, 144 }, { 70, 247, 145 }, { 66, 255, 146 }, { 74, 247, 147 }, { 70, 255, 148 }, { 74, 251, 149 }, { 74, 255, 150 }, { 78, 251, 151 },
+ { 82, 247, 152 }, { 78, 255, 153 }, { 86, 247, 154 }, { 82, 255, 155 }, { 86, 251, 156 }, { 86, 255, 157 }, { 90, 251, 158 }, { 94, 247, 159 },
+ { 90, 255, 160 }, { 98, 247, 161 }, { 94, 255, 162 }, { 98, 251, 163 }, { 98, 255, 164 }, { 102, 251, 165 }, { 110, 243, 166 }, { 102, 255, 167 },
+ { 110, 247, 168 }, { 106, 255, 169 }, { 114, 247, 170 }, { 110, 255, 171 }, { 114, 251, 172 }, { 114, 255, 173 }, { 118, 251, 174 }, { 122, 247, 175 },
+ { 118, 255, 176 }, { 126, 247, 177 }, { 122, 255, 178 }, { 126, 251, 179 }, { 126, 255, 180 }, { 135, 243, 181 }, { 131, 251, 182 }, { 131, 255, 183 },
+ { 135, 251, 184 }, { 139, 247, 185 }, { 135, 255, 186 }, { 143, 247, 187 }, { 139, 255, 188 }, { 143, 251, 189 }, { 143, 255, 190 }, { 147, 251, 191 },
+ { 151, 247, 192 }, { 147, 255, 193 }, { 155, 247, 194 }, { 151, 255, 195 }, { 155, 251, 196 }, { 155, 255, 197 }, { 159, 251, 198 }, { 167, 243, 199 },
+ { 159, 255, 200 }, { 167, 247, 201 }, { 163, 255, 202 }, { 171, 247, 203 }, { 167, 255, 204 }, { 171, 251, 205 }, { 171, 255, 206 }, { 175, 251, 207 },
+ { 179, 247, 208 }, { 175, 255, 209 }, { 183, 247, 210 }, { 179, 255, 211 }, { 183, 251, 212 }, { 183, 255, 213 }, { 187, 251, 214 }, { 191, 247, 215 },
+ { 187, 255, 216 }, { 195, 247, 217 }, { 191, 255, 218 }, { 195, 251, 219 }, { 195, 255, 220 }, { 199, 251, 221 }, { 203, 247, 222 }, { 199, 255, 223 },
+ { 207, 247, 224 }, { 203, 255, 225 }, { 207, 251, 226 }, { 207, 255, 227 }, { 211, 251, 228 }, { 215, 247, 229 }, { 211, 255, 230 }, { 219, 247, 231 },
+ { 215, 255, 232 }, { 219, 251, 233 }, { 219, 255, 234 }, { 223, 251, 235 }, { 231, 243, 236 }, { 223, 255, 237 }, { 231, 247, 238 }, { 227, 255, 239 },
+ { 235, 247, 240 }, { 231, 255, 241 }, { 235, 251, 242 }, { 235, 255, 243 }, { 239, 251, 244 }, { 243, 247, 245 }, { 239, 255, 246 }, { 247, 247, 247 },
+ { 243, 255, 248 }, { 247, 251, 249 }, { 247, 255, 250 }, { 251, 251, 251 }, { 255, 247, 252 }, { 251, 255, 253 }, { 251, 255, 253 }, { 255, 255, 255 },
+ }
+};
+
+Table g_mode2=
+{
+ 1,
+ 0,
+ {
+ { 0, 0, 0 }, { 0, 0, 0 }, { 0, 8, 3 }, { 0, 8, 3 }, { 0, 8, 3 }, { 0, 16, 5 }, { 0, 16, 5 }, { 0, 24, 8 },
+ { 0, 24, 8 }, { 0, 24, 8 }, { 0, 33, 11 }, { 0, 33, 11 }, { 0, 33, 11 }, { 0, 41, 13 }, { 0, 41, 13 }, { 0, 49, 16 },
+ { 0, 49, 16 }, { 0, 49, 16 }, { 0, 57, 19 }, { 0, 57, 19 }, { 0, 57, 19 }, { 8, 49, 21 }, { 0, 66, 22 }, { 0, 66, 22 },
+ { 0, 74, 24 }, { 33, 8, 25 }, { 0, 82, 27 }, { 0, 82, 27 }, { 41, 0, 28 }, { 16, 57, 29 }, { 0, 90, 30 }, { 0, 90, 30 },
+ { 0, 99, 32 }, { 33, 33, 33 }, { 0, 107, 35 }, { 0, 107, 35 }, { 33, 41, 36 }, { 0, 115, 38 }, { 0, 115, 38 }, { 0, 115, 38 },
+ { 0, 123, 40 }, { 33, 57, 41 }, { 0, 132, 43 }, { 0, 132, 43 }, { 33, 66, 44 }, { 0, 140, 46 }, { 0, 140, 46 }, { 66, 8, 47 },
+ { 16, 115, 48 }, { 0, 148, 49 }, { 66, 16, 50 }, { 0, 156, 51 }, { 33, 90, 52 }, { 0, 165, 54 }, { 0, 165, 54 }, { 33, 99, 55 },
+ { 24, 123, 56 }, { 0, 173, 57 }, { 66, 41, 58 }, { 0, 181, 59 }, { 8, 165, 60 }, { 74, 33, 61 }, { 0, 189, 62 }, { 33, 123, 63 },
+ { 0, 198, 65 }, { 0, 198, 65 }, { 66, 66, 66 }, { 8, 189, 67 }, { 0, 206, 68 }, { 66, 74, 69 }, { 0, 214, 70 }, { 33, 148, 71 },
+ { 99, 16, 72 }, { 0, 222, 73 }, { 66, 90, 74 }, { 107, 8, 75 }, { 0, 231, 76 }, { 66, 99, 77 }, { 0, 239, 78 }, { 33, 173, 79 },
+ { 99, 41, 80 }, { 0, 247, 81 }, { 33, 181, 82 }, { 99, 49, 83 }, { 0, 255, 84 }, { 66, 123, 85 }, { 8, 247, 86 }, { 16, 231, 87 },
+ { 66, 132, 88 }, { 8, 255, 89 }, { 33, 206, 90 }, { 99, 74, 91 }, { 16, 247, 92 }, { 41, 198, 93 }, { 16, 255, 94 }, { 24, 239, 95 },
+ { 66, 156, 96 }, { 24, 247, 97 }, { 33, 231, 98 }, { 99, 99, 99 }, { 24, 255, 100 }, { 33, 239, 101 }, { 99, 107, 102 }, { 33, 247, 103 },
+ { 66, 181, 104 }, { 132, 49, 105 }, { 33, 255, 106 }, { 99, 123, 107 }, { 140, 41, 108 }, { 41, 247, 109 }, { 99, 132, 110 }, { 41, 255, 111 },
+ { 66, 206, 112 }, { 132, 74, 113 }, { 49, 247, 114 }, { 66, 214, 115 }, { 132, 82, 116 }, { 49, 255, 117 }, { 99, 156, 118 }, { 57, 247, 119 },
+ { 66, 231, 120 }, { 99, 165, 121 }, { 57, 255, 122 }, { 66, 239, 123 }, { 132, 107, 124 }, { 66, 247, 125 }, { 74, 231, 126 }, { 140, 99, 127 },
+ { 66, 255, 128 }, { 99, 189, 129 }, { 165, 57, 130 }, { 74, 247, 131 }, { 132, 132, 132 }, { 74, 255, 133 }, { 82, 239, 134 }, { 132, 140, 135 },
+ { 82, 247, 136 }, { 99, 214, 137 }, { 165, 82, 138 }, { 82, 255, 139 }, { 132, 156, 140 }, { 173, 74, 141 }, { 90, 247, 142 }, { 132, 165, 143 },
+ { 90, 255, 144 }, { 99, 239, 145 }, { 165, 107, 146 }, { 115, 214, 147 }, { 99, 247, 148 }, { 165, 115, 149 }, { 99, 255, 150 }, { 132, 189, 151 },
+ { 198, 57, 152 }, { 107, 247, 153 }, { 132, 198, 154 }, { 123, 222, 155 }, { 107, 255, 156 }, { 165, 140, 157 }, { 115, 247, 158 }, { 132, 214, 159 },
+ { 173, 132, 160 }, { 115, 255, 161 }, { 132, 222, 162 }, { 198, 90, 163 }, { 123, 247, 164 }, { 165, 165, 165 }, { 123, 255, 166 }, { 132, 239, 167 },
+ { 165, 173, 168 }, { 231, 41, 169 }, { 132, 247, 170 }, { 198, 115, 171 }, { 132, 255, 172 }, { 165, 189, 173 }, { 206, 107, 174 }, { 140, 247, 175 },
+ { 165, 198, 176 }, { 231, 66, 177 }, { 140, 255, 178 }, { 198, 140, 179 }, { 148, 247, 180 }, { 156, 231, 181 }, { 198, 148, 182 }, { 148, 255, 183 },
+ { 165, 222, 184 }, { 231, 90, 185 }, { 156, 247, 186 }, { 165, 231, 187 }, { 156, 255, 188 }, { 165, 239, 189 }, { 198, 173, 190 }, { 165, 247, 192 },
+ { 165, 247, 192 }, { 206, 165, 193 }, { 181, 222, 194 }, { 165, 255, 195 }, { 231, 123, 196 }, { 173, 247, 197 }, { 198, 198, 198 }, { 231, 132, 199 },
+ { 173, 255, 200 }, { 198, 206, 201 }, { 181, 247, 203 }, { 181, 247, 203 }, { 231, 148, 204 }, { 181, 255, 205 }, { 198, 222, 206 }, { 239, 140, 207 },
+ { 189, 247, 208 }, { 198, 231, 209 }, { 189, 255, 211 }, { 189, 255, 211 }, { 231, 173, 212 }, { 198, 247, 214 }, { 198, 247, 214 }, { 231, 181, 215 },
+ { 198, 255, 217 }, { 198, 255, 217 }, { 198, 255, 217 }, { 206, 247, 219 }, { 214, 231, 220 }, { 206, 255, 222 }, { 206, 255, 222 }, { 231, 206, 223 },
+ { 214, 247, 225 }, { 214, 247, 225 }, { 239, 198, 226 }, { 214, 255, 227 }, { 222, 239, 228 }, { 222, 239, 228 }, { 222, 247, 230 }, { 231, 231, 231 },
+ { 222, 255, 233 }, { 222, 255, 233 }, { 231, 239, 234 }, { 231, 239, 234 }, { 231, 247, 236 }, { 231, 247, 236 }, { 231, 255, 239 }, { 231, 255, 239 },
+ { 231, 255, 239 }, { 239, 247, 242 }, { 239, 247, 242 }, { 239, 247, 242 }, { 239, 255, 244 }, { 239, 255, 244 }, { 247, 247, 247 }, { 247, 247, 247 },
+ { 247, 247, 247 }, { 247, 255, 250 }, { 247, 255, 250 }, { 247, 255, 250 }, { 255, 247, 252 }, { 255, 247, 252 }, { 255, 255, 255 }, { 255, 255, 255 },
+ }
+};
+
+Table g_mode3_p0=
+{
+ 1,
+ 0,
+ {
+ { 0, 0, 0 }, { 0, 2, 1 }, { 0, 6, 2 }, { 0, 8, 3 }, { 0, 12, 4 }, { 0, 14, 5 }, { 0, 18, 6 }, { 0, 20, 7 },
+ { 0, 24, 8 }, { 0, 26, 9 }, { 0, 30, 10 }, { 0, 32, 11 }, { 0, 36, 12 }, { 0, 40, 13 }, { 0, 42, 14 }, { 0, 46, 15 },
+ { 0, 48, 16 }, { 0, 52, 17 }, { 0, 54, 18 }, { 0, 58, 19 }, { 0, 60, 20 }, { 0, 64, 21 }, { 0, 66, 22 }, { 0, 70, 23 },
+ { 0, 72, 24 }, { 0, 76, 25 }, { 0, 78, 26 }, { 0, 82, 27 }, { 0, 84, 28 }, { 0, 88, 29 }, { 0, 90, 30 }, { 0, 94, 31 },
+ { 0, 96, 32 }, { 0, 100, 33 }, { 0, 104, 34 }, { 0, 106, 35 }, { 0, 110, 36 }, { 0, 112, 37 }, { 0, 116, 38 }, { 0, 118, 39 },
+ { 0, 122, 40 }, { 0, 124, 41 }, { 0, 128, 42 }, { 0, 130, 43 }, { 0, 134, 44 }, { 0, 136, 45 }, { 0, 140, 46 }, { 0, 142, 47 },
+ { 0, 146, 48 }, { 0, 148, 49 }, { 0, 152, 50 }, { 0, 154, 51 }, { 0, 158, 52 }, { 0, 160, 53 }, { 0, 164, 54 }, { 0, 168, 55 },
+ { 0, 170, 56 }, { 0, 174, 57 }, { 0, 176, 58 }, { 0, 180, 59 }, { 0, 182, 60 }, { 0, 186, 61 }, { 0, 188, 62 }, { 0, 192, 63 },
+ { 0, 194, 64 }, { 0, 198, 65 }, { 0, 200, 66 }, { 0, 204, 67 }, { 0, 206, 68 }, { 0, 210, 69 }, { 0, 212, 70 }, { 0, 216, 71 },
+ { 0, 218, 72 }, { 0, 222, 73 }, { 0, 224, 74 }, { 0, 228, 75 }, { 0, 232, 76 }, { 0, 234, 77 }, { 0, 238, 78 }, { 0, 240, 79 },
+ { 0, 244, 80 }, { 0, 246, 81 }, { 0, 250, 82 }, { 0, 252, 83 }, { 2, 252, 84 }, { 2, 254, 85 }, { 4, 254, 86 }, { 6, 252, 87 },
+ { 8, 252, 88 }, { 8, 254, 89 }, { 10, 254, 90 }, { 12, 252, 91 }, { 14, 252, 92 }, { 14, 254, 93 }, { 16, 254, 94 }, { 18, 252, 95 },
+ { 20, 252, 96 }, { 20, 254, 97 }, { 22, 254, 98 }, { 24, 252, 99 }, { 26, 250, 100 }, { 26, 254, 101 }, { 28, 252, 102 }, { 30, 252, 103 },
+ { 30, 254, 104 }, { 32, 254, 105 }, { 34, 252, 106 }, { 36, 252, 107 }, { 36, 254, 108 }, { 38, 254, 109 }, { 40, 252, 110 }, { 42, 252, 111 },
+ { 42, 254, 112 }, { 44, 254, 113 }, { 46, 252, 114 }, { 48, 252, 115 }, { 48, 254, 116 }, { 50, 254, 117 }, { 52, 252, 118 }, { 54, 252, 119 },
+ { 54, 254, 120 }, { 56, 254, 121 }, { 58, 252, 122 }, { 60, 252, 123 }, { 60, 254, 124 }, { 62, 254, 125 }, { 64, 252, 126 }, { 66, 252, 127 },
+ { 66, 254, 128 }, { 68, 254, 129 }, { 70, 252, 130 }, { 72, 252, 131 }, { 72, 254, 132 }, { 74, 254, 133 }, { 76, 252, 134 }, { 78, 252, 135 },
+ { 78, 254, 136 }, { 80, 254, 137 }, { 82, 252, 138 }, { 84, 252, 139 }, { 84, 254, 140 }, { 86, 254, 141 }, { 88, 252, 142 }, { 90, 250, 143 },
+ { 90, 254, 144 }, { 92, 252, 145 }, { 94, 252, 146 }, { 94, 254, 147 }, { 96, 254, 148 }, { 98, 252, 149 }, { 100, 252, 150 }, { 100, 254, 151 },
+ { 102, 254, 152 }, { 104, 252, 153 }, { 106, 252, 154 }, { 106, 254, 155 }, { 108, 254, 156 }, { 110, 252, 157 }, { 112, 252, 158 }, { 112, 254, 159 },
+ { 114, 254, 160 }, { 116, 252, 161 }, { 118, 252, 162 }, { 118, 254, 163 }, { 120, 254, 164 }, { 122, 252, 165 }, { 124, 252, 166 }, { 124, 254, 167 },
+ { 126, 254, 168 }, { 128, 252, 169 }, { 130, 252, 170 }, { 130, 254, 171 }, { 132, 254, 172 }, { 134, 252, 173 }, { 136, 252, 174 }, { 136, 254, 175 },
+ { 138, 254, 176 }, { 140, 252, 177 }, { 142, 252, 178 }, { 142, 254, 179 }, { 144, 254, 180 }, { 146, 252, 181 }, { 148, 252, 182 }, { 148, 254, 183 },
+ { 150, 254, 184 }, { 152, 252, 185 }, { 154, 250, 186 }, { 154, 254, 187 }, { 156, 252, 188 }, { 158, 252, 189 }, { 158, 254, 190 }, { 160, 254, 191 },
+ { 162, 252, 192 }, { 164, 252, 193 }, { 164, 254, 194 }, { 166, 254, 195 }, { 168, 252, 196 }, { 170, 252, 197 }, { 170, 254, 198 }, { 172, 254, 199 },
+ { 174, 252, 200 }, { 176, 252, 201 }, { 176, 254, 202 }, { 178, 254, 203 }, { 180, 252, 204 }, { 182, 252, 205 }, { 182, 254, 206 }, { 184, 254, 207 },
+ { 186, 252, 208 }, { 188, 252, 209 }, { 188, 254, 210 }, { 190, 254, 211 }, { 192, 252, 212 }, { 194, 252, 213 }, { 194, 254, 214 }, { 196, 254, 215 },
+ { 198, 252, 216 }, { 200, 252, 217 }, { 200, 254, 218 }, { 202, 254, 219 }, { 204, 252, 220 }, { 206, 252, 221 }, { 206, 254, 222 }, { 208, 254, 223 },
+ { 210, 252, 224 }, { 212, 252, 225 }, { 212, 254, 226 }, { 214, 254, 227 }, { 216, 252, 228 }, { 218, 250, 229 }, { 218, 254, 230 }, { 220, 252, 231 },
+ { 222, 252, 232 }, { 222, 254, 233 }, { 224, 254, 234 }, { 226, 252, 235 }, { 228, 252, 236 }, { 228, 254, 237 }, { 230, 254, 238 }, { 232, 252, 239 },
+ { 234, 252, 240 }, { 234, 254, 241 }, { 236, 254, 242 }, { 238, 252, 243 }, { 240, 252, 244 }, { 240, 254, 245 }, { 242, 254, 246 }, { 244, 252, 247 },
+ { 246, 252, 248 }, { 246, 254, 249 }, { 248, 254, 250 }, { 250, 252, 251 }, { 252, 252, 252 }, { 252, 254, 253 }, { 254, 254, 254 }, { 254, 254, 254 },
+ }
+};
+
+Table g_mode3_p1=
+{
+ 1,
+ 1,
+ {
+ { 1, 1, 1 }, { 1, 1, 1 }, { 1, 3, 2 }, { 1, 7, 3 }, { 1, 9, 4 }, { 1, 13, 5 }, { 1, 15, 6 }, { 1, 19, 7 },
+ { 1, 21, 8 }, { 1, 25, 9 }, { 1, 27, 10 }, { 1, 31, 11 }, { 1, 33, 12 }, { 1, 37, 13 }, { 1, 41, 14 }, { 1, 43, 15 },
+ { 1, 47, 16 }, { 1, 49, 17 }, { 1, 53, 18 }, { 1, 55, 19 }, { 1, 59, 20 }, { 1, 61, 21 }, { 1, 65, 22 }, { 1, 67, 23 },
+ { 1, 71, 24 }, { 1, 73, 25 }, { 1, 77, 26 }, { 1, 79, 27 }, { 1, 83, 28 }, { 1, 85, 29 }, { 1, 89, 30 }, { 1, 91, 31 },
+ { 1, 95, 32 }, { 1, 97, 33 }, { 1, 101, 34 }, { 1, 105, 35 }, { 1, 107, 36 }, { 1, 111, 37 }, { 1, 113, 38 }, { 1, 117, 39 },
+ { 1, 119, 40 }, { 1, 123, 41 }, { 1, 125, 42 }, { 1, 129, 43 }, { 1, 131, 44 }, { 1, 135, 45 }, { 1, 137, 46 }, { 1, 141, 47 },
+ { 1, 143, 48 }, { 1, 147, 49 }, { 1, 149, 50 }, { 1, 153, 51 }, { 1, 155, 52 }, { 1, 159, 53 }, { 1, 161, 54 }, { 1, 165, 55 },
+ { 1, 169, 56 }, { 1, 171, 57 }, { 1, 175, 58 }, { 1, 177, 59 }, { 1, 181, 60 }, { 1, 183, 61 }, { 1, 187, 62 }, { 1, 189, 63 },
+ { 1, 193, 64 }, { 1, 195, 65 }, { 1, 199, 66 }, { 1, 201, 67 }, { 1, 205, 68 }, { 1, 207, 69 }, { 1, 211, 70 }, { 1, 213, 71 },
+ { 1, 217, 72 }, { 1, 219, 73 }, { 1, 223, 74 }, { 1, 225, 75 }, { 1, 229, 76 }, { 1, 233, 77 }, { 1, 235, 78 }, { 1, 239, 79 },
+ { 1, 241, 80 }, { 1, 245, 81 }, { 1, 247, 82 }, { 1, 251, 83 }, { 1, 253, 84 }, { 3, 253, 85 }, { 3, 255, 86 }, { 5, 255, 87 },
+ { 7, 253, 88 }, { 9, 253, 89 }, { 9, 255, 90 }, { 11, 255, 91 }, { 13, 253, 92 }, { 15, 253, 93 }, { 15, 255, 94 }, { 17, 255, 95 },
+ { 19, 253, 96 }, { 21, 253, 97 }, { 21, 255, 98 }, { 23, 255, 99 }, { 25, 253, 100 }, { 27, 251, 101 }, { 27, 255, 102 }, { 29, 253, 103 },
+ { 31, 253, 104 }, { 31, 255, 105 }, { 33, 255, 106 }, { 35, 253, 107 }, { 37, 253, 108 }, { 37, 255, 109 }, { 39, 255, 110 }, { 41, 253, 111 },
+ { 43, 253, 112 }, { 43, 255, 113 }, { 45, 255, 114 }, { 47, 253, 115 }, { 49, 253, 116 }, { 49, 255, 117 }, { 51, 255, 118 }, { 53, 253, 119 },
+ { 55, 253, 120 }, { 55, 255, 121 }, { 57, 255, 122 }, { 59, 253, 123 }, { 61, 253, 124 }, { 61, 255, 125 }, { 63, 255, 126 }, { 65, 253, 127 },
+ { 67, 253, 128 }, { 67, 255, 129 }, { 69, 255, 130 }, { 71, 253, 131 }, { 73, 253, 132 }, { 73, 255, 133 }, { 75, 255, 134 }, { 77, 253, 135 },
+ { 79, 253, 136 }, { 79, 255, 137 }, { 81, 255, 138 }, { 83, 253, 139 }, { 85, 253, 140 }, { 85, 255, 141 }, { 87, 255, 142 }, { 89, 253, 143 },
+ { 91, 251, 144 }, { 91, 255, 145 }, { 93, 253, 146 }, { 95, 253, 147 }, { 95, 255, 148 }, { 97, 255, 149 }, { 99, 253, 150 }, { 101, 253, 151 },
+ { 101, 255, 152 }, { 103, 255, 153 }, { 105, 253, 154 }, { 107, 253, 155 }, { 107, 255, 156 }, { 109, 255, 157 }, { 111, 253, 158 }, { 113, 253, 159 },
+ { 113, 255, 160 }, { 115, 255, 161 }, { 117, 253, 162 }, { 119, 253, 163 }, { 119, 255, 164 }, { 121, 255, 165 }, { 123, 253, 166 }, { 125, 253, 167 },
+ { 125, 255, 168 }, { 127, 255, 169 }, { 129, 253, 170 }, { 131, 253, 171 }, { 131, 255, 172 }, { 133, 255, 173 }, { 135, 253, 174 }, { 137, 253, 175 },
+ { 137, 255, 176 }, { 139, 255, 177 }, { 141, 253, 178 }, { 143, 253, 179 }, { 143, 255, 180 }, { 145, 255, 181 }, { 147, 253, 182 }, { 149, 253, 183 },
+ { 149, 255, 184 }, { 151, 255, 185 }, { 153, 253, 186 }, { 155, 251, 187 }, { 155, 255, 188 }, { 157, 253, 189 }, { 159, 253, 190 }, { 159, 255, 191 },
+ { 161, 255, 192 }, { 163, 253, 193 }, { 165, 253, 194 }, { 165, 255, 195 }, { 167, 255, 196 }, { 169, 253, 197 }, { 171, 253, 198 }, { 171, 255, 199 },
+ { 173, 255, 200 }, { 175, 253, 201 }, { 177, 253, 202 }, { 177, 255, 203 }, { 179, 255, 204 }, { 181, 253, 205 }, { 183, 253, 206 }, { 183, 255, 207 },
+ { 185, 255, 208 }, { 187, 253, 209 }, { 189, 253, 210 }, { 189, 255, 211 }, { 191, 255, 212 }, { 193, 253, 213 }, { 195, 253, 214 }, { 195, 255, 215 },
+ { 197, 255, 216 }, { 199, 253, 217 }, { 201, 253, 218 }, { 201, 255, 219 }, { 203, 255, 220 }, { 205, 253, 221 }, { 207, 253, 222 }, { 207, 255, 223 },
+ { 209, 255, 224 }, { 211, 253, 225 }, { 213, 253, 226 }, { 213, 255, 227 }, { 215, 255, 228 }, { 217, 253, 229 }, { 219, 251, 230 }, { 219, 255, 231 },
+ { 221, 253, 232 }, { 223, 253, 233 }, { 223, 255, 234 }, { 225, 255, 235 }, { 227, 253, 236 }, { 229, 253, 237 }, { 229, 255, 238 }, { 231, 255, 239 },
+ { 233, 253, 240 }, { 235, 253, 241 }, { 235, 255, 242 }, { 237, 255, 243 }, { 239, 253, 244 }, { 241, 253, 245 }, { 241, 255, 246 }, { 243, 255, 247 },
+ { 245, 253, 248 }, { 247, 253, 249 }, { 247, 255, 250 }, { 249, 255, 251 }, { 251, 253, 252 }, { 253, 253, 253 }, { 253, 255, 254 }, { 255, 255, 255 },
+ }
+};
+
+Table g_mode4_rgb_low=
+{
+ 1,
+ 0,
+ {
+ { 0, 0, 0 }, { 0, 0, 0 }, { 0, 8, 3 }, { 0, 8, 3 }, { 0, 8, 3 }, { 0, 16, 5 }, { 0, 16, 5 }, { 0, 24, 8 },
+ { 0, 24, 8 }, { 0, 24, 8 }, { 0, 33, 11 }, { 0, 33, 11 }, { 0, 33, 11 }, { 0, 41, 13 }, { 0, 41, 13 }, { 0, 49, 16 },
+ { 0, 49, 16 }, { 0, 49, 16 }, { 0, 57, 19 }, { 0, 57, 19 }, { 0, 57, 19 }, { 8, 49, 21 }, { 0, 66, 22 }, { 0, 66, 22 },
+ { 0, 74, 24 }, { 33, 8, 25 }, { 0, 82, 27 }, { 0, 82, 27 }, { 41, 0, 28 }, { 16, 57, 29 }, { 0, 90, 30 }, { 0, 90, 30 },
+ { 0, 99, 32 }, { 33, 33, 33 }, { 0, 107, 35 }, { 0, 107, 35 }, { 33, 41, 36 }, { 0, 115, 38 }, { 0, 115, 38 }, { 0, 115, 38 },
+ { 0, 123, 40 }, { 33, 57, 41 }, { 0, 132, 43 }, { 0, 132, 43 }, { 33, 66, 44 }, { 0, 140, 46 }, { 0, 140, 46 }, { 66, 8, 47 },
+ { 16, 115, 48 }, { 0, 148, 49 }, { 66, 16, 50 }, { 0, 156, 51 }, { 33, 90, 52 }, { 0, 165, 54 }, { 0, 165, 54 }, { 33, 99, 55 },
+ { 24, 123, 56 }, { 0, 173, 57 }, { 66, 41, 58 }, { 0, 181, 59 }, { 8, 165, 60 }, { 74, 33, 61 }, { 0, 189, 62 }, { 33, 123, 63 },
+ { 0, 198, 65 }, { 0, 198, 65 }, { 66, 66, 66 }, { 8, 189, 67 }, { 0, 206, 68 }, { 66, 74, 69 }, { 0, 214, 70 }, { 33, 148, 71 },
+ { 99, 16, 72 }, { 0, 222, 73 }, { 66, 90, 74 }, { 107, 8, 75 }, { 0, 231, 76 }, { 66, 99, 77 }, { 0, 239, 78 }, { 33, 173, 79 },
+ { 99, 41, 80 }, { 0, 247, 81 }, { 33, 181, 82 }, { 99, 49, 83 }, { 0, 255, 84 }, { 66, 123, 85 }, { 8, 247, 86 }, { 16, 231, 87 },
+ { 66, 132, 88 }, { 8, 255, 89 }, { 33, 206, 90 }, { 99, 74, 91 }, { 16, 247, 92 }, { 41, 198, 93 }, { 16, 255, 94 }, { 24, 239, 95 },
+ { 66, 156, 96 }, { 24, 247, 97 }, { 33, 231, 98 }, { 99, 99, 99 }, { 24, 255, 100 }, { 33, 239, 101 }, { 99, 107, 102 }, { 33, 247, 103 },
+ { 66, 181, 104 }, { 132, 49, 105 }, { 33, 255, 106 }, { 99, 123, 107 }, { 140, 41, 108 }, { 41, 247, 109 }, { 99, 132, 110 }, { 41, 255, 111 },
+ { 66, 206, 112 }, { 132, 74, 113 }, { 49, 247, 114 }, { 66, 214, 115 }, { 132, 82, 116 }, { 49, 255, 117 }, { 99, 156, 118 }, { 57, 247, 119 },
+ { 66, 231, 120 }, { 99, 165, 121 }, { 57, 255, 122 }, { 66, 239, 123 }, { 132, 107, 124 }, { 66, 247, 125 }, { 74, 231, 126 }, { 140, 99, 127 },
+ { 66, 255, 128 }, { 99, 189, 129 }, { 165, 57, 130 }, { 74, 247, 131 }, { 132, 132, 132 }, { 74, 255, 133 }, { 82, 239, 134 }, { 132, 140, 135 },
+ { 82, 247, 136 }, { 99, 214, 137 }, { 165, 82, 138 }, { 82, 255, 139 }, { 132, 156, 140 }, { 173, 74, 141 }, { 90, 247, 142 }, { 132, 165, 143 },
+ { 90, 255, 144 }, { 99, 239, 145 }, { 165, 107, 146 }, { 115, 214, 147 }, { 99, 247, 148 }, { 165, 115, 149 }, { 99, 255, 150 }, { 132, 189, 151 },
+ { 198, 57, 152 }, { 107, 247, 153 }, { 132, 198, 154 }, { 123, 222, 155 }, { 107, 255, 156 }, { 165, 140, 157 }, { 115, 247, 158 }, { 132, 214, 159 },
+ { 173, 132, 160 }, { 115, 255, 161 }, { 132, 222, 162 }, { 198, 90, 163 }, { 123, 247, 164 }, { 165, 165, 165 }, { 123, 255, 166 }, { 132, 239, 167 },
+ { 165, 173, 168 }, { 231, 41, 169 }, { 132, 247, 170 }, { 198, 115, 171 }, { 132, 255, 172 }, { 165, 189, 173 }, { 206, 107, 174 }, { 140, 247, 175 },
+ { 165, 198, 176 }, { 231, 66, 177 }, { 140, 255, 178 }, { 198, 140, 179 }, { 148, 247, 180 }, { 156, 231, 181 }, { 198, 148, 182 }, { 148, 255, 183 },
+ { 165, 222, 184 }, { 231, 90, 185 }, { 156, 247, 186 }, { 165, 231, 187 }, { 156, 255, 188 }, { 165, 239, 189 }, { 198, 173, 190 }, { 165, 247, 192 },
+ { 165, 247, 192 }, { 206, 165, 193 }, { 181, 222, 194 }, { 165, 255, 195 }, { 231, 123, 196 }, { 173, 247, 197 }, { 198, 198, 198 }, { 231, 132, 199 },
+ { 173, 255, 200 }, { 198, 206, 201 }, { 181, 247, 203 }, { 181, 247, 203 }, { 231, 148, 204 }, { 181, 255, 205 }, { 198, 222, 206 }, { 239, 140, 207 },
+ { 189, 247, 208 }, { 198, 231, 209 }, { 189, 255, 211 }, { 189, 255, 211 }, { 231, 173, 212 }, { 198, 247, 214 }, { 198, 247, 214 }, { 231, 181, 215 },
+ { 198, 255, 217 }, { 198, 255, 217 }, { 198, 255, 217 }, { 206, 247, 219 }, { 214, 231, 220 }, { 206, 255, 222 }, { 206, 255, 222 }, { 231, 206, 223 },
+ { 214, 247, 225 }, { 214, 247, 225 }, { 239, 198, 226 }, { 214, 255, 227 }, { 222, 239, 228 }, { 222, 239, 228 }, { 222, 247, 230 }, { 231, 231, 231 },
+ { 222, 255, 233 }, { 222, 255, 233 }, { 231, 239, 234 }, { 231, 239, 234 }, { 231, 247, 236 }, { 231, 247, 236 }, { 231, 255, 239 }, { 231, 255, 239 },
+ { 231, 255, 239 }, { 239, 247, 242 }, { 239, 247, 242 }, { 239, 247, 242 }, { 239, 255, 244 }, { 239, 255, 244 }, { 247, 247, 247 }, { 247, 247, 247 },
+ { 247, 247, 247 }, { 247, 255, 250 }, { 247, 255, 250 }, { 247, 255, 250 }, { 255, 247, 252 }, { 255, 247, 252 }, { 255, 255, 255 }, { 255, 255, 255 },
+ }
+};
+
+Table g_mode4_rgb_high_i1=
+{
+ 1,
+ 0,
+ {
+ { 0, 0, 0 }, { 0, 8, 1 }, { 0, 16, 2 }, { 0, 24, 3 }, { 0, 24, 3 }, { 0, 33, 5 }, { 0, 41, 6 }, { 0, 49, 7 },
+ { 0, 57, 8 }, { 0, 66, 9 }, { 0, 74, 10 }, { 0, 74, 10 }, { 0, 82, 12 }, { 0, 90, 13 }, { 0, 99, 14 }, { 0, 107, 15 },
+ { 0, 115, 16 }, { 0, 123, 17 }, { 8, 82, 18 }, { 0, 132, 19 }, { 0, 140, 20 }, { 0, 148, 21 }, { 0, 156, 22 }, { 0, 165, 23 },
+ { 0, 173, 24 }, { 0, 181, 25 }, { 16, 90, 26 }, { 0, 189, 27 }, { 0, 198, 28 }, { 0, 206, 29 }, { 0, 214, 30 }, { 0, 222, 31 },
+ { 0, 231, 32 }, { 8, 189, 33 }, { 0, 239, 34 }, { 0, 247, 35 }, { 0, 255, 36 }, { 8, 214, 37 }, { 8, 222, 38 }, { 8, 231, 39 },
+ { 8, 239, 40 }, { 24, 148, 41 }, { 8, 247, 42 }, { 8, 255, 43 }, { 16, 214, 44 }, { 16, 222, 45 }, { 16, 231, 46 }, { 16, 239, 47 },
+ { 16, 247, 48 }, { 33, 148, 49 }, { 16, 255, 50 }, { 24, 214, 51 }, { 24, 222, 52 }, { 24, 231, 53 }, { 24, 239, 54 }, { 24, 247, 55 },
+ { 24, 255, 56 }, { 33, 206, 57 }, { 33, 214, 58 }, { 49, 123, 59 }, { 33, 222, 60 }, { 33, 231, 61 }, { 33, 239, 62 }, { 33, 247, 63 },
+ { 33, 255, 64 }, { 41, 214, 65 }, { 41, 222, 66 }, { 66, 74, 67 }, { 41, 231, 68 }, { 41, 239, 69 }, { 41, 247, 70 }, { 41, 255, 71 },
+ { 49, 214, 72 }, { 49, 222, 73 }, { 57, 181, 74 }, { 49, 231, 75 }, { 49, 239, 76 }, { 49, 247, 77 }, { 49, 255, 78 }, { 57, 214, 79 },
+ { 57, 222, 80 }, { 57, 231, 81 }, { 66, 181, 82 }, { 57, 239, 83 }, { 57, 247, 84 }, { 57, 255, 85 }, { 66, 206, 86 }, { 66, 214, 87 },
+ { 66, 222, 88 }, { 66, 231, 89 }, { 66, 239, 90 }, { 66, 247, 91 }, { 82, 156, 92 }, { 66, 255, 93 }, { 74, 214, 94 }, { 74, 222, 95 },
+ { 74, 231, 96 }, { 74, 239, 97 }, { 74, 247, 98 }, { 74, 255, 99 }, { 99, 107, 100 }, { 82, 214, 101 }, { 82, 222, 102 }, { 82, 231, 103 },
+ { 82, 239, 104 }, { 82, 247, 105 }, { 82, 255, 106 }, { 90, 214, 107 }, { 99, 165, 108 }, { 90, 222, 109 }, { 90, 231, 110 }, { 90, 239, 111 },
+ { 90, 247, 112 }, { 90, 255, 113 }, { 99, 206, 114 }, { 99, 214, 115 }, { 99, 222, 116 }, { 107, 181, 117 }, { 99, 231, 118 }, { 99, 239, 119 },
+ { 99, 247, 120 }, { 99, 255, 121 }, { 107, 214, 122 }, { 107, 222, 123 }, { 107, 231, 124 }, { 115, 189, 125 }, { 107, 239, 126 }, { 107, 247, 127 },
+ { 107, 255, 128 }, { 115, 214, 129 }, { 115, 222, 130 }, { 115, 231, 131 }, { 115, 239, 132 }, { 132, 140, 133 }, { 115, 247, 134 }, { 115, 255, 135 },
+ { 123, 214, 136 }, { 123, 222, 137 }, { 123, 231, 138 }, { 123, 239, 139 }, { 123, 247, 140 }, { 132, 198, 141 }, { 123, 255, 142 }, { 148, 115, 143 },
+ { 132, 214, 144 }, { 132, 222, 145 }, { 132, 231, 146 }, { 132, 239, 147 }, { 132, 247, 148 }, { 132, 255, 149 }, { 140, 214, 150 }, { 156, 123, 151 },
+ { 140, 222, 152 }, { 140, 231, 153 }, { 140, 239, 154 }, { 140, 247, 155 }, { 140, 255, 156 }, { 148, 214, 157 }, { 148, 222, 158 }, { 165, 123, 159 },
+ { 148, 231, 160 }, { 148, 239, 161 }, { 148, 247, 162 }, { 148, 255, 163 }, { 156, 214, 164 }, { 156, 222, 165 }, { 165, 173, 166 }, { 156, 231, 167 },
+ { 156, 239, 168 }, { 156, 247, 169 }, { 156, 255, 170 }, { 165, 206, 171 }, { 165, 214, 172 }, { 165, 222, 173 }, { 165, 231, 174 }, { 165, 239, 175 },
+ { 181, 148, 176 }, { 165, 247, 177 }, { 165, 255, 178 }, { 173, 214, 179 }, { 173, 222, 180 }, { 173, 231, 181 }, { 173, 239, 182 }, { 173, 247, 183 },
+ { 189, 156, 184 }, { 173, 255, 185 }, { 181, 214, 186 }, { 181, 222, 187 }, { 181, 231, 188 }, { 181, 239, 189 }, { 181, 247, 190 }, { 181, 255, 191 },
+ { 198, 156, 192 }, { 189, 214, 193 }, { 189, 222, 194 }, { 189, 231, 195 }, { 189, 239, 196 }, { 189, 247, 197 }, { 189, 255, 198 }, { 198, 206, 199 },
+ { 198, 214, 200 }, { 198, 222, 201 }, { 206, 181, 202 }, { 198, 231, 203 }, { 198, 239, 204 }, { 198, 247, 205 }, { 198, 255, 206 }, { 206, 214, 207 },
+ { 206, 222, 208 }, { 214, 181, 209 }, { 206, 231, 210 }, { 206, 239, 211 }, { 206, 247, 212 }, { 206, 255, 213 }, { 214, 214, 214 }, { 214, 222, 215 },
+ { 214, 231, 216 }, { 222, 189, 217 }, { 214, 239, 218 }, { 214, 247, 219 }, { 214, 255, 220 }, { 222, 214, 221 }, { 222, 222, 222 }, { 222, 231, 223 },
+ { 222, 239, 224 }, { 231, 189, 225 }, { 222, 247, 226 }, { 222, 255, 227 }, { 247, 115, 228 }, { 231, 214, 229 }, { 231, 222, 230 }, { 231, 231, 231 },
+ { 231, 239, 232 }, { 231, 247, 233 }, { 231, 255, 234 }, { 239, 214, 235 }, { 255, 123, 236 }, { 239, 222, 237 }, { 239, 231, 238 }, { 239, 239, 239 },
+ { 239, 247, 240 }, { 239, 255, 241 }, { 247, 214, 242 }, { 247, 222, 243 }, { 247, 222, 243 }, { 247, 231, 245 }, { 247, 239, 246 }, { 247, 247, 247 },
+ { 247, 255, 248 }, { 255, 214, 249 }, { 255, 222, 250 }, { 255, 222, 250 }, { 255, 231, 252 }, { 255, 239, 253 }, { 255, 247, 254 }, { 255, 255, 255 },
+ }
+};
+
+Table g_mode4_rgb_high_i2=
+{
+ 2,
+ 0,
+ {
+ { 0, 0, 0 }, { 0, 0, 0 }, { 0, 8, 2 }, { 0, 8, 2 }, { 0, 16, 5 }, { 0, 16, 5 }, { 8, 0, 6 }, { 0, 24, 7 },
+ { 8, 8, 8 }, { 0, 33, 9 }, { 8, 16, 10 }, { 0, 41, 12 }, { 0, 41, 12 }, { 8, 24, 13 }, { 0, 49, 14 }, { 8, 33, 15 },
+ { 0, 57, 16 }, { 8, 41, 17 }, { 16, 24, 18 }, { 0, 66, 19 }, { 8, 49, 20 }, { 0, 74, 21 }, { 8, 57, 22 }, { 0, 82, 23 },
+ { 8, 66, 24 }, { 0, 90, 25 }, { 33, 8, 26 }, { 8, 74, 27 }, { 0, 99, 28 }, { 8, 82, 29 }, { 0, 107, 30 }, { 8, 90, 31 },
+ { 0, 115, 32 }, { 24, 57, 33 }, { 8, 99, 34 }, { 0, 123, 35 }, { 8, 107, 36 }, { 0, 132, 37 }, { 8, 115, 38 }, { 0, 140, 39 },
+ { 8, 123, 40 }, { 41, 41, 41 }, { 0, 148, 42 }, { 8, 132, 43 }, { 0, 156, 44 }, { 8, 140, 45 }, { 0, 165, 46 }, { 8, 148, 47 },
+ { 41, 66, 48 }, { 0, 173, 49 }, { 8, 156, 50 }, { 0, 181, 51 }, { 8, 165, 52 }, { 0, 189, 53 }, { 8, 173, 54 }, { 16, 156, 55 },
+ { 0, 198, 56 }, { 8, 181, 57 }, { 0, 206, 58 }, { 8, 189, 59 }, { 0, 214, 60 }, { 8, 198, 61 }, { 0, 222, 62 }, { 33, 140, 63 },
+ { 8, 206, 64 }, { 0, 231, 65 }, { 8, 214, 66 }, { 0, 239, 67 }, { 8, 222, 68 }, { 0, 247, 69 }, { 24, 189, 70 }, { 8, 231, 71 },
+ { 0, 255, 72 }, { 8, 239, 73 }, { 16, 222, 74 }, { 8, 247, 75 }, { 16, 231, 76 }, { 8, 255, 77 }, { 41, 173, 78 }, { 16, 239, 79 },
+ { 24, 222, 80 }, { 16, 247, 81 }, { 24, 231, 82 }, { 16, 255, 83 }, { 24, 239, 84 }, { 41, 198, 85 }, { 33, 222, 86 }, { 24, 247, 87 },
+ { 49, 189, 88 }, { 24, 255, 89 }, { 41, 214, 90 }, { 33, 239, 91 }, { 41, 222, 92 }, { 33, 247, 93 }, { 41, 231, 94 }, { 33, 255, 95 },
+ { 66, 173, 96 }, { 41, 239, 97 }, { 49, 222, 98 }, { 41, 247, 99 }, { 49, 231, 100 }, { 41, 255, 101 }, { 49, 239, 102 }, { 57, 222, 103 },
+ { 74, 181, 104 }, { 49, 247, 105 }, { 57, 231, 106 }, { 49, 255, 107 }, { 57, 239, 108 }, { 74, 198, 109 }, { 57, 247, 110 }, { 74, 206, 111 },
+ { 66, 231, 112 }, { 57, 255, 113 }, { 107, 132, 114 }, { 66, 239, 115 }, { 74, 222, 116 }, { 66, 247, 117 }, { 74, 231, 118 }, { 66, 255, 119 },
+ { 74, 239, 120 }, { 82, 222, 121 }, { 99, 181, 122 }, { 74, 247, 123 }, { 82, 231, 124 }, { 74, 255, 125 }, { 82, 239, 126 }, { 90, 222, 127 },
+ { 82, 247, 128 }, { 99, 206, 129 }, { 90, 231, 130 }, { 82, 255, 131 }, { 90, 239, 132 }, { 107, 198, 133 }, { 90, 247, 134 }, { 107, 206, 135 },
+ { 90, 255, 136 }, { 107, 214, 137 }, { 99, 239, 138 }, { 107, 222, 139 }, { 140, 140, 140 }, { 99, 247, 141 }, { 107, 231, 142 }, { 99, 255, 143 },
+ { 107, 239, 144 }, { 115, 222, 145 }, { 107, 247, 146 }, { 140, 165, 147 }, { 115, 231, 148 }, { 107, 255, 149 }, { 115, 239, 150 }, { 123, 222, 151 },
+ { 115, 247, 152 }, { 123, 231, 153 }, { 115, 255, 154 }, { 132, 214, 155 }, { 123, 239, 156 }, { 132, 222, 157 }, { 123, 247, 158 }, { 140, 206, 159 },
+ { 123, 255, 160 }, { 140, 214, 161 }, { 132, 239, 162 }, { 140, 222, 163 }, { 132, 247, 164 }, { 156, 189, 165 }, { 140, 231, 166 }, { 132, 255, 167 },
+ { 140, 239, 168 }, { 148, 222, 169 }, { 140, 247, 170 }, { 148, 231, 171 }, { 140, 255, 172 }, { 173, 173, 173 }, { 148, 239, 174 }, { 156, 222, 175 },
+ { 148, 247, 176 }, { 156, 231, 177 }, { 148, 255, 178 }, { 156, 239, 179 }, { 173, 198, 180 }, { 165, 222, 181 }, { 156, 247, 182 }, { 181, 189, 183 },
+ { 156, 255, 184 }, { 173, 214, 185 }, { 165, 239, 186 }, { 173, 222, 187 }, { 165, 247, 188 }, { 173, 231, 189 }, { 165, 255, 190 }, { 198, 173, 191 },
+ { 173, 239, 192 }, { 181, 222, 193 }, { 173, 247, 194 }, { 181, 231, 195 }, { 173, 255, 196 }, { 181, 239, 197 }, { 189, 222, 198 }, { 206, 181, 199 },
+ { 181, 247, 200 }, { 189, 231, 201 }, { 181, 255, 202 }, { 189, 239, 203 }, { 206, 198, 204 }, { 189, 247, 205 }, { 206, 206, 206 }, { 198, 231, 207 },
+ { 189, 255, 208 }, { 239, 132, 209 }, { 198, 239, 210 }, { 206, 222, 211 }, { 198, 247, 212 }, { 206, 231, 213 }, { 198, 255, 214 }, { 206, 239, 215 },
+ { 214, 222, 216 }, { 231, 181, 217 }, { 206, 247, 218 }, { 214, 231, 219 }, { 206, 255, 220 }, { 214, 239, 221 }, { 222, 222, 222 }, { 214, 247, 223 },
+ { 231, 206, 224 }, { 222, 231, 225 }, { 214, 255, 226 }, { 222, 239, 227 }, { 231, 222, 228 }, { 222, 247, 229 }, { 239, 206, 230 }, { 222, 255, 231 },
+ { 239, 214, 232 }, { 231, 239, 233 }, { 239, 222, 234 }, { 247, 206, 235 }, { 231, 247, 236 }, { 239, 231, 237 }, { 231, 255, 238 }, { 239, 239, 239 },
+ { 247, 222, 240 }, { 239, 247, 241 }, { 239, 247, 241 }, { 247, 231, 243 }, { 239, 255, 244 }, { 247, 239, 245 }, { 255, 222, 246 }, { 247, 247, 247 },
+ { 255, 231, 248 }, { 247, 255, 249 }, { 247, 255, 249 }, { 255, 239, 251 }, { 255, 239, 251 }, { 255, 247, 253 }, { 255, 247, 253 }, { 255, 255, 255 },
+ }
+};
+
+Table g_mode4_rgb_high_i3=
+{
+ 3,
+ 0,
+ {
+ { 0, 0, 0 }, { 0, 0, 0 }, { 0, 8, 3 }, { 0, 8, 3 }, { 0, 8, 3 }, { 8, 0, 5 }, { 0, 16, 7 }, { 0, 16, 7 },
+ { 8, 8, 8 }, { 16, 0, 9 }, { 0, 24, 10 }, { 8, 16, 11 }, { 8, 16, 11 }, { 16, 8, 13 }, { 0, 33, 14 }, { 8, 24, 15 },
+ { 16, 16, 16 }, { 0, 41, 17 }, { 0, 41, 17 }, { 8, 33, 19 }, { 0, 49, 21 }, { 0, 49, 21 }, { 8, 41, 22 }, { 16, 33, 23 },
+ { 0, 57, 24 }, { 8, 49, 25 }, { 33, 16, 26 }, { 16, 41, 27 }, { 0, 66, 28 }, { 8, 57, 29 }, { 16, 49, 30 }, { 0, 74, 31 },
+ { 8, 66, 32 }, { 16, 57, 33 }, { 41, 24, 34 }, { 0, 82, 35 }, { 8, 74, 36 }, { 16, 66, 37 }, { 0, 90, 38 }, { 8, 82, 39 },
+ { 16, 74, 40 }, { 41, 41, 41 }, { 0, 99, 42 }, { 8, 90, 43 }, { 16, 82, 44 }, { 0, 107, 45 }, { 8, 99, 46 }, { 16, 90, 47 },
+ { 24, 82, 48 }, { 0, 115, 49 }, { 8, 107, 50 }, { 16, 99, 51 }, { 0, 123, 52 }, { 8, 115, 53 }, { 16, 107, 54 }, { 41, 74, 55 },
+ { 0, 132, 56 }, { 8, 123, 57 }, { 16, 115, 58 }, { 0, 140, 59 }, { 8, 132, 60 }, { 16, 123, 61 }, { 0, 148, 62 }, { 49, 82, 63 },
+ { 8, 140, 64 }, { 16, 132, 65 }, { 0, 156, 66 }, { 8, 148, 67 }, { 16, 140, 68 }, { 41, 107, 69 }, { 0, 165, 70 }, { 33, 123, 71 },
+ { 16, 148, 72 }, { 0, 173, 73 }, { 8, 165, 74 }, { 16, 156, 75 }, { 0, 181, 76 }, { 49, 115, 77 }, { 8, 173, 78 }, { 16, 165, 79 },
+ { 0, 189, 80 }, { 8, 181, 81 }, { 16, 173, 82 }, { 24, 165, 83 }, { 0, 198, 84 }, { 33, 156, 85 }, { 16, 181, 86 }, { 0, 206, 87 },
+ { 8, 198, 88 }, { 16, 189, 89 }, { 0, 214, 90 }, { 49, 148, 91 }, { 8, 206, 92 }, { 16, 198, 93 }, { 0, 222, 94 }, { 8, 214, 95 },
+ { 16, 206, 96 }, { 0, 231, 97 }, { 8, 222, 98 }, { 33, 189, 99 }, { 16, 214, 100 }, { 0, 239, 101 }, { 8, 231, 102 }, { 16, 222, 103 },
+ { 0, 247, 104 }, { 8, 239, 105 }, { 33, 206, 106 }, { 16, 231, 107 }, { 0, 255, 108 }, { 8, 247, 109 }, { 16, 239, 110 }, { 24, 231, 111 },
+ { 8, 255, 112 }, { 16, 247, 113 }, { 41, 214, 114 }, { 24, 239, 115 }, { 57, 198, 116 }, { 16, 255, 117 }, { 24, 247, 118 }, { 49, 214, 119 },
+ { 33, 239, 120 }, { 24, 255, 121 }, { 49, 222, 122 }, { 33, 247, 123 }, { 82, 181, 124 }, { 41, 239, 125 }, { 49, 231, 126 }, { 33, 255, 127 },
+ { 41, 247, 128 }, { 49, 239, 129 }, { 57, 231, 130 }, { 41, 255, 131 }, { 66, 222, 132 }, { 49, 247, 133 }, { 57, 239, 134 }, { 107, 173, 135 },
+ { 49, 255, 136 }, { 57, 247, 137 }, { 82, 214, 138 }, { 66, 239, 139 }, { 74, 231, 140 }, { 57, 255, 141 }, { 66, 247, 142 }, { 115, 181, 143 },
+ { 74, 239, 144 }, { 82, 231, 145 }, { 66, 255, 146 }, { 74, 247, 147 }, { 82, 239, 148 }, { 90, 231, 149 }, { 74, 255, 150 }, { 99, 222, 151 },
+ { 82, 247, 152 }, { 90, 239, 153 }, { 140, 173, 154 }, { 82, 255, 155 }, { 90, 247, 156 }, { 115, 214, 157 }, { 99, 239, 158 }, { 107, 231, 159 },
+ { 90, 255, 160 }, { 99, 247, 161 }, { 148, 181, 162 }, { 107, 239, 163 }, { 115, 231, 164 }, { 99, 255, 165 }, { 107, 247, 166 }, { 115, 239, 167 },
+ { 140, 206, 168 }, { 107, 255, 169 }, { 132, 222, 170 }, { 115, 247, 171 }, { 123, 239, 172 }, { 173, 173, 173 }, { 115, 255, 174 }, { 123, 247, 175 },
+ { 148, 214, 176 }, { 132, 239, 177 }, { 140, 231, 178 }, { 123, 255, 179 }, { 156, 214, 180 }, { 132, 247, 181 }, { 140, 239, 182 }, { 148, 231, 183 },
+ { 132, 255, 184 }, { 140, 247, 185 }, { 148, 239, 186 }, { 173, 206, 187 }, { 156, 231, 188 }, { 140, 255, 189 }, { 148, 247, 190 }, { 156, 239, 191 },
+ { 181, 206, 192 }, { 148, 255, 193 }, { 156, 247, 194 }, { 181, 214, 195 }, { 165, 239, 196 }, { 173, 231, 197 }, { 156, 255, 198 }, { 206, 189, 199 },
+ { 165, 247, 200 }, { 173, 239, 201 }, { 181, 231, 202 }, { 165, 255, 203 }, { 173, 247, 204 }, { 181, 239, 205 }, { 206, 206, 206 }, { 189, 231, 207 },
+ { 173, 255, 208 }, { 181, 247, 209 }, { 189, 239, 210 }, { 214, 206, 211 }, { 181, 255, 212 }, { 189, 247, 213 }, { 214, 214, 214 }, { 198, 239, 215 },
+ { 247, 173, 216 }, { 189, 255, 217 }, { 239, 189, 218 }, { 198, 247, 219 }, { 206, 239, 220 }, { 214, 231, 221 }, { 198, 255, 222 }, { 206, 247, 223 },
+ { 231, 214, 224 }, { 214, 239, 225 }, { 222, 231, 226 }, { 206, 255, 227 }, { 214, 247, 228 }, { 222, 239, 229 }, { 247, 206, 230 }, { 214, 255, 231 },
+ { 239, 222, 232 }, { 222, 247, 233 }, { 231, 239, 234 }, { 222, 255, 236 }, { 222, 255, 236 }, { 222, 255, 236 }, { 231, 247, 238 }, { 239, 239, 239 },
+ { 247, 231, 240 }, { 231, 255, 241 }, { 239, 247, 242 }, { 239, 247, 242 }, { 247, 239, 244 }, { 255, 231, 245 }, { 239, 255, 246 }, { 247, 247, 247 },
+ { 255, 239, 248 }, { 247, 255, 250 }, { 247, 255, 250 }, { 247, 255, 250 }, { 255, 247, 252 }, { 255, 247, 252 }, { 255, 255, 255 }, { 255, 255, 255 },
+ }
+};
+
+Table g_mode4_a_low=
+{
+ 1,
+ 0,
+ {
+ { 0, 0, 0 }, { 0, 4, 1 }, { 0, 4, 1 }, { 0, 8, 3 }, { 0, 12, 4 }, { 0, 16, 5 }, { 0, 16, 5 }, { 0, 20, 7 },
+ { 0, 24, 8 }, { 0, 28, 9 }, { 0, 28, 9 }, { 0, 32, 11 }, { 0, 36, 12 }, { 0, 40, 13 }, { 0, 44, 14 }, { 4, 36, 15 },
+ { 0, 48, 16 }, { 0, 52, 17 }, { 0, 56, 18 }, { 8, 40, 19 }, { 0, 60, 20 }, { 0, 65, 21 }, { 4, 60, 22 }, { 0, 69, 23 },
+ { 0, 73, 24 }, { 0, 77, 25 }, { 12, 56, 26 }, { 0, 81, 27 }, { 0, 85, 28 }, { 0, 89, 29 }, { 16, 60, 30 }, { 0, 93, 31 },
+ { 0, 97, 32 }, { 0, 101, 33 }, { 0, 105, 34 }, { 4, 97, 35 }, { 0, 109, 36 }, { 0, 113, 37 }, { 0, 117, 38 }, { 8, 101, 39 },
+ { 0, 121, 40 }, { 0, 125, 41 }, { 4, 121, 42 }, { 0, 130, 43 }, { 0, 134, 44 }, { 0, 138, 45 }, { 8, 125, 46 }, { 0, 142, 47 },
+ { 0, 146, 48 }, { 0, 150, 49 }, { 16, 121, 50 }, { 0, 154, 51 }, { 0, 158, 52 }, { 0, 162, 53 }, { 0, 166, 54 }, { 4, 158, 55 },
+ { 0, 170, 56 }, { 0, 174, 57 }, { 0, 178, 58 }, { 8, 162, 59 }, { 0, 182, 60 }, { 0, 186, 61 }, { 0, 190, 62 }, { 12, 166, 63 },
+ { 0, 195, 64 }, { 0, 199, 65 }, { 8, 186, 66 }, { 0, 203, 67 }, { 0, 207, 68 }, { 0, 211, 69 }, { 12, 190, 70 }, { 0, 215, 71 },
+ { 0, 219, 72 }, { 0, 223, 73 }, { 0, 227, 74 }, { 4, 219, 75 }, { 0, 231, 76 }, { 0, 235, 77 }, { 0, 239, 78 }, { 8, 223, 79 },
+ { 0, 243, 80 }, { 0, 247, 81 }, { 0, 251, 82 }, { 12, 227, 83 }, { 0, 255, 84 }, { 4, 251, 85 }, { 4, 255, 86 }, { 16, 231, 87 },
+ { 8, 251, 88 }, { 8, 255, 89 }, { 12, 251, 90 }, { 20, 235, 91 }, { 12, 255, 92 }, { 16, 251, 93 }, { 16, 255, 94 }, { 24, 239, 95 },
+ { 20, 251, 96 }, { 20, 255, 97 }, { 24, 251, 98 }, { 28, 243, 99 }, { 24, 255, 100 }, { 28, 251, 101 }, { 28, 255, 102 }, { 32, 247, 103 },
+ { 32, 251, 104 }, { 32, 255, 105 }, { 56, 207, 106 }, { 36, 251, 107 }, { 36, 255, 108 }, { 40, 251, 109 }, { 60, 211, 110 }, { 40, 255, 111 },
+ { 44, 251, 112 }, { 44, 255, 113 }, { 65, 215, 114 }, { 48, 251, 115 }, { 48, 255, 116 }, { 52, 251, 117 }, { 65, 227, 118 }, { 52, 255, 119 },
+ { 56, 251, 120 }, { 56, 255, 121 }, { 65, 239, 122 }, { 60, 251, 123 }, { 60, 255, 124 }, { 65, 247, 125 }, { 65, 251, 126 }, { 65, 255, 127 },
+ { 77, 231, 128 }, { 69, 251, 129 }, { 69, 255, 130 }, { 73, 251, 131 }, { 81, 235, 132 }, { 73, 255, 133 }, { 77, 251, 134 }, { 77, 255, 135 },
+ { 85, 239, 136 }, { 81, 251, 137 }, { 81, 255, 138 }, { 85, 251, 139 }, { 89, 243, 140 }, { 85, 255, 141 }, { 89, 251, 142 }, { 89, 255, 143 },
+ { 93, 247, 144 }, { 93, 251, 145 }, { 93, 255, 146 }, { 117, 207, 147 }, { 97, 251, 148 }, { 97, 255, 149 }, { 101, 251, 150 }, { 121, 211, 151 },
+ { 101, 255, 152 }, { 105, 251, 153 }, { 105, 255, 154 }, { 125, 215, 155 }, { 109, 251, 156 }, { 109, 255, 157 }, { 113, 251, 158 }, { 130, 219, 159 },
+ { 113, 255, 160 }, { 117, 251, 161 }, { 117, 255, 162 }, { 130, 231, 163 }, { 121, 251, 164 }, { 121, 255, 165 }, { 125, 251, 166 }, { 130, 243, 167 },
+ { 125, 255, 168 }, { 138, 231, 169 }, { 130, 251, 170 }, { 130, 255, 171 }, { 134, 251, 172 }, { 142, 235, 173 }, { 134, 255, 174 }, { 138, 251, 175 },
+ { 138, 255, 176 }, { 146, 239, 177 }, { 142, 251, 178 }, { 142, 255, 179 }, { 146, 251, 180 }, { 150, 243, 181 }, { 146, 255, 182 }, { 150, 251, 183 },
+ { 150, 255, 184 }, { 154, 247, 185 }, { 154, 251, 186 }, { 154, 255, 187 }, { 178, 207, 188 }, { 158, 251, 189 }, { 158, 255, 190 }, { 162, 251, 191 },
+ { 182, 211, 192 }, { 162, 255, 193 }, { 166, 251, 194 }, { 166, 255, 195 }, { 186, 215, 196 }, { 170, 251, 197 }, { 170, 255, 198 }, { 174, 251, 199 },
+ { 190, 219, 200 }, { 174, 255, 201 }, { 178, 251, 202 }, { 178, 255, 203 }, { 195, 223, 204 }, { 182, 251, 205 }, { 182, 255, 206 }, { 186, 251, 207 },
+ { 195, 235, 208 }, { 186, 255, 209 }, { 190, 251, 210 }, { 190, 255, 211 }, { 195, 247, 212 }, { 195, 251, 213 }, { 203, 235, 214 }, { 195, 255, 215 },
+ { 199, 251, 216 }, { 199, 255, 217 }, { 207, 239, 218 }, { 203, 251, 219 }, { 203, 255, 220 }, { 207, 251, 221 }, { 211, 243, 222 }, { 207, 255, 223 },
+ { 211, 251, 224 }, { 211, 255, 225 }, { 215, 247, 226 }, { 215, 251, 227 }, { 215, 255, 228 }, { 239, 207, 229 }, { 219, 251, 230 }, { 219, 255, 231 },
+ { 223, 251, 232 }, { 243, 211, 233 }, { 223, 255, 234 }, { 227, 251, 235 }, { 227, 255, 236 }, { 247, 215, 237 }, { 231, 251, 238 }, { 231, 255, 239 },
+ { 235, 251, 240 }, { 251, 219, 241 }, { 235, 255, 242 }, { 239, 251, 243 }, { 239, 255, 244 }, { 255, 223, 245 }, { 243, 251, 246 }, { 243, 255, 247 },
+ { 247, 251, 248 }, { 247, 251, 248 }, { 247, 255, 250 }, { 251, 251, 251 }, { 251, 255, 252 }, { 251, 255, 252 }, { 255, 251, 254 }, { 255, 255, 255 },
+ }
+};
+
+Table g_mode4_a_high_i1=
+{
+ 1,
+ 0,
+ {
+ { 0, 0, 0 }, { 0, 4, 1 }, { 0, 12, 2 }, { 0, 20, 3 }, { 0, 28, 4 }, { 0, 32, 5 }, { 0, 40, 6 }, { 0, 48, 7 },
+ { 0, 56, 8 }, { 0, 65, 9 }, { 0, 69, 10 }, { 0, 77, 11 }, { 0, 85, 12 }, { 0, 89, 13 }, { 0, 97, 14 }, { 0, 105, 15 },
+ { 0, 113, 16 }, { 0, 121, 17 }, { 0, 125, 18 }, { 0, 134, 19 }, { 0, 142, 20 }, { 0, 146, 21 }, { 0, 154, 22 }, { 0, 162, 23 },
+ { 0, 170, 24 }, { 0, 178, 25 }, { 0, 182, 26 }, { 0, 190, 27 }, { 0, 199, 28 }, { 0, 203, 29 }, { 0, 211, 30 }, { 0, 219, 31 },
+ { 0, 227, 32 }, { 0, 235, 33 }, { 0, 239, 34 }, { 0, 247, 35 }, { 0, 255, 36 }, { 4, 239, 37 }, { 4, 243, 38 }, { 4, 251, 39 },
+ { 8, 235, 40 }, { 8, 243, 41 }, { 8, 247, 42 }, { 8, 255, 43 }, { 12, 239, 44 }, { 12, 247, 45 }, { 12, 251, 46 }, { 16, 235, 47 },
+ { 16, 243, 48 }, { 16, 251, 49 }, { 16, 255, 50 }, { 20, 239, 51 }, { 20, 247, 52 }, { 20, 255, 53 }, { 24, 235, 54 }, { 24, 243, 55 },
+ { 24, 251, 56 }, { 28, 231, 57 }, { 28, 239, 58 }, { 28, 247, 59 }, { 28, 255, 60 }, { 32, 235, 61 }, { 32, 243, 62 }, { 32, 251, 63 },
+ { 36, 235, 64 }, { 36, 239, 65 }, { 36, 247, 66 }, { 36, 255, 67 }, { 40, 239, 68 }, { 40, 243, 69 }, { 40, 251, 70 }, { 44, 235, 71 },
+ { 44, 243, 72 }, { 44, 247, 73 }, { 44, 255, 74 }, { 48, 239, 75 }, { 48, 247, 76 }, { 48, 251, 77 }, { 52, 235, 78 }, { 52, 243, 79 },
+ { 52, 251, 80 }, { 52, 255, 81 }, { 56, 239, 82 }, { 56, 247, 83 }, { 56, 255, 84 }, { 60, 235, 85 }, { 60, 243, 86 }, { 60, 251, 87 },
+ { 65, 227, 88 }, { 65, 235, 89 }, { 65, 243, 90 }, { 65, 247, 91 }, { 65, 255, 92 }, { 69, 239, 93 }, { 69, 247, 94 }, { 69, 251, 95 },
+ { 73, 235, 96 }, { 73, 243, 97 }, { 73, 251, 98 }, { 73, 255, 99 }, { 77, 239, 100 }, { 77, 247, 101 }, { 77, 255, 102 }, { 81, 235, 103 },
+ { 81, 243, 104 }, { 81, 251, 105 }, { 85, 231, 106 }, { 85, 239, 107 }, { 85, 247, 108 }, { 85, 255, 109 }, { 89, 235, 110 }, { 89, 243, 111 },
+ { 89, 251, 112 }, { 93, 235, 113 }, { 93, 239, 114 }, { 93, 247, 115 }, { 93, 255, 116 }, { 97, 239, 117 }, { 97, 243, 118 }, { 97, 251, 119 },
+ { 101, 235, 120 }, { 101, 243, 121 }, { 101, 247, 122 }, { 101, 255, 123 }, { 105, 239, 124 }, { 105, 247, 125 }, { 105, 251, 126 }, { 109, 235, 127 },
+ { 109, 243, 128 }, { 109, 251, 129 }, { 109, 255, 130 }, { 113, 239, 131 }, { 113, 247, 132 }, { 113, 255, 133 }, { 117, 235, 134 }, { 117, 243, 135 },
+ { 117, 251, 136 }, { 121, 235, 137 }, { 121, 239, 138 }, { 121, 247, 139 }, { 121, 255, 140 }, { 125, 239, 141 }, { 125, 243, 142 }, { 125, 251, 143 },
+ { 130, 227, 144 }, { 130, 235, 145 }, { 130, 243, 146 }, { 130, 251, 147 }, { 130, 255, 148 }, { 134, 239, 149 }, { 134, 247, 150 }, { 134, 255, 151 },
+ { 138, 235, 152 }, { 138, 243, 153 }, { 138, 251, 154 }, { 142, 231, 155 }, { 142, 239, 156 }, { 142, 247, 157 }, { 142, 255, 158 }, { 146, 235, 159 },
+ { 146, 243, 160 }, { 146, 251, 161 }, { 150, 235, 162 }, { 150, 239, 163 }, { 150, 247, 164 }, { 150, 255, 165 }, { 154, 239, 166 }, { 154, 243, 167 },
+ { 154, 251, 168 }, { 158, 235, 169 }, { 158, 243, 170 }, { 158, 247, 171 }, { 158, 255, 172 }, { 162, 239, 173 }, { 162, 247, 174 }, { 162, 251, 175 },
+ { 166, 235, 176 }, { 166, 243, 177 }, { 166, 251, 178 }, { 166, 255, 179 }, { 170, 239, 180 }, { 170, 247, 181 }, { 170, 255, 182 }, { 174, 235, 183 },
+ { 174, 243, 184 }, { 174, 251, 185 }, { 178, 235, 186 }, { 178, 239, 187 }, { 178, 247, 188 }, { 178, 255, 189 }, { 182, 239, 190 }, { 182, 243, 191 },
+ { 182, 251, 192 }, { 186, 235, 193 }, { 186, 243, 194 }, { 186, 247, 195 }, { 186, 255, 196 }, { 190, 239, 197 }, { 190, 247, 198 }, { 190, 251, 199 },
+ { 195, 227, 200 }, { 195, 235, 201 }, { 195, 243, 202 }, { 195, 251, 203 }, { 199, 231, 204 }, { 199, 239, 205 }, { 199, 247, 206 }, { 199, 255, 207 },
+ { 203, 235, 208 }, { 203, 243, 209 }, { 203, 251, 210 }, { 207, 235, 211 }, { 207, 239, 212 }, { 207, 247, 213 }, { 207, 255, 214 }, { 211, 239, 215 },
+ { 211, 243, 216 }, { 211, 251, 217 }, { 215, 235, 218 }, { 215, 243, 219 }, { 215, 247, 220 }, { 215, 255, 221 }, { 219, 239, 222 }, { 219, 247, 223 },
+ { 219, 251, 224 }, { 223, 235, 225 }, { 223, 243, 226 }, { 223, 251, 227 }, { 223, 255, 228 }, { 227, 239, 229 }, { 227, 247, 230 }, { 227, 255, 231 },
+ { 231, 235, 232 }, { 231, 243, 233 }, { 231, 251, 234 }, { 235, 235, 235 }, { 235, 239, 236 }, { 235, 247, 237 }, { 235, 255, 238 }, { 239, 239, 239 },
+ { 239, 243, 240 }, { 239, 251, 241 }, { 243, 235, 242 }, { 243, 243, 243 }, { 243, 247, 244 }, { 243, 255, 245 }, { 247, 239, 246 }, { 247, 247, 247 },
+ { 247, 251, 248 }, { 251, 235, 249 }, { 251, 243, 250 }, { 251, 251, 251 }, { 251, 255, 252 }, { 255, 239, 253 }, { 255, 247, 254 }, { 255, 255, 255 },
+ }
+};
+
+Table g_mode4_a_high_i2=
+{
+ 2,
+ 0,
+ {
+ { 0, 0, 0 }, { 0, 4, 1 }, { 0, 8, 2 }, { 0, 12, 3 }, { 4, 4, 4 }, { 0, 16, 5 }, { 0, 20, 6 }, { 0, 24, 7 },
+ { 0, 28, 8 }, { 0, 32, 9 }, { 0, 36, 10 }, { 0, 40, 11 }, { 0, 44, 12 }, { 4, 36, 13 }, { 0, 48, 14 }, { 0, 52, 15 },
+ { 0, 56, 16 }, { 0, 60, 17 }, { 0, 65, 18 }, { 0, 69, 19 }, { 4, 60, 20 }, { 0, 73, 21 }, { 0, 77, 22 }, { 0, 81, 23 },
+ { 0, 85, 24 }, { 0, 89, 25 }, { 0, 93, 26 }, { 0, 97, 27 }, { 0, 101, 28 }, { 4, 93, 29 }, { 0, 105, 30 }, { 0, 109, 31 },
+ { 0, 113, 32 }, { 0, 117, 33 }, { 0, 121, 34 }, { 0, 125, 35 }, { 4, 117, 36 }, { 0, 130, 37 }, { 0, 134, 38 }, { 0, 138, 39 },
+ { 0, 142, 40 }, { 0, 146, 41 }, { 0, 150, 42 }, { 0, 154, 43 }, { 0, 158, 44 }, { 4, 150, 45 }, { 0, 162, 46 }, { 0, 166, 47 },
+ { 0, 170, 48 }, { 0, 174, 49 }, { 0, 178, 50 }, { 0, 182, 51 }, { 0, 186, 52 }, { 0, 190, 53 }, { 4, 182, 54 }, { 0, 195, 55 },
+ { 0, 199, 56 }, { 0, 203, 57 }, { 0, 207, 58 }, { 0, 211, 59 }, { 0, 215, 60 }, { 4, 207, 61 }, { 0, 219, 62 }, { 0, 223, 63 },
+ { 0, 227, 64 }, { 0, 231, 65 }, { 0, 235, 66 }, { 0, 239, 67 }, { 0, 243, 68 }, { 0, 247, 69 }, { 4, 239, 70 }, { 0, 251, 71 },
+ { 0, 255, 72 }, { 4, 251, 73 }, { 8, 243, 74 }, { 4, 255, 75 }, { 8, 251, 76 }, { 8, 255, 77 }, { 12, 247, 78 }, { 12, 251, 79 },
+ { 12, 255, 80 }, { 16, 247, 81 }, { 16, 251, 82 }, { 16, 255, 83 }, { 20, 247, 84 }, { 20, 251, 85 }, { 20, 255, 86 }, { 24, 247, 87 },
+ { 24, 251, 88 }, { 24, 255, 89 }, { 28, 247, 90 }, { 28, 251, 91 }, { 28, 255, 92 }, { 36, 239, 93 }, { 32, 251, 94 }, { 32, 255, 95 },
+ { 36, 251, 96 }, { 40, 243, 97 }, { 36, 255, 98 }, { 40, 251, 99 }, { 40, 255, 100 }, { 44, 247, 101 }, { 44, 251, 102 }, { 44, 255, 103 },
+ { 48, 247, 104 }, { 48, 251, 105 }, { 48, 255, 106 }, { 52, 247, 107 }, { 52, 251, 108 }, { 52, 255, 109 }, { 56, 247, 110 }, { 56, 251, 111 },
+ { 56, 255, 112 }, { 60, 247, 113 }, { 60, 251, 114 }, { 60, 255, 115 }, { 65, 247, 116 }, { 65, 251, 117 }, { 65, 255, 118 }, { 69, 247, 119 },
+ { 69, 251, 120 }, { 69, 255, 121 }, { 73, 247, 122 }, { 73, 251, 123 }, { 73, 255, 124 }, { 77, 247, 125 }, { 77, 251, 126 }, { 77, 255, 127 },
+ { 81, 247, 128 }, { 81, 251, 129 }, { 81, 255, 130 }, { 85, 247, 131 }, { 85, 251, 132 }, { 85, 255, 133 }, { 93, 239, 134 }, { 89, 251, 135 },
+ { 89, 255, 136 }, { 93, 251, 137 }, { 97, 243, 138 }, { 93, 255, 139 }, { 97, 251, 140 }, { 97, 255, 141 }, { 101, 247, 142 }, { 101, 251, 143 },
+ { 101, 255, 144 }, { 105, 247, 145 }, { 105, 251, 146 }, { 105, 255, 147 }, { 109, 247, 148 }, { 109, 251, 149 }, { 109, 255, 150 }, { 113, 247, 151 },
+ { 113, 251, 152 }, { 113, 255, 153 }, { 117, 247, 154 }, { 117, 251, 155 }, { 117, 255, 156 }, { 125, 239, 157 }, { 121, 251, 158 }, { 121, 255, 159 },
+ { 125, 251, 160 }, { 130, 239, 161 }, { 125, 255, 162 }, { 130, 247, 163 }, { 130, 251, 164 }, { 130, 255, 165 }, { 134, 247, 166 }, { 134, 251, 167 },
+ { 134, 255, 168 }, { 138, 247, 169 }, { 138, 251, 170 }, { 138, 255, 171 }, { 142, 247, 172 }, { 142, 251, 173 }, { 142, 255, 174 }, { 150, 239, 175 },
+ { 146, 251, 176 }, { 146, 255, 177 }, { 150, 251, 178 }, { 154, 243, 179 }, { 150, 255, 180 }, { 154, 251, 181 }, { 154, 255, 182 }, { 158, 247, 183 },
+ { 158, 251, 184 }, { 158, 255, 185 }, { 162, 247, 186 }, { 162, 251, 187 }, { 162, 255, 188 }, { 166, 247, 189 }, { 166, 251, 190 }, { 166, 255, 191 },
+ { 170, 247, 192 }, { 170, 251, 193 }, { 170, 255, 194 }, { 174, 247, 195 }, { 174, 251, 196 }, { 174, 255, 197 }, { 182, 239, 198 }, { 178, 251, 199 },
+ { 178, 255, 200 }, { 182, 251, 201 }, { 186, 243, 202 }, { 182, 255, 203 }, { 186, 251, 204 }, { 186, 255, 205 }, { 190, 247, 206 }, { 190, 251, 207 },
+ { 190, 255, 208 }, { 195, 243, 209 }, { 195, 247, 210 }, { 195, 251, 211 }, { 195, 255, 212 }, { 199, 247, 213 }, { 199, 251, 214 }, { 199, 255, 215 },
+ { 207, 239, 216 }, { 203, 251, 217 }, { 203, 255, 218 }, { 207, 251, 219 }, { 211, 243, 220 }, { 207, 255, 221 }, { 211, 251, 222 }, { 211, 255, 223 },
+ { 215, 247, 224 }, { 215, 251, 225 }, { 215, 255, 226 }, { 219, 247, 227 }, { 219, 251, 228 }, { 219, 255, 229 }, { 223, 247, 230 }, { 223, 251, 231 },
+ { 223, 255, 232 }, { 227, 247, 233 }, { 227, 251, 234 }, { 227, 255, 235 }, { 231, 247, 236 }, { 231, 251, 237 }, { 231, 255, 238 }, { 239, 239, 239 },
+ { 235, 251, 240 }, { 235, 255, 241 }, { 239, 251, 242 }, { 243, 243, 243 }, { 239, 255, 244 }, { 243, 251, 245 }, { 243, 255, 246 }, { 247, 247, 247 },
+ { 247, 251, 248 }, { 247, 255, 249 }, { 251, 247, 250 }, { 251, 251, 251 }, { 251, 255, 252 }, { 255, 247, 253 }, { 255, 251, 254 }, { 255, 255, 255 },
+ }
+};
+
+Table g_mode4_a_high_i3=
+{
+ 3,
+ 0,
+ {
+ { 0, 0, 0 }, { 0, 0, 0 }, { 0, 4, 2 }, { 0, 8, 3 }, { 4, 4, 4 }, { 0, 12, 5 }, { 4, 8, 6 }, { 0, 16, 7 },
+ { 0, 20, 8 }, { 4, 16, 9 }, { 0, 24, 10 }, { 4, 20, 11 }, { 0, 28, 12 }, { 8, 20, 13 }, { 0, 32, 14 }, { 0, 36, 15 },
+ { 4, 32, 16 }, { 0, 40, 17 }, { 4, 36, 18 }, { 0, 44, 19 }, { 0, 48, 20 }, { 4, 44, 21 }, { 0, 52, 22 }, { 4, 48, 23 },
+ { 0, 56, 24 }, { 0, 60, 25 }, { 4, 56, 26 }, { 0, 65, 27 }, { 4, 60, 28 }, { 0, 69, 29 }, { 4, 65, 30 }, { 0, 73, 31 },
+ { 0, 77, 32 }, { 4, 73, 33 }, { 0, 81, 34 }, { 4, 77, 35 }, { 0, 85, 36 }, { 8, 77, 37 }, { 0, 89, 38 }, { 0, 93, 39 },
+ { 4, 89, 40 }, { 0, 97, 41 }, { 4, 93, 42 }, { 0, 101, 43 }, { 0, 105, 44 }, { 4, 101, 45 }, { 0, 109, 46 }, { 4, 105, 47 },
+ { 0, 113, 48 }, { 0, 117, 49 }, { 4, 113, 50 }, { 0, 121, 51 }, { 4, 117, 52 }, { 0, 125, 53 }, { 8, 117, 54 }, { 0, 130, 55 },
+ { 8, 121, 56 }, { 0, 134, 57 }, { 0, 138, 58 }, { 4, 134, 59 }, { 0, 142, 60 }, { 4, 138, 61 }, { 0, 146, 62 }, { 0, 150, 63 },
+ { 4, 146, 64 }, { 0, 154, 65 }, { 4, 150, 66 }, { 0, 158, 67 }, { 0, 162, 68 }, { 4, 158, 69 }, { 0, 166, 70 }, { 4, 162, 71 },
+ { 0, 170, 72 }, { 0, 174, 73 }, { 4, 170, 74 }, { 0, 178, 75 }, { 4, 174, 76 }, { 0, 182, 77 }, { 0, 186, 78 }, { 4, 182, 79 },
+ { 0, 190, 80 }, { 4, 186, 81 }, { 0, 195, 82 }, { 8, 186, 83 }, { 0, 199, 84 }, { 4, 195, 85 }, { 0, 203, 86 }, { 0, 207, 87 },
+ { 4, 203, 88 }, { 0, 211, 89 }, { 4, 207, 90 }, { 0, 215, 91 }, { 0, 219, 92 }, { 4, 215, 93 }, { 0, 223, 94 }, { 4, 219, 95 },
+ { 0, 227, 96 }, { 0, 231, 97 }, { 4, 227, 98 }, { 0, 235, 99 }, { 4, 231, 100 }, { 0, 239, 101 }, { 8, 231, 102 }, { 0, 243, 103 },
+ { 0, 247, 104 }, { 4, 243, 105 }, { 0, 251, 106 }, { 4, 247, 107 }, { 0, 255, 108 }, { 8, 247, 109 }, { 4, 255, 110 }, { 8, 251, 111 },
+ { 8, 255, 112 }, { 12, 251, 113 }, { 20, 243, 114 }, { 12, 255, 115 }, { 20, 247, 116 }, { 16, 255, 117 }, { 24, 247, 118 }, { 20, 255, 119 },
+ { 24, 251, 120 }, { 24, 255, 121 }, { 28, 251, 122 }, { 32, 247, 123 }, { 28, 255, 124 }, { 36, 247, 125 }, { 32, 255, 126 }, { 36, 251, 127 },
+ { 36, 255, 128 }, { 40, 251, 129 }, { 44, 247, 130 }, { 40, 255, 131 }, { 48, 247, 132 }, { 44, 255, 133 }, { 48, 251, 134 }, { 48, 255, 135 },
+ { 52, 251, 136 }, { 56, 247, 137 }, { 52, 255, 138 }, { 60, 247, 139 }, { 56, 255, 140 }, { 60, 251, 141 }, { 60, 255, 142 }, { 65, 251, 143 },
+ { 69, 247, 144 }, { 65, 255, 145 }, { 69, 251, 146 }, { 69, 255, 147 }, { 73, 251, 148 }, { 77, 247, 149 }, { 73, 255, 150 }, { 81, 247, 151 },
+ { 77, 255, 152 }, { 81, 251, 153 }, { 81, 255, 154 }, { 85, 251, 155 }, { 89, 247, 156 }, { 85, 255, 157 }, { 93, 247, 158 }, { 89, 255, 159 },
+ { 93, 251, 160 }, { 93, 255, 161 }, { 97, 251, 162 }, { 101, 247, 163 }, { 97, 255, 164 }, { 105, 247, 165 }, { 101, 255, 166 }, { 105, 251, 167 },
+ { 105, 255, 168 }, { 109, 251, 169 }, { 113, 247, 170 }, { 109, 255, 171 }, { 117, 247, 172 }, { 113, 255, 173 }, { 117, 251, 174 }, { 117, 255, 175 },
+ { 121, 251, 176 }, { 134, 235, 177 }, { 121, 255, 178 }, { 130, 247, 179 }, { 125, 255, 180 }, { 130, 251, 181 }, { 134, 247, 182 }, { 130, 255, 183 },
+ { 138, 247, 184 }, { 134, 255, 185 }, { 138, 251, 186 }, { 138, 255, 187 }, { 142, 251, 188 }, { 146, 247, 189 }, { 142, 255, 190 }, { 150, 247, 191 },
+ { 146, 255, 192 }, { 150, 251, 193 }, { 150, 255, 194 }, { 154, 251, 195 }, { 158, 247, 196 }, { 154, 255, 197 }, { 162, 247, 198 }, { 158, 255, 199 },
+ { 162, 251, 200 }, { 162, 255, 201 }, { 166, 251, 202 }, { 174, 243, 203 }, { 166, 255, 204 }, { 174, 247, 205 }, { 170, 255, 206 }, { 178, 247, 207 },
+ { 174, 255, 208 }, { 178, 251, 209 }, { 178, 255, 210 }, { 182, 251, 211 }, { 186, 247, 212 }, { 182, 255, 213 }, { 190, 247, 214 }, { 186, 255, 215 },
+ { 190, 251, 216 }, { 190, 255, 217 }, { 199, 243, 218 }, { 195, 251, 219 }, { 195, 255, 220 }, { 199, 251, 221 }, { 203, 247, 222 }, { 199, 255, 223 },
+ { 207, 247, 224 }, { 203, 255, 225 }, { 207, 251, 226 }, { 207, 255, 227 }, { 211, 251, 228 }, { 215, 247, 229 }, { 211, 255, 230 }, { 219, 247, 231 },
+ { 215, 255, 232 }, { 219, 251, 233 }, { 219, 255, 234 }, { 223, 251, 235 }, { 231, 243, 236 }, { 223, 255, 237 }, { 231, 247, 238 }, { 227, 255, 239 },
+ { 235, 247, 240 }, { 231, 255, 241 }, { 235, 251, 242 }, { 235, 255, 243 }, { 239, 251, 244 }, { 243, 247, 245 }, { 239, 255, 246 }, { 247, 247, 247 },
+ { 243, 255, 248 }, { 247, 251, 249 }, { 247, 255, 250 }, { 251, 251, 251 }, { 255, 247, 252 }, { 251, 255, 253 }, { 251, 255, 253 }, { 255, 255, 255 },
+ }
+};
+
+Table g_mode5_rgb_low=
+{
+ 1,
+ 0,
+ {
+ { 0, 0, 0 }, { 0, 2, 1 }, { 0, 6, 2 }, { 0, 8, 3 }, { 0, 12, 4 }, { 0, 14, 5 }, { 0, 18, 6 }, { 0, 20, 7 },
+ { 0, 24, 8 }, { 0, 26, 9 }, { 0, 30, 10 }, { 0, 32, 11 }, { 0, 36, 12 }, { 0, 40, 13 }, { 0, 42, 14 }, { 0, 46, 15 },
+ { 0, 48, 16 }, { 0, 52, 17 }, { 0, 54, 18 }, { 0, 58, 19 }, { 0, 60, 20 }, { 0, 64, 21 }, { 0, 66, 22 }, { 0, 70, 23 },
+ { 0, 72, 24 }, { 0, 76, 25 }, { 0, 78, 26 }, { 0, 82, 27 }, { 0, 84, 28 }, { 0, 88, 29 }, { 0, 90, 30 }, { 0, 94, 31 },
+ { 0, 96, 32 }, { 0, 100, 33 }, { 0, 104, 34 }, { 0, 106, 35 }, { 0, 110, 36 }, { 0, 112, 37 }, { 0, 116, 38 }, { 0, 118, 39 },
+ { 0, 122, 40 }, { 0, 124, 41 }, { 0, 129, 42 }, { 0, 131, 43 }, { 0, 133, 44 }, { 0, 137, 45 }, { 0, 139, 46 }, { 0, 143, 47 },
+ { 0, 145, 48 }, { 0, 149, 49 }, { 0, 151, 50 }, { 0, 155, 51 }, { 0, 157, 52 }, { 0, 161, 53 }, { 0, 165, 54 }, { 0, 167, 55 },
+ { 0, 171, 56 }, { 0, 173, 57 }, { 0, 177, 58 }, { 0, 179, 59 }, { 0, 183, 60 }, { 0, 185, 61 }, { 0, 189, 62 }, { 0, 191, 63 },
+ { 0, 195, 64 }, { 0, 197, 65 }, { 0, 201, 66 }, { 0, 203, 67 }, { 0, 207, 68 }, { 0, 209, 69 }, { 0, 213, 70 }, { 0, 215, 71 },
+ { 0, 219, 72 }, { 0, 221, 73 }, { 0, 225, 74 }, { 0, 229, 75 }, { 0, 231, 76 }, { 0, 235, 77 }, { 0, 237, 78 }, { 0, 241, 79 },
+ { 0, 243, 80 }, { 0, 247, 81 }, { 0, 249, 82 }, { 0, 253, 83 }, { 0, 255, 84 }, { 2, 255, 85 }, { 4, 253, 86 }, { 6, 253, 87 },
+ { 6, 255, 88 }, { 8, 255, 89 }, { 10, 253, 90 }, { 12, 253, 91 }, { 12, 255, 92 }, { 14, 255, 93 }, { 16, 253, 94 }, { 18, 253, 95 },
+ { 18, 255, 96 }, { 20, 255, 97 }, { 22, 253, 98 }, { 24, 253, 99 }, { 24, 255, 100 }, { 26, 255, 101 }, { 28, 253, 102 }, { 30, 251, 103 },
+ { 30, 255, 104 }, { 32, 253, 105 }, { 34, 253, 106 }, { 34, 255, 107 }, { 36, 255, 108 }, { 38, 253, 109 }, { 40, 253, 110 }, { 40, 255, 111 },
+ { 42, 255, 112 }, { 44, 253, 113 }, { 46, 253, 114 }, { 46, 255, 115 }, { 48, 255, 116 }, { 50, 253, 117 }, { 52, 253, 118 }, { 52, 255, 119 },
+ { 54, 255, 120 }, { 56, 253, 121 }, { 58, 253, 122 }, { 58, 255, 123 }, { 60, 255, 124 }, { 62, 253, 125 }, { 64, 253, 126 }, { 64, 255, 127 },
+ { 66, 255, 128 }, { 68, 253, 129 }, { 70, 253, 130 }, { 70, 255, 131 }, { 72, 255, 132 }, { 74, 253, 133 }, { 76, 253, 134 }, { 76, 255, 135 },
+ { 78, 255, 136 }, { 80, 253, 137 }, { 82, 253, 138 }, { 82, 255, 139 }, { 84, 255, 140 }, { 86, 253, 141 }, { 88, 253, 142 }, { 88, 255, 143 },
+ { 90, 255, 144 }, { 92, 253, 145 }, { 94, 251, 146 }, { 94, 255, 147 }, { 96, 253, 148 }, { 98, 253, 149 }, { 98, 255, 150 }, { 100, 255, 151 },
+ { 102, 253, 152 }, { 104, 253, 153 }, { 104, 255, 154 }, { 106, 255, 155 }, { 108, 253, 156 }, { 110, 253, 157 }, { 110, 255, 158 }, { 112, 255, 159 },
+ { 114, 253, 160 }, { 116, 253, 161 }, { 116, 255, 162 }, { 118, 255, 163 }, { 120, 253, 164 }, { 122, 253, 165 }, { 122, 255, 166 }, { 124, 255, 167 },
+ { 126, 253, 168 }, { 129, 251, 169 }, { 129, 253, 170 }, { 131, 253, 171 }, { 131, 255, 172 }, { 133, 255, 173 }, { 135, 253, 174 }, { 137, 253, 175 },
+ { 137, 255, 176 }, { 139, 255, 177 }, { 141, 253, 178 }, { 143, 253, 179 }, { 143, 255, 180 }, { 145, 255, 181 }, { 147, 253, 182 }, { 149, 253, 183 },
+ { 149, 255, 184 }, { 151, 255, 185 }, { 153, 253, 186 }, { 155, 251, 187 }, { 155, 255, 188 }, { 157, 253, 189 }, { 159, 253, 190 }, { 159, 255, 191 },
+ { 161, 255, 192 }, { 163, 253, 193 }, { 165, 253, 194 }, { 165, 255, 195 }, { 167, 255, 196 }, { 169, 253, 197 }, { 171, 253, 198 }, { 171, 255, 199 },
+ { 173, 255, 200 }, { 175, 253, 201 }, { 177, 253, 202 }, { 177, 255, 203 }, { 179, 255, 204 }, { 181, 253, 205 }, { 183, 253, 206 }, { 183, 255, 207 },
+ { 185, 255, 208 }, { 187, 253, 209 }, { 189, 253, 210 }, { 189, 255, 211 }, { 191, 255, 212 }, { 193, 253, 213 }, { 195, 253, 214 }, { 195, 255, 215 },
+ { 197, 255, 216 }, { 199, 253, 217 }, { 201, 253, 218 }, { 201, 255, 219 }, { 203, 255, 220 }, { 205, 253, 221 }, { 207, 253, 222 }, { 207, 255, 223 },
+ { 209, 255, 224 }, { 211, 253, 225 }, { 213, 253, 226 }, { 213, 255, 227 }, { 215, 255, 228 }, { 217, 253, 229 }, { 219, 251, 230 }, { 219, 255, 231 },
+ { 221, 253, 232 }, { 223, 253, 233 }, { 223, 255, 234 }, { 225, 255, 235 }, { 227, 253, 236 }, { 229, 253, 237 }, { 229, 255, 238 }, { 231, 255, 239 },
+ { 233, 253, 240 }, { 235, 253, 241 }, { 235, 255, 242 }, { 237, 255, 243 }, { 239, 253, 244 }, { 241, 253, 245 }, { 241, 255, 246 }, { 243, 255, 247 },
+ { 245, 253, 248 }, { 247, 253, 249 }, { 247, 255, 250 }, { 249, 255, 251 }, { 251, 253, 252 }, { 253, 253, 253 }, { 253, 255, 254 }, { 255, 255, 255 },
+ }
+};
+
+Table g_mode6_p0_i1=
+{
+ 1,
+ 0,
+ {
+ { 0, 0, 0 }, { 0, 8, 1 }, { 0, 24, 2 }, { 0, 40, 3 }, { 0, 56, 4 }, { 0, 72, 5 }, { 0, 88, 6 }, { 0, 104, 7 },
+ { 0, 120, 8 }, { 0, 136, 9 }, { 0, 152, 10 }, { 0, 168, 11 }, { 0, 184, 12 }, { 0, 200, 13 }, { 0, 216, 14 }, { 0, 232, 15 },
+ { 0, 248, 16 }, { 2, 234, 17 }, { 2, 250, 18 }, { 4, 236, 19 }, { 4, 252, 20 }, { 6, 238, 21 }, { 6, 254, 22 }, { 8, 240, 23 },
+ { 10, 226, 24 }, { 10, 242, 25 }, { 12, 228, 26 }, { 12, 244, 27 }, { 14, 230, 28 }, { 14, 246, 29 }, { 16, 232, 30 }, { 16, 248, 31 },
+ { 18, 234, 32 }, { 18, 250, 33 }, { 20, 236, 34 }, { 20, 252, 35 }, { 22, 238, 36 }, { 22, 254, 37 }, { 24, 240, 38 }, { 26, 226, 39 },
+ { 26, 242, 40 }, { 28, 228, 41 }, { 28, 244, 42 }, { 30, 230, 43 }, { 30, 246, 44 }, { 32, 232, 45 }, { 32, 248, 46 }, { 34, 234, 47 },
+ { 34, 250, 48 }, { 36, 236, 49 }, { 36, 252, 50 }, { 38, 238, 51 }, { 38, 254, 52 }, { 40, 240, 53 }, { 42, 226, 54 }, { 42, 242, 55 },
+ { 44, 228, 56 }, { 44, 244, 57 }, { 46, 230, 58 }, { 46, 246, 59 }, { 48, 232, 60 }, { 48, 248, 61 }, { 50, 234, 62 }, { 50, 250, 63 },
+ { 52, 236, 64 }, { 52, 252, 65 }, { 54, 238, 66 }, { 54, 254, 67 }, { 56, 240, 68 }, { 58, 226, 69 }, { 58, 242, 70 }, { 60, 228, 71 },
+ { 60, 244, 72 }, { 62, 230, 73 }, { 62, 246, 74 }, { 64, 232, 75 }, { 64, 248, 76 }, { 66, 234, 77 }, { 66, 250, 78 }, { 68, 236, 79 },
+ { 68, 252, 80 }, { 70, 238, 81 }, { 70, 254, 82 }, { 72, 240, 83 }, { 74, 226, 84 }, { 74, 242, 85 }, { 76, 228, 86 }, { 76, 244, 87 },
+ { 78, 230, 88 }, { 78, 246, 89 }, { 80, 232, 90 }, { 80, 248, 91 }, { 82, 234, 92 }, { 82, 250, 93 }, { 84, 236, 94 }, { 84, 252, 95 },
+ { 86, 238, 96 }, { 86, 254, 97 }, { 88, 240, 98 }, { 90, 226, 99 }, { 90, 242, 100 }, { 92, 228, 101 }, { 92, 244, 102 }, { 94, 230, 103 },
+ { 94, 246, 104 }, { 96, 232, 105 }, { 96, 248, 106 }, { 98, 234, 107 }, { 98, 250, 108 }, { 100, 236, 109 }, { 100, 252, 110 }, { 102, 238, 111 },
+ { 102, 254, 112 }, { 104, 240, 113 }, { 106, 226, 114 }, { 106, 242, 115 }, { 108, 228, 116 }, { 108, 244, 117 }, { 110, 230, 118 }, { 110, 246, 119 },
+ { 112, 232, 120 }, { 112, 248, 121 }, { 114, 234, 122 }, { 114, 250, 123 }, { 116, 236, 124 }, { 116, 252, 125 }, { 118, 238, 126 }, { 118, 254, 127 },
+ { 120, 240, 128 }, { 122, 226, 129 }, { 122, 242, 130 }, { 124, 228, 131 }, { 124, 244, 132 }, { 126, 230, 133 }, { 126, 246, 134 }, { 128, 232, 135 },
+ { 128, 248, 136 }, { 130, 234, 137 }, { 130, 250, 138 }, { 132, 236, 139 }, { 132, 252, 140 }, { 134, 238, 141 }, { 134, 254, 142 }, { 136, 240, 143 },
+ { 138, 226, 144 }, { 138, 242, 145 }, { 140, 228, 146 }, { 140, 244, 147 }, { 142, 230, 148 }, { 142, 246, 149 }, { 144, 232, 150 }, { 144, 248, 151 },
+ { 146, 234, 152 }, { 146, 250, 153 }, { 148, 236, 154 }, { 148, 252, 155 }, { 150, 238, 156 }, { 150, 254, 157 }, { 152, 240, 158 }, { 154, 226, 159 },
+ { 154, 242, 160 }, { 156, 228, 161 }, { 156, 244, 162 }, { 158, 230, 163 }, { 158, 246, 164 }, { 160, 232, 165 }, { 160, 248, 166 }, { 162, 234, 167 },
+ { 162, 250, 168 }, { 164, 236, 169 }, { 164, 252, 170 }, { 166, 238, 171 }, { 166, 254, 172 }, { 168, 240, 173 }, { 170, 226, 174 }, { 170, 242, 175 },
+ { 172, 228, 176 }, { 172, 244, 177 }, { 174, 230, 178 }, { 174, 246, 179 }, { 176, 232, 180 }, { 176, 248, 181 }, { 178, 234, 182 }, { 178, 250, 183 },
+ { 180, 236, 184 }, { 180, 252, 185 }, { 182, 238, 186 }, { 182, 254, 187 }, { 184, 240, 188 }, { 186, 226, 189 }, { 186, 242, 190 }, { 188, 228, 191 },
+ { 188, 244, 192 }, { 190, 230, 193 }, { 190, 246, 194 }, { 192, 232, 195 }, { 192, 248, 196 }, { 194, 234, 197 }, { 194, 250, 198 }, { 196, 236, 199 },
+ { 196, 252, 200 }, { 198, 238, 201 }, { 198, 254, 202 }, { 200, 240, 203 }, { 202, 226, 204 }, { 202, 242, 205 }, { 204, 228, 206 }, { 204, 244, 207 },
+ { 206, 230, 208 }, { 206, 246, 209 }, { 208, 232, 210 }, { 208, 248, 211 }, { 210, 234, 212 }, { 210, 250, 213 }, { 212, 236, 214 }, { 212, 252, 215 },
+ { 214, 238, 216 }, { 214, 254, 217 }, { 216, 240, 218 }, { 218, 226, 219 }, { 218, 242, 220 }, { 220, 228, 221 }, { 220, 244, 222 }, { 222, 230, 223 },
+ { 222, 246, 224 }, { 224, 232, 225 }, { 224, 248, 226 }, { 226, 234, 227 }, { 226, 250, 228 }, { 228, 236, 229 }, { 228, 252, 230 }, { 230, 238, 231 },
+ { 230, 254, 232 }, { 232, 240, 233 }, { 234, 226, 234 }, { 234, 242, 235 }, { 236, 228, 236 }, { 236, 244, 237 }, { 238, 230, 238 }, { 238, 246, 239 },
+ { 240, 232, 240 }, { 240, 248, 241 }, { 242, 234, 242 }, { 242, 250, 243 }, { 244, 236, 244 }, { 244, 252, 245 }, { 246, 238, 246 }, { 246, 254, 247 },
+ { 248, 240, 248 }, { 250, 226, 249 }, { 250, 242, 250 }, { 252, 228, 251 }, { 252, 244, 252 }, { 254, 230, 253 }, { 254, 246, 254 }, { 254, 246, 254 },
+ }
+};
+
+Table g_mode6_p0_i2=
+{
+ 2,
+ 0,
+ {
+ { 0, 0, 0 }, { 0, 4, 1 }, { 0, 12, 2 }, { 0, 18, 3 }, { 0, 26, 4 }, { 0, 32, 5 }, { 0, 40, 6 }, { 0, 48, 7 },
+ { 0, 54, 8 }, { 0, 62, 9 }, { 0, 68, 10 }, { 0, 76, 11 }, { 0, 82, 12 }, { 0, 90, 13 }, { 0, 96, 14 }, { 0, 104, 15 },
+ { 0, 112, 16 }, { 0, 118, 17 }, { 0, 126, 18 }, { 0, 132, 19 }, { 0, 140, 20 }, { 0, 146, 21 }, { 0, 154, 22 }, { 0, 160, 23 },
+ { 0, 168, 24 }, { 0, 176, 25 }, { 0, 182, 26 }, { 0, 190, 27 }, { 0, 196, 28 }, { 0, 204, 29 }, { 0, 210, 30 }, { 0, 218, 31 },
+ { 0, 224, 32 }, { 0, 232, 33 }, { 0, 240, 34 }, { 0, 246, 35 }, { 0, 254, 36 }, { 2, 248, 37 }, { 4, 244, 38 }, { 4, 250, 39 },
+ { 6, 246, 40 }, { 6, 252, 41 }, { 8, 248, 42 }, { 8, 254, 43 }, { 10, 250, 44 }, { 12, 244, 45 }, { 12, 252, 46 }, { 14, 246, 47 },
+ { 14, 254, 48 }, { 16, 248, 49 }, { 18, 242, 50 }, { 18, 250, 51 }, { 20, 244, 52 }, { 20, 252, 53 }, { 22, 246, 54 }, { 22, 254, 55 },
+ { 24, 248, 56 }, { 26, 244, 57 }, { 26, 250, 58 }, { 28, 246, 59 }, { 28, 252, 60 }, { 30, 248, 61 }, { 30, 254, 62 }, { 32, 250, 63 },
+ { 34, 244, 64 }, { 34, 252, 65 }, { 36, 246, 66 }, { 36, 254, 67 }, { 38, 248, 68 }, { 40, 244, 69 }, { 40, 250, 70 }, { 42, 246, 71 },
+ { 42, 252, 72 }, { 44, 248, 73 }, { 44, 254, 74 }, { 46, 250, 75 }, { 48, 244, 76 }, { 48, 252, 77 }, { 50, 246, 78 }, { 50, 254, 79 },
+ { 52, 248, 80 }, { 54, 244, 81 }, { 54, 250, 82 }, { 56, 246, 83 }, { 56, 252, 84 }, { 58, 248, 85 }, { 58, 254, 86 }, { 60, 250, 87 },
+ { 62, 244, 88 }, { 62, 252, 89 }, { 64, 246, 90 }, { 64, 254, 91 }, { 66, 248, 92 }, { 68, 244, 93 }, { 68, 250, 94 }, { 70, 246, 95 },
+ { 70, 252, 96 }, { 72, 248, 97 }, { 72, 254, 98 }, { 74, 250, 99 }, { 76, 244, 100 }, { 76, 252, 101 }, { 78, 246, 102 }, { 78, 254, 103 },
+ { 80, 248, 104 }, { 82, 242, 105 }, { 82, 250, 106 }, { 84, 244, 107 }, { 84, 252, 108 }, { 86, 246, 109 }, { 86, 254, 110 }, { 88, 248, 111 },
+ { 90, 244, 112 }, { 90, 250, 113 }, { 92, 246, 114 }, { 92, 252, 115 }, { 94, 248, 116 }, { 94, 254, 117 }, { 96, 250, 118 }, { 98, 244, 119 },
+ { 98, 252, 120 }, { 100, 246, 121 }, { 100, 254, 122 }, { 102, 248, 123 }, { 104, 244, 124 }, { 104, 250, 125 }, { 106, 246, 126 }, { 106, 252, 127 },
+ { 108, 248, 128 }, { 108, 254, 129 }, { 110, 250, 130 }, { 112, 244, 131 }, { 112, 252, 132 }, { 114, 246, 133 }, { 114, 254, 134 }, { 116, 248, 135 },
+ { 118, 244, 136 }, { 118, 250, 137 }, { 120, 246, 138 }, { 120, 252, 139 }, { 122, 248, 140 }, { 122, 254, 141 }, { 124, 250, 142 }, { 126, 244, 143 },
+ { 126, 252, 144 }, { 128, 246, 145 }, { 128, 254, 146 }, { 130, 248, 147 }, { 132, 244, 148 }, { 132, 250, 149 }, { 134, 246, 150 }, { 134, 252, 151 },
+ { 136, 248, 152 }, { 136, 254, 153 }, { 138, 250, 154 }, { 140, 244, 155 }, { 140, 252, 156 }, { 142, 246, 157 }, { 142, 254, 158 }, { 144, 248, 159 },
+ { 146, 242, 160 }, { 146, 250, 161 }, { 148, 244, 162 }, { 148, 252, 163 }, { 150, 246, 164 }, { 150, 254, 165 }, { 152, 248, 166 }, { 154, 244, 167 },
+ { 154, 250, 168 }, { 156, 246, 169 }, { 156, 252, 170 }, { 158, 248, 171 }, { 158, 254, 172 }, { 160, 250, 173 }, { 162, 244, 174 }, { 162, 252, 175 },
+ { 164, 246, 176 }, { 164, 254, 177 }, { 166, 248, 178 }, { 168, 244, 179 }, { 168, 250, 180 }, { 170, 246, 181 }, { 170, 252, 182 }, { 172, 248, 183 },
+ { 172, 254, 184 }, { 174, 250, 185 }, { 176, 244, 186 }, { 176, 252, 187 }, { 178, 246, 188 }, { 178, 254, 189 }, { 180, 248, 190 }, { 182, 244, 191 },
+ { 182, 250, 192 }, { 184, 246, 193 }, { 184, 252, 194 }, { 186, 248, 195 }, { 186, 254, 196 }, { 188, 250, 197 }, { 190, 244, 198 }, { 190, 252, 199 },
+ { 192, 246, 200 }, { 192, 254, 201 }, { 194, 248, 202 }, { 196, 244, 203 }, { 196, 250, 204 }, { 198, 246, 205 }, { 198, 252, 206 }, { 200, 248, 207 },
+ { 200, 254, 208 }, { 202, 250, 209 }, { 204, 244, 210 }, { 204, 252, 211 }, { 206, 246, 212 }, { 206, 254, 213 }, { 208, 248, 214 }, { 210, 242, 215 },
+ { 210, 250, 216 }, { 212, 244, 217 }, { 212, 252, 218 }, { 214, 246, 219 }, { 214, 254, 220 }, { 216, 248, 221 }, { 218, 244, 222 }, { 218, 250, 223 },
+ { 220, 246, 224 }, { 220, 252, 225 }, { 222, 248, 226 }, { 222, 254, 227 }, { 224, 250, 228 }, { 226, 244, 229 }, { 226, 252, 230 }, { 228, 246, 231 },
+ { 228, 254, 232 }, { 230, 248, 233 }, { 232, 244, 234 }, { 232, 250, 235 }, { 234, 246, 236 }, { 234, 252, 237 }, { 236, 248, 238 }, { 236, 254, 239 },
+ { 238, 250, 240 }, { 240, 244, 241 }, { 240, 252, 242 }, { 242, 246, 243 }, { 242, 254, 244 }, { 244, 248, 245 }, { 246, 244, 246 }, { 246, 250, 247 },
+ { 248, 246, 248 }, { 248, 252, 249 }, { 250, 248, 250 }, { 250, 254, 251 }, { 252, 250, 252 }, { 254, 244, 253 }, { 254, 252, 254 }, { 254, 252, 254 },
+ }
+};
+
+Table g_mode6_p0_i3=
+{
+ 3,
+ 0,
+ {
+ { 0, 0, 0 }, { 0, 4, 1 }, { 0, 8, 2 }, { 0, 14, 3 }, { 0, 18, 4 }, { 0, 24, 5 }, { 0, 28, 6 }, { 0, 32, 7 },
+ { 0, 38, 8 }, { 0, 42, 9 }, { 0, 48, 10 }, { 0, 52, 11 }, { 0, 58, 12 }, { 0, 62, 13 }, { 0, 68, 14 }, { 0, 72, 15 },
+ { 0, 78, 16 }, { 0, 82, 17 }, { 0, 88, 18 }, { 0, 92, 19 }, { 0, 96, 20 }, { 0, 102, 21 }, { 0, 106, 22 }, { 0, 112, 23 },
+ { 0, 116, 24 }, { 0, 122, 25 }, { 0, 126, 26 }, { 0, 132, 27 }, { 0, 136, 28 }, { 0, 142, 29 }, { 0, 146, 30 }, { 0, 152, 31 },
+ { 0, 156, 32 }, { 0, 160, 33 }, { 0, 166, 34 }, { 0, 170, 35 }, { 0, 176, 36 }, { 0, 180, 37 }, { 0, 186, 38 }, { 0, 190, 39 },
+ { 0, 196, 40 }, { 0, 200, 41 }, { 0, 206, 42 }, { 0, 210, 43 }, { 0, 216, 44 }, { 0, 220, 45 }, { 0, 224, 46 }, { 0, 230, 47 },
+ { 0, 234, 48 }, { 0, 240, 49 }, { 0, 244, 50 }, { 0, 250, 51 }, { 0, 254, 52 }, { 2, 252, 53 }, { 4, 248, 54 }, { 4, 254, 55 },
+ { 6, 250, 56 }, { 8, 248, 57 }, { 8, 252, 58 }, { 10, 250, 59 }, { 10, 254, 60 }, { 12, 252, 61 }, { 14, 248, 62 }, { 14, 254, 63 },
+ { 16, 250, 64 }, { 18, 248, 65 }, { 18, 252, 66 }, { 20, 250, 67 }, { 20, 254, 68 }, { 22, 252, 69 }, { 24, 248, 70 }, { 24, 254, 71 },
+ { 26, 250, 72 }, { 28, 248, 73 }, { 28, 252, 74 }, { 30, 250, 75 }, { 30, 254, 76 }, { 32, 252, 77 }, { 34, 250, 78 }, { 34, 254, 79 },
+ { 36, 252, 80 }, { 38, 248, 81 }, { 38, 254, 82 }, { 40, 250, 83 }, { 42, 248, 84 }, { 42, 252, 85 }, { 44, 250, 86 }, { 44, 254, 87 },
+ { 46, 252, 88 }, { 48, 248, 89 }, { 48, 254, 90 }, { 50, 250, 91 }, { 52, 248, 92 }, { 52, 252, 93 }, { 54, 250, 94 }, { 54, 254, 95 },
+ { 56, 252, 96 }, { 58, 248, 97 }, { 58, 254, 98 }, { 60, 250, 99 }, { 62, 248, 100 }, { 62, 252, 101 }, { 64, 250, 102 }, { 64, 254, 103 },
+ { 66, 252, 104 }, { 68, 248, 105 }, { 68, 254, 106 }, { 70, 250, 107 }, { 72, 248, 108 }, { 72, 252, 109 }, { 74, 250, 110 }, { 74, 254, 111 },
+ { 76, 252, 112 }, { 78, 248, 113 }, { 78, 254, 114 }, { 80, 250, 115 }, { 82, 248, 116 }, { 82, 252, 117 }, { 84, 250, 118 }, { 84, 254, 119 },
+ { 86, 252, 120 }, { 88, 248, 121 }, { 88, 254, 122 }, { 90, 250, 123 }, { 92, 248, 124 }, { 92, 252, 125 }, { 94, 250, 126 }, { 94, 254, 127 },
+ { 96, 252, 128 }, { 98, 250, 129 }, { 98, 254, 130 }, { 100, 252, 131 }, { 102, 248, 132 }, { 102, 254, 133 }, { 104, 250, 134 }, { 106, 248, 135 },
+ { 106, 252, 136 }, { 108, 250, 137 }, { 108, 254, 138 }, { 110, 252, 139 }, { 112, 248, 140 }, { 112, 254, 141 }, { 114, 250, 142 }, { 116, 248, 143 },
+ { 116, 252, 144 }, { 118, 250, 145 }, { 118, 254, 146 }, { 120, 252, 147 }, { 122, 248, 148 }, { 122, 254, 149 }, { 124, 250, 150 }, { 126, 248, 151 },
+ { 126, 252, 152 }, { 128, 250, 153 }, { 128, 254, 154 }, { 130, 252, 155 }, { 132, 248, 156 }, { 132, 254, 157 }, { 134, 250, 158 }, { 136, 248, 159 },
+ { 136, 252, 160 }, { 138, 250, 161 }, { 138, 254, 162 }, { 140, 252, 163 }, { 142, 248, 164 }, { 142, 254, 165 }, { 144, 250, 166 }, { 146, 248, 167 },
+ { 146, 252, 168 }, { 148, 250, 169 }, { 148, 254, 170 }, { 150, 252, 171 }, { 152, 248, 172 }, { 152, 254, 173 }, { 154, 250, 174 }, { 156, 248, 175 },
+ { 156, 252, 176 }, { 158, 250, 177 }, { 158, 254, 178 }, { 160, 252, 179 }, { 162, 250, 180 }, { 162, 254, 181 }, { 164, 252, 182 }, { 166, 248, 183 },
+ { 166, 254, 184 }, { 168, 250, 185 }, { 170, 248, 186 }, { 170, 252, 187 }, { 172, 250, 188 }, { 172, 254, 189 }, { 174, 252, 190 }, { 176, 248, 191 },
+ { 176, 254, 192 }, { 178, 250, 193 }, { 180, 248, 194 }, { 180, 252, 195 }, { 182, 250, 196 }, { 182, 254, 197 }, { 184, 252, 198 }, { 186, 248, 199 },
+ { 186, 254, 200 }, { 188, 250, 201 }, { 190, 248, 202 }, { 190, 252, 203 }, { 192, 250, 204 }, { 192, 254, 205 }, { 194, 252, 206 }, { 196, 248, 207 },
+ { 196, 254, 208 }, { 198, 250, 209 }, { 200, 248, 210 }, { 200, 252, 211 }, { 202, 250, 212 }, { 202, 254, 213 }, { 204, 252, 214 }, { 206, 248, 215 },
+ { 206, 254, 216 }, { 208, 250, 217 }, { 210, 248, 218 }, { 210, 252, 219 }, { 212, 250, 220 }, { 212, 254, 221 }, { 214, 252, 222 }, { 216, 248, 223 },
+ { 216, 254, 224 }, { 218, 250, 225 }, { 220, 248, 226 }, { 220, 252, 227 }, { 222, 250, 228 }, { 222, 254, 229 }, { 224, 252, 230 }, { 226, 250, 231 },
+ { 226, 254, 232 }, { 228, 252, 233 }, { 230, 248, 234 }, { 230, 254, 235 }, { 232, 250, 236 }, { 234, 248, 237 }, { 234, 252, 238 }, { 236, 250, 239 },
+ { 236, 254, 240 }, { 238, 252, 241 }, { 240, 248, 242 }, { 240, 254, 243 }, { 242, 250, 244 }, { 244, 248, 245 }, { 244, 252, 246 }, { 246, 250, 247 },
+ { 246, 254, 248 }, { 248, 252, 249 }, { 250, 248, 250 }, { 250, 254, 251 }, { 252, 250, 252 }, { 254, 248, 253 }, { 254, 252, 254 }, { 254, 252, 254 },
+ }
+};
+
+Table g_mode6_p0_i4=
+{
+ 4,
+ 0,
+ {
+ { 0, 0, 0 }, { 0, 2, 1 }, { 0, 6, 2 }, { 0, 10, 3 }, { 0, 14, 4 }, { 0, 18, 5 }, { 0, 22, 6 }, { 0, 26, 7 },
+ { 0, 30, 8 }, { 0, 32, 9 }, { 0, 36, 10 }, { 0, 40, 11 }, { 0, 44, 12 }, { 0, 48, 13 }, { 0, 52, 14 }, { 0, 56, 15 },
+ { 0, 60, 16 }, { 0, 64, 17 }, { 0, 66, 18 }, { 0, 70, 19 }, { 0, 74, 20 }, { 0, 78, 21 }, { 0, 82, 22 }, { 0, 86, 23 },
+ { 0, 90, 24 }, { 0, 94, 25 }, { 0, 96, 26 }, { 0, 100, 27 }, { 0, 104, 28 }, { 0, 108, 29 }, { 0, 112, 30 }, { 0, 116, 31 },
+ { 0, 120, 32 }, { 0, 124, 33 }, { 0, 128, 34 }, { 0, 130, 35 }, { 0, 134, 36 }, { 0, 138, 37 }, { 0, 142, 38 }, { 0, 146, 39 },
+ { 0, 150, 40 }, { 0, 154, 41 }, { 0, 158, 42 }, { 0, 160, 43 }, { 0, 164, 44 }, { 0, 168, 45 }, { 0, 172, 46 }, { 0, 176, 47 },
+ { 0, 180, 48 }, { 0, 184, 49 }, { 0, 188, 50 }, { 0, 192, 51 }, { 0, 194, 52 }, { 0, 198, 53 }, { 0, 202, 54 }, { 0, 206, 55 },
+ { 0, 210, 56 }, { 0, 214, 57 }, { 0, 218, 58 }, { 0, 222, 59 }, { 0, 224, 60 }, { 0, 228, 61 }, { 0, 232, 62 }, { 0, 236, 63 },
+ { 0, 240, 64 }, { 0, 244, 65 }, { 0, 248, 66 }, { 0, 252, 67 }, { 2, 250, 68 }, { 2, 254, 69 }, { 4, 252, 70 }, { 6, 250, 71 },
+ { 6, 254, 72 }, { 8, 252, 73 }, { 10, 250, 74 }, { 10, 254, 75 }, { 12, 252, 76 }, { 14, 250, 77 }, { 14, 254, 78 }, { 16, 252, 79 },
+ { 18, 250, 80 }, { 18, 254, 81 }, { 20, 252, 82 }, { 22, 250, 83 }, { 22, 254, 84 }, { 24, 252, 85 }, { 26, 250, 86 }, { 26, 254, 87 },
+ { 28, 252, 88 }, { 30, 252, 89 }, { 30, 254, 90 }, { 32, 254, 91 }, { 34, 252, 92 }, { 36, 250, 93 }, { 36, 254, 94 }, { 38, 252, 95 },
+ { 40, 250, 96 }, { 40, 254, 97 }, { 42, 252, 98 }, { 44, 250, 99 }, { 44, 254, 100 }, { 46, 252, 101 }, { 48, 250, 102 }, { 48, 254, 103 },
+ { 50, 252, 104 }, { 52, 250, 105 }, { 52, 254, 106 }, { 54, 252, 107 }, { 56, 250, 108 }, { 56, 254, 109 }, { 58, 252, 110 }, { 60, 252, 111 },
+ { 60, 254, 112 }, { 62, 254, 113 }, { 64, 252, 114 }, { 66, 250, 115 }, { 66, 254, 116 }, { 68, 252, 117 }, { 70, 250, 118 }, { 70, 254, 119 },
+ { 72, 252, 120 }, { 74, 250, 121 }, { 74, 254, 122 }, { 76, 252, 123 }, { 78, 250, 124 }, { 78, 254, 125 }, { 80, 252, 126 }, { 82, 250, 127 },
+ { 82, 254, 128 }, { 84, 252, 129 }, { 86, 250, 130 }, { 86, 254, 131 }, { 88, 252, 132 }, { 90, 250, 133 }, { 90, 254, 134 }, { 92, 252, 135 },
+ { 94, 252, 136 }, { 94, 254, 137 }, { 96, 254, 138 }, { 98, 252, 139 }, { 100, 250, 140 }, { 100, 254, 141 }, { 102, 252, 142 }, { 104, 250, 143 },
+ { 104, 254, 144 }, { 106, 252, 145 }, { 108, 250, 146 }, { 108, 254, 147 }, { 110, 252, 148 }, { 112, 250, 149 }, { 112, 254, 150 }, { 114, 252, 151 },
+ { 116, 250, 152 }, { 116, 254, 153 }, { 118, 252, 154 }, { 120, 250, 155 }, { 120, 254, 156 }, { 122, 252, 157 }, { 124, 252, 158 }, { 124, 254, 159 },
+ { 126, 254, 160 }, { 128, 252, 161 }, { 130, 250, 162 }, { 130, 254, 163 }, { 132, 252, 164 }, { 134, 250, 165 }, { 134, 254, 166 }, { 136, 252, 167 },
+ { 138, 250, 168 }, { 138, 254, 169 }, { 140, 252, 170 }, { 142, 250, 171 }, { 142, 254, 172 }, { 144, 252, 173 }, { 146, 250, 174 }, { 146, 254, 175 },
+ { 148, 252, 176 }, { 150, 250, 177 }, { 150, 254, 178 }, { 152, 252, 179 }, { 154, 250, 180 }, { 154, 254, 181 }, { 156, 252, 182 }, { 158, 252, 183 },
+ { 158, 254, 184 }, { 160, 254, 185 }, { 162, 252, 186 }, { 164, 250, 187 }, { 164, 254, 188 }, { 166, 252, 189 }, { 168, 250, 190 }, { 168, 254, 191 },
+ { 170, 252, 192 }, { 172, 250, 193 }, { 172, 254, 194 }, { 174, 252, 195 }, { 176, 250, 196 }, { 176, 254, 197 }, { 178, 252, 198 }, { 180, 250, 199 },
+ { 180, 254, 200 }, { 182, 252, 201 }, { 184, 250, 202 }, { 184, 254, 203 }, { 186, 252, 204 }, { 188, 252, 205 }, { 188, 254, 206 }, { 190, 254, 207 },
+ { 192, 252, 208 }, { 194, 250, 209 }, { 194, 254, 210 }, { 196, 252, 211 }, { 198, 250, 212 }, { 198, 254, 213 }, { 200, 252, 214 }, { 202, 250, 215 },
+ { 202, 254, 216 }, { 204, 252, 217 }, { 206, 250, 218 }, { 206, 254, 219 }, { 208, 252, 220 }, { 210, 250, 221 }, { 210, 254, 222 }, { 212, 252, 223 },
+ { 214, 250, 224 }, { 214, 254, 225 }, { 216, 252, 226 }, { 218, 250, 227 }, { 218, 254, 228 }, { 220, 252, 229 }, { 222, 252, 230 }, { 222, 254, 231 },
+ { 224, 254, 232 }, { 226, 252, 233 }, { 228, 250, 234 }, { 228, 254, 235 }, { 230, 252, 236 }, { 232, 250, 237 }, { 232, 254, 238 }, { 234, 252, 239 },
+ { 236, 250, 240 }, { 236, 254, 241 }, { 238, 252, 242 }, { 240, 250, 243 }, { 240, 254, 244 }, { 242, 252, 245 }, { 244, 250, 246 }, { 244, 254, 247 },
+ { 246, 252, 248 }, { 248, 250, 249 }, { 248, 254, 250 }, { 250, 252, 251 }, { 252, 252, 252 }, { 252, 254, 253 }, { 254, 254, 254 }, { 254, 254, 254 },
+ }
+};
+
+Table g_mode6_p0_i5=
+{
+ 5,
+ 0,
+ {
+ { 0, 0, 0 }, { 0, 2, 1 }, { 0, 6, 2 }, { 0, 8, 3 }, { 0, 12, 4 }, { 0, 14, 5 }, { 0, 18, 6 }, { 0, 20, 7 },
+ { 0, 24, 8 }, { 0, 26, 9 }, { 0, 30, 10 }, { 0, 32, 11 }, { 0, 36, 12 }, { 0, 40, 13 }, { 0, 42, 14 }, { 0, 46, 15 },
+ { 0, 48, 16 }, { 0, 52, 17 }, { 0, 54, 18 }, { 0, 58, 19 }, { 0, 60, 20 }, { 0, 64, 21 }, { 0, 66, 22 }, { 0, 70, 23 },
+ { 0, 72, 24 }, { 0, 76, 25 }, { 0, 78, 26 }, { 0, 82, 27 }, { 0, 84, 28 }, { 0, 88, 29 }, { 0, 90, 30 }, { 0, 94, 31 },
+ { 0, 96, 32 }, { 0, 100, 33 }, { 0, 104, 34 }, { 0, 106, 35 }, { 0, 110, 36 }, { 0, 112, 37 }, { 0, 116, 38 }, { 0, 118, 39 },
+ { 0, 122, 40 }, { 0, 124, 41 }, { 0, 128, 42 }, { 0, 130, 43 }, { 0, 134, 44 }, { 0, 136, 45 }, { 0, 140, 46 }, { 0, 142, 47 },
+ { 0, 146, 48 }, { 0, 148, 49 }, { 0, 152, 50 }, { 0, 154, 51 }, { 0, 158, 52 }, { 0, 160, 53 }, { 0, 164, 54 }, { 0, 168, 55 },
+ { 0, 170, 56 }, { 0, 174, 57 }, { 0, 176, 58 }, { 0, 180, 59 }, { 0, 182, 60 }, { 0, 186, 61 }, { 0, 188, 62 }, { 0, 192, 63 },
+ { 0, 194, 64 }, { 0, 198, 65 }, { 0, 200, 66 }, { 0, 204, 67 }, { 0, 206, 68 }, { 0, 210, 69 }, { 0, 212, 70 }, { 0, 216, 71 },
+ { 0, 218, 72 }, { 0, 222, 73 }, { 0, 224, 74 }, { 0, 228, 75 }, { 0, 232, 76 }, { 0, 234, 77 }, { 0, 238, 78 }, { 0, 240, 79 },
+ { 0, 244, 80 }, { 0, 246, 81 }, { 0, 250, 82 }, { 0, 252, 83 }, { 2, 252, 84 }, { 2, 254, 85 }, { 4, 254, 86 }, { 6, 252, 87 },
+ { 8, 252, 88 }, { 8, 254, 89 }, { 10, 254, 90 }, { 12, 252, 91 }, { 14, 252, 92 }, { 14, 254, 93 }, { 16, 254, 94 }, { 18, 252, 95 },
+ { 20, 252, 96 }, { 20, 254, 97 }, { 22, 254, 98 }, { 24, 252, 99 }, { 26, 250, 100 }, { 26, 254, 101 }, { 28, 252, 102 }, { 30, 252, 103 },
+ { 30, 254, 104 }, { 32, 254, 105 }, { 34, 252, 106 }, { 36, 252, 107 }, { 36, 254, 108 }, { 38, 254, 109 }, { 40, 252, 110 }, { 42, 252, 111 },
+ { 42, 254, 112 }, { 44, 254, 113 }, { 46, 252, 114 }, { 48, 252, 115 }, { 48, 254, 116 }, { 50, 254, 117 }, { 52, 252, 118 }, { 54, 252, 119 },
+ { 54, 254, 120 }, { 56, 254, 121 }, { 58, 252, 122 }, { 60, 252, 123 }, { 60, 254, 124 }, { 62, 254, 125 }, { 64, 252, 126 }, { 66, 252, 127 },
+ { 66, 254, 128 }, { 68, 254, 129 }, { 70, 252, 130 }, { 72, 252, 131 }, { 72, 254, 132 }, { 74, 254, 133 }, { 76, 252, 134 }, { 78, 252, 135 },
+ { 78, 254, 136 }, { 80, 254, 137 }, { 82, 252, 138 }, { 84, 252, 139 }, { 84, 254, 140 }, { 86, 254, 141 }, { 88, 252, 142 }, { 90, 250, 143 },
+ { 90, 254, 144 }, { 92, 252, 145 }, { 94, 252, 146 }, { 94, 254, 147 }, { 96, 254, 148 }, { 98, 252, 149 }, { 100, 252, 150 }, { 100, 254, 151 },
+ { 102, 254, 152 }, { 104, 252, 153 }, { 106, 252, 154 }, { 106, 254, 155 }, { 108, 254, 156 }, { 110, 252, 157 }, { 112, 252, 158 }, { 112, 254, 159 },
+ { 114, 254, 160 }, { 116, 252, 161 }, { 118, 252, 162 }, { 118, 254, 163 }, { 120, 254, 164 }, { 122, 252, 165 }, { 124, 252, 166 }, { 124, 254, 167 },
+ { 126, 254, 168 }, { 128, 252, 169 }, { 130, 252, 170 }, { 130, 254, 171 }, { 132, 254, 172 }, { 134, 252, 173 }, { 136, 252, 174 }, { 136, 254, 175 },
+ { 138, 254, 176 }, { 140, 252, 177 }, { 142, 252, 178 }, { 142, 254, 179 }, { 144, 254, 180 }, { 146, 252, 181 }, { 148, 252, 182 }, { 148, 254, 183 },
+ { 150, 254, 184 }, { 152, 252, 185 }, { 154, 250, 186 }, { 154, 254, 187 }, { 156, 252, 188 }, { 158, 252, 189 }, { 158, 254, 190 }, { 160, 254, 191 },
+ { 162, 252, 192 }, { 164, 252, 193 }, { 164, 254, 194 }, { 166, 254, 195 }, { 168, 252, 196 }, { 170, 252, 197 }, { 170, 254, 198 }, { 172, 254, 199 },
+ { 174, 252, 200 }, { 176, 252, 201 }, { 176, 254, 202 }, { 178, 254, 203 }, { 180, 252, 204 }, { 182, 252, 205 }, { 182, 254, 206 }, { 184, 254, 207 },
+ { 186, 252, 208 }, { 188, 252, 209 }, { 188, 254, 210 }, { 190, 254, 211 }, { 192, 252, 212 }, { 194, 252, 213 }, { 194, 254, 214 }, { 196, 254, 215 },
+ { 198, 252, 216 }, { 200, 252, 217 }, { 200, 254, 218 }, { 202, 254, 219 }, { 204, 252, 220 }, { 206, 252, 221 }, { 206, 254, 222 }, { 208, 254, 223 },
+ { 210, 252, 224 }, { 212, 252, 225 }, { 212, 254, 226 }, { 214, 254, 227 }, { 216, 252, 228 }, { 218, 250, 229 }, { 218, 254, 230 }, { 220, 252, 231 },
+ { 222, 252, 232 }, { 222, 254, 233 }, { 224, 254, 234 }, { 226, 252, 235 }, { 228, 252, 236 }, { 228, 254, 237 }, { 230, 254, 238 }, { 232, 252, 239 },
+ { 234, 252, 240 }, { 234, 254, 241 }, { 236, 254, 242 }, { 238, 252, 243 }, { 240, 252, 244 }, { 240, 254, 245 }, { 242, 254, 246 }, { 244, 252, 247 },
+ { 246, 252, 248 }, { 246, 254, 249 }, { 248, 254, 250 }, { 250, 252, 251 }, { 252, 252, 252 }, { 252, 254, 253 }, { 254, 254, 254 }, { 254, 254, 254 },
+ }
+};
+
+Table g_mode6_p0_i6=
+{
+ 6,
+ 0,
+ {
+ { 0, 0, 0 }, { 0, 2, 1 }, { 0, 4, 2 }, { 0, 8, 3 }, { 0, 10, 4 }, { 0, 12, 5 }, { 0, 14, 6 }, { 0, 16, 7 },
+ { 0, 20, 8 }, { 0, 22, 9 }, { 0, 24, 10 }, { 0, 26, 11 }, { 0, 30, 12 }, { 0, 32, 13 }, { 0, 34, 14 }, { 0, 36, 15 },
+ { 0, 40, 16 }, { 0, 42, 17 }, { 0, 44, 18 }, { 0, 46, 19 }, { 0, 48, 20 }, { 0, 52, 21 }, { 0, 54, 22 }, { 0, 56, 23 },
+ { 0, 58, 24 }, { 0, 62, 25 }, { 0, 64, 26 }, { 0, 66, 27 }, { 0, 68, 28 }, { 0, 72, 29 }, { 0, 74, 30 }, { 0, 76, 31 },
+ { 0, 78, 32 }, { 0, 80, 33 }, { 0, 84, 34 }, { 0, 86, 35 }, { 0, 88, 36 }, { 0, 90, 37 }, { 0, 94, 38 }, { 0, 96, 39 },
+ { 0, 98, 40 }, { 0, 100, 41 }, { 0, 104, 42 }, { 0, 106, 43 }, { 0, 108, 44 }, { 0, 110, 45 }, { 0, 112, 46 }, { 0, 116, 47 },
+ { 0, 118, 48 }, { 0, 120, 49 }, { 0, 122, 50 }, { 0, 126, 51 }, { 0, 128, 52 }, { 0, 130, 53 }, { 0, 132, 54 }, { 0, 136, 55 },
+ { 0, 138, 56 }, { 0, 140, 57 }, { 0, 142, 58 }, { 0, 144, 59 }, { 0, 148, 60 }, { 0, 150, 61 }, { 0, 152, 62 }, { 0, 154, 63 },
+ { 0, 158, 64 }, { 0, 160, 65 }, { 0, 162, 66 }, { 0, 164, 67 }, { 0, 168, 68 }, { 0, 170, 69 }, { 0, 172, 70 }, { 0, 174, 71 },
+ { 0, 176, 72 }, { 0, 180, 73 }, { 0, 182, 74 }, { 0, 184, 75 }, { 0, 186, 76 }, { 0, 190, 77 }, { 0, 192, 78 }, { 0, 194, 79 },
+ { 0, 196, 80 }, { 0, 200, 81 }, { 0, 202, 82 }, { 0, 204, 83 }, { 0, 206, 84 }, { 0, 208, 85 }, { 0, 212, 86 }, { 0, 214, 87 },
+ { 0, 216, 88 }, { 0, 218, 89 }, { 0, 222, 90 }, { 0, 224, 91 }, { 0, 226, 92 }, { 0, 228, 93 }, { 0, 232, 94 }, { 0, 234, 95 },
+ { 0, 236, 96 }, { 0, 238, 97 }, { 0, 240, 98 }, { 0, 244, 99 }, { 0, 246, 100 }, { 0, 248, 101 }, { 0, 250, 102 }, { 0, 254, 103 },
+ { 2, 252, 104 }, { 4, 252, 105 }, { 4, 254, 106 }, { 6, 254, 107 }, { 8, 254, 108 }, { 10, 254, 109 }, { 12, 252, 110 }, { 14, 252, 111 },
+ { 14, 254, 112 }, { 16, 254, 113 }, { 18, 254, 114 }, { 20, 254, 115 }, { 22, 254, 116 }, { 24, 252, 117 }, { 26, 252, 118 }, { 26, 254, 119 },
+ { 28, 254, 120 }, { 30, 254, 121 }, { 32, 254, 122 }, { 34, 252, 123 }, { 36, 252, 124 }, { 36, 254, 125 }, { 38, 254, 126 }, { 40, 254, 127 },
+ { 42, 254, 128 }, { 44, 252, 129 }, { 46, 252, 130 }, { 46, 254, 131 }, { 48, 254, 132 }, { 50, 254, 133 }, { 52, 254, 134 }, { 54, 254, 135 },
+ { 56, 252, 136 }, { 58, 252, 137 }, { 58, 254, 138 }, { 60, 254, 139 }, { 62, 254, 140 }, { 64, 254, 141 }, { 66, 252, 142 }, { 68, 252, 143 },
+ { 68, 254, 144 }, { 70, 254, 145 }, { 72, 254, 146 }, { 74, 254, 147 }, { 76, 252, 148 }, { 78, 252, 149 }, { 78, 254, 150 }, { 80, 254, 151 },
+ { 82, 254, 152 }, { 84, 254, 153 }, { 86, 254, 154 }, { 88, 252, 155 }, { 90, 252, 156 }, { 90, 254, 157 }, { 92, 254, 158 }, { 94, 254, 159 },
+ { 96, 254, 160 }, { 98, 252, 161 }, { 100, 252, 162 }, { 100, 254, 163 }, { 102, 254, 164 }, { 104, 254, 165 }, { 106, 254, 166 }, { 108, 252, 167 },
+ { 110, 252, 168 }, { 110, 254, 169 }, { 112, 254, 170 }, { 114, 254, 171 }, { 116, 254, 172 }, { 118, 254, 173 }, { 120, 252, 174 }, { 122, 252, 175 },
+ { 122, 254, 176 }, { 124, 254, 177 }, { 126, 254, 178 }, { 128, 254, 179 }, { 130, 252, 180 }, { 132, 252, 181 }, { 132, 254, 182 }, { 134, 254, 183 },
+ { 136, 254, 184 }, { 138, 254, 185 }, { 140, 252, 186 }, { 142, 252, 187 }, { 142, 254, 188 }, { 144, 254, 189 }, { 146, 254, 190 }, { 148, 254, 191 },
+ { 150, 254, 192 }, { 152, 252, 193 }, { 154, 252, 194 }, { 154, 254, 195 }, { 156, 254, 196 }, { 158, 254, 197 }, { 160, 254, 198 }, { 162, 252, 199 },
+ { 164, 252, 200 }, { 164, 254, 201 }, { 166, 254, 202 }, { 168, 254, 203 }, { 170, 254, 204 }, { 172, 252, 205 }, { 174, 252, 206 }, { 174, 254, 207 },
+ { 176, 254, 208 }, { 178, 254, 209 }, { 180, 254, 210 }, { 182, 254, 211 }, { 184, 252, 212 }, { 186, 252, 213 }, { 186, 254, 214 }, { 188, 254, 215 },
+ { 190, 254, 216 }, { 192, 254, 217 }, { 194, 252, 218 }, { 196, 252, 219 }, { 196, 254, 220 }, { 198, 254, 221 }, { 200, 254, 222 }, { 202, 254, 223 },
+ { 204, 252, 224 }, { 206, 252, 225 }, { 206, 254, 226 }, { 208, 254, 227 }, { 210, 254, 228 }, { 212, 254, 229 }, { 214, 254, 230 }, { 216, 252, 231 },
+ { 218, 252, 232 }, { 218, 254, 233 }, { 220, 254, 234 }, { 222, 254, 235 }, { 224, 254, 236 }, { 226, 252, 237 }, { 228, 252, 238 }, { 228, 254, 239 },
+ { 230, 254, 240 }, { 232, 254, 241 }, { 234, 254, 242 }, { 236, 252, 243 }, { 238, 252, 244 }, { 238, 254, 245 }, { 240, 254, 246 }, { 242, 254, 247 },
+ { 244, 254, 248 }, { 246, 254, 249 }, { 248, 252, 250 }, { 250, 252, 251 }, { 250, 254, 252 }, { 252, 254, 253 }, { 254, 254, 254 }, { 254, 254, 254 },
+ }
+};
+
+Table g_mode6_p0_i7=
+{
+ 7,
+ 0,
+ {
+ { 0, 0, 0 }, { 0, 2, 1 }, { 0, 4, 2 }, { 0, 6, 3 }, { 0, 8, 4 }, { 0, 10, 5 }, { 0, 12, 6 }, { 0, 14, 7 },
+ { 0, 16, 8 }, { 0, 20, 9 }, { 0, 22, 10 }, { 0, 24, 11 }, { 0, 26, 12 }, { 0, 28, 13 }, { 0, 30, 14 }, { 0, 32, 15 },
+ { 0, 34, 16 }, { 0, 36, 17 }, { 0, 38, 18 }, { 0, 40, 19 }, { 0, 42, 20 }, { 0, 44, 21 }, { 0, 46, 22 }, { 0, 48, 23 },
+ { 0, 52, 24 }, { 0, 54, 25 }, { 0, 56, 26 }, { 0, 58, 27 }, { 0, 60, 28 }, { 0, 62, 29 }, { 0, 64, 30 }, { 0, 66, 31 },
+ { 0, 68, 32 }, { 0, 70, 33 }, { 0, 72, 34 }, { 0, 74, 35 }, { 0, 76, 36 }, { 0, 78, 37 }, { 0, 80, 38 }, { 0, 84, 39 },
+ { 0, 86, 40 }, { 0, 88, 41 }, { 0, 90, 42 }, { 0, 92, 43 }, { 0, 94, 44 }, { 0, 96, 45 }, { 0, 98, 46 }, { 0, 100, 47 },
+ { 0, 102, 48 }, { 0, 104, 49 }, { 0, 106, 50 }, { 0, 108, 51 }, { 0, 110, 52 }, { 0, 112, 53 }, { 0, 116, 54 }, { 0, 118, 55 },
+ { 0, 120, 56 }, { 0, 122, 57 }, { 0, 124, 58 }, { 0, 126, 59 }, { 0, 128, 60 }, { 0, 130, 61 }, { 0, 132, 62 }, { 0, 134, 63 },
+ { 0, 136, 64 }, { 0, 138, 65 }, { 0, 140, 66 }, { 0, 142, 67 }, { 0, 144, 68 }, { 0, 148, 69 }, { 0, 150, 70 }, { 0, 152, 71 },
+ { 0, 154, 72 }, { 0, 156, 73 }, { 0, 158, 74 }, { 0, 160, 75 }, { 0, 162, 76 }, { 0, 164, 77 }, { 0, 166, 78 }, { 0, 168, 79 },
+ { 0, 170, 80 }, { 0, 172, 81 }, { 0, 174, 82 }, { 0, 176, 83 }, { 0, 180, 84 }, { 0, 182, 85 }, { 0, 184, 86 }, { 0, 186, 87 },
+ { 0, 188, 88 }, { 0, 190, 89 }, { 0, 192, 90 }, { 0, 194, 91 }, { 0, 196, 92 }, { 0, 198, 93 }, { 0, 200, 94 }, { 0, 202, 95 },
+ { 0, 204, 96 }, { 0, 206, 97 }, { 0, 208, 98 }, { 0, 212, 99 }, { 0, 214, 100 }, { 0, 216, 101 }, { 0, 218, 102 }, { 0, 220, 103 },
+ { 0, 222, 104 }, { 0, 224, 105 }, { 0, 226, 106 }, { 0, 228, 107 }, { 0, 230, 108 }, { 0, 232, 109 }, { 0, 234, 110 }, { 0, 236, 111 },
+ { 0, 238, 112 }, { 0, 240, 113 }, { 0, 244, 114 }, { 0, 246, 115 }, { 0, 248, 116 }, { 0, 250, 117 }, { 0, 252, 118 }, { 0, 254, 119 },
+ { 2, 254, 120 }, { 4, 254, 121 }, { 6, 254, 122 }, { 8, 254, 123 }, { 10, 254, 124 }, { 12, 252, 125 }, { 14, 252, 126 }, { 14, 254, 127 },
+ { 16, 254, 128 }, { 18, 254, 129 }, { 20, 254, 130 }, { 22, 254, 131 }, { 24, 254, 132 }, { 26, 254, 133 }, { 28, 254, 134 }, { 30, 254, 135 },
+ { 32, 254, 136 }, { 34, 254, 137 }, { 36, 254, 138 }, { 38, 254, 139 }, { 40, 254, 140 }, { 42, 254, 141 }, { 44, 252, 142 }, { 46, 252, 143 },
+ { 46, 254, 144 }, { 48, 254, 145 }, { 50, 254, 146 }, { 52, 254, 147 }, { 54, 254, 148 }, { 56, 254, 149 }, { 58, 254, 150 }, { 60, 254, 151 },
+ { 62, 254, 152 }, { 64, 254, 153 }, { 66, 254, 154 }, { 68, 254, 155 }, { 70, 254, 156 }, { 72, 254, 157 }, { 74, 254, 158 }, { 76, 252, 159 },
+ { 78, 252, 160 }, { 78, 254, 161 }, { 80, 254, 162 }, { 82, 254, 163 }, { 84, 254, 164 }, { 86, 254, 165 }, { 88, 254, 166 }, { 90, 254, 167 },
+ { 92, 254, 168 }, { 94, 254, 169 }, { 96, 254, 170 }, { 98, 254, 171 }, { 100, 254, 172 }, { 102, 254, 173 }, { 104, 254, 174 }, { 106, 254, 175 },
+ { 108, 252, 176 }, { 110, 252, 177 }, { 110, 254, 178 }, { 112, 254, 179 }, { 114, 254, 180 }, { 116, 254, 181 }, { 118, 254, 182 }, { 120, 254, 183 },
+ { 122, 254, 184 }, { 124, 254, 185 }, { 126, 254, 186 }, { 128, 254, 187 }, { 130, 254, 188 }, { 132, 254, 189 }, { 134, 254, 190 }, { 136, 254, 191 },
+ { 138, 254, 192 }, { 140, 252, 193 }, { 142, 252, 194 }, { 142, 254, 195 }, { 144, 254, 196 }, { 146, 254, 197 }, { 148, 254, 198 }, { 150, 254, 199 },
+ { 152, 254, 200 }, { 154, 254, 201 }, { 156, 254, 202 }, { 158, 254, 203 }, { 160, 254, 204 }, { 162, 254, 205 }, { 164, 254, 206 }, { 166, 254, 207 },
+ { 168, 254, 208 }, { 170, 254, 209 }, { 172, 252, 210 }, { 174, 252, 211 }, { 174, 254, 212 }, { 176, 254, 213 }, { 178, 254, 214 }, { 180, 254, 215 },
+ { 182, 254, 216 }, { 184, 254, 217 }, { 186, 254, 218 }, { 188, 254, 219 }, { 190, 254, 220 }, { 192, 254, 221 }, { 194, 254, 222 }, { 196, 254, 223 },
+ { 198, 254, 224 }, { 200, 254, 225 }, { 202, 254, 226 }, { 204, 252, 227 }, { 206, 252, 228 }, { 206, 254, 229 }, { 208, 254, 230 }, { 210, 254, 231 },
+ { 212, 254, 232 }, { 214, 254, 233 }, { 216, 254, 234 }, { 218, 254, 235 }, { 220, 254, 236 }, { 222, 254, 237 }, { 224, 254, 238 }, { 226, 254, 239 },
+ { 228, 254, 240 }, { 230, 254, 241 }, { 232, 254, 242 }, { 234, 254, 243 }, { 236, 252, 244 }, { 238, 252, 245 }, { 238, 254, 246 }, { 240, 254, 247 },
+ { 242, 254, 248 }, { 244, 254, 249 }, { 246, 254, 250 }, { 248, 254, 251 }, { 250, 254, 252 }, { 252, 254, 253 }, { 254, 254, 254 }, { 254, 254, 254 },
+ }
+};
+
+Table g_mode6_p1_i1=
+{
+ 1,
+ 1,
+ {
+ { 1, 1, 1 }, { 1, 1, 1 }, { 1, 9, 2 }, { 1, 25, 3 }, { 1, 41, 4 }, { 1, 57, 5 }, { 1, 73, 6 }, { 1, 89, 7 },
+ { 1, 105, 8 }, { 1, 121, 9 }, { 1, 137, 10 }, { 1, 153, 11 }, { 1, 169, 12 }, { 1, 185, 13 }, { 1, 201, 14 }, { 1, 217, 15 },
+ { 1, 233, 16 }, { 1, 249, 17 }, { 3, 235, 18 }, { 3, 251, 19 }, { 5, 237, 20 }, { 5, 253, 21 }, { 7, 239, 22 }, { 7, 255, 23 },
+ { 9, 241, 24 }, { 11, 227, 25 }, { 11, 243, 26 }, { 13, 229, 27 }, { 13, 245, 28 }, { 15, 231, 29 }, { 15, 247, 30 }, { 17, 233, 31 },
+ { 17, 249, 32 }, { 19, 235, 33 }, { 19, 251, 34 }, { 21, 237, 35 }, { 21, 253, 36 }, { 23, 239, 37 }, { 23, 255, 38 }, { 25, 241, 39 },
+ { 27, 227, 40 }, { 27, 243, 41 }, { 29, 229, 42 }, { 29, 245, 43 }, { 31, 231, 44 }, { 31, 247, 45 }, { 33, 233, 46 }, { 33, 249, 47 },
+ { 35, 235, 48 }, { 35, 251, 49 }, { 37, 237, 50 }, { 37, 253, 51 }, { 39, 239, 52 }, { 39, 255, 53 }, { 41, 241, 54 }, { 43, 227, 55 },
+ { 43, 243, 56 }, { 45, 229, 57 }, { 45, 245, 58 }, { 47, 231, 59 }, { 47, 247, 60 }, { 49, 233, 61 }, { 49, 249, 62 }, { 51, 235, 63 },
+ { 51, 251, 64 }, { 53, 237, 65 }, { 53, 253, 66 }, { 55, 239, 67 }, { 55, 255, 68 }, { 57, 241, 69 }, { 59, 227, 70 }, { 59, 243, 71 },
+ { 61, 229, 72 }, { 61, 245, 73 }, { 63, 231, 74 }, { 63, 247, 75 }, { 65, 233, 76 }, { 65, 249, 77 }, { 67, 235, 78 }, { 67, 251, 79 },
+ { 69, 237, 80 }, { 69, 253, 81 }, { 71, 239, 82 }, { 71, 255, 83 }, { 73, 241, 84 }, { 75, 227, 85 }, { 75, 243, 86 }, { 77, 229, 87 },
+ { 77, 245, 88 }, { 79, 231, 89 }, { 79, 247, 90 }, { 81, 233, 91 }, { 81, 249, 92 }, { 83, 235, 93 }, { 83, 251, 94 }, { 85, 237, 95 },
+ { 85, 253, 96 }, { 87, 239, 97 }, { 87, 255, 98 }, { 89, 241, 99 }, { 91, 227, 100 }, { 91, 243, 101 }, { 93, 229, 102 }, { 93, 245, 103 },
+ { 95, 231, 104 }, { 95, 247, 105 }, { 97, 233, 106 }, { 97, 249, 107 }, { 99, 235, 108 }, { 99, 251, 109 }, { 101, 237, 110 }, { 101, 253, 111 },
+ { 103, 239, 112 }, { 103, 255, 113 }, { 105, 241, 114 }, { 107, 227, 115 }, { 107, 243, 116 }, { 109, 229, 117 }, { 109, 245, 118 }, { 111, 231, 119 },
+ { 111, 247, 120 }, { 113, 233, 121 }, { 113, 249, 122 }, { 115, 235, 123 }, { 115, 251, 124 }, { 117, 237, 125 }, { 117, 253, 126 }, { 119, 239, 127 },
+ { 119, 255, 128 }, { 121, 241, 129 }, { 123, 227, 130 }, { 123, 243, 131 }, { 125, 229, 132 }, { 125, 245, 133 }, { 127, 231, 134 }, { 127, 247, 135 },
+ { 129, 233, 136 }, { 129, 249, 137 }, { 131, 235, 138 }, { 131, 251, 139 }, { 133, 237, 140 }, { 133, 253, 141 }, { 135, 239, 142 }, { 135, 255, 143 },
+ { 137, 241, 144 }, { 139, 227, 145 }, { 139, 243, 146 }, { 141, 229, 147 }, { 141, 245, 148 }, { 143, 231, 149 }, { 143, 247, 150 }, { 145, 233, 151 },
+ { 145, 249, 152 }, { 147, 235, 153 }, { 147, 251, 154 }, { 149, 237, 155 }, { 149, 253, 156 }, { 151, 239, 157 }, { 151, 255, 158 }, { 153, 241, 159 },
+ { 155, 227, 160 }, { 155, 243, 161 }, { 157, 229, 162 }, { 157, 245, 163 }, { 159, 231, 164 }, { 159, 247, 165 }, { 161, 233, 166 }, { 161, 249, 167 },
+ { 163, 235, 168 }, { 163, 251, 169 }, { 165, 237, 170 }, { 165, 253, 171 }, { 167, 239, 172 }, { 167, 255, 173 }, { 169, 241, 174 }, { 171, 227, 175 },
+ { 171, 243, 176 }, { 173, 229, 177 }, { 173, 245, 178 }, { 175, 231, 179 }, { 175, 247, 180 }, { 177, 233, 181 }, { 177, 249, 182 }, { 179, 235, 183 },
+ { 179, 251, 184 }, { 181, 237, 185 }, { 181, 253, 186 }, { 183, 239, 187 }, { 183, 255, 188 }, { 185, 241, 189 }, { 187, 227, 190 }, { 187, 243, 191 },
+ { 189, 229, 192 }, { 189, 245, 193 }, { 191, 231, 194 }, { 191, 247, 195 }, { 193, 233, 196 }, { 193, 249, 197 }, { 195, 235, 198 }, { 195, 251, 199 },
+ { 197, 237, 200 }, { 197, 253, 201 }, { 199, 239, 202 }, { 199, 255, 203 }, { 201, 241, 204 }, { 203, 227, 205 }, { 203, 243, 206 }, { 205, 229, 207 },
+ { 205, 245, 208 }, { 207, 231, 209 }, { 207, 247, 210 }, { 209, 233, 211 }, { 209, 249, 212 }, { 211, 235, 213 }, { 211, 251, 214 }, { 213, 237, 215 },
+ { 213, 253, 216 }, { 215, 239, 217 }, { 215, 255, 218 }, { 217, 241, 219 }, { 219, 227, 220 }, { 219, 243, 221 }, { 221, 229, 222 }, { 221, 245, 223 },
+ { 223, 231, 224 }, { 223, 247, 225 }, { 225, 233, 226 }, { 225, 249, 227 }, { 227, 235, 228 }, { 227, 251, 229 }, { 229, 237, 230 }, { 229, 253, 231 },
+ { 231, 239, 232 }, { 231, 255, 233 }, { 233, 241, 234 }, { 235, 227, 235 }, { 235, 243, 236 }, { 237, 229, 237 }, { 237, 245, 238 }, { 239, 231, 239 },
+ { 239, 247, 240 }, { 241, 233, 241 }, { 241, 249, 242 }, { 243, 235, 243 }, { 243, 251, 244 }, { 245, 237, 245 }, { 245, 253, 246 }, { 247, 239, 247 },
+ { 247, 255, 248 }, { 249, 241, 249 }, { 251, 227, 250 }, { 251, 243, 251 }, { 253, 229, 252 }, { 253, 245, 253 }, { 255, 231, 254 }, { 255, 247, 255 },
+ }
+};
+
+Table g_mode6_p1_i2=
+{
+ 2,
+ 1,
+ {
+ { 1, 1, 1 }, { 1, 1, 1 }, { 1, 5, 2 }, { 1, 13, 3 }, { 1, 19, 4 }, { 1, 27, 5 }, { 1, 33, 6 }, { 1, 41, 7 },
+ { 1, 49, 8 }, { 1, 55, 9 }, { 1, 63, 10 }, { 1, 69, 11 }, { 1, 77, 12 }, { 1, 83, 13 }, { 1, 91, 14 }, { 1, 97, 15 },
+ { 1, 105, 16 }, { 1, 113, 17 }, { 1, 119, 18 }, { 1, 127, 19 }, { 1, 133, 20 }, { 1, 141, 21 }, { 1, 147, 22 }, { 1, 155, 23 },
+ { 1, 161, 24 }, { 1, 169, 25 }, { 1, 177, 26 }, { 1, 183, 27 }, { 1, 191, 28 }, { 1, 197, 29 }, { 1, 205, 30 }, { 1, 211, 31 },
+ { 1, 219, 32 }, { 1, 225, 33 }, { 1, 233, 34 }, { 1, 241, 35 }, { 1, 247, 36 }, { 1, 255, 37 }, { 3, 249, 38 }, { 5, 245, 39 },
+ { 5, 251, 40 }, { 7, 247, 41 }, { 7, 253, 42 }, { 9, 249, 43 }, { 9, 255, 44 }, { 11, 251, 45 }, { 13, 245, 46 }, { 13, 253, 47 },
+ { 15, 247, 48 }, { 15, 255, 49 }, { 17, 249, 50 }, { 19, 243, 51 }, { 19, 251, 52 }, { 21, 245, 53 }, { 21, 253, 54 }, { 23, 247, 55 },
+ { 23, 255, 56 }, { 25, 249, 57 }, { 27, 245, 58 }, { 27, 251, 59 }, { 29, 247, 60 }, { 29, 253, 61 }, { 31, 249, 62 }, { 31, 255, 63 },
+ { 33, 251, 64 }, { 35, 245, 65 }, { 35, 253, 66 }, { 37, 247, 67 }, { 37, 255, 68 }, { 39, 249, 69 }, { 41, 245, 70 }, { 41, 251, 71 },
+ { 43, 247, 72 }, { 43, 253, 73 }, { 45, 249, 74 }, { 45, 255, 75 }, { 47, 251, 76 }, { 49, 245, 77 }, { 49, 253, 78 }, { 51, 247, 79 },
+ { 51, 255, 80 }, { 53, 249, 81 }, { 55, 245, 82 }, { 55, 251, 83 }, { 57, 247, 84 }, { 57, 253, 85 }, { 59, 249, 86 }, { 59, 255, 87 },
+ { 61, 251, 88 }, { 63, 245, 89 }, { 63, 253, 90 }, { 65, 247, 91 }, { 65, 255, 92 }, { 67, 249, 93 }, { 69, 245, 94 }, { 69, 251, 95 },
+ { 71, 247, 96 }, { 71, 253, 97 }, { 73, 249, 98 }, { 73, 255, 99 }, { 75, 251, 100 }, { 77, 245, 101 }, { 77, 253, 102 }, { 79, 247, 103 },
+ { 79, 255, 104 }, { 81, 249, 105 }, { 83, 243, 106 }, { 83, 251, 107 }, { 85, 245, 108 }, { 85, 253, 109 }, { 87, 247, 110 }, { 87, 255, 111 },
+ { 89, 249, 112 }, { 91, 245, 113 }, { 91, 251, 114 }, { 93, 247, 115 }, { 93, 253, 116 }, { 95, 249, 117 }, { 95, 255, 118 }, { 97, 251, 119 },
+ { 99, 245, 120 }, { 99, 253, 121 }, { 101, 247, 122 }, { 101, 255, 123 }, { 103, 249, 124 }, { 105, 245, 125 }, { 105, 251, 126 }, { 107, 247, 127 },
+ { 107, 253, 128 }, { 109, 249, 129 }, { 109, 255, 130 }, { 111, 251, 131 }, { 113, 245, 132 }, { 113, 253, 133 }, { 115, 247, 134 }, { 115, 255, 135 },
+ { 117, 249, 136 }, { 119, 245, 137 }, { 119, 251, 138 }, { 121, 247, 139 }, { 121, 253, 140 }, { 123, 249, 141 }, { 123, 255, 142 }, { 125, 251, 143 },
+ { 127, 245, 144 }, { 127, 253, 145 }, { 129, 247, 146 }, { 129, 255, 147 }, { 131, 249, 148 }, { 133, 245, 149 }, { 133, 251, 150 }, { 135, 247, 151 },
+ { 135, 253, 152 }, { 137, 249, 153 }, { 137, 255, 154 }, { 139, 251, 155 }, { 141, 245, 156 }, { 141, 253, 157 }, { 143, 247, 158 }, { 143, 255, 159 },
+ { 145, 249, 160 }, { 147, 243, 161 }, { 147, 251, 162 }, { 149, 245, 163 }, { 149, 253, 164 }, { 151, 247, 165 }, { 151, 255, 166 }, { 153, 249, 167 },
+ { 155, 245, 168 }, { 155, 251, 169 }, { 157, 247, 170 }, { 157, 253, 171 }, { 159, 249, 172 }, { 159, 255, 173 }, { 161, 251, 174 }, { 163, 245, 175 },
+ { 163, 253, 176 }, { 165, 247, 177 }, { 165, 255, 178 }, { 167, 249, 179 }, { 169, 245, 180 }, { 169, 251, 181 }, { 171, 247, 182 }, { 171, 253, 183 },
+ { 173, 249, 184 }, { 173, 255, 185 }, { 175, 251, 186 }, { 177, 245, 187 }, { 177, 253, 188 }, { 179, 247, 189 }, { 179, 255, 190 }, { 181, 249, 191 },
+ { 183, 245, 192 }, { 183, 251, 193 }, { 185, 247, 194 }, { 185, 253, 195 }, { 187, 249, 196 }, { 187, 255, 197 }, { 189, 251, 198 }, { 191, 245, 199 },
+ { 191, 253, 200 }, { 193, 247, 201 }, { 193, 255, 202 }, { 195, 249, 203 }, { 197, 245, 204 }, { 197, 251, 205 }, { 199, 247, 206 }, { 199, 253, 207 },
+ { 201, 249, 208 }, { 201, 255, 209 }, { 203, 251, 210 }, { 205, 245, 211 }, { 205, 253, 212 }, { 207, 247, 213 }, { 207, 255, 214 }, { 209, 249, 215 },
+ { 211, 243, 216 }, { 211, 251, 217 }, { 213, 245, 218 }, { 213, 253, 219 }, { 215, 247, 220 }, { 215, 255, 221 }, { 217, 249, 222 }, { 219, 245, 223 },
+ { 219, 251, 224 }, { 221, 247, 225 }, { 221, 253, 226 }, { 223, 249, 227 }, { 223, 255, 228 }, { 225, 251, 229 }, { 227, 245, 230 }, { 227, 253, 231 },
+ { 229, 247, 232 }, { 229, 255, 233 }, { 231, 249, 234 }, { 233, 245, 235 }, { 233, 251, 236 }, { 235, 247, 237 }, { 235, 253, 238 }, { 237, 249, 239 },
+ { 237, 255, 240 }, { 239, 251, 241 }, { 241, 245, 242 }, { 241, 253, 243 }, { 243, 247, 244 }, { 243, 255, 245 }, { 245, 249, 246 }, { 247, 245, 247 },
+ { 247, 251, 248 }, { 249, 247, 249 }, { 249, 253, 250 }, { 251, 249, 251 }, { 251, 255, 252 }, { 253, 251, 253 }, { 255, 245, 254 }, { 255, 253, 255 },
+ }
+};
+
+Table g_mode6_p1_i3=
+{
+ 3,
+ 1,
+ {
+ { 1, 1, 1 }, { 1, 1, 1 }, { 1, 5, 2 }, { 1, 9, 3 }, { 1, 15, 4 }, { 1, 19, 5 }, { 1, 25, 6 }, { 1, 29, 7 },
+ { 1, 33, 8 }, { 1, 39, 9 }, { 1, 43, 10 }, { 1, 49, 11 }, { 1, 53, 12 }, { 1, 59, 13 }, { 1, 63, 14 }, { 1, 69, 15 },
+ { 1, 73, 16 }, { 1, 79, 17 }, { 1, 83, 18 }, { 1, 89, 19 }, { 1, 93, 20 }, { 1, 97, 21 }, { 1, 103, 22 }, { 1, 107, 23 },
+ { 1, 113, 24 }, { 1, 117, 25 }, { 1, 123, 26 }, { 1, 127, 27 }, { 1, 133, 28 }, { 1, 137, 29 }, { 1, 143, 30 }, { 1, 147, 31 },
+ { 1, 153, 32 }, { 1, 157, 33 }, { 1, 161, 34 }, { 1, 167, 35 }, { 1, 171, 36 }, { 1, 177, 37 }, { 1, 181, 38 }, { 1, 187, 39 },
+ { 1, 191, 40 }, { 1, 197, 41 }, { 1, 201, 42 }, { 1, 207, 43 }, { 1, 211, 44 }, { 1, 217, 45 }, { 1, 221, 46 }, { 1, 225, 47 },
+ { 1, 231, 48 }, { 1, 235, 49 }, { 1, 241, 50 }, { 1, 245, 51 }, { 1, 251, 52 }, { 1, 255, 53 }, { 3, 253, 54 }, { 5, 249, 55 },
+ { 5, 255, 56 }, { 7, 251, 57 }, { 9, 249, 58 }, { 9, 253, 59 }, { 11, 251, 60 }, { 11, 255, 61 }, { 13, 253, 62 }, { 15, 249, 63 },
+ { 15, 255, 64 }, { 17, 251, 65 }, { 19, 249, 66 }, { 19, 253, 67 }, { 21, 251, 68 }, { 21, 255, 69 }, { 23, 253, 70 }, { 25, 249, 71 },
+ { 25, 255, 72 }, { 27, 251, 73 }, { 29, 249, 74 }, { 29, 253, 75 }, { 31, 251, 76 }, { 31, 255, 77 }, { 33, 253, 78 }, { 35, 251, 79 },
+ { 35, 255, 80 }, { 37, 253, 81 }, { 39, 249, 82 }, { 39, 255, 83 }, { 41, 251, 84 }, { 43, 249, 85 }, { 43, 253, 86 }, { 45, 251, 87 },
+ { 45, 255, 88 }, { 47, 253, 89 }, { 49, 249, 90 }, { 49, 255, 91 }, { 51, 251, 92 }, { 53, 249, 93 }, { 53, 253, 94 }, { 55, 251, 95 },
+ { 55, 255, 96 }, { 57, 253, 97 }, { 59, 249, 98 }, { 59, 255, 99 }, { 61, 251, 100 }, { 63, 249, 101 }, { 63, 253, 102 }, { 65, 251, 103 },
+ { 65, 255, 104 }, { 67, 253, 105 }, { 69, 249, 106 }, { 69, 255, 107 }, { 71, 251, 108 }, { 73, 249, 109 }, { 73, 253, 110 }, { 75, 251, 111 },
+ { 75, 255, 112 }, { 77, 253, 113 }, { 79, 249, 114 }, { 79, 255, 115 }, { 81, 251, 116 }, { 83, 249, 117 }, { 83, 253, 118 }, { 85, 251, 119 },
+ { 85, 255, 120 }, { 87, 253, 121 }, { 89, 249, 122 }, { 89, 255, 123 }, { 91, 251, 124 }, { 93, 249, 125 }, { 93, 253, 126 }, { 95, 251, 127 },
+ { 95, 255, 128 }, { 97, 253, 129 }, { 99, 251, 130 }, { 99, 255, 131 }, { 101, 253, 132 }, { 103, 249, 133 }, { 103, 255, 134 }, { 105, 251, 135 },
+ { 107, 249, 136 }, { 107, 253, 137 }, { 109, 251, 138 }, { 109, 255, 139 }, { 111, 253, 140 }, { 113, 249, 141 }, { 113, 255, 142 }, { 115, 251, 143 },
+ { 117, 249, 144 }, { 117, 253, 145 }, { 119, 251, 146 }, { 119, 255, 147 }, { 121, 253, 148 }, { 123, 249, 149 }, { 123, 255, 150 }, { 125, 251, 151 },
+ { 127, 249, 152 }, { 127, 253, 153 }, { 129, 251, 154 }, { 129, 255, 155 }, { 131, 253, 156 }, { 133, 249, 157 }, { 133, 255, 158 }, { 135, 251, 159 },
+ { 137, 249, 160 }, { 137, 253, 161 }, { 139, 251, 162 }, { 139, 255, 163 }, { 141, 253, 164 }, { 143, 249, 165 }, { 143, 255, 166 }, { 145, 251, 167 },
+ { 147, 249, 168 }, { 147, 253, 169 }, { 149, 251, 170 }, { 149, 255, 171 }, { 151, 253, 172 }, { 153, 249, 173 }, { 153, 255, 174 }, { 155, 251, 175 },
+ { 157, 249, 176 }, { 157, 253, 177 }, { 159, 251, 178 }, { 159, 255, 179 }, { 161, 253, 180 }, { 163, 251, 181 }, { 163, 255, 182 }, { 165, 253, 183 },
+ { 167, 249, 184 }, { 167, 255, 185 }, { 169, 251, 186 }, { 171, 249, 187 }, { 171, 253, 188 }, { 173, 251, 189 }, { 173, 255, 190 }, { 175, 253, 191 },
+ { 177, 249, 192 }, { 177, 255, 193 }, { 179, 251, 194 }, { 181, 249, 195 }, { 181, 253, 196 }, { 183, 251, 197 }, { 183, 255, 198 }, { 185, 253, 199 },
+ { 187, 249, 200 }, { 187, 255, 201 }, { 189, 251, 202 }, { 191, 249, 203 }, { 191, 253, 204 }, { 193, 251, 205 }, { 193, 255, 206 }, { 195, 253, 207 },
+ { 197, 249, 208 }, { 197, 255, 209 }, { 199, 251, 210 }, { 201, 249, 211 }, { 201, 253, 212 }, { 203, 251, 213 }, { 203, 255, 214 }, { 205, 253, 215 },
+ { 207, 249, 216 }, { 207, 255, 217 }, { 209, 251, 218 }, { 211, 249, 219 }, { 211, 253, 220 }, { 213, 251, 221 }, { 213, 255, 222 }, { 215, 253, 223 },
+ { 217, 249, 224 }, { 217, 255, 225 }, { 219, 251, 226 }, { 221, 249, 227 }, { 221, 253, 228 }, { 223, 251, 229 }, { 223, 255, 230 }, { 225, 253, 231 },
+ { 227, 251, 232 }, { 227, 255, 233 }, { 229, 253, 234 }, { 231, 249, 235 }, { 231, 255, 236 }, { 233, 251, 237 }, { 235, 249, 238 }, { 235, 253, 239 },
+ { 237, 251, 240 }, { 237, 255, 241 }, { 239, 253, 242 }, { 241, 249, 243 }, { 241, 255, 244 }, { 243, 251, 245 }, { 245, 249, 246 }, { 245, 253, 247 },
+ { 247, 251, 248 }, { 247, 255, 249 }, { 249, 253, 250 }, { 251, 249, 251 }, { 251, 255, 252 }, { 253, 251, 253 }, { 255, 249, 254 }, { 255, 253, 255 },
+ }
+};
+
+Table g_mode6_p1_i4=
+{
+ 4,
+ 1,
+ {
+ { 1, 1, 1 }, { 1, 1, 1 }, { 1, 3, 2 }, { 1, 7, 3 }, { 1, 11, 4 }, { 1, 15, 5 }, { 1, 19, 6 }, { 1, 23, 7 },
+ { 1, 27, 8 }, { 1, 31, 9 }, { 1, 33, 10 }, { 1, 37, 11 }, { 1, 41, 12 }, { 1, 45, 13 }, { 1, 49, 14 }, { 1, 53, 15 },
+ { 1, 57, 16 }, { 1, 61, 17 }, { 1, 65, 18 }, { 1, 67, 19 }, { 1, 71, 20 }, { 1, 75, 21 }, { 1, 79, 22 }, { 1, 83, 23 },
+ { 1, 87, 24 }, { 1, 91, 25 }, { 1, 95, 26 }, { 1, 97, 27 }, { 1, 101, 28 }, { 1, 105, 29 }, { 1, 109, 30 }, { 1, 113, 31 },
+ { 1, 117, 32 }, { 1, 121, 33 }, { 1, 125, 34 }, { 1, 129, 35 }, { 1, 131, 36 }, { 1, 135, 37 }, { 1, 139, 38 }, { 1, 143, 39 },
+ { 1, 147, 40 }, { 1, 151, 41 }, { 1, 155, 42 }, { 1, 159, 43 }, { 1, 161, 44 }, { 1, 165, 45 }, { 1, 169, 46 }, { 1, 173, 47 },
+ { 1, 177, 48 }, { 1, 181, 49 }, { 1, 185, 50 }, { 1, 189, 51 }, { 1, 193, 52 }, { 1, 195, 53 }, { 1, 199, 54 }, { 1, 203, 55 },
+ { 1, 207, 56 }, { 1, 211, 57 }, { 1, 215, 58 }, { 1, 219, 59 }, { 1, 223, 60 }, { 1, 225, 61 }, { 1, 229, 62 }, { 1, 233, 63 },
+ { 1, 237, 64 }, { 1, 241, 65 }, { 1, 245, 66 }, { 1, 249, 67 }, { 1, 253, 68 }, { 3, 251, 69 }, { 3, 255, 70 }, { 5, 253, 71 },
+ { 7, 251, 72 }, { 7, 255, 73 }, { 9, 253, 74 }, { 11, 251, 75 }, { 11, 255, 76 }, { 13, 253, 77 }, { 15, 251, 78 }, { 15, 255, 79 },
+ { 17, 253, 80 }, { 19, 251, 81 }, { 19, 255, 82 }, { 21, 253, 83 }, { 23, 251, 84 }, { 23, 255, 85 }, { 25, 253, 86 }, { 27, 251, 87 },
+ { 27, 255, 88 }, { 29, 253, 89 }, { 31, 253, 90 }, { 31, 255, 91 }, { 33, 255, 92 }, { 35, 253, 93 }, { 37, 251, 94 }, { 37, 255, 95 },
+ { 39, 253, 96 }, { 41, 251, 97 }, { 41, 255, 98 }, { 43, 253, 99 }, { 45, 251, 100 }, { 45, 255, 101 }, { 47, 253, 102 }, { 49, 251, 103 },
+ { 49, 255, 104 }, { 51, 253, 105 }, { 53, 251, 106 }, { 53, 255, 107 }, { 55, 253, 108 }, { 57, 251, 109 }, { 57, 255, 110 }, { 59, 253, 111 },
+ { 61, 253, 112 }, { 61, 255, 113 }, { 63, 255, 114 }, { 65, 253, 115 }, { 67, 251, 116 }, { 67, 255, 117 }, { 69, 253, 118 }, { 71, 251, 119 },
+ { 71, 255, 120 }, { 73, 253, 121 }, { 75, 251, 122 }, { 75, 255, 123 }, { 77, 253, 124 }, { 79, 251, 125 }, { 79, 255, 126 }, { 81, 253, 127 },
+ { 83, 251, 128 }, { 83, 255, 129 }, { 85, 253, 130 }, { 87, 251, 131 }, { 87, 255, 132 }, { 89, 253, 133 }, { 91, 251, 134 }, { 91, 255, 135 },
+ { 93, 253, 136 }, { 95, 253, 137 }, { 95, 255, 138 }, { 97, 255, 139 }, { 99, 253, 140 }, { 101, 251, 141 }, { 101, 255, 142 }, { 103, 253, 143 },
+ { 105, 251, 144 }, { 105, 255, 145 }, { 107, 253, 146 }, { 109, 251, 147 }, { 109, 255, 148 }, { 111, 253, 149 }, { 113, 251, 150 }, { 113, 255, 151 },
+ { 115, 253, 152 }, { 117, 251, 153 }, { 117, 255, 154 }, { 119, 253, 155 }, { 121, 251, 156 }, { 121, 255, 157 }, { 123, 253, 158 }, { 125, 253, 159 },
+ { 125, 255, 160 }, { 127, 255, 161 }, { 129, 253, 162 }, { 131, 251, 163 }, { 131, 255, 164 }, { 133, 253, 165 }, { 135, 251, 166 }, { 135, 255, 167 },
+ { 137, 253, 168 }, { 139, 251, 169 }, { 139, 255, 170 }, { 141, 253, 171 }, { 143, 251, 172 }, { 143, 255, 173 }, { 145, 253, 174 }, { 147, 251, 175 },
+ { 147, 255, 176 }, { 149, 253, 177 }, { 151, 251, 178 }, { 151, 255, 179 }, { 153, 253, 180 }, { 155, 251, 181 }, { 155, 255, 182 }, { 157, 253, 183 },
+ { 159, 253, 184 }, { 159, 255, 185 }, { 161, 255, 186 }, { 163, 253, 187 }, { 165, 251, 188 }, { 165, 255, 189 }, { 167, 253, 190 }, { 169, 251, 191 },
+ { 169, 255, 192 }, { 171, 253, 193 }, { 173, 251, 194 }, { 173, 255, 195 }, { 175, 253, 196 }, { 177, 251, 197 }, { 177, 255, 198 }, { 179, 253, 199 },
+ { 181, 251, 200 }, { 181, 255, 201 }, { 183, 253, 202 }, { 185, 251, 203 }, { 185, 255, 204 }, { 187, 253, 205 }, { 189, 253, 206 }, { 189, 255, 207 },
+ { 191, 255, 208 }, { 193, 253, 209 }, { 195, 251, 210 }, { 195, 255, 211 }, { 197, 253, 212 }, { 199, 251, 213 }, { 199, 255, 214 }, { 201, 253, 215 },
+ { 203, 251, 216 }, { 203, 255, 217 }, { 205, 253, 218 }, { 207, 251, 219 }, { 207, 255, 220 }, { 209, 253, 221 }, { 211, 251, 222 }, { 211, 255, 223 },
+ { 213, 253, 224 }, { 215, 251, 225 }, { 215, 255, 226 }, { 217, 253, 227 }, { 219, 251, 228 }, { 219, 255, 229 }, { 221, 253, 230 }, { 223, 253, 231 },
+ { 223, 255, 232 }, { 225, 255, 233 }, { 227, 253, 234 }, { 229, 251, 235 }, { 229, 255, 236 }, { 231, 253, 237 }, { 233, 251, 238 }, { 233, 255, 239 },
+ { 235, 253, 240 }, { 237, 251, 241 }, { 237, 255, 242 }, { 239, 253, 243 }, { 241, 251, 244 }, { 241, 255, 245 }, { 243, 253, 246 }, { 245, 251, 247 },
+ { 245, 255, 248 }, { 247, 253, 249 }, { 249, 251, 250 }, { 249, 255, 251 }, { 251, 253, 252 }, { 253, 253, 253 }, { 253, 255, 254 }, { 255, 255, 255 },
+ }
+};
+
+Table g_mode6_p1_i5=
+{
+ 5,
+ 1,
+ {
+ { 1, 1, 1 }, { 1, 1, 1 }, { 1, 3, 2 }, { 1, 7, 3 }, { 1, 9, 4 }, { 1, 13, 5 }, { 1, 15, 6 }, { 1, 19, 7 },
+ { 1, 21, 8 }, { 1, 25, 9 }, { 1, 27, 10 }, { 1, 31, 11 }, { 1, 33, 12 }, { 1, 37, 13 }, { 1, 41, 14 }, { 1, 43, 15 },
+ { 1, 47, 16 }, { 1, 49, 17 }, { 1, 53, 18 }, { 1, 55, 19 }, { 1, 59, 20 }, { 1, 61, 21 }, { 1, 65, 22 }, { 1, 67, 23 },
+ { 1, 71, 24 }, { 1, 73, 25 }, { 1, 77, 26 }, { 1, 79, 27 }, { 1, 83, 28 }, { 1, 85, 29 }, { 1, 89, 30 }, { 1, 91, 31 },
+ { 1, 95, 32 }, { 1, 97, 33 }, { 1, 101, 34 }, { 1, 105, 35 }, { 1, 107, 36 }, { 1, 111, 37 }, { 1, 113, 38 }, { 1, 117, 39 },
+ { 1, 119, 40 }, { 1, 123, 41 }, { 1, 125, 42 }, { 1, 129, 43 }, { 1, 131, 44 }, { 1, 135, 45 }, { 1, 137, 46 }, { 1, 141, 47 },
+ { 1, 143, 48 }, { 1, 147, 49 }, { 1, 149, 50 }, { 1, 153, 51 }, { 1, 155, 52 }, { 1, 159, 53 }, { 1, 161, 54 }, { 1, 165, 55 },
+ { 1, 169, 56 }, { 1, 171, 57 }, { 1, 175, 58 }, { 1, 177, 59 }, { 1, 181, 60 }, { 1, 183, 61 }, { 1, 187, 62 }, { 1, 189, 63 },
+ { 1, 193, 64 }, { 1, 195, 65 }, { 1, 199, 66 }, { 1, 201, 67 }, { 1, 205, 68 }, { 1, 207, 69 }, { 1, 211, 70 }, { 1, 213, 71 },
+ { 1, 217, 72 }, { 1, 219, 73 }, { 1, 223, 74 }, { 1, 225, 75 }, { 1, 229, 76 }, { 1, 233, 77 }, { 1, 235, 78 }, { 1, 239, 79 },
+ { 1, 241, 80 }, { 1, 245, 81 }, { 1, 247, 82 }, { 1, 251, 83 }, { 1, 253, 84 }, { 3, 253, 85 }, { 3, 255, 86 }, { 5, 255, 87 },
+ { 7, 253, 88 }, { 9, 253, 89 }, { 9, 255, 90 }, { 11, 255, 91 }, { 13, 253, 92 }, { 15, 253, 93 }, { 15, 255, 94 }, { 17, 255, 95 },
+ { 19, 253, 96 }, { 21, 253, 97 }, { 21, 255, 98 }, { 23, 255, 99 }, { 25, 253, 100 }, { 27, 251, 101 }, { 27, 255, 102 }, { 29, 253, 103 },
+ { 31, 253, 104 }, { 31, 255, 105 }, { 33, 255, 106 }, { 35, 253, 107 }, { 37, 253, 108 }, { 37, 255, 109 }, { 39, 255, 110 }, { 41, 253, 111 },
+ { 43, 253, 112 }, { 43, 255, 113 }, { 45, 255, 114 }, { 47, 253, 115 }, { 49, 253, 116 }, { 49, 255, 117 }, { 51, 255, 118 }, { 53, 253, 119 },
+ { 55, 253, 120 }, { 55, 255, 121 }, { 57, 255, 122 }, { 59, 253, 123 }, { 61, 253, 124 }, { 61, 255, 125 }, { 63, 255, 126 }, { 65, 253, 127 },
+ { 67, 253, 128 }, { 67, 255, 129 }, { 69, 255, 130 }, { 71, 253, 131 }, { 73, 253, 132 }, { 73, 255, 133 }, { 75, 255, 134 }, { 77, 253, 135 },
+ { 79, 253, 136 }, { 79, 255, 137 }, { 81, 255, 138 }, { 83, 253, 139 }, { 85, 253, 140 }, { 85, 255, 141 }, { 87, 255, 142 }, { 89, 253, 143 },
+ { 91, 251, 144 }, { 91, 255, 145 }, { 93, 253, 146 }, { 95, 253, 147 }, { 95, 255, 148 }, { 97, 255, 149 }, { 99, 253, 150 }, { 101, 253, 151 },
+ { 101, 255, 152 }, { 103, 255, 153 }, { 105, 253, 154 }, { 107, 253, 155 }, { 107, 255, 156 }, { 109, 255, 157 }, { 111, 253, 158 }, { 113, 253, 159 },
+ { 113, 255, 160 }, { 115, 255, 161 }, { 117, 253, 162 }, { 119, 253, 163 }, { 119, 255, 164 }, { 121, 255, 165 }, { 123, 253, 166 }, { 125, 253, 167 },
+ { 125, 255, 168 }, { 127, 255, 169 }, { 129, 253, 170 }, { 131, 253, 171 }, { 131, 255, 172 }, { 133, 255, 173 }, { 135, 253, 174 }, { 137, 253, 175 },
+ { 137, 255, 176 }, { 139, 255, 177 }, { 141, 253, 178 }, { 143, 253, 179 }, { 143, 255, 180 }, { 145, 255, 181 }, { 147, 253, 182 }, { 149, 253, 183 },
+ { 149, 255, 184 }, { 151, 255, 185 }, { 153, 253, 186 }, { 155, 251, 187 }, { 155, 255, 188 }, { 157, 253, 189 }, { 159, 253, 190 }, { 159, 255, 191 },
+ { 161, 255, 192 }, { 163, 253, 193 }, { 165, 253, 194 }, { 165, 255, 195 }, { 167, 255, 196 }, { 169, 253, 197 }, { 171, 253, 198 }, { 171, 255, 199 },
+ { 173, 255, 200 }, { 175, 253, 201 }, { 177, 253, 202 }, { 177, 255, 203 }, { 179, 255, 204 }, { 181, 253, 205 }, { 183, 253, 206 }, { 183, 255, 207 },
+ { 185, 255, 208 }, { 187, 253, 209 }, { 189, 253, 210 }, { 189, 255, 211 }, { 191, 255, 212 }, { 193, 253, 213 }, { 195, 253, 214 }, { 195, 255, 215 },
+ { 197, 255, 216 }, { 199, 253, 217 }, { 201, 253, 218 }, { 201, 255, 219 }, { 203, 255, 220 }, { 205, 253, 221 }, { 207, 253, 222 }, { 207, 255, 223 },
+ { 209, 255, 224 }, { 211, 253, 225 }, { 213, 253, 226 }, { 213, 255, 227 }, { 215, 255, 228 }, { 217, 253, 229 }, { 219, 251, 230 }, { 219, 255, 231 },
+ { 221, 253, 232 }, { 223, 253, 233 }, { 223, 255, 234 }, { 225, 255, 235 }, { 227, 253, 236 }, { 229, 253, 237 }, { 229, 255, 238 }, { 231, 255, 239 },
+ { 233, 253, 240 }, { 235, 253, 241 }, { 235, 255, 242 }, { 237, 255, 243 }, { 239, 253, 244 }, { 241, 253, 245 }, { 241, 255, 246 }, { 243, 255, 247 },
+ { 245, 253, 248 }, { 247, 253, 249 }, { 247, 255, 250 }, { 249, 255, 251 }, { 251, 253, 252 }, { 253, 253, 253 }, { 253, 255, 254 }, { 255, 255, 255 },
+ }
+};
+
+Table g_mode6_p1_i6=
+{
+ 6,
+ 1,
+ {
+ { 1, 1, 1 }, { 1, 1, 1 }, { 1, 3, 2 }, { 1, 5, 3 }, { 1, 9, 4 }, { 1, 11, 5 }, { 1, 13, 6 }, { 1, 15, 7 },
+ { 1, 17, 8 }, { 1, 21, 9 }, { 1, 23, 10 }, { 1, 25, 11 }, { 1, 27, 12 }, { 1, 31, 13 }, { 1, 33, 14 }, { 1, 35, 15 },
+ { 1, 37, 16 }, { 1, 41, 17 }, { 1, 43, 18 }, { 1, 45, 19 }, { 1, 47, 20 }, { 1, 49, 21 }, { 1, 53, 22 }, { 1, 55, 23 },
+ { 1, 57, 24 }, { 1, 59, 25 }, { 1, 63, 26 }, { 1, 65, 27 }, { 1, 67, 28 }, { 1, 69, 29 }, { 1, 73, 30 }, { 1, 75, 31 },
+ { 1, 77, 32 }, { 1, 79, 33 }, { 1, 81, 34 }, { 1, 85, 35 }, { 1, 87, 36 }, { 1, 89, 37 }, { 1, 91, 38 }, { 1, 95, 39 },
+ { 1, 97, 40 }, { 1, 99, 41 }, { 1, 101, 42 }, { 1, 105, 43 }, { 1, 107, 44 }, { 1, 109, 45 }, { 1, 111, 46 }, { 1, 113, 47 },
+ { 1, 117, 48 }, { 1, 119, 49 }, { 1, 121, 50 }, { 1, 123, 51 }, { 1, 127, 52 }, { 1, 129, 53 }, { 1, 131, 54 }, { 1, 133, 55 },
+ { 1, 137, 56 }, { 1, 139, 57 }, { 1, 141, 58 }, { 1, 143, 59 }, { 1, 145, 60 }, { 1, 149, 61 }, { 1, 151, 62 }, { 1, 153, 63 },
+ { 1, 155, 64 }, { 1, 159, 65 }, { 1, 161, 66 }, { 1, 163, 67 }, { 1, 165, 68 }, { 1, 169, 69 }, { 1, 171, 70 }, { 1, 173, 71 },
+ { 1, 175, 72 }, { 1, 177, 73 }, { 1, 181, 74 }, { 1, 183, 75 }, { 1, 185, 76 }, { 1, 187, 77 }, { 1, 191, 78 }, { 1, 193, 79 },
+ { 1, 195, 80 }, { 1, 197, 81 }, { 1, 201, 82 }, { 1, 203, 83 }, { 1, 205, 84 }, { 1, 207, 85 }, { 1, 209, 86 }, { 1, 213, 87 },
+ { 1, 215, 88 }, { 1, 217, 89 }, { 1, 219, 90 }, { 1, 223, 91 }, { 1, 225, 92 }, { 1, 227, 93 }, { 1, 229, 94 }, { 1, 233, 95 },
+ { 1, 235, 96 }, { 1, 237, 97 }, { 1, 239, 98 }, { 1, 241, 99 }, { 1, 245, 100 }, { 1, 247, 101 }, { 1, 249, 102 }, { 1, 251, 103 },
+ { 1, 255, 104 }, { 3, 253, 105 }, { 5, 253, 106 }, { 5, 255, 107 }, { 7, 255, 108 }, { 9, 255, 109 }, { 11, 255, 110 }, { 13, 253, 111 },
+ { 15, 253, 112 }, { 15, 255, 113 }, { 17, 255, 114 }, { 19, 255, 115 }, { 21, 255, 116 }, { 23, 255, 117 }, { 25, 253, 118 }, { 27, 253, 119 },
+ { 27, 255, 120 }, { 29, 255, 121 }, { 31, 255, 122 }, { 33, 255, 123 }, { 35, 253, 124 }, { 37, 253, 125 }, { 37, 255, 126 }, { 39, 255, 127 },
+ { 41, 255, 128 }, { 43, 255, 129 }, { 45, 253, 130 }, { 47, 253, 131 }, { 47, 255, 132 }, { 49, 255, 133 }, { 51, 255, 134 }, { 53, 255, 135 },
+ { 55, 255, 136 }, { 57, 253, 137 }, { 59, 253, 138 }, { 59, 255, 139 }, { 61, 255, 140 }, { 63, 255, 141 }, { 65, 255, 142 }, { 67, 253, 143 },
+ { 69, 253, 144 }, { 69, 255, 145 }, { 71, 255, 146 }, { 73, 255, 147 }, { 75, 255, 148 }, { 77, 253, 149 }, { 79, 253, 150 }, { 79, 255, 151 },
+ { 81, 255, 152 }, { 83, 255, 153 }, { 85, 255, 154 }, { 87, 255, 155 }, { 89, 253, 156 }, { 91, 253, 157 }, { 91, 255, 158 }, { 93, 255, 159 },
+ { 95, 255, 160 }, { 97, 255, 161 }, { 99, 253, 162 }, { 101, 253, 163 }, { 101, 255, 164 }, { 103, 255, 165 }, { 105, 255, 166 }, { 107, 255, 167 },
+ { 109, 253, 168 }, { 111, 253, 169 }, { 111, 255, 170 }, { 113, 255, 171 }, { 115, 255, 172 }, { 117, 255, 173 }, { 119, 255, 174 }, { 121, 253, 175 },
+ { 123, 253, 176 }, { 123, 255, 177 }, { 125, 255, 178 }, { 127, 255, 179 }, { 129, 255, 180 }, { 131, 253, 181 }, { 133, 253, 182 }, { 133, 255, 183 },
+ { 135, 255, 184 }, { 137, 255, 185 }, { 139, 255, 186 }, { 141, 253, 187 }, { 143, 253, 188 }, { 143, 255, 189 }, { 145, 255, 190 }, { 147, 255, 191 },
+ { 149, 255, 192 }, { 151, 255, 193 }, { 153, 253, 194 }, { 155, 253, 195 }, { 155, 255, 196 }, { 157, 255, 197 }, { 159, 255, 198 }, { 161, 255, 199 },
+ { 163, 253, 200 }, { 165, 253, 201 }, { 165, 255, 202 }, { 167, 255, 203 }, { 169, 255, 204 }, { 171, 255, 205 }, { 173, 253, 206 }, { 175, 253, 207 },
+ { 175, 255, 208 }, { 177, 255, 209 }, { 179, 255, 210 }, { 181, 255, 211 }, { 183, 255, 212 }, { 185, 253, 213 }, { 187, 253, 214 }, { 187, 255, 215 },
+ { 189, 255, 216 }, { 191, 255, 217 }, { 193, 255, 218 }, { 195, 253, 219 }, { 197, 253, 220 }, { 197, 255, 221 }, { 199, 255, 222 }, { 201, 255, 223 },
+ { 203, 255, 224 }, { 205, 253, 225 }, { 207, 253, 226 }, { 207, 255, 227 }, { 209, 255, 228 }, { 211, 255, 229 }, { 213, 255, 230 }, { 215, 255, 231 },
+ { 217, 253, 232 }, { 219, 253, 233 }, { 219, 255, 234 }, { 221, 255, 235 }, { 223, 255, 236 }, { 225, 255, 237 }, { 227, 253, 238 }, { 229, 253, 239 },
+ { 229, 255, 240 }, { 231, 255, 241 }, { 233, 255, 242 }, { 235, 255, 243 }, { 237, 253, 244 }, { 239, 253, 245 }, { 239, 255, 246 }, { 241, 255, 247 },
+ { 243, 255, 248 }, { 245, 255, 249 }, { 247, 255, 250 }, { 249, 253, 251 }, { 251, 253, 252 }, { 251, 255, 253 }, { 253, 255, 254 }, { 255, 255, 255 },
+ }
+};
+
+Table g_mode6_p1_i7=
+{
+ 7,
+ 1,
+ {
+ { 1, 1, 1 }, { 1, 1, 1 }, { 1, 3, 2 }, { 1, 5, 3 }, { 1, 7, 4 }, { 1, 9, 5 }, { 1, 11, 6 }, { 1, 13, 7 },
+ { 1, 15, 8 }, { 1, 17, 9 }, { 1, 21, 10 }, { 1, 23, 11 }, { 1, 25, 12 }, { 1, 27, 13 }, { 1, 29, 14 }, { 1, 31, 15 },
+ { 1, 33, 16 }, { 1, 35, 17 }, { 1, 37, 18 }, { 1, 39, 19 }, { 1, 41, 20 }, { 1, 43, 21 }, { 1, 45, 22 }, { 1, 47, 23 },
+ { 1, 49, 24 }, { 1, 53, 25 }, { 1, 55, 26 }, { 1, 57, 27 }, { 1, 59, 28 }, { 1, 61, 29 }, { 1, 63, 30 }, { 1, 65, 31 },
+ { 1, 67, 32 }, { 1, 69, 33 }, { 1, 71, 34 }, { 1, 73, 35 }, { 1, 75, 36 }, { 1, 77, 37 }, { 1, 79, 38 }, { 1, 81, 39 },
+ { 1, 85, 40 }, { 1, 87, 41 }, { 1, 89, 42 }, { 1, 91, 43 }, { 1, 93, 44 }, { 1, 95, 45 }, { 1, 97, 46 }, { 1, 99, 47 },
+ { 1, 101, 48 }, { 1, 103, 49 }, { 1, 105, 50 }, { 1, 107, 51 }, { 1, 109, 52 }, { 1, 111, 53 }, { 1, 113, 54 }, { 1, 117, 55 },
+ { 1, 119, 56 }, { 1, 121, 57 }, { 1, 123, 58 }, { 1, 125, 59 }, { 1, 127, 60 }, { 1, 129, 61 }, { 1, 131, 62 }, { 1, 133, 63 },
+ { 1, 135, 64 }, { 1, 137, 65 }, { 1, 139, 66 }, { 1, 141, 67 }, { 1, 143, 68 }, { 1, 145, 69 }, { 1, 149, 70 }, { 1, 151, 71 },
+ { 1, 153, 72 }, { 1, 155, 73 }, { 1, 157, 74 }, { 1, 159, 75 }, { 1, 161, 76 }, { 1, 163, 77 }, { 1, 165, 78 }, { 1, 167, 79 },
+ { 1, 169, 80 }, { 1, 171, 81 }, { 1, 173, 82 }, { 1, 175, 83 }, { 1, 177, 84 }, { 1, 181, 85 }, { 1, 183, 86 }, { 1, 185, 87 },
+ { 1, 187, 88 }, { 1, 189, 89 }, { 1, 191, 90 }, { 1, 193, 91 }, { 1, 195, 92 }, { 1, 197, 93 }, { 1, 199, 94 }, { 1, 201, 95 },
+ { 1, 203, 96 }, { 1, 205, 97 }, { 1, 207, 98 }, { 1, 209, 99 }, { 1, 213, 100 }, { 1, 215, 101 }, { 1, 217, 102 }, { 1, 219, 103 },
+ { 1, 221, 104 }, { 1, 223, 105 }, { 1, 225, 106 }, { 1, 227, 107 }, { 1, 229, 108 }, { 1, 231, 109 }, { 1, 233, 110 }, { 1, 235, 111 },
+ { 1, 237, 112 }, { 1, 239, 113 }, { 1, 241, 114 }, { 1, 245, 115 }, { 1, 247, 116 }, { 1, 249, 117 }, { 1, 251, 118 }, { 1, 253, 119 },
+ { 1, 255, 120 }, { 3, 255, 121 }, { 5, 255, 122 }, { 7, 255, 123 }, { 9, 255, 124 }, { 11, 255, 125 }, { 13, 253, 126 }, { 15, 253, 127 },
+ { 15, 255, 128 }, { 17, 255, 129 }, { 19, 255, 130 }, { 21, 255, 131 }, { 23, 255, 132 }, { 25, 255, 133 }, { 27, 255, 134 }, { 29, 255, 135 },
+ { 31, 255, 136 }, { 33, 255, 137 }, { 35, 255, 138 }, { 37, 255, 139 }, { 39, 255, 140 }, { 41, 255, 141 }, { 43, 255, 142 }, { 45, 253, 143 },
+ { 47, 253, 144 }, { 47, 255, 145 }, { 49, 255, 146 }, { 51, 255, 147 }, { 53, 255, 148 }, { 55, 255, 149 }, { 57, 255, 150 }, { 59, 255, 151 },
+ { 61, 255, 152 }, { 63, 255, 153 }, { 65, 255, 154 }, { 67, 255, 155 }, { 69, 255, 156 }, { 71, 255, 157 }, { 73, 255, 158 }, { 75, 255, 159 },
+ { 77, 253, 160 }, { 79, 253, 161 }, { 79, 255, 162 }, { 81, 255, 163 }, { 83, 255, 164 }, { 85, 255, 165 }, { 87, 255, 166 }, { 89, 255, 167 },
+ { 91, 255, 168 }, { 93, 255, 169 }, { 95, 255, 170 }, { 97, 255, 171 }, { 99, 255, 172 }, { 101, 255, 173 }, { 103, 255, 174 }, { 105, 255, 175 },
+ { 107, 255, 176 }, { 109, 253, 177 }, { 111, 253, 178 }, { 111, 255, 179 }, { 113, 255, 180 }, { 115, 255, 181 }, { 117, 255, 182 }, { 119, 255, 183 },
+ { 121, 255, 184 }, { 123, 255, 185 }, { 125, 255, 186 }, { 127, 255, 187 }, { 129, 255, 188 }, { 131, 255, 189 }, { 133, 255, 190 }, { 135, 255, 191 },
+ { 137, 255, 192 }, { 139, 255, 193 }, { 141, 253, 194 }, { 143, 253, 195 }, { 143, 255, 196 }, { 145, 255, 197 }, { 147, 255, 198 }, { 149, 255, 199 },
+ { 151, 255, 200 }, { 153, 255, 201 }, { 155, 255, 202 }, { 157, 255, 203 }, { 159, 255, 204 }, { 161, 255, 205 }, { 163, 255, 206 }, { 165, 255, 207 },
+ { 167, 255, 208 }, { 169, 255, 209 }, { 171, 255, 210 }, { 173, 253, 211 }, { 175, 253, 212 }, { 175, 255, 213 }, { 177, 255, 214 }, { 179, 255, 215 },
+ { 181, 255, 216 }, { 183, 255, 217 }, { 185, 255, 218 }, { 187, 255, 219 }, { 189, 255, 220 }, { 191, 255, 221 }, { 193, 255, 222 }, { 195, 255, 223 },
+ { 197, 255, 224 }, { 199, 255, 225 }, { 201, 255, 226 }, { 203, 255, 227 }, { 205, 253, 228 }, { 207, 253, 229 }, { 207, 255, 230 }, { 209, 255, 231 },
+ { 211, 255, 232 }, { 213, 255, 233 }, { 215, 255, 234 }, { 217, 255, 235 }, { 219, 255, 236 }, { 221, 255, 237 }, { 223, 255, 238 }, { 225, 255, 239 },
+ { 227, 255, 240 }, { 229, 255, 241 }, { 231, 255, 242 }, { 233, 255, 243 }, { 235, 255, 244 }, { 237, 253, 245 }, { 239, 253, 246 }, { 239, 255, 247 },
+ { 241, 255, 248 }, { 243, 255, 249 }, { 245, 255, 250 }, { 247, 255, 251 }, { 249, 255, 252 }, { 251, 255, 253 }, { 253, 255, 254 }, { 255, 255, 255 },
+ }
+};
+
+Table g_mode7_p00=
+{
+ 1,
+ 0,
+ {
+ { 0, 0, 0 }, { 0, 2, 1 }, { 0, 6, 2 }, { 0, 8, 3 }, { 0, 12, 4 }, { 0, 14, 5 }, { 0, 18, 6 }, { 0, 20, 7 },
+ { 0, 24, 8 }, { 0, 26, 9 }, { 0, 30, 10 }, { 0, 32, 11 }, { 0, 36, 12 }, { 0, 40, 13 }, { 0, 42, 14 }, { 0, 46, 15 },
+ { 0, 48, 16 }, { 0, 52, 17 }, { 0, 54, 18 }, { 0, 58, 19 }, { 0, 60, 20 }, { 0, 64, 21 }, { 0, 66, 22 }, { 0, 70, 23 },
+ { 0, 72, 24 }, { 0, 76, 25 }, { 0, 78, 26 }, { 0, 82, 27 }, { 0, 84, 28 }, { 0, 88, 29 }, { 0, 90, 30 }, { 0, 94, 31 },
+ { 0, 96, 32 }, { 0, 100, 33 }, { 0, 104, 34 }, { 0, 106, 35 }, { 0, 110, 36 }, { 0, 112, 37 }, { 0, 116, 38 }, { 0, 118, 39 },
+ { 0, 122, 40 }, { 0, 124, 41 }, { 0, 128, 42 }, { 0, 130, 43 }, { 0, 134, 44 }, { 0, 136, 45 }, { 0, 140, 46 }, { 0, 142, 47 },
+ { 0, 146, 48 }, { 0, 148, 49 }, { 0, 152, 50 }, { 0, 154, 51 }, { 0, 158, 52 }, { 0, 160, 53 }, { 0, 164, 54 }, { 0, 168, 55 },
+ { 0, 170, 56 }, { 0, 174, 57 }, { 0, 176, 58 }, { 0, 180, 59 }, { 0, 182, 60 }, { 0, 186, 61 }, { 0, 188, 62 }, { 0, 192, 63 },
+ { 0, 194, 64 }, { 0, 198, 65 }, { 0, 200, 66 }, { 0, 204, 67 }, { 0, 206, 68 }, { 0, 210, 69 }, { 0, 212, 70 }, { 0, 216, 71 },
+ { 0, 218, 72 }, { 0, 222, 73 }, { 0, 224, 74 }, { 0, 228, 75 }, { 0, 232, 76 }, { 0, 234, 77 }, { 0, 238, 78 }, { 0, 240, 79 },
+ { 0, 244, 80 }, { 0, 246, 81 }, { 0, 250, 82 }, { 0, 252, 83 }, { 2, 252, 84 }, { 2, 254, 85 }, { 4, 254, 86 }, { 6, 252, 87 },
+ { 8, 252, 88 }, { 8, 254, 89 }, { 10, 254, 90 }, { 12, 252, 91 }, { 14, 252, 92 }, { 14, 254, 93 }, { 16, 254, 94 }, { 18, 252, 95 },
+ { 20, 252, 96 }, { 20, 254, 97 }, { 22, 254, 98 }, { 24, 252, 99 }, { 26, 250, 100 }, { 26, 254, 101 }, { 28, 252, 102 }, { 30, 252, 103 },
+ { 30, 254, 104 }, { 32, 254, 105 }, { 34, 252, 106 }, { 36, 252, 107 }, { 36, 254, 108 }, { 38, 254, 109 }, { 40, 252, 110 }, { 42, 252, 111 },
+ { 42, 254, 112 }, { 44, 254, 113 }, { 46, 252, 114 }, { 48, 252, 115 }, { 48, 254, 116 }, { 50, 254, 117 }, { 52, 252, 118 }, { 54, 252, 119 },
+ { 54, 254, 120 }, { 56, 254, 121 }, { 58, 252, 122 }, { 60, 252, 123 }, { 60, 254, 124 }, { 62, 254, 125 }, { 64, 252, 126 }, { 66, 252, 127 },
+ { 66, 254, 128 }, { 68, 254, 129 }, { 70, 252, 130 }, { 72, 252, 131 }, { 72, 254, 132 }, { 74, 254, 133 }, { 76, 252, 134 }, { 78, 252, 135 },
+ { 78, 254, 136 }, { 80, 254, 137 }, { 82, 252, 138 }, { 84, 252, 139 }, { 84, 254, 140 }, { 86, 254, 141 }, { 88, 252, 142 }, { 90, 250, 143 },
+ { 90, 254, 144 }, { 92, 252, 145 }, { 94, 252, 146 }, { 94, 254, 147 }, { 96, 254, 148 }, { 98, 252, 149 }, { 100, 252, 150 }, { 100, 254, 151 },
+ { 102, 254, 152 }, { 104, 252, 153 }, { 106, 252, 154 }, { 106, 254, 155 }, { 108, 254, 156 }, { 110, 252, 157 }, { 112, 252, 158 }, { 112, 254, 159 },
+ { 114, 254, 160 }, { 116, 252, 161 }, { 118, 252, 162 }, { 118, 254, 163 }, { 120, 254, 164 }, { 122, 252, 165 }, { 124, 252, 166 }, { 124, 254, 167 },
+ { 126, 254, 168 }, { 128, 252, 169 }, { 130, 252, 170 }, { 130, 254, 171 }, { 132, 254, 172 }, { 134, 252, 173 }, { 136, 252, 174 }, { 136, 254, 175 },
+ { 138, 254, 176 }, { 140, 252, 177 }, { 142, 252, 178 }, { 142, 254, 179 }, { 144, 254, 180 }, { 146, 252, 181 }, { 148, 252, 182 }, { 148, 254, 183 },
+ { 150, 254, 184 }, { 152, 252, 185 }, { 154, 250, 186 }, { 154, 254, 187 }, { 156, 252, 188 }, { 158, 252, 189 }, { 158, 254, 190 }, { 160, 254, 191 },
+ { 162, 252, 192 }, { 164, 252, 193 }, { 164, 254, 194 }, { 166, 254, 195 }, { 168, 252, 196 }, { 170, 252, 197 }, { 170, 254, 198 }, { 172, 254, 199 },
+ { 174, 252, 200 }, { 176, 252, 201 }, { 176, 254, 202 }, { 178, 254, 203 }, { 180, 252, 204 }, { 182, 252, 205 }, { 182, 254, 206 }, { 184, 254, 207 },
+ { 186, 252, 208 }, { 188, 252, 209 }, { 188, 254, 210 }, { 190, 254, 211 }, { 192, 252, 212 }, { 194, 252, 213 }, { 194, 254, 214 }, { 196, 254, 215 },
+ { 198, 252, 216 }, { 200, 252, 217 }, { 200, 254, 218 }, { 202, 254, 219 }, { 204, 252, 220 }, { 206, 252, 221 }, { 206, 254, 222 }, { 208, 254, 223 },
+ { 210, 252, 224 }, { 212, 252, 225 }, { 212, 254, 226 }, { 214, 254, 227 }, { 216, 252, 228 }, { 218, 250, 229 }, { 218, 254, 230 }, { 220, 252, 231 },
+ { 222, 252, 232 }, { 222, 254, 233 }, { 224, 254, 234 }, { 226, 252, 235 }, { 228, 252, 236 }, { 228, 254, 237 }, { 230, 254, 238 }, { 232, 252, 239 },
+ { 234, 252, 240 }, { 234, 254, 241 }, { 236, 254, 242 }, { 238, 252, 243 }, { 240, 252, 244 }, { 240, 254, 245 }, { 242, 254, 246 }, { 244, 252, 247 },
+ { 246, 252, 248 }, { 246, 254, 249 }, { 248, 254, 250 }, { 250, 252, 251 }, { 252, 252, 252 }, { 252, 254, 253 }, { 254, 254, 254 }, { 254, 254, 254 },
+ }
+};
+
+Table g_mode7_p01=
+{
+ 1,
+ 2,
+ {
+ { 0, 1, 0 }, { 0, 3, 1 }, { 0, 5, 2 }, { 0, 9, 3 }, { 0, 11, 4 }, { 0, 15, 5 }, { 0, 17, 6 }, { 0, 21, 7 },
+ { 0, 23, 8 }, { 0, 27, 9 }, { 0, 29, 10 }, { 0, 33, 11 }, { 0, 37, 12 }, { 0, 39, 13 }, { 0, 43, 14 }, { 0, 45, 15 },
+ { 0, 49, 16 }, { 0, 51, 17 }, { 0, 55, 18 }, { 0, 57, 19 }, { 0, 61, 20 }, { 0, 63, 21 }, { 0, 67, 22 }, { 0, 69, 23 },
+ { 0, 73, 24 }, { 0, 75, 25 }, { 0, 79, 26 }, { 0, 81, 27 }, { 0, 85, 28 }, { 0, 87, 29 }, { 0, 91, 30 }, { 0, 93, 31 },
+ { 0, 97, 32 }, { 0, 101, 33 }, { 0, 103, 34 }, { 0, 107, 35 }, { 0, 109, 36 }, { 0, 113, 37 }, { 0, 115, 38 }, { 0, 119, 39 },
+ { 0, 121, 40 }, { 0, 125, 41 }, { 0, 127, 42 }, { 0, 131, 43 }, { 0, 133, 44 }, { 0, 137, 45 }, { 0, 139, 46 }, { 0, 143, 47 },
+ { 0, 145, 48 }, { 0, 149, 49 }, { 0, 151, 50 }, { 0, 155, 51 }, { 0, 157, 52 }, { 0, 161, 53 }, { 0, 165, 54 }, { 0, 167, 55 },
+ { 0, 171, 56 }, { 0, 173, 57 }, { 0, 177, 58 }, { 0, 179, 59 }, { 0, 183, 60 }, { 0, 185, 61 }, { 0, 189, 62 }, { 0, 191, 63 },
+ { 0, 195, 64 }, { 0, 197, 65 }, { 0, 201, 66 }, { 0, 203, 67 }, { 0, 207, 68 }, { 0, 209, 69 }, { 0, 213, 70 }, { 0, 215, 71 },
+ { 0, 219, 72 }, { 0, 221, 73 }, { 0, 225, 74 }, { 0, 229, 75 }, { 0, 231, 76 }, { 0, 235, 77 }, { 0, 237, 78 }, { 0, 241, 79 },
+ { 0, 243, 80 }, { 0, 247, 81 }, { 0, 249, 82 }, { 0, 253, 83 }, { 0, 255, 84 }, { 2, 255, 85 }, { 4, 253, 86 }, { 6, 253, 87 },
+ { 6, 255, 88 }, { 8, 255, 89 }, { 10, 253, 90 }, { 12, 253, 91 }, { 12, 255, 92 }, { 14, 255, 93 }, { 16, 253, 94 }, { 18, 253, 95 },
+ { 18, 255, 96 }, { 20, 255, 97 }, { 22, 253, 98 }, { 24, 253, 99 }, { 24, 255, 100 }, { 26, 255, 101 }, { 28, 253, 102 }, { 30, 251, 103 },
+ { 30, 255, 104 }, { 32, 253, 105 }, { 34, 253, 106 }, { 34, 255, 107 }, { 36, 255, 108 }, { 38, 253, 109 }, { 40, 253, 110 }, { 40, 255, 111 },
+ { 42, 255, 112 }, { 44, 253, 113 }, { 46, 253, 114 }, { 46, 255, 115 }, { 48, 255, 116 }, { 50, 253, 117 }, { 52, 253, 118 }, { 52, 255, 119 },
+ { 54, 255, 120 }, { 56, 253, 121 }, { 58, 253, 122 }, { 58, 255, 123 }, { 60, 255, 124 }, { 62, 253, 125 }, { 64, 253, 126 }, { 64, 255, 127 },
+ { 66, 255, 128 }, { 68, 253, 129 }, { 70, 253, 130 }, { 70, 255, 131 }, { 72, 255, 132 }, { 74, 253, 133 }, { 76, 253, 134 }, { 76, 255, 135 },
+ { 78, 255, 136 }, { 80, 253, 137 }, { 82, 253, 138 }, { 82, 255, 139 }, { 84, 255, 140 }, { 86, 253, 141 }, { 88, 253, 142 }, { 88, 255, 143 },
+ { 90, 255, 144 }, { 92, 253, 145 }, { 94, 251, 146 }, { 94, 255, 147 }, { 96, 253, 148 }, { 98, 253, 149 }, { 98, 255, 150 }, { 100, 255, 151 },
+ { 102, 253, 152 }, { 104, 253, 153 }, { 104, 255, 154 }, { 106, 255, 155 }, { 108, 253, 156 }, { 110, 253, 157 }, { 110, 255, 158 }, { 112, 255, 159 },
+ { 114, 253, 160 }, { 116, 253, 161 }, { 116, 255, 162 }, { 118, 255, 163 }, { 120, 253, 164 }, { 122, 253, 165 }, { 122, 255, 166 }, { 124, 255, 167 },
+ { 126, 253, 168 }, { 128, 253, 169 }, { 128, 255, 170 }, { 130, 255, 171 }, { 132, 253, 172 }, { 134, 253, 173 }, { 134, 255, 174 }, { 136, 255, 175 },
+ { 138, 253, 176 }, { 140, 253, 177 }, { 140, 255, 178 }, { 142, 255, 179 }, { 144, 253, 180 }, { 146, 253, 181 }, { 146, 255, 182 }, { 148, 255, 183 },
+ { 150, 253, 184 }, { 152, 253, 185 }, { 152, 255, 186 }, { 154, 255, 187 }, { 156, 253, 188 }, { 158, 251, 189 }, { 158, 255, 190 }, { 160, 253, 191 },
+ { 162, 253, 192 }, { 162, 255, 193 }, { 164, 255, 194 }, { 166, 253, 195 }, { 168, 253, 196 }, { 168, 255, 197 }, { 170, 255, 198 }, { 172, 253, 199 },
+ { 174, 253, 200 }, { 174, 255, 201 }, { 176, 255, 202 }, { 178, 253, 203 }, { 180, 253, 204 }, { 180, 255, 205 }, { 182, 255, 206 }, { 184, 253, 207 },
+ { 186, 253, 208 }, { 186, 255, 209 }, { 188, 255, 210 }, { 190, 253, 211 }, { 192, 253, 212 }, { 192, 255, 213 }, { 194, 255, 214 }, { 196, 253, 215 },
+ { 198, 253, 216 }, { 198, 255, 217 }, { 200, 255, 218 }, { 202, 253, 219 }, { 204, 253, 220 }, { 204, 255, 221 }, { 206, 255, 222 }, { 208, 253, 223 },
+ { 210, 253, 224 }, { 210, 255, 225 }, { 212, 255, 226 }, { 214, 253, 227 }, { 216, 253, 228 }, { 216, 255, 229 }, { 218, 255, 230 }, { 220, 253, 231 },
+ { 222, 251, 232 }, { 222, 255, 233 }, { 224, 253, 234 }, { 226, 253, 235 }, { 226, 255, 236 }, { 228, 255, 237 }, { 230, 253, 238 }, { 232, 253, 239 },
+ { 232, 255, 240 }, { 234, 255, 241 }, { 236, 253, 242 }, { 238, 253, 243 }, { 238, 255, 244 }, { 240, 255, 245 }, { 242, 253, 246 }, { 244, 253, 247 },
+ { 244, 255, 248 }, { 246, 255, 249 }, { 248, 253, 250 }, { 250, 253, 251 }, { 250, 255, 252 }, { 252, 255, 253 }, { 254, 253, 254 }, { 254, 253, 254 },
+ }
+};
+
+Table g_mode7_p10=
+{
+ 1,
+ 1,
+ {
+ { 1, 0, 1 }, { 1, 0, 1 }, { 1, 4, 2 }, { 1, 6, 3 }, { 1, 10, 4 }, { 1, 12, 5 }, { 1, 16, 6 }, { 1, 18, 7 },
+ { 1, 22, 8 }, { 1, 24, 9 }, { 1, 28, 10 }, { 1, 30, 11 }, { 1, 34, 12 }, { 1, 38, 13 }, { 1, 40, 14 }, { 1, 44, 15 },
+ { 1, 46, 16 }, { 1, 50, 17 }, { 1, 52, 18 }, { 1, 56, 19 }, { 1, 58, 20 }, { 1, 62, 21 }, { 1, 64, 22 }, { 1, 68, 23 },
+ { 1, 70, 24 }, { 1, 74, 25 }, { 1, 76, 26 }, { 1, 80, 27 }, { 1, 82, 28 }, { 1, 86, 29 }, { 1, 88, 30 }, { 1, 92, 31 },
+ { 1, 94, 32 }, { 1, 98, 33 }, { 1, 102, 34 }, { 1, 104, 35 }, { 1, 108, 36 }, { 1, 110, 37 }, { 1, 114, 38 }, { 1, 116, 39 },
+ { 1, 120, 40 }, { 1, 122, 41 }, { 1, 126, 42 }, { 1, 128, 43 }, { 1, 132, 44 }, { 1, 134, 45 }, { 1, 138, 46 }, { 1, 140, 47 },
+ { 1, 144, 48 }, { 1, 146, 49 }, { 1, 150, 50 }, { 1, 152, 51 }, { 1, 156, 52 }, { 1, 158, 53 }, { 1, 162, 54 }, { 1, 166, 55 },
+ { 1, 168, 56 }, { 1, 172, 57 }, { 1, 174, 58 }, { 1, 178, 59 }, { 1, 180, 60 }, { 1, 184, 61 }, { 1, 186, 62 }, { 1, 190, 63 },
+ { 1, 192, 64 }, { 1, 196, 65 }, { 1, 198, 66 }, { 1, 202, 67 }, { 1, 204, 68 }, { 1, 208, 69 }, { 1, 210, 70 }, { 1, 214, 71 },
+ { 1, 216, 72 }, { 1, 220, 73 }, { 1, 222, 74 }, { 1, 226, 75 }, { 1, 230, 76 }, { 1, 232, 77 }, { 1, 236, 78 }, { 1, 238, 79 },
+ { 1, 242, 80 }, { 1, 244, 81 }, { 1, 248, 82 }, { 1, 250, 83 }, { 1, 254, 84 }, { 3, 252, 85 }, { 5, 252, 86 }, { 5, 254, 87 },
+ { 7, 254, 88 }, { 9, 252, 89 }, { 11, 252, 90 }, { 11, 254, 91 }, { 13, 254, 92 }, { 15, 252, 93 }, { 17, 252, 94 }, { 17, 254, 95 },
+ { 19, 254, 96 }, { 21, 252, 97 }, { 23, 252, 98 }, { 23, 254, 99 }, { 25, 254, 100 }, { 27, 252, 101 }, { 29, 250, 102 }, { 29, 254, 103 },
+ { 31, 252, 104 }, { 33, 252, 105 }, { 33, 254, 106 }, { 35, 254, 107 }, { 37, 252, 108 }, { 39, 252, 109 }, { 39, 254, 110 }, { 41, 254, 111 },
+ { 43, 252, 112 }, { 45, 252, 113 }, { 45, 254, 114 }, { 47, 254, 115 }, { 49, 252, 116 }, { 51, 252, 117 }, { 51, 254, 118 }, { 53, 254, 119 },
+ { 55, 252, 120 }, { 57, 252, 121 }, { 57, 254, 122 }, { 59, 254, 123 }, { 61, 252, 124 }, { 63, 252, 125 }, { 63, 254, 126 }, { 65, 254, 127 },
+ { 67, 252, 128 }, { 69, 252, 129 }, { 69, 254, 130 }, { 71, 254, 131 }, { 73, 252, 132 }, { 75, 252, 133 }, { 75, 254, 134 }, { 77, 254, 135 },
+ { 79, 252, 136 }, { 81, 252, 137 }, { 81, 254, 138 }, { 83, 254, 139 }, { 85, 252, 140 }, { 87, 252, 141 }, { 87, 254, 142 }, { 89, 254, 143 },
+ { 91, 252, 144 }, { 93, 250, 145 }, { 93, 254, 146 }, { 95, 252, 147 }, { 97, 252, 148 }, { 97, 254, 149 }, { 99, 254, 150 }, { 101, 252, 151 },
+ { 103, 252, 152 }, { 103, 254, 153 }, { 105, 254, 154 }, { 107, 252, 155 }, { 109, 252, 156 }, { 109, 254, 157 }, { 111, 254, 158 }, { 113, 252, 159 },
+ { 115, 252, 160 }, { 115, 254, 161 }, { 117, 254, 162 }, { 119, 252, 163 }, { 121, 252, 164 }, { 121, 254, 165 }, { 123, 254, 166 }, { 125, 252, 167 },
+ { 127, 252, 168 }, { 127, 254, 169 }, { 129, 254, 170 }, { 131, 252, 171 }, { 133, 252, 172 }, { 133, 254, 173 }, { 135, 254, 174 }, { 137, 252, 175 },
+ { 139, 252, 176 }, { 139, 254, 177 }, { 141, 254, 178 }, { 143, 252, 179 }, { 145, 252, 180 }, { 145, 254, 181 }, { 147, 254, 182 }, { 149, 252, 183 },
+ { 151, 252, 184 }, { 151, 254, 185 }, { 153, 254, 186 }, { 155, 252, 187 }, { 157, 250, 188 }, { 157, 254, 189 }, { 159, 252, 190 }, { 161, 252, 191 },
+ { 161, 254, 192 }, { 163, 254, 193 }, { 165, 252, 194 }, { 167, 252, 195 }, { 167, 254, 196 }, { 169, 254, 197 }, { 171, 252, 198 }, { 173, 252, 199 },
+ { 173, 254, 200 }, { 175, 254, 201 }, { 177, 252, 202 }, { 179, 252, 203 }, { 179, 254, 204 }, { 181, 254, 205 }, { 183, 252, 206 }, { 185, 252, 207 },
+ { 185, 254, 208 }, { 187, 254, 209 }, { 189, 252, 210 }, { 191, 252, 211 }, { 191, 254, 212 }, { 193, 254, 213 }, { 195, 252, 214 }, { 197, 252, 215 },
+ { 197, 254, 216 }, { 199, 254, 217 }, { 201, 252, 218 }, { 203, 252, 219 }, { 203, 254, 220 }, { 205, 254, 221 }, { 207, 252, 222 }, { 209, 252, 223 },
+ { 209, 254, 224 }, { 211, 254, 225 }, { 213, 252, 226 }, { 215, 252, 227 }, { 215, 254, 228 }, { 217, 254, 229 }, { 219, 252, 230 }, { 221, 250, 231 },
+ { 221, 254, 232 }, { 223, 252, 233 }, { 225, 252, 234 }, { 225, 254, 235 }, { 227, 254, 236 }, { 229, 252, 237 }, { 231, 252, 238 }, { 231, 254, 239 },
+ { 233, 254, 240 }, { 235, 252, 241 }, { 237, 252, 242 }, { 237, 254, 243 }, { 239, 254, 244 }, { 241, 252, 245 }, { 243, 252, 246 }, { 243, 254, 247 },
+ { 245, 254, 248 }, { 247, 252, 249 }, { 249, 252, 250 }, { 249, 254, 251 }, { 251, 254, 252 }, { 253, 252, 253 }, { 255, 252, 254 }, { 255, 254, 255 },
+ }
+};
+
+Table g_mode7_p11=
+{
+ 1,
+ 3,
+ {
+ { 1, 1, 1 }, { 1, 1, 1 }, { 1, 3, 2 }, { 1, 7, 3 }, { 1, 9, 4 }, { 1, 13, 5 }, { 1, 15, 6 }, { 1, 19, 7 },
+ { 1, 21, 8 }, { 1, 25, 9 }, { 1, 27, 10 }, { 1, 31, 11 }, { 1, 33, 12 }, { 1, 37, 13 }, { 1, 41, 14 }, { 1, 43, 15 },
+ { 1, 47, 16 }, { 1, 49, 17 }, { 1, 53, 18 }, { 1, 55, 19 }, { 1, 59, 20 }, { 1, 61, 21 }, { 1, 65, 22 }, { 1, 67, 23 },
+ { 1, 71, 24 }, { 1, 73, 25 }, { 1, 77, 26 }, { 1, 79, 27 }, { 1, 83, 28 }, { 1, 85, 29 }, { 1, 89, 30 }, { 1, 91, 31 },
+ { 1, 95, 32 }, { 1, 97, 33 }, { 1, 101, 34 }, { 1, 105, 35 }, { 1, 107, 36 }, { 1, 111, 37 }, { 1, 113, 38 }, { 1, 117, 39 },
+ { 1, 119, 40 }, { 1, 123, 41 }, { 1, 125, 42 }, { 1, 129, 43 }, { 1, 131, 44 }, { 1, 135, 45 }, { 1, 137, 46 }, { 1, 141, 47 },
+ { 1, 143, 48 }, { 1, 147, 49 }, { 1, 149, 50 }, { 1, 153, 51 }, { 1, 155, 52 }, { 1, 159, 53 }, { 1, 161, 54 }, { 1, 165, 55 },
+ { 1, 169, 56 }, { 1, 171, 57 }, { 1, 175, 58 }, { 1, 177, 59 }, { 1, 181, 60 }, { 1, 183, 61 }, { 1, 187, 62 }, { 1, 189, 63 },
+ { 1, 193, 64 }, { 1, 195, 65 }, { 1, 199, 66 }, { 1, 201, 67 }, { 1, 205, 68 }, { 1, 207, 69 }, { 1, 211, 70 }, { 1, 213, 71 },
+ { 1, 217, 72 }, { 1, 219, 73 }, { 1, 223, 74 }, { 1, 225, 75 }, { 1, 229, 76 }, { 1, 233, 77 }, { 1, 235, 78 }, { 1, 239, 79 },
+ { 1, 241, 80 }, { 1, 245, 81 }, { 1, 247, 82 }, { 1, 251, 83 }, { 1, 253, 84 }, { 3, 253, 85 }, { 3, 255, 86 }, { 5, 255, 87 },
+ { 7, 253, 88 }, { 9, 253, 89 }, { 9, 255, 90 }, { 11, 255, 91 }, { 13, 253, 92 }, { 15, 253, 93 }, { 15, 255, 94 }, { 17, 255, 95 },
+ { 19, 253, 96 }, { 21, 253, 97 }, { 21, 255, 98 }, { 23, 255, 99 }, { 25, 253, 100 }, { 27, 251, 101 }, { 27, 255, 102 }, { 29, 253, 103 },
+ { 31, 253, 104 }, { 31, 255, 105 }, { 33, 255, 106 }, { 35, 253, 107 }, { 37, 253, 108 }, { 37, 255, 109 }, { 39, 255, 110 }, { 41, 253, 111 },
+ { 43, 253, 112 }, { 43, 255, 113 }, { 45, 255, 114 }, { 47, 253, 115 }, { 49, 253, 116 }, { 49, 255, 117 }, { 51, 255, 118 }, { 53, 253, 119 },
+ { 55, 253, 120 }, { 55, 255, 121 }, { 57, 255, 122 }, { 59, 253, 123 }, { 61, 253, 124 }, { 61, 255, 125 }, { 63, 255, 126 }, { 65, 253, 127 },
+ { 67, 253, 128 }, { 67, 255, 129 }, { 69, 255, 130 }, { 71, 253, 131 }, { 73, 253, 132 }, { 73, 255, 133 }, { 75, 255, 134 }, { 77, 253, 135 },
+ { 79, 253, 136 }, { 79, 255, 137 }, { 81, 255, 138 }, { 83, 253, 139 }, { 85, 253, 140 }, { 85, 255, 141 }, { 87, 255, 142 }, { 89, 253, 143 },
+ { 91, 251, 144 }, { 91, 255, 145 }, { 93, 253, 146 }, { 95, 253, 147 }, { 95, 255, 148 }, { 97, 255, 149 }, { 99, 253, 150 }, { 101, 253, 151 },
+ { 101, 255, 152 }, { 103, 255, 153 }, { 105, 253, 154 }, { 107, 253, 155 }, { 107, 255, 156 }, { 109, 255, 157 }, { 111, 253, 158 }, { 113, 253, 159 },
+ { 113, 255, 160 }, { 115, 255, 161 }, { 117, 253, 162 }, { 119, 253, 163 }, { 119, 255, 164 }, { 121, 255, 165 }, { 123, 253, 166 }, { 125, 253, 167 },
+ { 125, 255, 168 }, { 127, 255, 169 }, { 129, 253, 170 }, { 131, 253, 171 }, { 131, 255, 172 }, { 133, 255, 173 }, { 135, 253, 174 }, { 137, 253, 175 },
+ { 137, 255, 176 }, { 139, 255, 177 }, { 141, 253, 178 }, { 143, 253, 179 }, { 143, 255, 180 }, { 145, 255, 181 }, { 147, 253, 182 }, { 149, 253, 183 },
+ { 149, 255, 184 }, { 151, 255, 185 }, { 153, 253, 186 }, { 155, 251, 187 }, { 155, 255, 188 }, { 157, 253, 189 }, { 159, 253, 190 }, { 159, 255, 191 },
+ { 161, 255, 192 }, { 163, 253, 193 }, { 165, 253, 194 }, { 165, 255, 195 }, { 167, 255, 196 }, { 169, 253, 197 }, { 171, 253, 198 }, { 171, 255, 199 },
+ { 173, 255, 200 }, { 175, 253, 201 }, { 177, 253, 202 }, { 177, 255, 203 }, { 179, 255, 204 }, { 181, 253, 205 }, { 183, 253, 206 }, { 183, 255, 207 },
+ { 185, 255, 208 }, { 187, 253, 209 }, { 189, 253, 210 }, { 189, 255, 211 }, { 191, 255, 212 }, { 193, 253, 213 }, { 195, 253, 214 }, { 195, 255, 215 },
+ { 197, 255, 216 }, { 199, 253, 217 }, { 201, 253, 218 }, { 201, 255, 219 }, { 203, 255, 220 }, { 205, 253, 221 }, { 207, 253, 222 }, { 207, 255, 223 },
+ { 209, 255, 224 }, { 211, 253, 225 }, { 213, 253, 226 }, { 213, 255, 227 }, { 215, 255, 228 }, { 217, 253, 229 }, { 219, 251, 230 }, { 219, 255, 231 },
+ { 221, 253, 232 }, { 223, 253, 233 }, { 223, 255, 234 }, { 225, 255, 235 }, { 227, 253, 236 }, { 229, 253, 237 }, { 229, 255, 238 }, { 231, 255, 239 },
+ { 233, 253, 240 }, { 235, 253, 241 }, { 235, 255, 242 }, { 237, 255, 243 }, { 239, 253, 244 }, { 241, 253, 245 }, { 241, 255, 246 }, { 243, 255, 247 },
+ { 245, 253, 248 }, { 247, 253, 249 }, { 247, 255, 250 }, { 249, 255, 251 }, { 251, 253, 252 }, { 253, 253, 253 }, { 253, 255, 254 }, { 255, 255, 255 },
+ }
+};
+
+}}}
diff --git a/thirdparty/cvtt/LICENSE.txt b/thirdparty/cvtt/LICENSE.txt
new file mode 100644
index 0000000000..6964f6e43f
--- /dev/null
+++ b/thirdparty/cvtt/LICENSE.txt
@@ -0,0 +1,45 @@
+Convection Texture Tools Stand-Alone Kernels
+
+Copyright (c) 2018 Eric Lasota
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject
+to the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+**************************************************************************
+
+Based on DirectX Texture Library
+
+Copyright (c) 2018 Microsoft Corp
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this
+software and associated documentation files (the "Software"), to deal in the Software
+without restriction, including without limitation the rights to use, copy, modify,
+merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be included in all copies
+or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
+OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file
diff --git a/thirdparty/enet/godot.cpp b/thirdparty/enet/godot.cpp
index 7813b70286..73a09f9b1d 100644
--- a/thirdparty/enet/godot.cpp
+++ b/thirdparty/enet/godot.cpp
@@ -33,7 +33,7 @@
*/
#include "core/io/ip.h"
-#include "core/io/packet_peer_udp.h"
+#include "core/io/net_socket.h"
#include "core/os/os.h"
// This must be last for windows to compile (tested with MinGW)
@@ -90,6 +90,16 @@ int enet_address_get_host(const ENetAddress *address, char *name, size_t nameLen
return -1;
}
+ENetSocket enet_socket_create(ENetSocketType type) {
+
+ NetSocket *socket = NetSocket::create();
+ IP::Type ip_type = IP::TYPE_ANY;
+ socket->open(NetSocket::TYPE_UDP, ip_type);
+ socket->set_blocking_enabled(false);
+
+ return socket;
+}
+
int enet_socket_bind(ENetSocket socket, const ENetAddress *address) {
IP_Address ip;
@@ -99,23 +109,15 @@ int enet_socket_bind(ENetSocket socket, const ENetAddress *address) {
ip.set_ipv6(address->host);
}
- PacketPeerUDP *sock = (PacketPeerUDP *)socket;
- if (sock->listen(address->port, ip) != OK) {
+ NetSocket *sock = (NetSocket *)socket;
+ if (sock->bind(ip, address->port) != OK) {
return -1;
}
return 0;
}
-ENetSocket enet_socket_create(ENetSocketType type) {
-
- PacketPeerUDP *socket = PacketPeerUDP::create();
- socket->set_blocking_mode(false);
-
- return socket;
-}
-
void enet_socket_destroy(ENetSocket socket) {
- PacketPeerUDP *sock = (PacketPeerUDP *)socket;
+ NetSocket *sock = (NetSocket *)socket;
sock->close();
memdelete(sock);
}
@@ -124,13 +126,12 @@ int enet_socket_send(ENetSocket socket, const ENetAddress *address, const ENetBu
ERR_FAIL_COND_V(address == NULL, -1);
- PacketPeerUDP *sock = (PacketPeerUDP *)socket;
+ NetSocket *sock = (NetSocket *)socket;
IP_Address dest;
Error err;
size_t i = 0;
dest.set_ipv6(address->host);
- sock->set_dest_address(dest, address->port);
// Create a single packet.
PoolVector<uint8_t> out;
@@ -148,10 +149,11 @@ int enet_socket_send(ENetSocket socket, const ENetAddress *address, const ENetBu
pos += buffers[i].dataLength;
}
- err = sock->put_packet((const uint8_t *)&w[0], size);
+ int sent = 0;
+ err = sock->sendto((const uint8_t *)&w[0], size, sent, dest, address->port);
if (err != OK) {
- if (err == ERR_UNAVAILABLE) { // blocking call
+ if (err == ERR_BUSY) { // Blocking call
return 0;
}
@@ -159,31 +161,36 @@ int enet_socket_send(ENetSocket socket, const ENetAddress *address, const ENetBu
return -1;
}
- return size;
+ return sent;
}
int enet_socket_receive(ENetSocket socket, ENetAddress *address, ENetBuffer *buffers, size_t bufferCount) {
ERR_FAIL_COND_V(bufferCount != 1, -1);
- PacketPeerUDP *sock = (PacketPeerUDP *)socket;
+ NetSocket *sock = (NetSocket *)socket;
+
+ Error ret = sock->poll(NetSocket::POLL_TYPE_IN, 0);
- if (sock->get_available_packet_count() == 0) {
+ if (ret == ERR_BUSY)
return 0;
- }
- const uint8_t *buffer;
- int buffer_size;
- Error err = sock->get_packet(&buffer, buffer_size);
- if (err)
+ if (ret != OK)
return -1;
- copymem(buffers[0].data, buffer, buffer_size);
+ int read;
+ IP_Address ip;
+
+ Error err = sock->recvfrom((uint8_t *)buffers[0].data, buffers[0].dataLength, read, ip, address->port);
+ if (err == ERR_BUSY)
+ return 0;
- enet_address_set_ip(address, sock->get_packet_address().get_ipv6(), 16);
- address->port = sock->get_packet_port();
+ if (err != OK)
+ return -1;
+
+ enet_address_set_ip(address, ip.get_ipv6(), 16);
- return buffer_size;
+ return read;
}
// Not implemented
diff --git a/thirdparty/fonts/NotoSansDevanagariUI_Regular.ttf b/thirdparty/fonts/NotoSansDevanagariUI_Regular.ttf
new file mode 100644
index 0000000000..1f9fb2e857
--- /dev/null
+++ b/thirdparty/fonts/NotoSansDevanagariUI_Regular.ttf
Binary files differ
diff --git a/thirdparty/glad/glad.c b/thirdparty/glad/glad.c
index dd6fe8b8f3..8cc09e46e1 100644
--- a/thirdparty/glad/glad.c
+++ b/thirdparty/glad/glad.c
@@ -1,6 +1,6 @@
/*
- OpenGL loader generated by glad 0.1.25 on Sat Jul 28 10:59:43 2018.
+ OpenGL loader generated by glad 0.1.28 on Thu Nov 22 16:50:04 2018.
Language/Generator: C/C++
Specification: gl
@@ -13,11 +13,12 @@
Loader: True
Local files: False
Omit khrplatform: False
+ Reproducible: False
Commandline:
--profile="compatibility" --api="gl=3.3" --generator="c" --spec="gl" --extensions="GL_ARB_debug_output,GL_ARB_framebuffer_object,GL_EXT_framebuffer_object"
Online:
- http://glad.dav1d.de/#profile=compatibility&language=c&specification=gl&loader=on&api=gl%3D3.3&extensions=GL_ARB_debug_output&extensions=GL_ARB_framebuffer_object&extensions=GL_EXT_framebuffer_object
+ https://glad.dav1d.de/#profile=compatibility&language=c&specification=gl&loader=on&api=gl%3D3.3&extensions=GL_ARB_debug_output&extensions=GL_ARB_framebuffer_object&extensions=GL_EXT_framebuffer_object
*/
#include <stdio.h>
@@ -77,7 +78,7 @@ void close_gl(void) {
#include <dlfcn.h>
static void* libGL;
-#ifndef __APPLE__
+#if !defined(__APPLE__) && !defined(__HAIKU__)
typedef void* (APIENTRYP PFNGLXGETPROCADDRESSPROC_PRIVATE)(const char*);
static PFNGLXGETPROCADDRESSPROC_PRIVATE gladGetProcAddressPtr;
#endif
@@ -100,7 +101,7 @@ int open_gl(void) {
libGL = dlopen(NAMES[index], RTLD_NOW | RTLD_GLOBAL);
if(libGL != NULL) {
-#ifdef __APPLE__
+#if defined(__APPLE__) || defined(__HAIKU__)
return 1;
#else
gladGetProcAddressPtr = (PFNGLXGETPROCADDRESSPROC_PRIVATE)dlsym(libGL,
@@ -127,7 +128,7 @@ void* get_proc(const char *namez) {
void* result = NULL;
if(libGL == NULL) return NULL;
-#ifndef __APPLE__
+#if !defined(__APPLE__) && !defined(__HAIKU__)
if(gladGetProcAddressPtr != NULL) {
result = gladGetProcAddressPtr(namez);
}
@@ -154,7 +155,7 @@ int gladLoadGL(void) {
return status;
}
-struct gladGLversionStruct GLVersion;
+struct gladGLversionStruct GLVersion = { 0, 0 };
#if defined(GL_ES_VERSION_3_0) || defined(GL_VERSION_3_0)
#define _GLAD_IS_SOME_NEW_VERSION 1
@@ -179,7 +180,11 @@ static int get_exts(void) {
num_exts_i = 0;
glGetIntegerv(GL_NUM_EXTENSIONS, &num_exts_i);
if (num_exts_i > 0) {
- exts_i = (char **)realloc((void *)exts_i, (size_t)num_exts_i * (sizeof *exts_i));
+ char **tmp_exts_i = (char **)realloc((void *)exts_i, (size_t)num_exts_i * (sizeof *exts_i));
+ if (tmp_exts_i == NULL) {
+ return 0;
+ }
+ exts_i = tmp_exts_i;
}
if (exts_i == NULL) {
@@ -253,766 +258,766 @@ static int has_ext(const char *ext) {
return 0;
}
-int GLAD_GL_VERSION_1_0;
-int GLAD_GL_VERSION_1_1;
-int GLAD_GL_VERSION_1_2;
-int GLAD_GL_VERSION_1_3;
-int GLAD_GL_VERSION_1_4;
-int GLAD_GL_VERSION_1_5;
-int GLAD_GL_VERSION_2_0;
-int GLAD_GL_VERSION_2_1;
-int GLAD_GL_VERSION_3_0;
-int GLAD_GL_VERSION_3_1;
-int GLAD_GL_VERSION_3_2;
-int GLAD_GL_VERSION_3_3;
-PFNGLCOPYTEXIMAGE1DPROC glad_glCopyTexImage1D;
-PFNGLVERTEXATTRIBI3UIPROC glad_glVertexAttribI3ui;
-PFNGLWINDOWPOS2SPROC glad_glWindowPos2s;
-PFNGLWINDOWPOS2IPROC glad_glWindowPos2i;
-PFNGLWINDOWPOS2FPROC glad_glWindowPos2f;
-PFNGLWINDOWPOS2DPROC glad_glWindowPos2d;
-PFNGLVERTEX2FVPROC glad_glVertex2fv;
-PFNGLINDEXIPROC glad_glIndexi;
-PFNGLFRAMEBUFFERRENDERBUFFERPROC glad_glFramebufferRenderbuffer;
-PFNGLRECTDVPROC glad_glRectdv;
-PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC glad_glCompressedTexSubImage3D;
-PFNGLEVALCOORD2DPROC glad_glEvalCoord2d;
-PFNGLEVALCOORD2FPROC glad_glEvalCoord2f;
-PFNGLINDEXDPROC glad_glIndexd;
-PFNGLVERTEXATTRIB1SVPROC glad_glVertexAttrib1sv;
-PFNGLINDEXFPROC glad_glIndexf;
-PFNGLBINDSAMPLERPROC glad_glBindSampler;
-PFNGLLINEWIDTHPROC glad_glLineWidth;
-PFNGLCOLORP3UIVPROC glad_glColorP3uiv;
-PFNGLGETINTEGERI_VPROC glad_glGetIntegeri_v;
-PFNGLGETMAPFVPROC glad_glGetMapfv;
-PFNGLINDEXSPROC glad_glIndexs;
-PFNGLCOMPILESHADERPROC glad_glCompileShader;
-PFNGLGETTRANSFORMFEEDBACKVARYINGPROC glad_glGetTransformFeedbackVarying;
-PFNGLWINDOWPOS2IVPROC glad_glWindowPos2iv;
-PFNGLINDEXFVPROC glad_glIndexfv;
-PFNGLFOGIVPROC glad_glFogiv;
-PFNGLSTENCILMASKSEPARATEPROC glad_glStencilMaskSeparate;
-PFNGLRASTERPOS2FVPROC glad_glRasterPos2fv;
-PFNGLLIGHTMODELIVPROC glad_glLightModeliv;
-PFNGLCOLOR4UIPROC glad_glColor4ui;
-PFNGLSECONDARYCOLOR3FVPROC glad_glSecondaryColor3fv;
-PFNGLMULTITEXCOORDP3UIPROC glad_glMultiTexCoordP3ui;
-PFNGLFOGFVPROC glad_glFogfv;
-PFNGLVERTEXP4UIPROC glad_glVertexP4ui;
-PFNGLENABLEIPROC glad_glEnablei;
-PFNGLVERTEX4IVPROC glad_glVertex4iv;
-PFNGLEVALCOORD1FVPROC glad_glEvalCoord1fv;
-PFNGLWINDOWPOS2SVPROC glad_glWindowPos2sv;
-PFNGLVERTEXATTRIBP4UIPROC glad_glVertexAttribP4ui;
-PFNGLCREATESHADERPROC glad_glCreateShader;
-PFNGLISBUFFERPROC glad_glIsBuffer;
-PFNGLGETMULTISAMPLEFVPROC glad_glGetMultisamplefv;
-PFNGLGENRENDERBUFFERSPROC glad_glGenRenderbuffers;
-PFNGLCOPYTEXSUBIMAGE2DPROC glad_glCopyTexSubImage2D;
-PFNGLCOMPRESSEDTEXIMAGE2DPROC glad_glCompressedTexImage2D;
-PFNGLVERTEXATTRIB1FPROC glad_glVertexAttrib1f;
-PFNGLBLENDFUNCSEPARATEPROC glad_glBlendFuncSeparate;
-PFNGLVERTEX4FVPROC glad_glVertex4fv;
-PFNGLBINDTEXTUREPROC glad_glBindTexture;
-PFNGLVERTEXATTRIB1SPROC glad_glVertexAttrib1s;
-PFNGLTEXCOORD2FVPROC glad_glTexCoord2fv;
-PFNGLSAMPLEMASKIPROC glad_glSampleMaski;
-PFNGLVERTEXP2UIPROC glad_glVertexP2ui;
-PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC glad_glDrawRangeElementsBaseVertex;
-PFNGLTEXCOORD4FVPROC glad_glTexCoord4fv;
-PFNGLUNIFORMMATRIX3X2FVPROC glad_glUniformMatrix3x2fv;
-PFNGLPOINTSIZEPROC glad_glPointSize;
-PFNGLVERTEXATTRIB2DVPROC glad_glVertexAttrib2dv;
-PFNGLDELETEPROGRAMPROC glad_glDeleteProgram;
-PFNGLCOLOR4BVPROC glad_glColor4bv;
-PFNGLRASTERPOS2FPROC glad_glRasterPos2f;
-PFNGLRASTERPOS2DPROC glad_glRasterPos2d;
-PFNGLLOADIDENTITYPROC glad_glLoadIdentity;
-PFNGLRASTERPOS2IPROC glad_glRasterPos2i;
-PFNGLRENDERBUFFERSTORAGEPROC glad_glRenderbufferStorage;
-PFNGLUNIFORMMATRIX4X3FVPROC glad_glUniformMatrix4x3fv;
-PFNGLCOLOR3BPROC glad_glColor3b;
-PFNGLCLEARBUFFERFVPROC glad_glClearBufferfv;
-PFNGLEDGEFLAGPROC glad_glEdgeFlag;
-PFNGLDELETESAMPLERSPROC glad_glDeleteSamplers;
-PFNGLVERTEX3DPROC glad_glVertex3d;
-PFNGLVERTEX3FPROC glad_glVertex3f;
-PFNGLVERTEX3IPROC glad_glVertex3i;
-PFNGLCOLOR3IPROC glad_glColor3i;
-PFNGLUNIFORM3FPROC glad_glUniform3f;
-PFNGLVERTEXATTRIB4UBVPROC glad_glVertexAttrib4ubv;
-PFNGLCOLOR3SPROC glad_glColor3s;
-PFNGLVERTEX3SPROC glad_glVertex3s;
-PFNGLTEXCOORDP2UIPROC glad_glTexCoordP2ui;
-PFNGLCOLORMASKIPROC glad_glColorMaski;
-PFNGLCLEARBUFFERFIPROC glad_glClearBufferfi;
-PFNGLTEXCOORD1IVPROC glad_glTexCoord1iv;
-PFNGLBLITFRAMEBUFFERPROC glad_glBlitFramebuffer;
-PFNGLMULTITEXCOORDP2UIPROC glad_glMultiTexCoordP2ui;
-PFNGLGETSAMPLERPARAMETERIIVPROC glad_glGetSamplerParameterIiv;
-PFNGLGETFRAGDATAINDEXPROC glad_glGetFragDataIndex;
-PFNGLVERTEXATTRIB3FPROC glad_glVertexAttrib3f;
-PFNGLVERTEX2IVPROC glad_glVertex2iv;
-PFNGLCOLOR3SVPROC glad_glColor3sv;
-PFNGLGETVERTEXATTRIBDVPROC glad_glGetVertexAttribdv;
-PFNGLUNIFORMMATRIX3X4FVPROC glad_glUniformMatrix3x4fv;
-PFNGLNORMALPOINTERPROC glad_glNormalPointer;
-PFNGLTEXCOORDP3UIVPROC glad_glTexCoordP3uiv;
-PFNGLVERTEX4SVPROC glad_glVertex4sv;
-PFNGLPASSTHROUGHPROC glad_glPassThrough;
-PFNGLMULTITEXCOORDP4UIPROC glad_glMultiTexCoordP4ui;
-PFNGLFOGIPROC glad_glFogi;
-PFNGLBEGINPROC glad_glBegin;
-PFNGLEVALCOORD2DVPROC glad_glEvalCoord2dv;
-PFNGLCOLOR3UBVPROC glad_glColor3ubv;
-PFNGLVERTEXPOINTERPROC glad_glVertexPointer;
-PFNGLSECONDARYCOLOR3UIVPROC glad_glSecondaryColor3uiv;
-PFNGLDELETEFRAMEBUFFERSPROC glad_glDeleteFramebuffers;
-PFNGLDRAWARRAYSPROC glad_glDrawArrays;
-PFNGLUNIFORM1UIPROC glad_glUniform1ui;
-PFNGLMULTITEXCOORD1DPROC glad_glMultiTexCoord1d;
-PFNGLMULTITEXCOORD1FPROC glad_glMultiTexCoord1f;
-PFNGLLIGHTFVPROC glad_glLightfv;
-PFNGLTEXCOORDP3UIPROC glad_glTexCoordP3ui;
-PFNGLVERTEXATTRIB3DPROC glad_glVertexAttrib3d;
-PFNGLCLEARPROC glad_glClear;
-PFNGLMULTITEXCOORD1IPROC glad_glMultiTexCoord1i;
-PFNGLGETACTIVEUNIFORMNAMEPROC glad_glGetActiveUniformName;
-PFNGLMULTITEXCOORD1SPROC glad_glMultiTexCoord1s;
-PFNGLISENABLEDPROC glad_glIsEnabled;
-PFNGLSTENCILOPPROC glad_glStencilOp;
-PFNGLGETQUERYOBJECTUIVPROC glad_glGetQueryObjectuiv;
-PFNGLFRAMEBUFFERTEXTURE2DPROC glad_glFramebufferTexture2D;
-PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glad_glGetFramebufferAttachmentParameteriv;
-PFNGLTRANSLATEFPROC glad_glTranslatef;
-PFNGLVERTEXATTRIB4NUBPROC glad_glVertexAttrib4Nub;
-PFNGLTRANSLATEDPROC glad_glTranslated;
-PFNGLTEXCOORD3SVPROC glad_glTexCoord3sv;
-PFNGLGETFRAGDATALOCATIONPROC glad_glGetFragDataLocation;
-PFNGLTEXIMAGE1DPROC glad_glTexImage1D;
-PFNGLVERTEXP3UIVPROC glad_glVertexP3uiv;
-PFNGLTEXPARAMETERIVPROC glad_glTexParameteriv;
-PFNGLSECONDARYCOLOR3BVPROC glad_glSecondaryColor3bv;
-PFNGLGETMATERIALFVPROC glad_glGetMaterialfv;
-PFNGLGETTEXIMAGEPROC glad_glGetTexImage;
-PFNGLFOGCOORDFVPROC glad_glFogCoordfv;
-PFNGLPIXELMAPUIVPROC glad_glPixelMapuiv;
-PFNGLGETSHADERINFOLOGPROC glad_glGetShaderInfoLog;
-PFNGLGETQUERYOBJECTI64VPROC glad_glGetQueryObjecti64v;
-PFNGLGENFRAMEBUFFERSPROC glad_glGenFramebuffers;
-PFNGLINDEXSVPROC glad_glIndexsv;
-PFNGLGETATTACHEDSHADERSPROC glad_glGetAttachedShaders;
-PFNGLISRENDERBUFFERPROC glad_glIsRenderbuffer;
-PFNGLVERTEX3IVPROC glad_glVertex3iv;
-PFNGLBITMAPPROC glad_glBitmap;
-PFNGLMATERIALIPROC glad_glMateriali;
-PFNGLISVERTEXARRAYPROC glad_glIsVertexArray;
-PFNGLDISABLEVERTEXATTRIBARRAYPROC glad_glDisableVertexAttribArray;
-PFNGLGETQUERYIVPROC glad_glGetQueryiv;
-PFNGLTEXCOORD4FPROC glad_glTexCoord4f;
-PFNGLTEXCOORD4DPROC glad_glTexCoord4d;
-PFNGLGETSAMPLERPARAMETERFVPROC glad_glGetSamplerParameterfv;
-PFNGLTEXCOORD4IPROC glad_glTexCoord4i;
-PFNGLMATERIALFPROC glad_glMaterialf;
-PFNGLTEXCOORD4SPROC glad_glTexCoord4s;
-PFNGLGETUNIFORMINDICESPROC glad_glGetUniformIndices;
-PFNGLISSHADERPROC glad_glIsShader;
-PFNGLMULTITEXCOORD2SPROC glad_glMultiTexCoord2s;
-PFNGLVERTEXATTRIBI4UBVPROC glad_glVertexAttribI4ubv;
-PFNGLVERTEX3DVPROC glad_glVertex3dv;
-PFNGLGETINTEGER64VPROC glad_glGetInteger64v;
-PFNGLPOINTPARAMETERIVPROC glad_glPointParameteriv;
-PFNGLENABLEPROC glad_glEnable;
-PFNGLGETACTIVEUNIFORMSIVPROC glad_glGetActiveUniformsiv;
-PFNGLCOLOR4FVPROC glad_glColor4fv;
-PFNGLTEXCOORD1FVPROC glad_glTexCoord1fv;
-PFNGLTEXCOORD2SVPROC glad_glTexCoord2sv;
-PFNGLVERTEXATTRIB4DVPROC glad_glVertexAttrib4dv;
-PFNGLMULTITEXCOORD1DVPROC glad_glMultiTexCoord1dv;
-PFNGLMULTITEXCOORD2IPROC glad_glMultiTexCoord2i;
-PFNGLTEXCOORD3FVPROC glad_glTexCoord3fv;
-PFNGLSECONDARYCOLOR3USVPROC glad_glSecondaryColor3usv;
-PFNGLTEXGENFPROC glad_glTexGenf;
-PFNGLMULTITEXCOORDP3UIVPROC glad_glMultiTexCoordP3uiv;
-PFNGLVERTEXATTRIBP3UIPROC glad_glVertexAttribP3ui;
-PFNGLMULTITEXCOORDP1UIPROC glad_glMultiTexCoordP1ui;
-PFNGLGETPOINTERVPROC glad_glGetPointerv;
-PFNGLPOLYGONOFFSETPROC glad_glPolygonOffset;
-PFNGLGETUNIFORMUIVPROC glad_glGetUniformuiv;
-PFNGLNORMAL3FVPROC glad_glNormal3fv;
-PFNGLSECONDARYCOLOR3SPROC glad_glSecondaryColor3s;
-PFNGLDEPTHRANGEPROC glad_glDepthRange;
-PFNGLFRUSTUMPROC glad_glFrustum;
-PFNGLMULTITEXCOORD4SVPROC glad_glMultiTexCoord4sv;
-PFNGLDRAWBUFFERPROC glad_glDrawBuffer;
-PFNGLPUSHMATRIXPROC glad_glPushMatrix;
-PFNGLRASTERPOS3FVPROC glad_glRasterPos3fv;
-PFNGLORTHOPROC glad_glOrtho;
-PFNGLDRAWELEMENTSINSTANCEDPROC glad_glDrawElementsInstanced;
-PFNGLWINDOWPOS3SVPROC glad_glWindowPos3sv;
-PFNGLCLEARINDEXPROC glad_glClearIndex;
-PFNGLMAP1DPROC glad_glMap1d;
-PFNGLMAP1FPROC glad_glMap1f;
-PFNGLFLUSHPROC glad_glFlush;
-PFNGLGETRENDERBUFFERPARAMETERIVPROC glad_glGetRenderbufferParameteriv;
-PFNGLINDEXIVPROC glad_glIndexiv;
-PFNGLRASTERPOS3SVPROC glad_glRasterPos3sv;
-PFNGLGETVERTEXATTRIBPOINTERVPROC glad_glGetVertexAttribPointerv;
-PFNGLPIXELZOOMPROC glad_glPixelZoom;
-PFNGLFENCESYNCPROC glad_glFenceSync;
-PFNGLDELETEVERTEXARRAYSPROC glad_glDeleteVertexArrays;
-PFNGLCOLORP3UIPROC glad_glColorP3ui;
-PFNGLVERTEXATTRIB3SVPROC glad_glVertexAttrib3sv;
-PFNGLBEGINCONDITIONALRENDERPROC glad_glBeginConditionalRender;
-PFNGLDRAWELEMENTSBASEVERTEXPROC glad_glDrawElementsBaseVertex;
-PFNGLGETTEXLEVELPARAMETERIVPROC glad_glGetTexLevelParameteriv;
-PFNGLLIGHTIPROC glad_glLighti;
-PFNGLMULTITEXCOORDP4UIVPROC glad_glMultiTexCoordP4uiv;
-PFNGLLIGHTFPROC glad_glLightf;
-PFNGLGETATTRIBLOCATIONPROC glad_glGetAttribLocation;
-PFNGLSTENCILFUNCSEPARATEPROC glad_glStencilFuncSeparate;
-PFNGLGENSAMPLERSPROC glad_glGenSamplers;
-PFNGLCLAMPCOLORPROC glad_glClampColor;
-PFNGLUNIFORM4IVPROC glad_glUniform4iv;
-PFNGLCLEARSTENCILPROC glad_glClearStencil;
-PFNGLTEXCOORDP1UIVPROC glad_glTexCoordP1uiv;
-PFNGLMULTITEXCOORD3FVPROC glad_glMultiTexCoord3fv;
-PFNGLGETPIXELMAPUIVPROC glad_glGetPixelMapuiv;
-PFNGLGENTEXTURESPROC glad_glGenTextures;
-PFNGLTEXCOORD4IVPROC glad_glTexCoord4iv;
-PFNGLGETTEXPARAMETERIUIVPROC glad_glGetTexParameterIuiv;
-PFNGLINDEXPOINTERPROC glad_glIndexPointer;
-PFNGLVERTEXATTRIB4NBVPROC glad_glVertexAttrib4Nbv;
-PFNGLISSYNCPROC glad_glIsSync;
-PFNGLVERTEX2FPROC glad_glVertex2f;
-PFNGLVERTEX2DPROC glad_glVertex2d;
-PFNGLDELETERENDERBUFFERSPROC glad_glDeleteRenderbuffers;
-PFNGLUNIFORM2IPROC glad_glUniform2i;
-PFNGLMAPGRID2DPROC glad_glMapGrid2d;
-PFNGLMAPGRID2FPROC glad_glMapGrid2f;
-PFNGLTEXCOORDP4UIPROC glad_glTexCoordP4ui;
-PFNGLVERTEX2IPROC glad_glVertex2i;
-PFNGLVERTEXATTRIBPOINTERPROC glad_glVertexAttribPointer;
-PFNGLFRAMEBUFFERTEXTURELAYERPROC glad_glFramebufferTextureLayer;
-PFNGLVERTEX2SPROC glad_glVertex2s;
-PFNGLNORMAL3BVPROC glad_glNormal3bv;
-PFNGLVERTEXATTRIB4NUIVPROC glad_glVertexAttrib4Nuiv;
-PFNGLFLUSHMAPPEDBUFFERRANGEPROC glad_glFlushMappedBufferRange;
-PFNGLSECONDARYCOLOR3SVPROC glad_glSecondaryColor3sv;
-PFNGLVERTEX3SVPROC glad_glVertex3sv;
-PFNGLGENQUERIESPROC glad_glGenQueries;
-PFNGLGETPIXELMAPFVPROC glad_glGetPixelMapfv;
-PFNGLTEXENVFPROC glad_glTexEnvf;
-PFNGLVERTEXATTRIBP1UIPROC glad_glVertexAttribP1ui;
-PFNGLTEXSUBIMAGE3DPROC glad_glTexSubImage3D;
-PFNGLGETINTEGER64I_VPROC glad_glGetInteger64i_v;
-PFNGLFOGCOORDDPROC glad_glFogCoordd;
-PFNGLFOGCOORDFPROC glad_glFogCoordf;
-PFNGLCOPYTEXIMAGE2DPROC glad_glCopyTexImage2D;
-PFNGLTEXENVIPROC glad_glTexEnvi;
-PFNGLMULTITEXCOORD1IVPROC glad_glMultiTexCoord1iv;
-PFNGLISENABLEDIPROC glad_glIsEnabledi;
-PFNGLSECONDARYCOLORP3UIPROC glad_glSecondaryColorP3ui;
-PFNGLVERTEXATTRIBI2IPROC glad_glVertexAttribI2i;
-PFNGLBINDFRAGDATALOCATIONINDEXEDPROC glad_glBindFragDataLocationIndexed;
-PFNGLMULTITEXCOORD2DVPROC glad_glMultiTexCoord2dv;
-PFNGLUNIFORM2IVPROC glad_glUniform2iv;
-PFNGLVERTEXATTRIB1FVPROC glad_glVertexAttrib1fv;
-PFNGLUNIFORM4UIVPROC glad_glUniform4uiv;
-PFNGLMATRIXMODEPROC glad_glMatrixMode;
-PFNGLFEEDBACKBUFFERPROC glad_glFeedbackBuffer;
-PFNGLGETMAPIVPROC glad_glGetMapiv;
-PFNGLFRAMEBUFFERTEXTURE1DPROC glad_glFramebufferTexture1D;
-PFNGLGETSHADERIVPROC glad_glGetShaderiv;
-PFNGLMULTITEXCOORD2DPROC glad_glMultiTexCoord2d;
-PFNGLMULTITEXCOORD2FPROC glad_glMultiTexCoord2f;
-PFNGLBINDFRAGDATALOCATIONPROC glad_glBindFragDataLocation;
-PFNGLPRIORITIZETEXTURESPROC glad_glPrioritizeTextures;
-PFNGLCALLLISTPROC glad_glCallList;
-PFNGLSECONDARYCOLOR3UBVPROC glad_glSecondaryColor3ubv;
-PFNGLGETDOUBLEVPROC glad_glGetDoublev;
-PFNGLMULTITEXCOORD3IVPROC glad_glMultiTexCoord3iv;
-PFNGLVERTEXATTRIB1DPROC glad_glVertexAttrib1d;
-PFNGLLIGHTMODELFPROC glad_glLightModelf;
-PFNGLGETUNIFORMIVPROC glad_glGetUniformiv;
-PFNGLVERTEX2SVPROC glad_glVertex2sv;
-PFNGLLIGHTMODELIPROC glad_glLightModeli;
-PFNGLWINDOWPOS3IVPROC glad_glWindowPos3iv;
-PFNGLMULTITEXCOORDP1UIVPROC glad_glMultiTexCoordP1uiv;
-PFNGLUNIFORM3FVPROC glad_glUniform3fv;
-PFNGLPIXELSTOREIPROC glad_glPixelStorei;
-PFNGLCALLLISTSPROC glad_glCallLists;
-PFNGLMAPBUFFERPROC glad_glMapBuffer;
-PFNGLSECONDARYCOLOR3DPROC glad_glSecondaryColor3d;
-PFNGLTEXCOORD3IPROC glad_glTexCoord3i;
-PFNGLMULTITEXCOORD4FVPROC glad_glMultiTexCoord4fv;
-PFNGLRASTERPOS3IPROC glad_glRasterPos3i;
-PFNGLSECONDARYCOLOR3BPROC glad_glSecondaryColor3b;
-PFNGLRASTERPOS3DPROC glad_glRasterPos3d;
-PFNGLRASTERPOS3FPROC glad_glRasterPos3f;
-PFNGLCOMPRESSEDTEXIMAGE3DPROC glad_glCompressedTexImage3D;
-PFNGLTEXCOORD3FPROC glad_glTexCoord3f;
-PFNGLDELETESYNCPROC glad_glDeleteSync;
-PFNGLTEXCOORD3DPROC glad_glTexCoord3d;
-PFNGLTEXIMAGE2DMULTISAMPLEPROC glad_glTexImage2DMultisample;
-PFNGLGETVERTEXATTRIBIVPROC glad_glGetVertexAttribiv;
-PFNGLMULTIDRAWELEMENTSPROC glad_glMultiDrawElements;
-PFNGLVERTEXATTRIB3FVPROC glad_glVertexAttrib3fv;
-PFNGLTEXCOORD3SPROC glad_glTexCoord3s;
-PFNGLUNIFORM3IVPROC glad_glUniform3iv;
-PFNGLRASTERPOS3SPROC glad_glRasterPos3s;
-PFNGLPOLYGONMODEPROC glad_glPolygonMode;
-PFNGLDRAWBUFFERSPROC glad_glDrawBuffers;
-PFNGLGETACTIVEUNIFORMBLOCKIVPROC glad_glGetActiveUniformBlockiv;
-PFNGLARETEXTURESRESIDENTPROC glad_glAreTexturesResident;
-PFNGLISLISTPROC glad_glIsList;
-PFNGLRASTERPOS2SVPROC glad_glRasterPos2sv;
-PFNGLRASTERPOS4SVPROC glad_glRasterPos4sv;
-PFNGLCOLOR4SPROC glad_glColor4s;
-PFNGLUSEPROGRAMPROC glad_glUseProgram;
-PFNGLLINESTIPPLEPROC glad_glLineStipple;
-PFNGLMULTITEXCOORD1SVPROC glad_glMultiTexCoord1sv;
-PFNGLGETPROGRAMINFOLOGPROC glad_glGetProgramInfoLog;
-PFNGLGETBUFFERPARAMETERIVPROC glad_glGetBufferParameteriv;
-PFNGLMULTITEXCOORD2IVPROC glad_glMultiTexCoord2iv;
-PFNGLUNIFORMMATRIX2X4FVPROC glad_glUniformMatrix2x4fv;
-PFNGLBINDVERTEXARRAYPROC glad_glBindVertexArray;
-PFNGLCOLOR4BPROC glad_glColor4b;
-PFNGLSECONDARYCOLOR3FPROC glad_glSecondaryColor3f;
-PFNGLCOLOR4FPROC glad_glColor4f;
-PFNGLCOLOR4DPROC glad_glColor4d;
-PFNGLCOLOR4IPROC glad_glColor4i;
-PFNGLSAMPLERPARAMETERIIVPROC glad_glSamplerParameterIiv;
-PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC glad_glMultiDrawElementsBaseVertex;
-PFNGLRASTERPOS3IVPROC glad_glRasterPos3iv;
-PFNGLVERTEX2DVPROC glad_glVertex2dv;
-PFNGLTEXCOORD4SVPROC glad_glTexCoord4sv;
-PFNGLUNIFORM2UIVPROC glad_glUniform2uiv;
-PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC glad_glCompressedTexSubImage1D;
-PFNGLFINISHPROC glad_glFinish;
-PFNGLGETBOOLEANVPROC glad_glGetBooleanv;
-PFNGLDELETESHADERPROC glad_glDeleteShader;
-PFNGLDRAWELEMENTSPROC glad_glDrawElements;
-PFNGLRASTERPOS2SPROC glad_glRasterPos2s;
-PFNGLGETMAPDVPROC glad_glGetMapdv;
-PFNGLVERTEXATTRIB4NSVPROC glad_glVertexAttrib4Nsv;
-PFNGLMATERIALFVPROC glad_glMaterialfv;
-PFNGLVIEWPORTPROC glad_glViewport;
-PFNGLUNIFORM1UIVPROC glad_glUniform1uiv;
-PFNGLTRANSFORMFEEDBACKVARYINGSPROC glad_glTransformFeedbackVaryings;
-PFNGLINDEXDVPROC glad_glIndexdv;
-PFNGLCOPYTEXSUBIMAGE3DPROC glad_glCopyTexSubImage3D;
-PFNGLTEXCOORD3IVPROC glad_glTexCoord3iv;
-PFNGLVERTEXATTRIBI3IPROC glad_glVertexAttribI3i;
-PFNGLCLEARDEPTHPROC glad_glClearDepth;
-PFNGLVERTEXATTRIBI4USVPROC glad_glVertexAttribI4usv;
-PFNGLTEXPARAMETERFPROC glad_glTexParameterf;
-PFNGLTEXPARAMETERIPROC glad_glTexParameteri;
-PFNGLGETSHADERSOURCEPROC glad_glGetShaderSource;
-PFNGLTEXBUFFERPROC glad_glTexBuffer;
-PFNGLPOPNAMEPROC glad_glPopName;
-PFNGLVALIDATEPROGRAMPROC glad_glValidateProgram;
-PFNGLPIXELSTOREFPROC glad_glPixelStoref;
-PFNGLUNIFORM3UIVPROC glad_glUniform3uiv;
-PFNGLRASTERPOS4FVPROC glad_glRasterPos4fv;
-PFNGLEVALCOORD1DVPROC glad_glEvalCoord1dv;
-PFNGLMULTITEXCOORDP2UIVPROC glad_glMultiTexCoordP2uiv;
-PFNGLRECTIPROC glad_glRecti;
-PFNGLCOLOR4UBPROC glad_glColor4ub;
-PFNGLMULTTRANSPOSEMATRIXFPROC glad_glMultTransposeMatrixf;
-PFNGLRECTFPROC glad_glRectf;
-PFNGLRECTDPROC glad_glRectd;
-PFNGLNORMAL3SVPROC glad_glNormal3sv;
-PFNGLNEWLISTPROC glad_glNewList;
-PFNGLCOLOR4USPROC glad_glColor4us;
-PFNGLVERTEXATTRIBP1UIVPROC glad_glVertexAttribP1uiv;
-PFNGLLINKPROGRAMPROC glad_glLinkProgram;
-PFNGLHINTPROC glad_glHint;
-PFNGLRECTSPROC glad_glRects;
-PFNGLTEXCOORD2DVPROC glad_glTexCoord2dv;
-PFNGLRASTERPOS4IVPROC glad_glRasterPos4iv;
-PFNGLGETSTRINGPROC glad_glGetString;
-PFNGLVERTEXATTRIBP2UIVPROC glad_glVertexAttribP2uiv;
-PFNGLEDGEFLAGVPROC glad_glEdgeFlagv;
-PFNGLDETACHSHADERPROC glad_glDetachShader;
-PFNGLSCALEFPROC glad_glScalef;
-PFNGLENDQUERYPROC glad_glEndQuery;
-PFNGLSCALEDPROC glad_glScaled;
-PFNGLEDGEFLAGPOINTERPROC glad_glEdgeFlagPointer;
-PFNGLCOPYPIXELSPROC glad_glCopyPixels;
-PFNGLVERTEXATTRIBI2UIPROC glad_glVertexAttribI2ui;
-PFNGLPOPATTRIBPROC glad_glPopAttrib;
-PFNGLDELETETEXTURESPROC glad_glDeleteTextures;
-PFNGLSTENCILOPSEPARATEPROC glad_glStencilOpSeparate;
-PFNGLDELETEQUERIESPROC glad_glDeleteQueries;
-PFNGLNORMALP3UIVPROC glad_glNormalP3uiv;
-PFNGLVERTEXATTRIB4FPROC glad_glVertexAttrib4f;
-PFNGLVERTEXATTRIB4DPROC glad_glVertexAttrib4d;
-PFNGLINITNAMESPROC glad_glInitNames;
-PFNGLGETBUFFERPARAMETERI64VPROC glad_glGetBufferParameteri64v;
-PFNGLCOLOR3DVPROC glad_glColor3dv;
-PFNGLVERTEXATTRIBI1IPROC glad_glVertexAttribI1i;
-PFNGLGETTEXPARAMETERIVPROC glad_glGetTexParameteriv;
-PFNGLWAITSYNCPROC glad_glWaitSync;
-PFNGLVERTEXATTRIB4SPROC glad_glVertexAttrib4s;
-PFNGLCOLORMATERIALPROC glad_glColorMaterial;
-PFNGLSAMPLECOVERAGEPROC glad_glSampleCoverage;
-PFNGLSAMPLERPARAMETERIPROC glad_glSamplerParameteri;
-PFNGLSAMPLERPARAMETERFPROC glad_glSamplerParameterf;
-PFNGLUNIFORM1FPROC glad_glUniform1f;
-PFNGLGETVERTEXATTRIBFVPROC glad_glGetVertexAttribfv;
-PFNGLRENDERMODEPROC glad_glRenderMode;
-PFNGLGETCOMPRESSEDTEXIMAGEPROC glad_glGetCompressedTexImage;
-PFNGLWINDOWPOS2DVPROC glad_glWindowPos2dv;
-PFNGLUNIFORM1IPROC glad_glUniform1i;
-PFNGLGETACTIVEATTRIBPROC glad_glGetActiveAttrib;
-PFNGLUNIFORM3IPROC glad_glUniform3i;
-PFNGLPIXELTRANSFERIPROC glad_glPixelTransferi;
-PFNGLTEXSUBIMAGE2DPROC glad_glTexSubImage2D;
-PFNGLDISABLEPROC glad_glDisable;
-PFNGLLOGICOPPROC glad_glLogicOp;
-PFNGLEVALPOINT2PROC glad_glEvalPoint2;
-PFNGLPIXELTRANSFERFPROC glad_glPixelTransferf;
-PFNGLSECONDARYCOLOR3IPROC glad_glSecondaryColor3i;
-PFNGLUNIFORM4UIPROC glad_glUniform4ui;
-PFNGLCOLOR3FPROC glad_glColor3f;
-PFNGLBINDFRAMEBUFFERPROC glad_glBindFramebuffer;
-PFNGLGETTEXENVFVPROC glad_glGetTexEnvfv;
-PFNGLRECTFVPROC glad_glRectfv;
-PFNGLCULLFACEPROC glad_glCullFace;
-PFNGLGETLIGHTFVPROC glad_glGetLightfv;
-PFNGLCOLOR3DPROC glad_glColor3d;
-PFNGLTEXGENDPROC glad_glTexGend;
-PFNGLTEXGENIPROC glad_glTexGeni;
-PFNGLMULTITEXCOORD3SPROC glad_glMultiTexCoord3s;
-PFNGLGETSTRINGIPROC glad_glGetStringi;
-PFNGLMULTITEXCOORD3IPROC glad_glMultiTexCoord3i;
-PFNGLMULTITEXCOORD3FPROC glad_glMultiTexCoord3f;
-PFNGLMULTITEXCOORD3DPROC glad_glMultiTexCoord3d;
-PFNGLATTACHSHADERPROC glad_glAttachShader;
-PFNGLFOGCOORDDVPROC glad_glFogCoorddv;
-PFNGLUNIFORMMATRIX2X3FVPROC glad_glUniformMatrix2x3fv;
-PFNGLGETTEXGENFVPROC glad_glGetTexGenfv;
-PFNGLQUERYCOUNTERPROC glad_glQueryCounter;
-PFNGLFOGCOORDPOINTERPROC glad_glFogCoordPointer;
-PFNGLPROVOKINGVERTEXPROC glad_glProvokingVertex;
-PFNGLFRAMEBUFFERTEXTURE3DPROC glad_glFramebufferTexture3D;
-PFNGLTEXGENIVPROC glad_glTexGeniv;
-PFNGLRASTERPOS2DVPROC glad_glRasterPos2dv;
-PFNGLSECONDARYCOLOR3DVPROC glad_glSecondaryColor3dv;
-PFNGLCLIENTACTIVETEXTUREPROC glad_glClientActiveTexture;
-PFNGLVERTEXATTRIBI4SVPROC glad_glVertexAttribI4sv;
-PFNGLSECONDARYCOLOR3USPROC glad_glSecondaryColor3us;
-PFNGLNORMALP3UIPROC glad_glNormalP3ui;
-PFNGLTEXENVFVPROC glad_glTexEnvfv;
-PFNGLREADBUFFERPROC glad_glReadBuffer;
-PFNGLTEXPARAMETERIUIVPROC glad_glTexParameterIuiv;
-PFNGLDRAWARRAYSINSTANCEDPROC glad_glDrawArraysInstanced;
-PFNGLGENERATEMIPMAPPROC glad_glGenerateMipmap;
-PFNGLWINDOWPOS3FVPROC glad_glWindowPos3fv;
-PFNGLLIGHTMODELFVPROC glad_glLightModelfv;
-PFNGLSAMPLERPARAMETERIVPROC glad_glSamplerParameteriv;
-PFNGLDELETELISTSPROC glad_glDeleteLists;
-PFNGLGETCLIPPLANEPROC glad_glGetClipPlane;
-PFNGLVERTEX4DVPROC glad_glVertex4dv;
-PFNGLTEXCOORD2DPROC glad_glTexCoord2d;
-PFNGLPOPMATRIXPROC glad_glPopMatrix;
-PFNGLTEXCOORD2FPROC glad_glTexCoord2f;
-PFNGLCOLOR4IVPROC glad_glColor4iv;
-PFNGLINDEXUBVPROC glad_glIndexubv;
-PFNGLUNMAPBUFFERPROC glad_glUnmapBuffer;
-PFNGLTEXCOORD2IPROC glad_glTexCoord2i;
-PFNGLRASTERPOS4DPROC glad_glRasterPos4d;
-PFNGLRASTERPOS4FPROC glad_glRasterPos4f;
-PFNGLVERTEXATTRIB3SPROC glad_glVertexAttrib3s;
-PFNGLTEXCOORD2SPROC glad_glTexCoord2s;
-PFNGLBINDRENDERBUFFERPROC glad_glBindRenderbuffer;
-PFNGLVERTEX3FVPROC glad_glVertex3fv;
-PFNGLTEXCOORD4DVPROC glad_glTexCoord4dv;
-PFNGLMATERIALIVPROC glad_glMaterialiv;
-PFNGLVERTEXATTRIBP4UIVPROC glad_glVertexAttribP4uiv;
-PFNGLISPROGRAMPROC glad_glIsProgram;
-PFNGLVERTEXATTRIB4BVPROC glad_glVertexAttrib4bv;
-PFNGLVERTEX4SPROC glad_glVertex4s;
-PFNGLVERTEXATTRIB4FVPROC glad_glVertexAttrib4fv;
-PFNGLNORMAL3DVPROC glad_glNormal3dv;
-PFNGLUNIFORM4IPROC glad_glUniform4i;
-PFNGLACTIVETEXTUREPROC glad_glActiveTexture;
-PFNGLENABLEVERTEXATTRIBARRAYPROC glad_glEnableVertexAttribArray;
-PFNGLROTATEDPROC glad_glRotated;
-PFNGLROTATEFPROC glad_glRotatef;
-PFNGLVERTEX4IPROC glad_glVertex4i;
-PFNGLREADPIXELSPROC glad_glReadPixels;
-PFNGLVERTEXATTRIBI3IVPROC glad_glVertexAttribI3iv;
-PFNGLLOADNAMEPROC glad_glLoadName;
-PFNGLUNIFORM4FPROC glad_glUniform4f;
-PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glad_glRenderbufferStorageMultisample;
-PFNGLGENVERTEXARRAYSPROC glad_glGenVertexArrays;
-PFNGLSHADEMODELPROC glad_glShadeModel;
-PFNGLMAPGRID1DPROC glad_glMapGrid1d;
-PFNGLGETUNIFORMFVPROC glad_glGetUniformfv;
-PFNGLMAPGRID1FPROC glad_glMapGrid1f;
-PFNGLSAMPLERPARAMETERFVPROC glad_glSamplerParameterfv;
-PFNGLDISABLECLIENTSTATEPROC glad_glDisableClientState;
-PFNGLMULTITEXCOORD3SVPROC glad_glMultiTexCoord3sv;
-PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC glad_glDrawElementsInstancedBaseVertex;
-PFNGLSECONDARYCOLORPOINTERPROC glad_glSecondaryColorPointer;
-PFNGLALPHAFUNCPROC glad_glAlphaFunc;
-PFNGLUNIFORM1IVPROC glad_glUniform1iv;
-PFNGLMULTITEXCOORD4IVPROC glad_glMultiTexCoord4iv;
-PFNGLGETQUERYOBJECTIVPROC glad_glGetQueryObjectiv;
-PFNGLSTENCILFUNCPROC glad_glStencilFunc;
-PFNGLMULTITEXCOORD1FVPROC glad_glMultiTexCoord1fv;
-PFNGLUNIFORMBLOCKBINDINGPROC glad_glUniformBlockBinding;
-PFNGLCOLOR4UIVPROC glad_glColor4uiv;
-PFNGLRECTIVPROC glad_glRectiv;
-PFNGLCOLORP4UIPROC glad_glColorP4ui;
-PFNGLRASTERPOS3DVPROC glad_glRasterPos3dv;
-PFNGLEVALMESH2PROC glad_glEvalMesh2;
-PFNGLEVALMESH1PROC glad_glEvalMesh1;
-PFNGLTEXCOORDPOINTERPROC glad_glTexCoordPointer;
-PFNGLVERTEXATTRIB4NUBVPROC glad_glVertexAttrib4Nubv;
-PFNGLVERTEXATTRIBI4IVPROC glad_glVertexAttribI4iv;
-PFNGLEVALCOORD2FVPROC glad_glEvalCoord2fv;
-PFNGLCOLOR4UBVPROC glad_glColor4ubv;
-PFNGLLOADTRANSPOSEMATRIXDPROC glad_glLoadTransposeMatrixd;
-PFNGLLOADTRANSPOSEMATRIXFPROC glad_glLoadTransposeMatrixf;
-PFNGLVERTEXATTRIBI4IPROC glad_glVertexAttribI4i;
-PFNGLRASTERPOS2IVPROC glad_glRasterPos2iv;
-PFNGLGETBUFFERSUBDATAPROC glad_glGetBufferSubData;
-PFNGLTEXENVIVPROC glad_glTexEnviv;
-PFNGLBLENDEQUATIONSEPARATEPROC glad_glBlendEquationSeparate;
-PFNGLVERTEXATTRIBI1UIPROC glad_glVertexAttribI1ui;
-PFNGLGENBUFFERSPROC glad_glGenBuffers;
-PFNGLSELECTBUFFERPROC glad_glSelectBuffer;
-PFNGLVERTEXATTRIB2SVPROC glad_glVertexAttrib2sv;
-PFNGLPUSHATTRIBPROC glad_glPushAttrib;
-PFNGLVERTEXATTRIBIPOINTERPROC glad_glVertexAttribIPointer;
-PFNGLBLENDFUNCPROC glad_glBlendFunc;
-PFNGLCREATEPROGRAMPROC glad_glCreateProgram;
-PFNGLTEXIMAGE3DPROC glad_glTexImage3D;
-PFNGLISFRAMEBUFFERPROC glad_glIsFramebuffer;
-PFNGLLIGHTIVPROC glad_glLightiv;
-PFNGLPRIMITIVERESTARTINDEXPROC glad_glPrimitiveRestartIndex;
-PFNGLTEXGENFVPROC glad_glTexGenfv;
-PFNGLENDPROC glad_glEnd;
-PFNGLDELETEBUFFERSPROC glad_glDeleteBuffers;
-PFNGLSCISSORPROC glad_glScissor;
-PFNGLTEXCOORDP4UIVPROC glad_glTexCoordP4uiv;
-PFNGLCLIPPLANEPROC glad_glClipPlane;
-PFNGLPUSHNAMEPROC glad_glPushName;
-PFNGLTEXGENDVPROC glad_glTexGendv;
-PFNGLINDEXUBPROC glad_glIndexub;
-PFNGLVERTEXP2UIVPROC glad_glVertexP2uiv;
-PFNGLSECONDARYCOLOR3IVPROC glad_glSecondaryColor3iv;
-PFNGLRASTERPOS4IPROC glad_glRasterPos4i;
-PFNGLMULTTRANSPOSEMATRIXDPROC glad_glMultTransposeMatrixd;
-PFNGLCLEARCOLORPROC glad_glClearColor;
-PFNGLVERTEXATTRIB4UIVPROC glad_glVertexAttrib4uiv;
-PFNGLNORMAL3SPROC glad_glNormal3s;
-PFNGLVERTEXATTRIB4NIVPROC glad_glVertexAttrib4Niv;
-PFNGLCLEARBUFFERIVPROC glad_glClearBufferiv;
-PFNGLPOINTPARAMETERIPROC glad_glPointParameteri;
-PFNGLCOLORP4UIVPROC glad_glColorP4uiv;
-PFNGLBLENDCOLORPROC glad_glBlendColor;
-PFNGLWINDOWPOS3DPROC glad_glWindowPos3d;
-PFNGLVERTEXATTRIBI2UIVPROC glad_glVertexAttribI2uiv;
-PFNGLSAMPLERPARAMETERIUIVPROC glad_glSamplerParameterIuiv;
-PFNGLUNIFORM3UIPROC glad_glUniform3ui;
-PFNGLCOLOR4DVPROC glad_glColor4dv;
-PFNGLVERTEXATTRIBI4UIVPROC glad_glVertexAttribI4uiv;
-PFNGLPOINTPARAMETERFVPROC glad_glPointParameterfv;
-PFNGLUNIFORM2FVPROC glad_glUniform2fv;
-PFNGLSECONDARYCOLOR3UBPROC glad_glSecondaryColor3ub;
-PFNGLSECONDARYCOLOR3UIPROC glad_glSecondaryColor3ui;
-PFNGLTEXCOORD3DVPROC glad_glTexCoord3dv;
-PFNGLGETSAMPLERPARAMETERIUIVPROC glad_glGetSamplerParameterIuiv;
-PFNGLBINDBUFFERRANGEPROC glad_glBindBufferRange;
-PFNGLNORMAL3IVPROC glad_glNormal3iv;
-PFNGLWINDOWPOS3SPROC glad_glWindowPos3s;
-PFNGLPOINTPARAMETERFPROC glad_glPointParameterf;
-PFNGLGETVERTEXATTRIBIUIVPROC glad_glGetVertexAttribIuiv;
-PFNGLWINDOWPOS3IPROC glad_glWindowPos3i;
-PFNGLMULTITEXCOORD4SPROC glad_glMultiTexCoord4s;
-PFNGLWINDOWPOS3FPROC glad_glWindowPos3f;
-PFNGLCOLOR3USPROC glad_glColor3us;
-PFNGLCOLOR3UIVPROC glad_glColor3uiv;
-PFNGLVERTEXATTRIB4NUSVPROC glad_glVertexAttrib4Nusv;
-PFNGLGETLIGHTIVPROC glad_glGetLightiv;
-PFNGLDEPTHFUNCPROC glad_glDepthFunc;
-PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC glad_glCompressedTexSubImage2D;
-PFNGLLISTBASEPROC glad_glListBase;
-PFNGLMULTITEXCOORD4FPROC glad_glMultiTexCoord4f;
-PFNGLCOLOR3UBPROC glad_glColor3ub;
-PFNGLMULTITEXCOORD4DPROC glad_glMultiTexCoord4d;
-PFNGLVERTEXATTRIBI4BVPROC glad_glVertexAttribI4bv;
-PFNGLGETTEXPARAMETERFVPROC glad_glGetTexParameterfv;
-PFNGLCOLOR3UIPROC glad_glColor3ui;
-PFNGLMULTITEXCOORD4IPROC glad_glMultiTexCoord4i;
-PFNGLGETPOLYGONSTIPPLEPROC glad_glGetPolygonStipple;
-PFNGLCLIENTWAITSYNCPROC glad_glClientWaitSync;
-PFNGLVERTEXATTRIBI4UIPROC glad_glVertexAttribI4ui;
-PFNGLMULTITEXCOORD4DVPROC glad_glMultiTexCoord4dv;
-PFNGLCOLORMASKPROC glad_glColorMask;
-PFNGLTEXPARAMETERIIVPROC glad_glTexParameterIiv;
-PFNGLBLENDEQUATIONPROC glad_glBlendEquation;
-PFNGLGETUNIFORMLOCATIONPROC glad_glGetUniformLocation;
-PFNGLGETSAMPLERPARAMETERIVPROC glad_glGetSamplerParameteriv;
-PFNGLRASTERPOS4SPROC glad_glRasterPos4s;
-PFNGLENDTRANSFORMFEEDBACKPROC glad_glEndTransformFeedback;
-PFNGLVERTEXATTRIB4USVPROC glad_glVertexAttrib4usv;
-PFNGLMULTITEXCOORD3DVPROC glad_glMultiTexCoord3dv;
-PFNGLCOLOR4SVPROC glad_glColor4sv;
-PFNGLPOPCLIENTATTRIBPROC glad_glPopClientAttrib;
-PFNGLBEGINTRANSFORMFEEDBACKPROC glad_glBeginTransformFeedback;
-PFNGLFOGFPROC glad_glFogf;
-PFNGLVERTEXATTRIBI1IVPROC glad_glVertexAttribI1iv;
-PFNGLISSAMPLERPROC glad_glIsSampler;
-PFNGLVERTEXP3UIPROC glad_glVertexP3ui;
-PFNGLVERTEXATTRIBDIVISORPROC glad_glVertexAttribDivisor;
-PFNGLCOLOR3IVPROC glad_glColor3iv;
-PFNGLCOMPRESSEDTEXIMAGE1DPROC glad_glCompressedTexImage1D;
-PFNGLCOPYTEXSUBIMAGE1DPROC glad_glCopyTexSubImage1D;
-PFNGLTEXCOORD1IPROC glad_glTexCoord1i;
-PFNGLCHECKFRAMEBUFFERSTATUSPROC glad_glCheckFramebufferStatus;
-PFNGLTEXCOORD1DPROC glad_glTexCoord1d;
-PFNGLTEXCOORD1FPROC glad_glTexCoord1f;
-PFNGLENDCONDITIONALRENDERPROC glad_glEndConditionalRender;
-PFNGLENABLECLIENTSTATEPROC glad_glEnableClientState;
-PFNGLBINDATTRIBLOCATIONPROC glad_glBindAttribLocation;
-PFNGLUNIFORMMATRIX4X2FVPROC glad_glUniformMatrix4x2fv;
-PFNGLMULTITEXCOORD2SVPROC glad_glMultiTexCoord2sv;
-PFNGLVERTEXATTRIB1DVPROC glad_glVertexAttrib1dv;
-PFNGLDRAWRANGEELEMENTSPROC glad_glDrawRangeElements;
-PFNGLTEXCOORD1SPROC glad_glTexCoord1s;
-PFNGLBINDBUFFERBASEPROC glad_glBindBufferBase;
-PFNGLBUFFERSUBDATAPROC glad_glBufferSubData;
-PFNGLVERTEXATTRIB4IVPROC glad_glVertexAttrib4iv;
-PFNGLGENLISTSPROC glad_glGenLists;
-PFNGLCOLOR3BVPROC glad_glColor3bv;
-PFNGLMAPBUFFERRANGEPROC glad_glMapBufferRange;
-PFNGLFRAMEBUFFERTEXTUREPROC glad_glFramebufferTexture;
-PFNGLGETTEXGENDVPROC glad_glGetTexGendv;
-PFNGLMULTIDRAWARRAYSPROC glad_glMultiDrawArrays;
-PFNGLENDLISTPROC glad_glEndList;
-PFNGLVERTEXP4UIVPROC glad_glVertexP4uiv;
-PFNGLUNIFORM2UIPROC glad_glUniform2ui;
-PFNGLVERTEXATTRIBI2IVPROC glad_glVertexAttribI2iv;
-PFNGLCOLOR3USVPROC glad_glColor3usv;
-PFNGLWINDOWPOS2FVPROC glad_glWindowPos2fv;
-PFNGLDISABLEIPROC glad_glDisablei;
-PFNGLINDEXMASKPROC glad_glIndexMask;
-PFNGLPUSHCLIENTATTRIBPROC glad_glPushClientAttrib;
-PFNGLSHADERSOURCEPROC glad_glShaderSource;
-PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC glad_glGetActiveUniformBlockName;
-PFNGLVERTEXATTRIBI3UIVPROC glad_glVertexAttribI3uiv;
-PFNGLCLEARACCUMPROC glad_glClearAccum;
-PFNGLGETSYNCIVPROC glad_glGetSynciv;
-PFNGLTEXCOORDP2UIVPROC glad_glTexCoordP2uiv;
-PFNGLUNIFORM2FPROC glad_glUniform2f;
-PFNGLBEGINQUERYPROC glad_glBeginQuery;
-PFNGLGETUNIFORMBLOCKINDEXPROC glad_glGetUniformBlockIndex;
-PFNGLBINDBUFFERPROC glad_glBindBuffer;
-PFNGLMAP2DPROC glad_glMap2d;
-PFNGLMAP2FPROC glad_glMap2f;
-PFNGLVERTEX4DPROC glad_glVertex4d;
-PFNGLUNIFORMMATRIX2FVPROC glad_glUniformMatrix2fv;
-PFNGLTEXCOORD1SVPROC glad_glTexCoord1sv;
-PFNGLBUFFERDATAPROC glad_glBufferData;
-PFNGLEVALPOINT1PROC glad_glEvalPoint1;
-PFNGLGETTEXPARAMETERIIVPROC glad_glGetTexParameterIiv;
-PFNGLTEXCOORD1DVPROC glad_glTexCoord1dv;
-PFNGLTEXCOORDP1UIPROC glad_glTexCoordP1ui;
-PFNGLGETERRORPROC glad_glGetError;
-PFNGLGETTEXENVIVPROC glad_glGetTexEnviv;
-PFNGLGETPROGRAMIVPROC glad_glGetProgramiv;
-PFNGLVERTEXATTRIBP2UIPROC glad_glVertexAttribP2ui;
-PFNGLGETFLOATVPROC glad_glGetFloatv;
-PFNGLTEXSUBIMAGE1DPROC glad_glTexSubImage1D;
-PFNGLMULTITEXCOORD2FVPROC glad_glMultiTexCoord2fv;
-PFNGLVERTEXATTRIB2FVPROC glad_glVertexAttrib2fv;
-PFNGLEVALCOORD1DPROC glad_glEvalCoord1d;
-PFNGLGETTEXLEVELPARAMETERFVPROC glad_glGetTexLevelParameterfv;
-PFNGLEVALCOORD1FPROC glad_glEvalCoord1f;
-PFNGLPIXELMAPFVPROC glad_glPixelMapfv;
-PFNGLVERTEXATTRIBP3UIVPROC glad_glVertexAttribP3uiv;
-PFNGLGETPIXELMAPUSVPROC glad_glGetPixelMapusv;
-PFNGLSECONDARYCOLORP3UIVPROC glad_glSecondaryColorP3uiv;
-PFNGLGETINTEGERVPROC glad_glGetIntegerv;
-PFNGLACCUMPROC glad_glAccum;
-PFNGLGETBUFFERPOINTERVPROC glad_glGetBufferPointerv;
-PFNGLGETVERTEXATTRIBIIVPROC glad_glGetVertexAttribIiv;
-PFNGLRASTERPOS4DVPROC glad_glRasterPos4dv;
-PFNGLTEXCOORD2IVPROC glad_glTexCoord2iv;
-PFNGLISQUERYPROC glad_glIsQuery;
-PFNGLVERTEXATTRIB4SVPROC glad_glVertexAttrib4sv;
-PFNGLWINDOWPOS3DVPROC glad_glWindowPos3dv;
-PFNGLTEXIMAGE2DPROC glad_glTexImage2D;
-PFNGLSTENCILMASKPROC glad_glStencilMask;
-PFNGLDRAWPIXELSPROC glad_glDrawPixels;
-PFNGLMULTMATRIXDPROC glad_glMultMatrixd;
-PFNGLMULTMATRIXFPROC glad_glMultMatrixf;
-PFNGLISTEXTUREPROC glad_glIsTexture;
-PFNGLGETMATERIALIVPROC glad_glGetMaterialiv;
-PFNGLUNIFORM1FVPROC glad_glUniform1fv;
-PFNGLLOADMATRIXFPROC glad_glLoadMatrixf;
-PFNGLLOADMATRIXDPROC glad_glLoadMatrixd;
-PFNGLTEXPARAMETERFVPROC glad_glTexParameterfv;
-PFNGLUNIFORMMATRIX3FVPROC glad_glUniformMatrix3fv;
-PFNGLVERTEX4FPROC glad_glVertex4f;
-PFNGLRECTSVPROC glad_glRectsv;
-PFNGLCOLOR4USVPROC glad_glColor4usv;
-PFNGLPOLYGONSTIPPLEPROC glad_glPolygonStipple;
-PFNGLINTERLEAVEDARRAYSPROC glad_glInterleavedArrays;
-PFNGLNORMAL3IPROC glad_glNormal3i;
-PFNGLNORMAL3FPROC glad_glNormal3f;
-PFNGLNORMAL3DPROC glad_glNormal3d;
-PFNGLNORMAL3BPROC glad_glNormal3b;
-PFNGLPIXELMAPUSVPROC glad_glPixelMapusv;
-PFNGLGETTEXGENIVPROC glad_glGetTexGeniv;
-PFNGLARRAYELEMENTPROC glad_glArrayElement;
-PFNGLCOPYBUFFERSUBDATAPROC glad_glCopyBufferSubData;
-PFNGLVERTEXATTRIBI1UIVPROC glad_glVertexAttribI1uiv;
-PFNGLVERTEXATTRIB2DPROC glad_glVertexAttrib2d;
-PFNGLVERTEXATTRIB2FPROC glad_glVertexAttrib2f;
-PFNGLVERTEXATTRIB3DVPROC glad_glVertexAttrib3dv;
-PFNGLGETQUERYOBJECTUI64VPROC glad_glGetQueryObjectui64v;
-PFNGLDEPTHMASKPROC glad_glDepthMask;
-PFNGLVERTEXATTRIB2SPROC glad_glVertexAttrib2s;
-PFNGLCOLOR3FVPROC glad_glColor3fv;
-PFNGLTEXIMAGE3DMULTISAMPLEPROC glad_glTexImage3DMultisample;
-PFNGLUNIFORMMATRIX4FVPROC glad_glUniformMatrix4fv;
-PFNGLUNIFORM4FVPROC glad_glUniform4fv;
-PFNGLGETACTIVEUNIFORMPROC glad_glGetActiveUniform;
-PFNGLCOLORPOINTERPROC glad_glColorPointer;
-PFNGLFRONTFACEPROC glad_glFrontFace;
-PFNGLGETBOOLEANI_VPROC glad_glGetBooleani_v;
-PFNGLCLEARBUFFERUIVPROC glad_glClearBufferuiv;
-int GLAD_GL_ARB_framebuffer_object;
-int GLAD_GL_EXT_framebuffer_object;
-int GLAD_GL_ARB_debug_output;
-PFNGLDEBUGMESSAGECONTROLARBPROC glad_glDebugMessageControlARB;
-PFNGLDEBUGMESSAGEINSERTARBPROC glad_glDebugMessageInsertARB;
-PFNGLDEBUGMESSAGECALLBACKARBPROC glad_glDebugMessageCallbackARB;
-PFNGLGETDEBUGMESSAGELOGARBPROC glad_glGetDebugMessageLogARB;
-PFNGLISRENDERBUFFEREXTPROC glad_glIsRenderbufferEXT;
-PFNGLBINDRENDERBUFFEREXTPROC glad_glBindRenderbufferEXT;
-PFNGLDELETERENDERBUFFERSEXTPROC glad_glDeleteRenderbuffersEXT;
-PFNGLGENRENDERBUFFERSEXTPROC glad_glGenRenderbuffersEXT;
-PFNGLRENDERBUFFERSTORAGEEXTPROC glad_glRenderbufferStorageEXT;
-PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC glad_glGetRenderbufferParameterivEXT;
-PFNGLISFRAMEBUFFEREXTPROC glad_glIsFramebufferEXT;
-PFNGLBINDFRAMEBUFFEREXTPROC glad_glBindFramebufferEXT;
-PFNGLDELETEFRAMEBUFFERSEXTPROC glad_glDeleteFramebuffersEXT;
-PFNGLGENFRAMEBUFFERSEXTPROC glad_glGenFramebuffersEXT;
-PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glad_glCheckFramebufferStatusEXT;
-PFNGLFRAMEBUFFERTEXTURE1DEXTPROC glad_glFramebufferTexture1DEXT;
-PFNGLFRAMEBUFFERTEXTURE2DEXTPROC glad_glFramebufferTexture2DEXT;
-PFNGLFRAMEBUFFERTEXTURE3DEXTPROC glad_glFramebufferTexture3DEXT;
-PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC glad_glFramebufferRenderbufferEXT;
-PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC glad_glGetFramebufferAttachmentParameterivEXT;
-PFNGLGENERATEMIPMAPEXTPROC glad_glGenerateMipmapEXT;
+int GLAD_GL_VERSION_1_0 = 0;
+int GLAD_GL_VERSION_1_1 = 0;
+int GLAD_GL_VERSION_1_2 = 0;
+int GLAD_GL_VERSION_1_3 = 0;
+int GLAD_GL_VERSION_1_4 = 0;
+int GLAD_GL_VERSION_1_5 = 0;
+int GLAD_GL_VERSION_2_0 = 0;
+int GLAD_GL_VERSION_2_1 = 0;
+int GLAD_GL_VERSION_3_0 = 0;
+int GLAD_GL_VERSION_3_1 = 0;
+int GLAD_GL_VERSION_3_2 = 0;
+int GLAD_GL_VERSION_3_3 = 0;
+PFNGLACCUMPROC glad_glAccum = NULL;
+PFNGLACTIVETEXTUREPROC glad_glActiveTexture = NULL;
+PFNGLALPHAFUNCPROC glad_glAlphaFunc = NULL;
+PFNGLARETEXTURESRESIDENTPROC glad_glAreTexturesResident = NULL;
+PFNGLARRAYELEMENTPROC glad_glArrayElement = NULL;
+PFNGLATTACHSHADERPROC glad_glAttachShader = NULL;
+PFNGLBEGINPROC glad_glBegin = NULL;
+PFNGLBEGINCONDITIONALRENDERPROC glad_glBeginConditionalRender = NULL;
+PFNGLBEGINQUERYPROC glad_glBeginQuery = NULL;
+PFNGLBEGINTRANSFORMFEEDBACKPROC glad_glBeginTransformFeedback = NULL;
+PFNGLBINDATTRIBLOCATIONPROC glad_glBindAttribLocation = NULL;
+PFNGLBINDBUFFERPROC glad_glBindBuffer = NULL;
+PFNGLBINDBUFFERBASEPROC glad_glBindBufferBase = NULL;
+PFNGLBINDBUFFERRANGEPROC glad_glBindBufferRange = NULL;
+PFNGLBINDFRAGDATALOCATIONPROC glad_glBindFragDataLocation = NULL;
+PFNGLBINDFRAGDATALOCATIONINDEXEDPROC glad_glBindFragDataLocationIndexed = NULL;
+PFNGLBINDFRAMEBUFFERPROC glad_glBindFramebuffer = NULL;
+PFNGLBINDRENDERBUFFERPROC glad_glBindRenderbuffer = NULL;
+PFNGLBINDSAMPLERPROC glad_glBindSampler = NULL;
+PFNGLBINDTEXTUREPROC glad_glBindTexture = NULL;
+PFNGLBINDVERTEXARRAYPROC glad_glBindVertexArray = NULL;
+PFNGLBITMAPPROC glad_glBitmap = NULL;
+PFNGLBLENDCOLORPROC glad_glBlendColor = NULL;
+PFNGLBLENDEQUATIONPROC glad_glBlendEquation = NULL;
+PFNGLBLENDEQUATIONSEPARATEPROC glad_glBlendEquationSeparate = NULL;
+PFNGLBLENDFUNCPROC glad_glBlendFunc = NULL;
+PFNGLBLENDFUNCSEPARATEPROC glad_glBlendFuncSeparate = NULL;
+PFNGLBLITFRAMEBUFFERPROC glad_glBlitFramebuffer = NULL;
+PFNGLBUFFERDATAPROC glad_glBufferData = NULL;
+PFNGLBUFFERSUBDATAPROC glad_glBufferSubData = NULL;
+PFNGLCALLLISTPROC glad_glCallList = NULL;
+PFNGLCALLLISTSPROC glad_glCallLists = NULL;
+PFNGLCHECKFRAMEBUFFERSTATUSPROC glad_glCheckFramebufferStatus = NULL;
+PFNGLCLAMPCOLORPROC glad_glClampColor = NULL;
+PFNGLCLEARPROC glad_glClear = NULL;
+PFNGLCLEARACCUMPROC glad_glClearAccum = NULL;
+PFNGLCLEARBUFFERFIPROC glad_glClearBufferfi = NULL;
+PFNGLCLEARBUFFERFVPROC glad_glClearBufferfv = NULL;
+PFNGLCLEARBUFFERIVPROC glad_glClearBufferiv = NULL;
+PFNGLCLEARBUFFERUIVPROC glad_glClearBufferuiv = NULL;
+PFNGLCLEARCOLORPROC glad_glClearColor = NULL;
+PFNGLCLEARDEPTHPROC glad_glClearDepth = NULL;
+PFNGLCLEARINDEXPROC glad_glClearIndex = NULL;
+PFNGLCLEARSTENCILPROC glad_glClearStencil = NULL;
+PFNGLCLIENTACTIVETEXTUREPROC glad_glClientActiveTexture = NULL;
+PFNGLCLIENTWAITSYNCPROC glad_glClientWaitSync = NULL;
+PFNGLCLIPPLANEPROC glad_glClipPlane = NULL;
+PFNGLCOLOR3BPROC glad_glColor3b = NULL;
+PFNGLCOLOR3BVPROC glad_glColor3bv = NULL;
+PFNGLCOLOR3DPROC glad_glColor3d = NULL;
+PFNGLCOLOR3DVPROC glad_glColor3dv = NULL;
+PFNGLCOLOR3FPROC glad_glColor3f = NULL;
+PFNGLCOLOR3FVPROC glad_glColor3fv = NULL;
+PFNGLCOLOR3IPROC glad_glColor3i = NULL;
+PFNGLCOLOR3IVPROC glad_glColor3iv = NULL;
+PFNGLCOLOR3SPROC glad_glColor3s = NULL;
+PFNGLCOLOR3SVPROC glad_glColor3sv = NULL;
+PFNGLCOLOR3UBPROC glad_glColor3ub = NULL;
+PFNGLCOLOR3UBVPROC glad_glColor3ubv = NULL;
+PFNGLCOLOR3UIPROC glad_glColor3ui = NULL;
+PFNGLCOLOR3UIVPROC glad_glColor3uiv = NULL;
+PFNGLCOLOR3USPROC glad_glColor3us = NULL;
+PFNGLCOLOR3USVPROC glad_glColor3usv = NULL;
+PFNGLCOLOR4BPROC glad_glColor4b = NULL;
+PFNGLCOLOR4BVPROC glad_glColor4bv = NULL;
+PFNGLCOLOR4DPROC glad_glColor4d = NULL;
+PFNGLCOLOR4DVPROC glad_glColor4dv = NULL;
+PFNGLCOLOR4FPROC glad_glColor4f = NULL;
+PFNGLCOLOR4FVPROC glad_glColor4fv = NULL;
+PFNGLCOLOR4IPROC glad_glColor4i = NULL;
+PFNGLCOLOR4IVPROC glad_glColor4iv = NULL;
+PFNGLCOLOR4SPROC glad_glColor4s = NULL;
+PFNGLCOLOR4SVPROC glad_glColor4sv = NULL;
+PFNGLCOLOR4UBPROC glad_glColor4ub = NULL;
+PFNGLCOLOR4UBVPROC glad_glColor4ubv = NULL;
+PFNGLCOLOR4UIPROC glad_glColor4ui = NULL;
+PFNGLCOLOR4UIVPROC glad_glColor4uiv = NULL;
+PFNGLCOLOR4USPROC glad_glColor4us = NULL;
+PFNGLCOLOR4USVPROC glad_glColor4usv = NULL;
+PFNGLCOLORMASKPROC glad_glColorMask = NULL;
+PFNGLCOLORMASKIPROC glad_glColorMaski = NULL;
+PFNGLCOLORMATERIALPROC glad_glColorMaterial = NULL;
+PFNGLCOLORP3UIPROC glad_glColorP3ui = NULL;
+PFNGLCOLORP3UIVPROC glad_glColorP3uiv = NULL;
+PFNGLCOLORP4UIPROC glad_glColorP4ui = NULL;
+PFNGLCOLORP4UIVPROC glad_glColorP4uiv = NULL;
+PFNGLCOLORPOINTERPROC glad_glColorPointer = NULL;
+PFNGLCOMPILESHADERPROC glad_glCompileShader = NULL;
+PFNGLCOMPRESSEDTEXIMAGE1DPROC glad_glCompressedTexImage1D = NULL;
+PFNGLCOMPRESSEDTEXIMAGE2DPROC glad_glCompressedTexImage2D = NULL;
+PFNGLCOMPRESSEDTEXIMAGE3DPROC glad_glCompressedTexImage3D = NULL;
+PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC glad_glCompressedTexSubImage1D = NULL;
+PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC glad_glCompressedTexSubImage2D = NULL;
+PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC glad_glCompressedTexSubImage3D = NULL;
+PFNGLCOPYBUFFERSUBDATAPROC glad_glCopyBufferSubData = NULL;
+PFNGLCOPYPIXELSPROC glad_glCopyPixels = NULL;
+PFNGLCOPYTEXIMAGE1DPROC glad_glCopyTexImage1D = NULL;
+PFNGLCOPYTEXIMAGE2DPROC glad_glCopyTexImage2D = NULL;
+PFNGLCOPYTEXSUBIMAGE1DPROC glad_glCopyTexSubImage1D = NULL;
+PFNGLCOPYTEXSUBIMAGE2DPROC glad_glCopyTexSubImage2D = NULL;
+PFNGLCOPYTEXSUBIMAGE3DPROC glad_glCopyTexSubImage3D = NULL;
+PFNGLCREATEPROGRAMPROC glad_glCreateProgram = NULL;
+PFNGLCREATESHADERPROC glad_glCreateShader = NULL;
+PFNGLCULLFACEPROC glad_glCullFace = NULL;
+PFNGLDELETEBUFFERSPROC glad_glDeleteBuffers = NULL;
+PFNGLDELETEFRAMEBUFFERSPROC glad_glDeleteFramebuffers = NULL;
+PFNGLDELETELISTSPROC glad_glDeleteLists = NULL;
+PFNGLDELETEPROGRAMPROC glad_glDeleteProgram = NULL;
+PFNGLDELETEQUERIESPROC glad_glDeleteQueries = NULL;
+PFNGLDELETERENDERBUFFERSPROC glad_glDeleteRenderbuffers = NULL;
+PFNGLDELETESAMPLERSPROC glad_glDeleteSamplers = NULL;
+PFNGLDELETESHADERPROC glad_glDeleteShader = NULL;
+PFNGLDELETESYNCPROC glad_glDeleteSync = NULL;
+PFNGLDELETETEXTURESPROC glad_glDeleteTextures = NULL;
+PFNGLDELETEVERTEXARRAYSPROC glad_glDeleteVertexArrays = NULL;
+PFNGLDEPTHFUNCPROC glad_glDepthFunc = NULL;
+PFNGLDEPTHMASKPROC glad_glDepthMask = NULL;
+PFNGLDEPTHRANGEPROC glad_glDepthRange = NULL;
+PFNGLDETACHSHADERPROC glad_glDetachShader = NULL;
+PFNGLDISABLEPROC glad_glDisable = NULL;
+PFNGLDISABLECLIENTSTATEPROC glad_glDisableClientState = NULL;
+PFNGLDISABLEVERTEXATTRIBARRAYPROC glad_glDisableVertexAttribArray = NULL;
+PFNGLDISABLEIPROC glad_glDisablei = NULL;
+PFNGLDRAWARRAYSPROC glad_glDrawArrays = NULL;
+PFNGLDRAWARRAYSINSTANCEDPROC glad_glDrawArraysInstanced = NULL;
+PFNGLDRAWBUFFERPROC glad_glDrawBuffer = NULL;
+PFNGLDRAWBUFFERSPROC glad_glDrawBuffers = NULL;
+PFNGLDRAWELEMENTSPROC glad_glDrawElements = NULL;
+PFNGLDRAWELEMENTSBASEVERTEXPROC glad_glDrawElementsBaseVertex = NULL;
+PFNGLDRAWELEMENTSINSTANCEDPROC glad_glDrawElementsInstanced = NULL;
+PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC glad_glDrawElementsInstancedBaseVertex = NULL;
+PFNGLDRAWPIXELSPROC glad_glDrawPixels = NULL;
+PFNGLDRAWRANGEELEMENTSPROC glad_glDrawRangeElements = NULL;
+PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC glad_glDrawRangeElementsBaseVertex = NULL;
+PFNGLEDGEFLAGPROC glad_glEdgeFlag = NULL;
+PFNGLEDGEFLAGPOINTERPROC glad_glEdgeFlagPointer = NULL;
+PFNGLEDGEFLAGVPROC glad_glEdgeFlagv = NULL;
+PFNGLENABLEPROC glad_glEnable = NULL;
+PFNGLENABLECLIENTSTATEPROC glad_glEnableClientState = NULL;
+PFNGLENABLEVERTEXATTRIBARRAYPROC glad_glEnableVertexAttribArray = NULL;
+PFNGLENABLEIPROC glad_glEnablei = NULL;
+PFNGLENDPROC glad_glEnd = NULL;
+PFNGLENDCONDITIONALRENDERPROC glad_glEndConditionalRender = NULL;
+PFNGLENDLISTPROC glad_glEndList = NULL;
+PFNGLENDQUERYPROC glad_glEndQuery = NULL;
+PFNGLENDTRANSFORMFEEDBACKPROC glad_glEndTransformFeedback = NULL;
+PFNGLEVALCOORD1DPROC glad_glEvalCoord1d = NULL;
+PFNGLEVALCOORD1DVPROC glad_glEvalCoord1dv = NULL;
+PFNGLEVALCOORD1FPROC glad_glEvalCoord1f = NULL;
+PFNGLEVALCOORD1FVPROC glad_glEvalCoord1fv = NULL;
+PFNGLEVALCOORD2DPROC glad_glEvalCoord2d = NULL;
+PFNGLEVALCOORD2DVPROC glad_glEvalCoord2dv = NULL;
+PFNGLEVALCOORD2FPROC glad_glEvalCoord2f = NULL;
+PFNGLEVALCOORD2FVPROC glad_glEvalCoord2fv = NULL;
+PFNGLEVALMESH1PROC glad_glEvalMesh1 = NULL;
+PFNGLEVALMESH2PROC glad_glEvalMesh2 = NULL;
+PFNGLEVALPOINT1PROC glad_glEvalPoint1 = NULL;
+PFNGLEVALPOINT2PROC glad_glEvalPoint2 = NULL;
+PFNGLFEEDBACKBUFFERPROC glad_glFeedbackBuffer = NULL;
+PFNGLFENCESYNCPROC glad_glFenceSync = NULL;
+PFNGLFINISHPROC glad_glFinish = NULL;
+PFNGLFLUSHPROC glad_glFlush = NULL;
+PFNGLFLUSHMAPPEDBUFFERRANGEPROC glad_glFlushMappedBufferRange = NULL;
+PFNGLFOGCOORDPOINTERPROC glad_glFogCoordPointer = NULL;
+PFNGLFOGCOORDDPROC glad_glFogCoordd = NULL;
+PFNGLFOGCOORDDVPROC glad_glFogCoorddv = NULL;
+PFNGLFOGCOORDFPROC glad_glFogCoordf = NULL;
+PFNGLFOGCOORDFVPROC glad_glFogCoordfv = NULL;
+PFNGLFOGFPROC glad_glFogf = NULL;
+PFNGLFOGFVPROC glad_glFogfv = NULL;
+PFNGLFOGIPROC glad_glFogi = NULL;
+PFNGLFOGIVPROC glad_glFogiv = NULL;
+PFNGLFRAMEBUFFERRENDERBUFFERPROC glad_glFramebufferRenderbuffer = NULL;
+PFNGLFRAMEBUFFERTEXTUREPROC glad_glFramebufferTexture = NULL;
+PFNGLFRAMEBUFFERTEXTURE1DPROC glad_glFramebufferTexture1D = NULL;
+PFNGLFRAMEBUFFERTEXTURE2DPROC glad_glFramebufferTexture2D = NULL;
+PFNGLFRAMEBUFFERTEXTURE3DPROC glad_glFramebufferTexture3D = NULL;
+PFNGLFRAMEBUFFERTEXTURELAYERPROC glad_glFramebufferTextureLayer = NULL;
+PFNGLFRONTFACEPROC glad_glFrontFace = NULL;
+PFNGLFRUSTUMPROC glad_glFrustum = NULL;
+PFNGLGENBUFFERSPROC glad_glGenBuffers = NULL;
+PFNGLGENFRAMEBUFFERSPROC glad_glGenFramebuffers = NULL;
+PFNGLGENLISTSPROC glad_glGenLists = NULL;
+PFNGLGENQUERIESPROC glad_glGenQueries = NULL;
+PFNGLGENRENDERBUFFERSPROC glad_glGenRenderbuffers = NULL;
+PFNGLGENSAMPLERSPROC glad_glGenSamplers = NULL;
+PFNGLGENTEXTURESPROC glad_glGenTextures = NULL;
+PFNGLGENVERTEXARRAYSPROC glad_glGenVertexArrays = NULL;
+PFNGLGENERATEMIPMAPPROC glad_glGenerateMipmap = NULL;
+PFNGLGETACTIVEATTRIBPROC glad_glGetActiveAttrib = NULL;
+PFNGLGETACTIVEUNIFORMPROC glad_glGetActiveUniform = NULL;
+PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC glad_glGetActiveUniformBlockName = NULL;
+PFNGLGETACTIVEUNIFORMBLOCKIVPROC glad_glGetActiveUniformBlockiv = NULL;
+PFNGLGETACTIVEUNIFORMNAMEPROC glad_glGetActiveUniformName = NULL;
+PFNGLGETACTIVEUNIFORMSIVPROC glad_glGetActiveUniformsiv = NULL;
+PFNGLGETATTACHEDSHADERSPROC glad_glGetAttachedShaders = NULL;
+PFNGLGETATTRIBLOCATIONPROC glad_glGetAttribLocation = NULL;
+PFNGLGETBOOLEANI_VPROC glad_glGetBooleani_v = NULL;
+PFNGLGETBOOLEANVPROC glad_glGetBooleanv = NULL;
+PFNGLGETBUFFERPARAMETERI64VPROC glad_glGetBufferParameteri64v = NULL;
+PFNGLGETBUFFERPARAMETERIVPROC glad_glGetBufferParameteriv = NULL;
+PFNGLGETBUFFERPOINTERVPROC glad_glGetBufferPointerv = NULL;
+PFNGLGETBUFFERSUBDATAPROC glad_glGetBufferSubData = NULL;
+PFNGLGETCLIPPLANEPROC glad_glGetClipPlane = NULL;
+PFNGLGETCOMPRESSEDTEXIMAGEPROC glad_glGetCompressedTexImage = NULL;
+PFNGLGETDOUBLEVPROC glad_glGetDoublev = NULL;
+PFNGLGETERRORPROC glad_glGetError = NULL;
+PFNGLGETFLOATVPROC glad_glGetFloatv = NULL;
+PFNGLGETFRAGDATAINDEXPROC glad_glGetFragDataIndex = NULL;
+PFNGLGETFRAGDATALOCATIONPROC glad_glGetFragDataLocation = NULL;
+PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glad_glGetFramebufferAttachmentParameteriv = NULL;
+PFNGLGETINTEGER64I_VPROC glad_glGetInteger64i_v = NULL;
+PFNGLGETINTEGER64VPROC glad_glGetInteger64v = NULL;
+PFNGLGETINTEGERI_VPROC glad_glGetIntegeri_v = NULL;
+PFNGLGETINTEGERVPROC glad_glGetIntegerv = NULL;
+PFNGLGETLIGHTFVPROC glad_glGetLightfv = NULL;
+PFNGLGETLIGHTIVPROC glad_glGetLightiv = NULL;
+PFNGLGETMAPDVPROC glad_glGetMapdv = NULL;
+PFNGLGETMAPFVPROC glad_glGetMapfv = NULL;
+PFNGLGETMAPIVPROC glad_glGetMapiv = NULL;
+PFNGLGETMATERIALFVPROC glad_glGetMaterialfv = NULL;
+PFNGLGETMATERIALIVPROC glad_glGetMaterialiv = NULL;
+PFNGLGETMULTISAMPLEFVPROC glad_glGetMultisamplefv = NULL;
+PFNGLGETPIXELMAPFVPROC glad_glGetPixelMapfv = NULL;
+PFNGLGETPIXELMAPUIVPROC glad_glGetPixelMapuiv = NULL;
+PFNGLGETPIXELMAPUSVPROC glad_glGetPixelMapusv = NULL;
+PFNGLGETPOINTERVPROC glad_glGetPointerv = NULL;
+PFNGLGETPOLYGONSTIPPLEPROC glad_glGetPolygonStipple = NULL;
+PFNGLGETPROGRAMINFOLOGPROC glad_glGetProgramInfoLog = NULL;
+PFNGLGETPROGRAMIVPROC glad_glGetProgramiv = NULL;
+PFNGLGETQUERYOBJECTI64VPROC glad_glGetQueryObjecti64v = NULL;
+PFNGLGETQUERYOBJECTIVPROC glad_glGetQueryObjectiv = NULL;
+PFNGLGETQUERYOBJECTUI64VPROC glad_glGetQueryObjectui64v = NULL;
+PFNGLGETQUERYOBJECTUIVPROC glad_glGetQueryObjectuiv = NULL;
+PFNGLGETQUERYIVPROC glad_glGetQueryiv = NULL;
+PFNGLGETRENDERBUFFERPARAMETERIVPROC glad_glGetRenderbufferParameteriv = NULL;
+PFNGLGETSAMPLERPARAMETERIIVPROC glad_glGetSamplerParameterIiv = NULL;
+PFNGLGETSAMPLERPARAMETERIUIVPROC glad_glGetSamplerParameterIuiv = NULL;
+PFNGLGETSAMPLERPARAMETERFVPROC glad_glGetSamplerParameterfv = NULL;
+PFNGLGETSAMPLERPARAMETERIVPROC glad_glGetSamplerParameteriv = NULL;
+PFNGLGETSHADERINFOLOGPROC glad_glGetShaderInfoLog = NULL;
+PFNGLGETSHADERSOURCEPROC glad_glGetShaderSource = NULL;
+PFNGLGETSHADERIVPROC glad_glGetShaderiv = NULL;
+PFNGLGETSTRINGPROC glad_glGetString = NULL;
+PFNGLGETSTRINGIPROC glad_glGetStringi = NULL;
+PFNGLGETSYNCIVPROC glad_glGetSynciv = NULL;
+PFNGLGETTEXENVFVPROC glad_glGetTexEnvfv = NULL;
+PFNGLGETTEXENVIVPROC glad_glGetTexEnviv = NULL;
+PFNGLGETTEXGENDVPROC glad_glGetTexGendv = NULL;
+PFNGLGETTEXGENFVPROC glad_glGetTexGenfv = NULL;
+PFNGLGETTEXGENIVPROC glad_glGetTexGeniv = NULL;
+PFNGLGETTEXIMAGEPROC glad_glGetTexImage = NULL;
+PFNGLGETTEXLEVELPARAMETERFVPROC glad_glGetTexLevelParameterfv = NULL;
+PFNGLGETTEXLEVELPARAMETERIVPROC glad_glGetTexLevelParameteriv = NULL;
+PFNGLGETTEXPARAMETERIIVPROC glad_glGetTexParameterIiv = NULL;
+PFNGLGETTEXPARAMETERIUIVPROC glad_glGetTexParameterIuiv = NULL;
+PFNGLGETTEXPARAMETERFVPROC glad_glGetTexParameterfv = NULL;
+PFNGLGETTEXPARAMETERIVPROC glad_glGetTexParameteriv = NULL;
+PFNGLGETTRANSFORMFEEDBACKVARYINGPROC glad_glGetTransformFeedbackVarying = NULL;
+PFNGLGETUNIFORMBLOCKINDEXPROC glad_glGetUniformBlockIndex = NULL;
+PFNGLGETUNIFORMINDICESPROC glad_glGetUniformIndices = NULL;
+PFNGLGETUNIFORMLOCATIONPROC glad_glGetUniformLocation = NULL;
+PFNGLGETUNIFORMFVPROC glad_glGetUniformfv = NULL;
+PFNGLGETUNIFORMIVPROC glad_glGetUniformiv = NULL;
+PFNGLGETUNIFORMUIVPROC glad_glGetUniformuiv = NULL;
+PFNGLGETVERTEXATTRIBIIVPROC glad_glGetVertexAttribIiv = NULL;
+PFNGLGETVERTEXATTRIBIUIVPROC glad_glGetVertexAttribIuiv = NULL;
+PFNGLGETVERTEXATTRIBPOINTERVPROC glad_glGetVertexAttribPointerv = NULL;
+PFNGLGETVERTEXATTRIBDVPROC glad_glGetVertexAttribdv = NULL;
+PFNGLGETVERTEXATTRIBFVPROC glad_glGetVertexAttribfv = NULL;
+PFNGLGETVERTEXATTRIBIVPROC glad_glGetVertexAttribiv = NULL;
+PFNGLHINTPROC glad_glHint = NULL;
+PFNGLINDEXMASKPROC glad_glIndexMask = NULL;
+PFNGLINDEXPOINTERPROC glad_glIndexPointer = NULL;
+PFNGLINDEXDPROC glad_glIndexd = NULL;
+PFNGLINDEXDVPROC glad_glIndexdv = NULL;
+PFNGLINDEXFPROC glad_glIndexf = NULL;
+PFNGLINDEXFVPROC glad_glIndexfv = NULL;
+PFNGLINDEXIPROC glad_glIndexi = NULL;
+PFNGLINDEXIVPROC glad_glIndexiv = NULL;
+PFNGLINDEXSPROC glad_glIndexs = NULL;
+PFNGLINDEXSVPROC glad_glIndexsv = NULL;
+PFNGLINDEXUBPROC glad_glIndexub = NULL;
+PFNGLINDEXUBVPROC glad_glIndexubv = NULL;
+PFNGLINITNAMESPROC glad_glInitNames = NULL;
+PFNGLINTERLEAVEDARRAYSPROC glad_glInterleavedArrays = NULL;
+PFNGLISBUFFERPROC glad_glIsBuffer = NULL;
+PFNGLISENABLEDPROC glad_glIsEnabled = NULL;
+PFNGLISENABLEDIPROC glad_glIsEnabledi = NULL;
+PFNGLISFRAMEBUFFERPROC glad_glIsFramebuffer = NULL;
+PFNGLISLISTPROC glad_glIsList = NULL;
+PFNGLISPROGRAMPROC glad_glIsProgram = NULL;
+PFNGLISQUERYPROC glad_glIsQuery = NULL;
+PFNGLISRENDERBUFFERPROC glad_glIsRenderbuffer = NULL;
+PFNGLISSAMPLERPROC glad_glIsSampler = NULL;
+PFNGLISSHADERPROC glad_glIsShader = NULL;
+PFNGLISSYNCPROC glad_glIsSync = NULL;
+PFNGLISTEXTUREPROC glad_glIsTexture = NULL;
+PFNGLISVERTEXARRAYPROC glad_glIsVertexArray = NULL;
+PFNGLLIGHTMODELFPROC glad_glLightModelf = NULL;
+PFNGLLIGHTMODELFVPROC glad_glLightModelfv = NULL;
+PFNGLLIGHTMODELIPROC glad_glLightModeli = NULL;
+PFNGLLIGHTMODELIVPROC glad_glLightModeliv = NULL;
+PFNGLLIGHTFPROC glad_glLightf = NULL;
+PFNGLLIGHTFVPROC glad_glLightfv = NULL;
+PFNGLLIGHTIPROC glad_glLighti = NULL;
+PFNGLLIGHTIVPROC glad_glLightiv = NULL;
+PFNGLLINESTIPPLEPROC glad_glLineStipple = NULL;
+PFNGLLINEWIDTHPROC glad_glLineWidth = NULL;
+PFNGLLINKPROGRAMPROC glad_glLinkProgram = NULL;
+PFNGLLISTBASEPROC glad_glListBase = NULL;
+PFNGLLOADIDENTITYPROC glad_glLoadIdentity = NULL;
+PFNGLLOADMATRIXDPROC glad_glLoadMatrixd = NULL;
+PFNGLLOADMATRIXFPROC glad_glLoadMatrixf = NULL;
+PFNGLLOADNAMEPROC glad_glLoadName = NULL;
+PFNGLLOADTRANSPOSEMATRIXDPROC glad_glLoadTransposeMatrixd = NULL;
+PFNGLLOADTRANSPOSEMATRIXFPROC glad_glLoadTransposeMatrixf = NULL;
+PFNGLLOGICOPPROC glad_glLogicOp = NULL;
+PFNGLMAP1DPROC glad_glMap1d = NULL;
+PFNGLMAP1FPROC glad_glMap1f = NULL;
+PFNGLMAP2DPROC glad_glMap2d = NULL;
+PFNGLMAP2FPROC glad_glMap2f = NULL;
+PFNGLMAPBUFFERPROC glad_glMapBuffer = NULL;
+PFNGLMAPBUFFERRANGEPROC glad_glMapBufferRange = NULL;
+PFNGLMAPGRID1DPROC glad_glMapGrid1d = NULL;
+PFNGLMAPGRID1FPROC glad_glMapGrid1f = NULL;
+PFNGLMAPGRID2DPROC glad_glMapGrid2d = NULL;
+PFNGLMAPGRID2FPROC glad_glMapGrid2f = NULL;
+PFNGLMATERIALFPROC glad_glMaterialf = NULL;
+PFNGLMATERIALFVPROC glad_glMaterialfv = NULL;
+PFNGLMATERIALIPROC glad_glMateriali = NULL;
+PFNGLMATERIALIVPROC glad_glMaterialiv = NULL;
+PFNGLMATRIXMODEPROC glad_glMatrixMode = NULL;
+PFNGLMULTMATRIXDPROC glad_glMultMatrixd = NULL;
+PFNGLMULTMATRIXFPROC glad_glMultMatrixf = NULL;
+PFNGLMULTTRANSPOSEMATRIXDPROC glad_glMultTransposeMatrixd = NULL;
+PFNGLMULTTRANSPOSEMATRIXFPROC glad_glMultTransposeMatrixf = NULL;
+PFNGLMULTIDRAWARRAYSPROC glad_glMultiDrawArrays = NULL;
+PFNGLMULTIDRAWELEMENTSPROC glad_glMultiDrawElements = NULL;
+PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC glad_glMultiDrawElementsBaseVertex = NULL;
+PFNGLMULTITEXCOORD1DPROC glad_glMultiTexCoord1d = NULL;
+PFNGLMULTITEXCOORD1DVPROC glad_glMultiTexCoord1dv = NULL;
+PFNGLMULTITEXCOORD1FPROC glad_glMultiTexCoord1f = NULL;
+PFNGLMULTITEXCOORD1FVPROC glad_glMultiTexCoord1fv = NULL;
+PFNGLMULTITEXCOORD1IPROC glad_glMultiTexCoord1i = NULL;
+PFNGLMULTITEXCOORD1IVPROC glad_glMultiTexCoord1iv = NULL;
+PFNGLMULTITEXCOORD1SPROC glad_glMultiTexCoord1s = NULL;
+PFNGLMULTITEXCOORD1SVPROC glad_glMultiTexCoord1sv = NULL;
+PFNGLMULTITEXCOORD2DPROC glad_glMultiTexCoord2d = NULL;
+PFNGLMULTITEXCOORD2DVPROC glad_glMultiTexCoord2dv = NULL;
+PFNGLMULTITEXCOORD2FPROC glad_glMultiTexCoord2f = NULL;
+PFNGLMULTITEXCOORD2FVPROC glad_glMultiTexCoord2fv = NULL;
+PFNGLMULTITEXCOORD2IPROC glad_glMultiTexCoord2i = NULL;
+PFNGLMULTITEXCOORD2IVPROC glad_glMultiTexCoord2iv = NULL;
+PFNGLMULTITEXCOORD2SPROC glad_glMultiTexCoord2s = NULL;
+PFNGLMULTITEXCOORD2SVPROC glad_glMultiTexCoord2sv = NULL;
+PFNGLMULTITEXCOORD3DPROC glad_glMultiTexCoord3d = NULL;
+PFNGLMULTITEXCOORD3DVPROC glad_glMultiTexCoord3dv = NULL;
+PFNGLMULTITEXCOORD3FPROC glad_glMultiTexCoord3f = NULL;
+PFNGLMULTITEXCOORD3FVPROC glad_glMultiTexCoord3fv = NULL;
+PFNGLMULTITEXCOORD3IPROC glad_glMultiTexCoord3i = NULL;
+PFNGLMULTITEXCOORD3IVPROC glad_glMultiTexCoord3iv = NULL;
+PFNGLMULTITEXCOORD3SPROC glad_glMultiTexCoord3s = NULL;
+PFNGLMULTITEXCOORD3SVPROC glad_glMultiTexCoord3sv = NULL;
+PFNGLMULTITEXCOORD4DPROC glad_glMultiTexCoord4d = NULL;
+PFNGLMULTITEXCOORD4DVPROC glad_glMultiTexCoord4dv = NULL;
+PFNGLMULTITEXCOORD4FPROC glad_glMultiTexCoord4f = NULL;
+PFNGLMULTITEXCOORD4FVPROC glad_glMultiTexCoord4fv = NULL;
+PFNGLMULTITEXCOORD4IPROC glad_glMultiTexCoord4i = NULL;
+PFNGLMULTITEXCOORD4IVPROC glad_glMultiTexCoord4iv = NULL;
+PFNGLMULTITEXCOORD4SPROC glad_glMultiTexCoord4s = NULL;
+PFNGLMULTITEXCOORD4SVPROC glad_glMultiTexCoord4sv = NULL;
+PFNGLMULTITEXCOORDP1UIPROC glad_glMultiTexCoordP1ui = NULL;
+PFNGLMULTITEXCOORDP1UIVPROC glad_glMultiTexCoordP1uiv = NULL;
+PFNGLMULTITEXCOORDP2UIPROC glad_glMultiTexCoordP2ui = NULL;
+PFNGLMULTITEXCOORDP2UIVPROC glad_glMultiTexCoordP2uiv = NULL;
+PFNGLMULTITEXCOORDP3UIPROC glad_glMultiTexCoordP3ui = NULL;
+PFNGLMULTITEXCOORDP3UIVPROC glad_glMultiTexCoordP3uiv = NULL;
+PFNGLMULTITEXCOORDP4UIPROC glad_glMultiTexCoordP4ui = NULL;
+PFNGLMULTITEXCOORDP4UIVPROC glad_glMultiTexCoordP4uiv = NULL;
+PFNGLNEWLISTPROC glad_glNewList = NULL;
+PFNGLNORMAL3BPROC glad_glNormal3b = NULL;
+PFNGLNORMAL3BVPROC glad_glNormal3bv = NULL;
+PFNGLNORMAL3DPROC glad_glNormal3d = NULL;
+PFNGLNORMAL3DVPROC glad_glNormal3dv = NULL;
+PFNGLNORMAL3FPROC glad_glNormal3f = NULL;
+PFNGLNORMAL3FVPROC glad_glNormal3fv = NULL;
+PFNGLNORMAL3IPROC glad_glNormal3i = NULL;
+PFNGLNORMAL3IVPROC glad_glNormal3iv = NULL;
+PFNGLNORMAL3SPROC glad_glNormal3s = NULL;
+PFNGLNORMAL3SVPROC glad_glNormal3sv = NULL;
+PFNGLNORMALP3UIPROC glad_glNormalP3ui = NULL;
+PFNGLNORMALP3UIVPROC glad_glNormalP3uiv = NULL;
+PFNGLNORMALPOINTERPROC glad_glNormalPointer = NULL;
+PFNGLORTHOPROC glad_glOrtho = NULL;
+PFNGLPASSTHROUGHPROC glad_glPassThrough = NULL;
+PFNGLPIXELMAPFVPROC glad_glPixelMapfv = NULL;
+PFNGLPIXELMAPUIVPROC glad_glPixelMapuiv = NULL;
+PFNGLPIXELMAPUSVPROC glad_glPixelMapusv = NULL;
+PFNGLPIXELSTOREFPROC glad_glPixelStoref = NULL;
+PFNGLPIXELSTOREIPROC glad_glPixelStorei = NULL;
+PFNGLPIXELTRANSFERFPROC glad_glPixelTransferf = NULL;
+PFNGLPIXELTRANSFERIPROC glad_glPixelTransferi = NULL;
+PFNGLPIXELZOOMPROC glad_glPixelZoom = NULL;
+PFNGLPOINTPARAMETERFPROC glad_glPointParameterf = NULL;
+PFNGLPOINTPARAMETERFVPROC glad_glPointParameterfv = NULL;
+PFNGLPOINTPARAMETERIPROC glad_glPointParameteri = NULL;
+PFNGLPOINTPARAMETERIVPROC glad_glPointParameteriv = NULL;
+PFNGLPOINTSIZEPROC glad_glPointSize = NULL;
+PFNGLPOLYGONMODEPROC glad_glPolygonMode = NULL;
+PFNGLPOLYGONOFFSETPROC glad_glPolygonOffset = NULL;
+PFNGLPOLYGONSTIPPLEPROC glad_glPolygonStipple = NULL;
+PFNGLPOPATTRIBPROC glad_glPopAttrib = NULL;
+PFNGLPOPCLIENTATTRIBPROC glad_glPopClientAttrib = NULL;
+PFNGLPOPMATRIXPROC glad_glPopMatrix = NULL;
+PFNGLPOPNAMEPROC glad_glPopName = NULL;
+PFNGLPRIMITIVERESTARTINDEXPROC glad_glPrimitiveRestartIndex = NULL;
+PFNGLPRIORITIZETEXTURESPROC glad_glPrioritizeTextures = NULL;
+PFNGLPROVOKINGVERTEXPROC glad_glProvokingVertex = NULL;
+PFNGLPUSHATTRIBPROC glad_glPushAttrib = NULL;
+PFNGLPUSHCLIENTATTRIBPROC glad_glPushClientAttrib = NULL;
+PFNGLPUSHMATRIXPROC glad_glPushMatrix = NULL;
+PFNGLPUSHNAMEPROC glad_glPushName = NULL;
+PFNGLQUERYCOUNTERPROC glad_glQueryCounter = NULL;
+PFNGLRASTERPOS2DPROC glad_glRasterPos2d = NULL;
+PFNGLRASTERPOS2DVPROC glad_glRasterPos2dv = NULL;
+PFNGLRASTERPOS2FPROC glad_glRasterPos2f = NULL;
+PFNGLRASTERPOS2FVPROC glad_glRasterPos2fv = NULL;
+PFNGLRASTERPOS2IPROC glad_glRasterPos2i = NULL;
+PFNGLRASTERPOS2IVPROC glad_glRasterPos2iv = NULL;
+PFNGLRASTERPOS2SPROC glad_glRasterPos2s = NULL;
+PFNGLRASTERPOS2SVPROC glad_glRasterPos2sv = NULL;
+PFNGLRASTERPOS3DPROC glad_glRasterPos3d = NULL;
+PFNGLRASTERPOS3DVPROC glad_glRasterPos3dv = NULL;
+PFNGLRASTERPOS3FPROC glad_glRasterPos3f = NULL;
+PFNGLRASTERPOS3FVPROC glad_glRasterPos3fv = NULL;
+PFNGLRASTERPOS3IPROC glad_glRasterPos3i = NULL;
+PFNGLRASTERPOS3IVPROC glad_glRasterPos3iv = NULL;
+PFNGLRASTERPOS3SPROC glad_glRasterPos3s = NULL;
+PFNGLRASTERPOS3SVPROC glad_glRasterPos3sv = NULL;
+PFNGLRASTERPOS4DPROC glad_glRasterPos4d = NULL;
+PFNGLRASTERPOS4DVPROC glad_glRasterPos4dv = NULL;
+PFNGLRASTERPOS4FPROC glad_glRasterPos4f = NULL;
+PFNGLRASTERPOS4FVPROC glad_glRasterPos4fv = NULL;
+PFNGLRASTERPOS4IPROC glad_glRasterPos4i = NULL;
+PFNGLRASTERPOS4IVPROC glad_glRasterPos4iv = NULL;
+PFNGLRASTERPOS4SPROC glad_glRasterPos4s = NULL;
+PFNGLRASTERPOS4SVPROC glad_glRasterPos4sv = NULL;
+PFNGLREADBUFFERPROC glad_glReadBuffer = NULL;
+PFNGLREADPIXELSPROC glad_glReadPixels = NULL;
+PFNGLRECTDPROC glad_glRectd = NULL;
+PFNGLRECTDVPROC glad_glRectdv = NULL;
+PFNGLRECTFPROC glad_glRectf = NULL;
+PFNGLRECTFVPROC glad_glRectfv = NULL;
+PFNGLRECTIPROC glad_glRecti = NULL;
+PFNGLRECTIVPROC glad_glRectiv = NULL;
+PFNGLRECTSPROC glad_glRects = NULL;
+PFNGLRECTSVPROC glad_glRectsv = NULL;
+PFNGLRENDERMODEPROC glad_glRenderMode = NULL;
+PFNGLRENDERBUFFERSTORAGEPROC glad_glRenderbufferStorage = NULL;
+PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glad_glRenderbufferStorageMultisample = NULL;
+PFNGLROTATEDPROC glad_glRotated = NULL;
+PFNGLROTATEFPROC glad_glRotatef = NULL;
+PFNGLSAMPLECOVERAGEPROC glad_glSampleCoverage = NULL;
+PFNGLSAMPLEMASKIPROC glad_glSampleMaski = NULL;
+PFNGLSAMPLERPARAMETERIIVPROC glad_glSamplerParameterIiv = NULL;
+PFNGLSAMPLERPARAMETERIUIVPROC glad_glSamplerParameterIuiv = NULL;
+PFNGLSAMPLERPARAMETERFPROC glad_glSamplerParameterf = NULL;
+PFNGLSAMPLERPARAMETERFVPROC glad_glSamplerParameterfv = NULL;
+PFNGLSAMPLERPARAMETERIPROC glad_glSamplerParameteri = NULL;
+PFNGLSAMPLERPARAMETERIVPROC glad_glSamplerParameteriv = NULL;
+PFNGLSCALEDPROC glad_glScaled = NULL;
+PFNGLSCALEFPROC glad_glScalef = NULL;
+PFNGLSCISSORPROC glad_glScissor = NULL;
+PFNGLSECONDARYCOLOR3BPROC glad_glSecondaryColor3b = NULL;
+PFNGLSECONDARYCOLOR3BVPROC glad_glSecondaryColor3bv = NULL;
+PFNGLSECONDARYCOLOR3DPROC glad_glSecondaryColor3d = NULL;
+PFNGLSECONDARYCOLOR3DVPROC glad_glSecondaryColor3dv = NULL;
+PFNGLSECONDARYCOLOR3FPROC glad_glSecondaryColor3f = NULL;
+PFNGLSECONDARYCOLOR3FVPROC glad_glSecondaryColor3fv = NULL;
+PFNGLSECONDARYCOLOR3IPROC glad_glSecondaryColor3i = NULL;
+PFNGLSECONDARYCOLOR3IVPROC glad_glSecondaryColor3iv = NULL;
+PFNGLSECONDARYCOLOR3SPROC glad_glSecondaryColor3s = NULL;
+PFNGLSECONDARYCOLOR3SVPROC glad_glSecondaryColor3sv = NULL;
+PFNGLSECONDARYCOLOR3UBPROC glad_glSecondaryColor3ub = NULL;
+PFNGLSECONDARYCOLOR3UBVPROC glad_glSecondaryColor3ubv = NULL;
+PFNGLSECONDARYCOLOR3UIPROC glad_glSecondaryColor3ui = NULL;
+PFNGLSECONDARYCOLOR3UIVPROC glad_glSecondaryColor3uiv = NULL;
+PFNGLSECONDARYCOLOR3USPROC glad_glSecondaryColor3us = NULL;
+PFNGLSECONDARYCOLOR3USVPROC glad_glSecondaryColor3usv = NULL;
+PFNGLSECONDARYCOLORP3UIPROC glad_glSecondaryColorP3ui = NULL;
+PFNGLSECONDARYCOLORP3UIVPROC glad_glSecondaryColorP3uiv = NULL;
+PFNGLSECONDARYCOLORPOINTERPROC glad_glSecondaryColorPointer = NULL;
+PFNGLSELECTBUFFERPROC glad_glSelectBuffer = NULL;
+PFNGLSHADEMODELPROC glad_glShadeModel = NULL;
+PFNGLSHADERSOURCEPROC glad_glShaderSource = NULL;
+PFNGLSTENCILFUNCPROC glad_glStencilFunc = NULL;
+PFNGLSTENCILFUNCSEPARATEPROC glad_glStencilFuncSeparate = NULL;
+PFNGLSTENCILMASKPROC glad_glStencilMask = NULL;
+PFNGLSTENCILMASKSEPARATEPROC glad_glStencilMaskSeparate = NULL;
+PFNGLSTENCILOPPROC glad_glStencilOp = NULL;
+PFNGLSTENCILOPSEPARATEPROC glad_glStencilOpSeparate = NULL;
+PFNGLTEXBUFFERPROC glad_glTexBuffer = NULL;
+PFNGLTEXCOORD1DPROC glad_glTexCoord1d = NULL;
+PFNGLTEXCOORD1DVPROC glad_glTexCoord1dv = NULL;
+PFNGLTEXCOORD1FPROC glad_glTexCoord1f = NULL;
+PFNGLTEXCOORD1FVPROC glad_glTexCoord1fv = NULL;
+PFNGLTEXCOORD1IPROC glad_glTexCoord1i = NULL;
+PFNGLTEXCOORD1IVPROC glad_glTexCoord1iv = NULL;
+PFNGLTEXCOORD1SPROC glad_glTexCoord1s = NULL;
+PFNGLTEXCOORD1SVPROC glad_glTexCoord1sv = NULL;
+PFNGLTEXCOORD2DPROC glad_glTexCoord2d = NULL;
+PFNGLTEXCOORD2DVPROC glad_glTexCoord2dv = NULL;
+PFNGLTEXCOORD2FPROC glad_glTexCoord2f = NULL;
+PFNGLTEXCOORD2FVPROC glad_glTexCoord2fv = NULL;
+PFNGLTEXCOORD2IPROC glad_glTexCoord2i = NULL;
+PFNGLTEXCOORD2IVPROC glad_glTexCoord2iv = NULL;
+PFNGLTEXCOORD2SPROC glad_glTexCoord2s = NULL;
+PFNGLTEXCOORD2SVPROC glad_glTexCoord2sv = NULL;
+PFNGLTEXCOORD3DPROC glad_glTexCoord3d = NULL;
+PFNGLTEXCOORD3DVPROC glad_glTexCoord3dv = NULL;
+PFNGLTEXCOORD3FPROC glad_glTexCoord3f = NULL;
+PFNGLTEXCOORD3FVPROC glad_glTexCoord3fv = NULL;
+PFNGLTEXCOORD3IPROC glad_glTexCoord3i = NULL;
+PFNGLTEXCOORD3IVPROC glad_glTexCoord3iv = NULL;
+PFNGLTEXCOORD3SPROC glad_glTexCoord3s = NULL;
+PFNGLTEXCOORD3SVPROC glad_glTexCoord3sv = NULL;
+PFNGLTEXCOORD4DPROC glad_glTexCoord4d = NULL;
+PFNGLTEXCOORD4DVPROC glad_glTexCoord4dv = NULL;
+PFNGLTEXCOORD4FPROC glad_glTexCoord4f = NULL;
+PFNGLTEXCOORD4FVPROC glad_glTexCoord4fv = NULL;
+PFNGLTEXCOORD4IPROC glad_glTexCoord4i = NULL;
+PFNGLTEXCOORD4IVPROC glad_glTexCoord4iv = NULL;
+PFNGLTEXCOORD4SPROC glad_glTexCoord4s = NULL;
+PFNGLTEXCOORD4SVPROC glad_glTexCoord4sv = NULL;
+PFNGLTEXCOORDP1UIPROC glad_glTexCoordP1ui = NULL;
+PFNGLTEXCOORDP1UIVPROC glad_glTexCoordP1uiv = NULL;
+PFNGLTEXCOORDP2UIPROC glad_glTexCoordP2ui = NULL;
+PFNGLTEXCOORDP2UIVPROC glad_glTexCoordP2uiv = NULL;
+PFNGLTEXCOORDP3UIPROC glad_glTexCoordP3ui = NULL;
+PFNGLTEXCOORDP3UIVPROC glad_glTexCoordP3uiv = NULL;
+PFNGLTEXCOORDP4UIPROC glad_glTexCoordP4ui = NULL;
+PFNGLTEXCOORDP4UIVPROC glad_glTexCoordP4uiv = NULL;
+PFNGLTEXCOORDPOINTERPROC glad_glTexCoordPointer = NULL;
+PFNGLTEXENVFPROC glad_glTexEnvf = NULL;
+PFNGLTEXENVFVPROC glad_glTexEnvfv = NULL;
+PFNGLTEXENVIPROC glad_glTexEnvi = NULL;
+PFNGLTEXENVIVPROC glad_glTexEnviv = NULL;
+PFNGLTEXGENDPROC glad_glTexGend = NULL;
+PFNGLTEXGENDVPROC glad_glTexGendv = NULL;
+PFNGLTEXGENFPROC glad_glTexGenf = NULL;
+PFNGLTEXGENFVPROC glad_glTexGenfv = NULL;
+PFNGLTEXGENIPROC glad_glTexGeni = NULL;
+PFNGLTEXGENIVPROC glad_glTexGeniv = NULL;
+PFNGLTEXIMAGE1DPROC glad_glTexImage1D = NULL;
+PFNGLTEXIMAGE2DPROC glad_glTexImage2D = NULL;
+PFNGLTEXIMAGE2DMULTISAMPLEPROC glad_glTexImage2DMultisample = NULL;
+PFNGLTEXIMAGE3DPROC glad_glTexImage3D = NULL;
+PFNGLTEXIMAGE3DMULTISAMPLEPROC glad_glTexImage3DMultisample = NULL;
+PFNGLTEXPARAMETERIIVPROC glad_glTexParameterIiv = NULL;
+PFNGLTEXPARAMETERIUIVPROC glad_glTexParameterIuiv = NULL;
+PFNGLTEXPARAMETERFPROC glad_glTexParameterf = NULL;
+PFNGLTEXPARAMETERFVPROC glad_glTexParameterfv = NULL;
+PFNGLTEXPARAMETERIPROC glad_glTexParameteri = NULL;
+PFNGLTEXPARAMETERIVPROC glad_glTexParameteriv = NULL;
+PFNGLTEXSUBIMAGE1DPROC glad_glTexSubImage1D = NULL;
+PFNGLTEXSUBIMAGE2DPROC glad_glTexSubImage2D = NULL;
+PFNGLTEXSUBIMAGE3DPROC glad_glTexSubImage3D = NULL;
+PFNGLTRANSFORMFEEDBACKVARYINGSPROC glad_glTransformFeedbackVaryings = NULL;
+PFNGLTRANSLATEDPROC glad_glTranslated = NULL;
+PFNGLTRANSLATEFPROC glad_glTranslatef = NULL;
+PFNGLUNIFORM1FPROC glad_glUniform1f = NULL;
+PFNGLUNIFORM1FVPROC glad_glUniform1fv = NULL;
+PFNGLUNIFORM1IPROC glad_glUniform1i = NULL;
+PFNGLUNIFORM1IVPROC glad_glUniform1iv = NULL;
+PFNGLUNIFORM1UIPROC glad_glUniform1ui = NULL;
+PFNGLUNIFORM1UIVPROC glad_glUniform1uiv = NULL;
+PFNGLUNIFORM2FPROC glad_glUniform2f = NULL;
+PFNGLUNIFORM2FVPROC glad_glUniform2fv = NULL;
+PFNGLUNIFORM2IPROC glad_glUniform2i = NULL;
+PFNGLUNIFORM2IVPROC glad_glUniform2iv = NULL;
+PFNGLUNIFORM2UIPROC glad_glUniform2ui = NULL;
+PFNGLUNIFORM2UIVPROC glad_glUniform2uiv = NULL;
+PFNGLUNIFORM3FPROC glad_glUniform3f = NULL;
+PFNGLUNIFORM3FVPROC glad_glUniform3fv = NULL;
+PFNGLUNIFORM3IPROC glad_glUniform3i = NULL;
+PFNGLUNIFORM3IVPROC glad_glUniform3iv = NULL;
+PFNGLUNIFORM3UIPROC glad_glUniform3ui = NULL;
+PFNGLUNIFORM3UIVPROC glad_glUniform3uiv = NULL;
+PFNGLUNIFORM4FPROC glad_glUniform4f = NULL;
+PFNGLUNIFORM4FVPROC glad_glUniform4fv = NULL;
+PFNGLUNIFORM4IPROC glad_glUniform4i = NULL;
+PFNGLUNIFORM4IVPROC glad_glUniform4iv = NULL;
+PFNGLUNIFORM4UIPROC glad_glUniform4ui = NULL;
+PFNGLUNIFORM4UIVPROC glad_glUniform4uiv = NULL;
+PFNGLUNIFORMBLOCKBINDINGPROC glad_glUniformBlockBinding = NULL;
+PFNGLUNIFORMMATRIX2FVPROC glad_glUniformMatrix2fv = NULL;
+PFNGLUNIFORMMATRIX2X3FVPROC glad_glUniformMatrix2x3fv = NULL;
+PFNGLUNIFORMMATRIX2X4FVPROC glad_glUniformMatrix2x4fv = NULL;
+PFNGLUNIFORMMATRIX3FVPROC glad_glUniformMatrix3fv = NULL;
+PFNGLUNIFORMMATRIX3X2FVPROC glad_glUniformMatrix3x2fv = NULL;
+PFNGLUNIFORMMATRIX3X4FVPROC glad_glUniformMatrix3x4fv = NULL;
+PFNGLUNIFORMMATRIX4FVPROC glad_glUniformMatrix4fv = NULL;
+PFNGLUNIFORMMATRIX4X2FVPROC glad_glUniformMatrix4x2fv = NULL;
+PFNGLUNIFORMMATRIX4X3FVPROC glad_glUniformMatrix4x3fv = NULL;
+PFNGLUNMAPBUFFERPROC glad_glUnmapBuffer = NULL;
+PFNGLUSEPROGRAMPROC glad_glUseProgram = NULL;
+PFNGLVALIDATEPROGRAMPROC glad_glValidateProgram = NULL;
+PFNGLVERTEX2DPROC glad_glVertex2d = NULL;
+PFNGLVERTEX2DVPROC glad_glVertex2dv = NULL;
+PFNGLVERTEX2FPROC glad_glVertex2f = NULL;
+PFNGLVERTEX2FVPROC glad_glVertex2fv = NULL;
+PFNGLVERTEX2IPROC glad_glVertex2i = NULL;
+PFNGLVERTEX2IVPROC glad_glVertex2iv = NULL;
+PFNGLVERTEX2SPROC glad_glVertex2s = NULL;
+PFNGLVERTEX2SVPROC glad_glVertex2sv = NULL;
+PFNGLVERTEX3DPROC glad_glVertex3d = NULL;
+PFNGLVERTEX3DVPROC glad_glVertex3dv = NULL;
+PFNGLVERTEX3FPROC glad_glVertex3f = NULL;
+PFNGLVERTEX3FVPROC glad_glVertex3fv = NULL;
+PFNGLVERTEX3IPROC glad_glVertex3i = NULL;
+PFNGLVERTEX3IVPROC glad_glVertex3iv = NULL;
+PFNGLVERTEX3SPROC glad_glVertex3s = NULL;
+PFNGLVERTEX3SVPROC glad_glVertex3sv = NULL;
+PFNGLVERTEX4DPROC glad_glVertex4d = NULL;
+PFNGLVERTEX4DVPROC glad_glVertex4dv = NULL;
+PFNGLVERTEX4FPROC glad_glVertex4f = NULL;
+PFNGLVERTEX4FVPROC glad_glVertex4fv = NULL;
+PFNGLVERTEX4IPROC glad_glVertex4i = NULL;
+PFNGLVERTEX4IVPROC glad_glVertex4iv = NULL;
+PFNGLVERTEX4SPROC glad_glVertex4s = NULL;
+PFNGLVERTEX4SVPROC glad_glVertex4sv = NULL;
+PFNGLVERTEXATTRIB1DPROC glad_glVertexAttrib1d = NULL;
+PFNGLVERTEXATTRIB1DVPROC glad_glVertexAttrib1dv = NULL;
+PFNGLVERTEXATTRIB1FPROC glad_glVertexAttrib1f = NULL;
+PFNGLVERTEXATTRIB1FVPROC glad_glVertexAttrib1fv = NULL;
+PFNGLVERTEXATTRIB1SPROC glad_glVertexAttrib1s = NULL;
+PFNGLVERTEXATTRIB1SVPROC glad_glVertexAttrib1sv = NULL;
+PFNGLVERTEXATTRIB2DPROC glad_glVertexAttrib2d = NULL;
+PFNGLVERTEXATTRIB2DVPROC glad_glVertexAttrib2dv = NULL;
+PFNGLVERTEXATTRIB2FPROC glad_glVertexAttrib2f = NULL;
+PFNGLVERTEXATTRIB2FVPROC glad_glVertexAttrib2fv = NULL;
+PFNGLVERTEXATTRIB2SPROC glad_glVertexAttrib2s = NULL;
+PFNGLVERTEXATTRIB2SVPROC glad_glVertexAttrib2sv = NULL;
+PFNGLVERTEXATTRIB3DPROC glad_glVertexAttrib3d = NULL;
+PFNGLVERTEXATTRIB3DVPROC glad_glVertexAttrib3dv = NULL;
+PFNGLVERTEXATTRIB3FPROC glad_glVertexAttrib3f = NULL;
+PFNGLVERTEXATTRIB3FVPROC glad_glVertexAttrib3fv = NULL;
+PFNGLVERTEXATTRIB3SPROC glad_glVertexAttrib3s = NULL;
+PFNGLVERTEXATTRIB3SVPROC glad_glVertexAttrib3sv = NULL;
+PFNGLVERTEXATTRIB4NBVPROC glad_glVertexAttrib4Nbv = NULL;
+PFNGLVERTEXATTRIB4NIVPROC glad_glVertexAttrib4Niv = NULL;
+PFNGLVERTEXATTRIB4NSVPROC glad_glVertexAttrib4Nsv = NULL;
+PFNGLVERTEXATTRIB4NUBPROC glad_glVertexAttrib4Nub = NULL;
+PFNGLVERTEXATTRIB4NUBVPROC glad_glVertexAttrib4Nubv = NULL;
+PFNGLVERTEXATTRIB4NUIVPROC glad_glVertexAttrib4Nuiv = NULL;
+PFNGLVERTEXATTRIB4NUSVPROC glad_glVertexAttrib4Nusv = NULL;
+PFNGLVERTEXATTRIB4BVPROC glad_glVertexAttrib4bv = NULL;
+PFNGLVERTEXATTRIB4DPROC glad_glVertexAttrib4d = NULL;
+PFNGLVERTEXATTRIB4DVPROC glad_glVertexAttrib4dv = NULL;
+PFNGLVERTEXATTRIB4FPROC glad_glVertexAttrib4f = NULL;
+PFNGLVERTEXATTRIB4FVPROC glad_glVertexAttrib4fv = NULL;
+PFNGLVERTEXATTRIB4IVPROC glad_glVertexAttrib4iv = NULL;
+PFNGLVERTEXATTRIB4SPROC glad_glVertexAttrib4s = NULL;
+PFNGLVERTEXATTRIB4SVPROC glad_glVertexAttrib4sv = NULL;
+PFNGLVERTEXATTRIB4UBVPROC glad_glVertexAttrib4ubv = NULL;
+PFNGLVERTEXATTRIB4UIVPROC glad_glVertexAttrib4uiv = NULL;
+PFNGLVERTEXATTRIB4USVPROC glad_glVertexAttrib4usv = NULL;
+PFNGLVERTEXATTRIBDIVISORPROC glad_glVertexAttribDivisor = NULL;
+PFNGLVERTEXATTRIBI1IPROC glad_glVertexAttribI1i = NULL;
+PFNGLVERTEXATTRIBI1IVPROC glad_glVertexAttribI1iv = NULL;
+PFNGLVERTEXATTRIBI1UIPROC glad_glVertexAttribI1ui = NULL;
+PFNGLVERTEXATTRIBI1UIVPROC glad_glVertexAttribI1uiv = NULL;
+PFNGLVERTEXATTRIBI2IPROC glad_glVertexAttribI2i = NULL;
+PFNGLVERTEXATTRIBI2IVPROC glad_glVertexAttribI2iv = NULL;
+PFNGLVERTEXATTRIBI2UIPROC glad_glVertexAttribI2ui = NULL;
+PFNGLVERTEXATTRIBI2UIVPROC glad_glVertexAttribI2uiv = NULL;
+PFNGLVERTEXATTRIBI3IPROC glad_glVertexAttribI3i = NULL;
+PFNGLVERTEXATTRIBI3IVPROC glad_glVertexAttribI3iv = NULL;
+PFNGLVERTEXATTRIBI3UIPROC glad_glVertexAttribI3ui = NULL;
+PFNGLVERTEXATTRIBI3UIVPROC glad_glVertexAttribI3uiv = NULL;
+PFNGLVERTEXATTRIBI4BVPROC glad_glVertexAttribI4bv = NULL;
+PFNGLVERTEXATTRIBI4IPROC glad_glVertexAttribI4i = NULL;
+PFNGLVERTEXATTRIBI4IVPROC glad_glVertexAttribI4iv = NULL;
+PFNGLVERTEXATTRIBI4SVPROC glad_glVertexAttribI4sv = NULL;
+PFNGLVERTEXATTRIBI4UBVPROC glad_glVertexAttribI4ubv = NULL;
+PFNGLVERTEXATTRIBI4UIPROC glad_glVertexAttribI4ui = NULL;
+PFNGLVERTEXATTRIBI4UIVPROC glad_glVertexAttribI4uiv = NULL;
+PFNGLVERTEXATTRIBI4USVPROC glad_glVertexAttribI4usv = NULL;
+PFNGLVERTEXATTRIBIPOINTERPROC glad_glVertexAttribIPointer = NULL;
+PFNGLVERTEXATTRIBP1UIPROC glad_glVertexAttribP1ui = NULL;
+PFNGLVERTEXATTRIBP1UIVPROC glad_glVertexAttribP1uiv = NULL;
+PFNGLVERTEXATTRIBP2UIPROC glad_glVertexAttribP2ui = NULL;
+PFNGLVERTEXATTRIBP2UIVPROC glad_glVertexAttribP2uiv = NULL;
+PFNGLVERTEXATTRIBP3UIPROC glad_glVertexAttribP3ui = NULL;
+PFNGLVERTEXATTRIBP3UIVPROC glad_glVertexAttribP3uiv = NULL;
+PFNGLVERTEXATTRIBP4UIPROC glad_glVertexAttribP4ui = NULL;
+PFNGLVERTEXATTRIBP4UIVPROC glad_glVertexAttribP4uiv = NULL;
+PFNGLVERTEXATTRIBPOINTERPROC glad_glVertexAttribPointer = NULL;
+PFNGLVERTEXP2UIPROC glad_glVertexP2ui = NULL;
+PFNGLVERTEXP2UIVPROC glad_glVertexP2uiv = NULL;
+PFNGLVERTEXP3UIPROC glad_glVertexP3ui = NULL;
+PFNGLVERTEXP3UIVPROC glad_glVertexP3uiv = NULL;
+PFNGLVERTEXP4UIPROC glad_glVertexP4ui = NULL;
+PFNGLVERTEXP4UIVPROC glad_glVertexP4uiv = NULL;
+PFNGLVERTEXPOINTERPROC glad_glVertexPointer = NULL;
+PFNGLVIEWPORTPROC glad_glViewport = NULL;
+PFNGLWAITSYNCPROC glad_glWaitSync = NULL;
+PFNGLWINDOWPOS2DPROC glad_glWindowPos2d = NULL;
+PFNGLWINDOWPOS2DVPROC glad_glWindowPos2dv = NULL;
+PFNGLWINDOWPOS2FPROC glad_glWindowPos2f = NULL;
+PFNGLWINDOWPOS2FVPROC glad_glWindowPos2fv = NULL;
+PFNGLWINDOWPOS2IPROC glad_glWindowPos2i = NULL;
+PFNGLWINDOWPOS2IVPROC glad_glWindowPos2iv = NULL;
+PFNGLWINDOWPOS2SPROC glad_glWindowPos2s = NULL;
+PFNGLWINDOWPOS2SVPROC glad_glWindowPos2sv = NULL;
+PFNGLWINDOWPOS3DPROC glad_glWindowPos3d = NULL;
+PFNGLWINDOWPOS3DVPROC glad_glWindowPos3dv = NULL;
+PFNGLWINDOWPOS3FPROC glad_glWindowPos3f = NULL;
+PFNGLWINDOWPOS3FVPROC glad_glWindowPos3fv = NULL;
+PFNGLWINDOWPOS3IPROC glad_glWindowPos3i = NULL;
+PFNGLWINDOWPOS3IVPROC glad_glWindowPos3iv = NULL;
+PFNGLWINDOWPOS3SPROC glad_glWindowPos3s = NULL;
+PFNGLWINDOWPOS3SVPROC glad_glWindowPos3sv = NULL;
+int GLAD_GL_ARB_debug_output = 0;
+int GLAD_GL_ARB_framebuffer_object = 0;
+int GLAD_GL_EXT_framebuffer_object = 0;
+PFNGLDEBUGMESSAGECONTROLARBPROC glad_glDebugMessageControlARB = NULL;
+PFNGLDEBUGMESSAGEINSERTARBPROC glad_glDebugMessageInsertARB = NULL;
+PFNGLDEBUGMESSAGECALLBACKARBPROC glad_glDebugMessageCallbackARB = NULL;
+PFNGLGETDEBUGMESSAGELOGARBPROC glad_glGetDebugMessageLogARB = NULL;
+PFNGLISRENDERBUFFEREXTPROC glad_glIsRenderbufferEXT = NULL;
+PFNGLBINDRENDERBUFFEREXTPROC glad_glBindRenderbufferEXT = NULL;
+PFNGLDELETERENDERBUFFERSEXTPROC glad_glDeleteRenderbuffersEXT = NULL;
+PFNGLGENRENDERBUFFERSEXTPROC glad_glGenRenderbuffersEXT = NULL;
+PFNGLRENDERBUFFERSTORAGEEXTPROC glad_glRenderbufferStorageEXT = NULL;
+PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC glad_glGetRenderbufferParameterivEXT = NULL;
+PFNGLISFRAMEBUFFEREXTPROC glad_glIsFramebufferEXT = NULL;
+PFNGLBINDFRAMEBUFFEREXTPROC glad_glBindFramebufferEXT = NULL;
+PFNGLDELETEFRAMEBUFFERSEXTPROC glad_glDeleteFramebuffersEXT = NULL;
+PFNGLGENFRAMEBUFFERSEXTPROC glad_glGenFramebuffersEXT = NULL;
+PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glad_glCheckFramebufferStatusEXT = NULL;
+PFNGLFRAMEBUFFERTEXTURE1DEXTPROC glad_glFramebufferTexture1DEXT = NULL;
+PFNGLFRAMEBUFFERTEXTURE2DEXTPROC glad_glFramebufferTexture2DEXT = NULL;
+PFNGLFRAMEBUFFERTEXTURE3DEXTPROC glad_glFramebufferTexture3DEXT = NULL;
+PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC glad_glFramebufferRenderbufferEXT = NULL;
+PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC glad_glGetFramebufferAttachmentParameterivEXT = NULL;
+PFNGLGENERATEMIPMAPEXTPROC glad_glGenerateMipmapEXT = NULL;
static void load_GL_VERSION_1_0(GLADloadproc load) {
if(!GLAD_GL_VERSION_1_0) return;
glad_glCullFace = (PFNGLCULLFACEPROC)load("glCullFace");
diff --git a/thirdparty/glad/glad/glad.h b/thirdparty/glad/glad/glad.h
index 4d92d33b37..52b05e0ae6 100644
--- a/thirdparty/glad/glad/glad.h
+++ b/thirdparty/glad/glad/glad.h
@@ -1,6 +1,6 @@
/*
- OpenGL loader generated by glad 0.1.25 on Sat Jul 28 10:59:43 2018.
+ OpenGL loader generated by glad 0.1.28 on Thu Nov 22 16:50:04 2018.
Language/Generator: C/C++
Specification: gl
@@ -13,11 +13,12 @@
Loader: True
Local files: False
Omit khrplatform: False
+ Reproducible: False
Commandline:
--profile="compatibility" --api="gl=3.3" --generator="c" --spec="gl" --extensions="GL_ARB_debug_output,GL_ARB_framebuffer_object,GL_EXT_framebuffer_object"
Online:
- http://glad.dav1d.de/#profile=compatibility&language=c&specification=gl&loader=on&api=gl%3D3.3&extensions=GL_ARB_debug_output&extensions=GL_ARB_framebuffer_object&extensions=GL_EXT_framebuffer_object
+ https://glad.dav1d.de/#profile=compatibility&language=c&specification=gl&loader=on&api=gl%3D3.3&extensions=GL_ARB_debug_output&extensions=GL_ARB_framebuffer_object&extensions=GL_EXT_framebuffer_object
*/
@@ -46,6 +47,10 @@
#define APIENTRYP APIENTRY *
#endif
+#ifndef GLAPIENTRY
+#define GLAPIENTRY APIENTRY
+#endif
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -89,59 +94,21 @@ GLAPI int gladLoadGL(void);
GLAPI int gladLoadGLLoader(GLADloadproc);
-#include <stddef.h>
#include <KHR/khrplatform.h>
-#ifndef GLEXT_64_TYPES_DEFINED
-/* This code block is duplicated in glxext.h, so must be protected */
-#define GLEXT_64_TYPES_DEFINED
-/* Define int32_t, int64_t, and uint64_t types for UST/MSC */
-/* (as used in the GL_EXT_timer_query extension). */
-#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
-#include <inttypes.h>
-#elif defined(__sun__) || defined(__digital__)
-#include <inttypes.h>
-#if defined(__STDC__)
-#if defined(__arch64__) || defined(_LP64)
-typedef long int int64_t;
-typedef unsigned long int uint64_t;
-#else
-typedef long long int int64_t;
-typedef unsigned long long int uint64_t;
-#endif /* __arch64__ */
-#endif /* __STDC__ */
-#elif defined( __VMS ) || defined(__sgi)
-#include <inttypes.h>
-#elif defined(__SCO__) || defined(__USLC__)
-#include <stdint.h>
-#elif defined(__UNIXOS2__) || defined(__SOL64__)
-typedef long int int32_t;
-typedef long long int int64_t;
-typedef unsigned long long int uint64_t;
-#elif defined(_WIN32) && defined(__GNUC__)
-#include <stdint.h>
-#elif defined(_WIN32)
-typedef __int32 int32_t;
-typedef __int64 int64_t;
-typedef unsigned __int64 uint64_t;
-#else
-/* Fallback if nothing above works */
-#include <inttypes.h>
-#endif
-#endif
typedef unsigned int GLenum;
typedef unsigned char GLboolean;
typedef unsigned int GLbitfield;
typedef void GLvoid;
-typedef signed char GLbyte;
-typedef short GLshort;
+typedef khronos_int8_t GLbyte;
+typedef khronos_uint8_t GLubyte;
+typedef khronos_int16_t GLshort;
+typedef khronos_uint16_t GLushort;
typedef int GLint;
-typedef int GLclampx;
-typedef unsigned char GLubyte;
-typedef unsigned short GLushort;
typedef unsigned int GLuint;
+typedef khronos_int32_t GLclampx;
typedef int GLsizei;
-typedef float GLfloat;
-typedef float GLclampf;
+typedef khronos_float_t GLfloat;
+typedef khronos_float_t GLclampf;
typedef double GLdouble;
typedef double GLclampd;
typedef void *GLeglClientBufferEXT;
@@ -153,25 +120,17 @@ typedef void *GLhandleARB;
#else
typedef unsigned int GLhandleARB;
#endif
-typedef unsigned short GLhalfARB;
-typedef unsigned short GLhalf;
-typedef GLint GLfixed;
+typedef khronos_uint16_t GLhalf;
+typedef khronos_uint16_t GLhalfARB;
+typedef khronos_int32_t GLfixed;
typedef khronos_intptr_t GLintptr;
+typedef khronos_intptr_t GLintptrARB;
typedef khronos_ssize_t GLsizeiptr;
-typedef int64_t GLint64;
-typedef uint64_t GLuint64;
-#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ > 1060)
-typedef long GLintptrARB;
-#else
-typedef ptrdiff_t GLintptrARB;
-#endif
-#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ > 1060)
-typedef long GLsizeiptrARB;
-#else
-typedef ptrdiff_t GLsizeiptrARB;
-#endif
-typedef int64_t GLint64EXT;
-typedef uint64_t GLuint64EXT;
+typedef khronos_ssize_t GLsizeiptrARB;
+typedef khronos_int64_t GLint64;
+typedef khronos_int64_t GLint64EXT;
+typedef khronos_uint64_t GLuint64;
+typedef khronos_uint64_t GLuint64EXT;
typedef struct __GLsync *GLsync;
struct _cl_context;
struct _cl_event;
diff --git a/thirdparty/libogg/ogg/config_types.h b/thirdparty/libogg/ogg/config_types.h
index 5ea49b8abd..e630657547 100644
--- a/thirdparty/libogg/ogg/config_types.h
+++ b/thirdparty/libogg/ogg/config_types.h
@@ -1,7 +1,7 @@
#ifndef __CONFIG_TYPES_H__
#define __CONFIG_TYPES_H__
-#include "int_types.h"
+#include "core/int_types.h"
typedef int16_t ogg_int16_t;
typedef uint16_t ogg_uint16_t;
diff --git a/thirdparty/libvpx/vpx_config.h b/thirdparty/libvpx/vpx_config.h
index fb9e13c4ad..6caec50c81 100644
--- a/thirdparty/libvpx/vpx_config.h
+++ b/thirdparty/libvpx/vpx_config.h
@@ -67,6 +67,12 @@
#define CONFIG_BIG_ENDIAN 0 //TODO: Autodetect
+#ifdef __EMSCRIPTEN__
+#define CONFIG_MULTITHREAD 0
+#else
+#define CONFIG_MULTITHREAD 1
+#endif
+
#ifdef _WIN32
#define HAVE_PTHREAD_H 0
#define HAVE_UNISTD_H 0
@@ -95,7 +101,6 @@
#define CONFIG_RUNTIME_CPU_DETECT 1
#define CONFIG_POSTPROC 0
#define CONFIG_VP9_POSTPROC 0
-#define CONFIG_MULTITHREAD 1
#define CONFIG_INTERNAL_STATS 0
#define CONFIG_VP8_ENCODER 0
#define CONFIG_VP8_DECODER 1
diff --git a/thirdparty/libwebp/src/dec/alphai_dec.h b/thirdparty/libwebp/src/dec/alphai_dec.h
index e0fa281a55..a64104abeb 100644
--- a/thirdparty/libwebp/src/dec/alphai_dec.h
+++ b/thirdparty/libwebp/src/dec/alphai_dec.h
@@ -51,4 +51,4 @@ void WebPDeallocateAlphaMemory(VP8Decoder* const dec);
} // extern "C"
#endif
-#endif /* WEBP_DEC_ALPHAI_DEC_H_ */
+#endif // WEBP_DEC_ALPHAI_DEC_H_
diff --git a/thirdparty/libwebp/src/dec/buffer_dec.c b/thirdparty/libwebp/src/dec/buffer_dec.c
index 75eb3c40b4..3cd94eb4d9 100644
--- a/thirdparty/libwebp/src/dec/buffer_dec.c
+++ b/thirdparty/libwebp/src/dec/buffer_dec.c
@@ -74,7 +74,8 @@ static VP8StatusCode CheckDecBuffer(const WebPDecBuffer* const buffer) {
} else { // RGB checks
const WebPRGBABuffer* const buf = &buffer->u.RGBA;
const int stride = abs(buf->stride);
- const uint64_t size = MIN_BUFFER_SIZE(width, height, stride);
+ const uint64_t size =
+ MIN_BUFFER_SIZE(width * kModeBpp[mode], height, stride);
ok &= (size <= buf->size);
ok &= (stride >= width * kModeBpp[mode]);
ok &= (buf->rgba != NULL);
diff --git a/thirdparty/libwebp/src/dec/common_dec.h b/thirdparty/libwebp/src/dec/common_dec.h
index 9995f1a51a..b158550a80 100644
--- a/thirdparty/libwebp/src/dec/common_dec.h
+++ b/thirdparty/libwebp/src/dec/common_dec.h
@@ -51,4 +51,4 @@ enum { MB_FEATURE_TREE_PROBS = 3,
NUM_PROBAS = 11
};
-#endif // WEBP_DEC_COMMON_DEC_H_
+#endif // WEBP_DEC_COMMON_DEC_H_
diff --git a/thirdparty/libwebp/src/dec/frame_dec.c b/thirdparty/libwebp/src/dec/frame_dec.c
index a9d5430d00..bda9e1a6f6 100644
--- a/thirdparty/libwebp/src/dec/frame_dec.c
+++ b/thirdparty/libwebp/src/dec/frame_dec.c
@@ -338,7 +338,6 @@ void VP8InitDithering(const WebPDecoderOptions* const options,
for (s = 0; s < NUM_MB_SEGMENTS; ++s) {
VP8QuantMatrix* const dqm = &dec->dqm_[s];
if (dqm->uv_quant_ < DITHER_AMP_TAB_SIZE) {
- // TODO(skal): should we specially dither more for uv_quant_ < 0?
const int idx = (dqm->uv_quant_ < 0) ? 0 : dqm->uv_quant_;
dqm->dither_ = (f * kQuantToDitherAmp[idx]) >> 3;
}
@@ -669,15 +668,9 @@ int VP8GetThreadMethod(const WebPDecoderOptions* const options,
(void)height;
assert(headers == NULL || !headers->is_lossless);
#if defined(WEBP_USE_THREAD)
- if (width < MIN_WIDTH_FOR_THREADS) return 0;
- // TODO(skal): tune the heuristic further
-#if 0
- if (height < 2 * width) return 2;
+ if (width >= MIN_WIDTH_FOR_THREADS) return 2;
#endif
- return 2;
-#else // !WEBP_USE_THREAD
return 0;
-#endif
}
#undef MT_CACHE_LINES
diff --git a/thirdparty/libwebp/src/dec/idec_dec.c b/thirdparty/libwebp/src/dec/idec_dec.c
index a371ed7500..9bc9166808 100644
--- a/thirdparty/libwebp/src/dec/idec_dec.c
+++ b/thirdparty/libwebp/src/dec/idec_dec.c
@@ -140,10 +140,9 @@ static void DoRemap(WebPIDecoder* const idec, ptrdiff_t offset) {
if (NeedCompressedAlpha(idec)) {
ALPHDecoder* const alph_dec = dec->alph_dec_;
dec->alpha_data_ += offset;
- if (alph_dec != NULL) {
+ if (alph_dec != NULL && alph_dec->vp8l_dec_ != NULL) {
if (alph_dec->method_ == ALPHA_LOSSLESS_COMPRESSION) {
VP8LDecoder* const alph_vp8l_dec = alph_dec->vp8l_dec_;
- assert(alph_vp8l_dec != NULL);
assert(dec->alpha_data_size_ >= ALPHA_HEADER_LEN);
VP8LBitReaderSetBuffer(&alph_vp8l_dec->br_,
dec->alpha_data_ + ALPHA_HEADER_LEN,
@@ -283,10 +282,8 @@ static void RestoreContext(const MBContext* context, VP8Decoder* const dec,
static VP8StatusCode IDecError(WebPIDecoder* const idec, VP8StatusCode error) {
if (idec->state_ == STATE_VP8_DATA) {
- VP8Io* const io = &idec->io_;
- if (io->teardown != NULL) {
- io->teardown(io);
- }
+ // Synchronize the thread, clean-up and check for errors.
+ VP8ExitCritical((VP8Decoder*)idec->dec_, &idec->io_);
}
idec->state_ = STATE_ERROR;
return error;
@@ -451,7 +448,10 @@ static VP8StatusCode DecodeRemaining(WebPIDecoder* const idec) {
VP8Decoder* const dec = (VP8Decoder*)idec->dec_;
VP8Io* const io = &idec->io_;
- assert(dec->ready_);
+ // Make sure partition #0 has been read before, to set dec to ready_.
+ if (!dec->ready_) {
+ return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR);
+ }
for (; dec->mb_y_ < dec->mb_h_; ++dec->mb_y_) {
if (idec->last_mb_y_ != dec->mb_y_) {
if (!VP8ParseIntraModeRow(&dec->br_, dec)) {
@@ -473,6 +473,12 @@ static VP8StatusCode DecodeRemaining(WebPIDecoder* const idec) {
MemDataSize(&idec->mem_) > MAX_MB_SIZE) {
return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR);
}
+ // Synchronize the threads.
+ if (dec->mt_method_ > 0) {
+ if (!WebPGetWorkerInterface()->Sync(&dec->worker_)) {
+ return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR);
+ }
+ }
RestoreContext(&context, dec, token_br);
return VP8_STATUS_SUSPENDED;
}
@@ -491,6 +497,7 @@ static VP8StatusCode DecodeRemaining(WebPIDecoder* const idec) {
}
// Synchronize the thread and check for errors.
if (!VP8ExitCritical(dec, io)) {
+ idec->state_ = STATE_ERROR; // prevent re-entry in IDecError
return IDecError(idec, VP8_STATUS_USER_ABORT);
}
dec->ready_ = 0;
@@ -571,6 +578,10 @@ static VP8StatusCode IDecode(WebPIDecoder* idec) {
status = DecodePartition0(idec);
}
if (idec->state_ == STATE_VP8_DATA) {
+ const VP8Decoder* const dec = (VP8Decoder*)idec->dec_;
+ if (dec == NULL) {
+ return VP8_STATUS_SUSPENDED; // can't continue if we have no decoder.
+ }
status = DecodeRemaining(idec);
}
if (idec->state_ == STATE_VP8L_HEADER) {
diff --git a/thirdparty/libwebp/src/dec/vp8_dec.h b/thirdparty/libwebp/src/dec/vp8_dec.h
index ca85b340cf..a05405df72 100644
--- a/thirdparty/libwebp/src/dec/vp8_dec.h
+++ b/thirdparty/libwebp/src/dec/vp8_dec.h
@@ -182,4 +182,4 @@ WEBP_EXTERN int VP8LGetInfo(
} // extern "C"
#endif
-#endif /* WEBP_DEC_VP8_DEC_H_ */
+#endif // WEBP_DEC_VP8_DEC_H_
diff --git a/thirdparty/libwebp/src/dec/vp8i_dec.h b/thirdparty/libwebp/src/dec/vp8i_dec.h
index c929933e1c..e5e89df57d 100644
--- a/thirdparty/libwebp/src/dec/vp8i_dec.h
+++ b/thirdparty/libwebp/src/dec/vp8i_dec.h
@@ -32,7 +32,7 @@ extern "C" {
// version numbers
#define DEC_MAJ_VERSION 1
#define DEC_MIN_VERSION 0
-#define DEC_REV_VERSION 0
+#define DEC_REV_VERSION 1
// YUV-cache parameters. Cache is 32-bytes wide (= one cacheline).
// Constraints are: We need to store one 16x16 block of luma samples (y),
@@ -316,4 +316,4 @@ const uint8_t* VP8DecompressAlphaRows(VP8Decoder* const dec,
} // extern "C"
#endif
-#endif /* WEBP_DEC_VP8I_DEC_H_ */
+#endif // WEBP_DEC_VP8I_DEC_H_
diff --git a/thirdparty/libwebp/src/dec/vp8l_dec.c b/thirdparty/libwebp/src/dec/vp8l_dec.c
index 0570f53a77..333bb3e80d 100644
--- a/thirdparty/libwebp/src/dec/vp8l_dec.c
+++ b/thirdparty/libwebp/src/dec/vp8l_dec.c
@@ -362,12 +362,19 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
VP8LMetadata* const hdr = &dec->hdr_;
uint32_t* huffman_image = NULL;
HTreeGroup* htree_groups = NULL;
+ // When reading htrees, some might be unused, as the format allows it.
+ // We will still read them but put them in this htree_group_bogus.
+ HTreeGroup htree_group_bogus;
HuffmanCode* huffman_tables = NULL;
+ HuffmanCode* huffman_tables_bogus = NULL;
HuffmanCode* next = NULL;
int num_htree_groups = 1;
+ int num_htree_groups_max = 1;
int max_alphabet_size = 0;
int* code_lengths = NULL;
const int table_size = kTableSize[color_cache_bits];
+ int* mapping = NULL;
+ int ok = 0;
if (allow_recursion && VP8LReadBits(br, 1)) {
// use meta Huffman codes.
@@ -384,9 +391,41 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
// The huffman data is stored in red and green bytes.
const int group = (huffman_image[i] >> 8) & 0xffff;
huffman_image[i] = group;
- if (group >= num_htree_groups) {
- num_htree_groups = group + 1;
+ if (group >= num_htree_groups_max) {
+ num_htree_groups_max = group + 1;
+ }
+ }
+ // Check the validity of num_htree_groups_max. If it seems too big, use a
+ // smaller value for later. This will prevent big memory allocations to end
+ // up with a bad bitstream anyway.
+ // The value of 1000 is totally arbitrary. We know that num_htree_groups_max
+ // is smaller than (1 << 16) and should be smaller than the number of pixels
+ // (though the format allows it to be bigger).
+ if (num_htree_groups_max > 1000 || num_htree_groups_max > xsize * ysize) {
+ // Create a mapping from the used indices to the minimal set of used
+ // values [0, num_htree_groups)
+ mapping = (int*)WebPSafeMalloc(num_htree_groups_max, sizeof(*mapping));
+ if (mapping == NULL) {
+ dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
+ goto Error;
+ }
+ // -1 means a value is unmapped, and therefore unused in the Huffman
+ // image.
+ memset(mapping, 0xff, num_htree_groups_max * sizeof(*mapping));
+ for (num_htree_groups = 0, i = 0; i < huffman_pixs; ++i) {
+ // Get the current mapping for the group and remap the Huffman image.
+ int* const mapped_group = &mapping[huffman_image[i]];
+ if (*mapped_group == -1) *mapped_group = num_htree_groups++;
+ huffman_image[i] = *mapped_group;
+ }
+ huffman_tables_bogus = (HuffmanCode*)WebPSafeMalloc(
+ table_size, sizeof(*huffman_tables_bogus));
+ if (huffman_tables_bogus == NULL) {
+ dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
+ goto Error;
}
+ } else {
+ num_htree_groups = num_htree_groups_max;
}
}
@@ -403,11 +442,11 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
}
}
+ code_lengths = (int*)WebPSafeCalloc((uint64_t)max_alphabet_size,
+ sizeof(*code_lengths));
huffman_tables = (HuffmanCode*)WebPSafeMalloc(num_htree_groups * table_size,
sizeof(*huffman_tables));
htree_groups = VP8LHtreeGroupsNew(num_htree_groups);
- code_lengths = (int*)WebPSafeCalloc((uint64_t)max_alphabet_size,
- sizeof(*code_lengths));
if (htree_groups == NULL || code_lengths == NULL || huffman_tables == NULL) {
dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
@@ -415,28 +454,35 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
}
next = huffman_tables;
- for (i = 0; i < num_htree_groups; ++i) {
- HTreeGroup* const htree_group = &htree_groups[i];
+ for (i = 0; i < num_htree_groups_max; ++i) {
+ // If the index "i" is unused in the Huffman image, read the coefficients
+ // but store them to a bogus htree_group.
+ const int is_bogus = (mapping != NULL && mapping[i] == -1);
+ HTreeGroup* const htree_group =
+ is_bogus ? &htree_group_bogus :
+ &htree_groups[(mapping == NULL) ? i : mapping[i]];
HuffmanCode** const htrees = htree_group->htrees;
+ HuffmanCode* huffman_tables_i = is_bogus ? huffman_tables_bogus : next;
int size;
int total_size = 0;
int is_trivial_literal = 1;
int max_bits = 0;
for (j = 0; j < HUFFMAN_CODES_PER_META_CODE; ++j) {
int alphabet_size = kAlphabetSize[j];
- htrees[j] = next;
+ htrees[j] = huffman_tables_i;
if (j == 0 && color_cache_bits > 0) {
alphabet_size += 1 << color_cache_bits;
}
- size = ReadHuffmanCode(alphabet_size, dec, code_lengths, next);
+ size =
+ ReadHuffmanCode(alphabet_size, dec, code_lengths, huffman_tables_i);
if (size == 0) {
goto Error;
}
if (is_trivial_literal && kLiteralMap[j] == 1) {
- is_trivial_literal = (next->bits == 0);
+ is_trivial_literal = (huffman_tables_i->bits == 0);
}
- total_size += next->bits;
- next += size;
+ total_size += huffman_tables_i->bits;
+ huffman_tables_i += size;
if (j <= ALPHA) {
int local_max_bits = code_lengths[0];
int k;
@@ -448,38 +494,41 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
max_bits += local_max_bits;
}
}
+ if (!is_bogus) next = huffman_tables_i;
htree_group->is_trivial_literal = is_trivial_literal;
htree_group->is_trivial_code = 0;
if (is_trivial_literal) {
const int red = htrees[RED][0].value;
const int blue = htrees[BLUE][0].value;
const int alpha = htrees[ALPHA][0].value;
- htree_group->literal_arb =
- ((uint32_t)alpha << 24) | (red << 16) | blue;
+ htree_group->literal_arb = ((uint32_t)alpha << 24) | (red << 16) | blue;
if (total_size == 0 && htrees[GREEN][0].value < NUM_LITERAL_CODES) {
htree_group->is_trivial_code = 1;
htree_group->literal_arb |= htrees[GREEN][0].value << 8;
}
}
- htree_group->use_packed_table = !htree_group->is_trivial_code &&
- (max_bits < HUFFMAN_PACKED_BITS);
+ htree_group->use_packed_table =
+ !htree_group->is_trivial_code && (max_bits < HUFFMAN_PACKED_BITS);
if (htree_group->use_packed_table) BuildPackedTable(htree_group);
}
- WebPSafeFree(code_lengths);
+ ok = 1;
- // All OK. Finalize pointers and return.
+ // All OK. Finalize pointers.
hdr->huffman_image_ = huffman_image;
hdr->num_htree_groups_ = num_htree_groups;
hdr->htree_groups_ = htree_groups;
hdr->huffman_tables_ = huffman_tables;
- return 1;
Error:
WebPSafeFree(code_lengths);
- WebPSafeFree(huffman_image);
- WebPSafeFree(huffman_tables);
- VP8LHtreeGroupsFree(htree_groups);
- return 0;
+ WebPSafeFree(huffman_tables_bogus);
+ WebPSafeFree(mapping);
+ if (!ok) {
+ WebPSafeFree(huffman_image);
+ WebPSafeFree(huffman_tables);
+ VP8LHtreeGroupsFree(htree_groups);
+ }
+ return ok;
}
//------------------------------------------------------------------------------
@@ -884,7 +933,11 @@ static WEBP_INLINE void CopyBlock8b(uint8_t* const dst, int dist, int length) {
#endif
break;
case 2:
+#if !defined(WORDS_BIGENDIAN)
memcpy(&pattern, src, sizeof(uint16_t));
+#else
+ pattern = ((uint32_t)src[0] << 8) | src[1];
+#endif
#if defined(__arm__) || defined(_M_ARM)
pattern |= pattern << 16;
#elif defined(WEBP_USE_MIPS_DSP_R2)
@@ -1523,7 +1576,6 @@ int VP8LDecodeAlphaHeader(ALPHDecoder* const alph_dec,
if (dec == NULL) return 0;
assert(alph_dec != NULL);
- alph_dec->vp8l_dec_ = dec;
dec->width_ = alph_dec->width_;
dec->height_ = alph_dec->height_;
@@ -1555,11 +1607,12 @@ int VP8LDecodeAlphaHeader(ALPHDecoder* const alph_dec,
if (!ok) goto Err;
+ // Only set here, once we are sure it is valid (to avoid thread races).
+ alph_dec->vp8l_dec_ = dec;
return 1;
Err:
- VP8LDelete(alph_dec->vp8l_dec_);
- alph_dec->vp8l_dec_ = NULL;
+ VP8LDelete(dec);
return 0;
}
diff --git a/thirdparty/libwebp/src/dec/vp8li_dec.h b/thirdparty/libwebp/src/dec/vp8li_dec.h
index 8e500cf9ff..0a4d613f99 100644
--- a/thirdparty/libwebp/src/dec/vp8li_dec.h
+++ b/thirdparty/libwebp/src/dec/vp8li_dec.h
@@ -132,4 +132,4 @@ void VP8LDelete(VP8LDecoder* const dec);
} // extern "C"
#endif
-#endif /* WEBP_DEC_VP8LI_DEC_H_ */
+#endif // WEBP_DEC_VP8LI_DEC_H_
diff --git a/thirdparty/libwebp/src/dec/webpi_dec.h b/thirdparty/libwebp/src/dec/webpi_dec.h
index c378ba6fc3..24baff5d27 100644
--- a/thirdparty/libwebp/src/dec/webpi_dec.h
+++ b/thirdparty/libwebp/src/dec/webpi_dec.h
@@ -130,4 +130,4 @@ int WebPAvoidSlowMemory(const WebPDecBuffer* const output,
} // extern "C"
#endif
-#endif /* WEBP_DEC_WEBPI_DEC_H_ */
+#endif // WEBP_DEC_WEBPI_DEC_H_
diff --git a/thirdparty/libwebp/src/demux/demux.c b/thirdparty/libwebp/src/demux/demux.c
index 684215e3de..a69c65b7cf 100644
--- a/thirdparty/libwebp/src/demux/demux.c
+++ b/thirdparty/libwebp/src/demux/demux.c
@@ -25,7 +25,7 @@
#define DMUX_MAJ_VERSION 1
#define DMUX_MIN_VERSION 0
-#define DMUX_REV_VERSION 0
+#define DMUX_REV_VERSION 1
typedef struct {
size_t start_; // start location of the data
diff --git a/thirdparty/libwebp/src/dsp/dsp.h b/thirdparty/libwebp/src/dsp/dsp.h
index 4ab77a5130..fafc2d05d3 100644
--- a/thirdparty/libwebp/src/dsp/dsp.h
+++ b/thirdparty/libwebp/src/dsp/dsp.h
@@ -76,10 +76,6 @@ extern "C" {
#define WEBP_USE_SSE41
#endif
-#if defined(__AVX2__) || defined(WEBP_HAVE_AVX2)
-#define WEBP_USE_AVX2
-#endif
-
// The intrinsics currently cause compiler errors with arm-nacl-gcc and the
// inline assembly would need to be modified for use with Native Client.
#if (defined(__ARM_NEON__) || \
@@ -679,4 +675,4 @@ void VP8FiltersInit(void);
} // extern "C"
#endif
-#endif /* WEBP_DSP_DSP_H_ */
+#endif // WEBP_DSP_DSP_H_
diff --git a/thirdparty/libwebp/src/dsp/enc.c b/thirdparty/libwebp/src/dsp/enc.c
index fa23b40a30..2fddbc4c52 100644
--- a/thirdparty/libwebp/src/dsp/enc.c
+++ b/thirdparty/libwebp/src/dsp/enc.c
@@ -734,7 +734,6 @@ VP8BlockCopy VP8Copy16x8;
extern void VP8EncDspInitSSE2(void);
extern void VP8EncDspInitSSE41(void);
-extern void VP8EncDspInitAVX2(void);
extern void VP8EncDspInitNEON(void);
extern void VP8EncDspInitMIPS32(void);
extern void VP8EncDspInitMIPSdspR2(void);
@@ -784,11 +783,6 @@ WEBP_DSP_INIT_FUNC(VP8EncDspInit) {
#endif
}
#endif
-#if defined(WEBP_USE_AVX2)
- if (VP8GetCPUInfo(kAVX2)) {
- VP8EncDspInitAVX2();
- }
-#endif
#if defined(WEBP_USE_MIPS32)
if (VP8GetCPUInfo(kMIPS32)) {
VP8EncDspInitMIPS32();
diff --git a/thirdparty/libwebp/src/dsp/enc_avx2.c b/thirdparty/libwebp/src/dsp/enc_avx2.c
deleted file mode 100644
index 8bc5798fee..0000000000
--- a/thirdparty/libwebp/src/dsp/enc_avx2.c
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright 2014 Google Inc. All Rights Reserved.
-//
-// Use of this source code is governed by a BSD-style license
-// that can be found in the COPYING file in the root of the source
-// tree. An additional intellectual property rights grant can be found
-// in the file PATENTS. All contributing project authors may
-// be found in the AUTHORS file in the root of the source tree.
-// -----------------------------------------------------------------------------
-//
-// AVX2 version of speed-critical encoding functions.
-
-#include "src/dsp/dsp.h"
-
-#if defined(WEBP_USE_AVX2)
-
-#endif // WEBP_USE_AVX2
-
-//------------------------------------------------------------------------------
-// Entry point
-
-WEBP_DSP_INIT_STUB(VP8EncDspInitAVX2)
diff --git a/thirdparty/libwebp/src/dsp/lossless.c b/thirdparty/libwebp/src/dsp/lossless.c
index f9b3c182d3..d21aa6a0a0 100644
--- a/thirdparty/libwebp/src/dsp/lossless.c
+++ b/thirdparty/libwebp/src/dsp/lossless.c
@@ -23,8 +23,6 @@
#include "src/dsp/lossless.h"
#include "src/dsp/lossless_common.h"
-#define MAX_DIFF_COST (1e30f)
-
//------------------------------------------------------------------------------
// Image transforms.
diff --git a/thirdparty/libwebp/src/dsp/lossless.h b/thirdparty/libwebp/src/dsp/lossless.h
index b2bbdfc93c..f709cc86b2 100644
--- a/thirdparty/libwebp/src/dsp/lossless.h
+++ b/thirdparty/libwebp/src/dsp/lossless.h
@@ -163,7 +163,7 @@ extern VP8LCostCombinedFunc VP8LExtraCostCombined;
extern VP8LCombinedShannonEntropyFunc VP8LCombinedShannonEntropy;
typedef struct { // small struct to hold counters
- int counts[2]; // index: 0=zero steak, 1=non-zero streak
+ int counts[2]; // index: 0=zero streak, 1=non-zero streak
int streaks[2][2]; // [zero/non-zero][streak<3 / streak>=3]
} VP8LStreaks;
@@ -194,10 +194,14 @@ extern VP8LGetEntropyUnrefinedFunc VP8LGetEntropyUnrefined;
void VP8LBitsEntropyUnrefined(const uint32_t* const array, int n,
VP8LBitEntropy* const entropy);
-typedef void (*VP8LHistogramAddFunc)(const VP8LHistogram* const a,
- const VP8LHistogram* const b,
- VP8LHistogram* const out);
-extern VP8LHistogramAddFunc VP8LHistogramAdd;
+typedef void (*VP8LAddVectorFunc)(const uint32_t* a, const uint32_t* b,
+ uint32_t* out, int size);
+extern VP8LAddVectorFunc VP8LAddVector;
+typedef void (*VP8LAddVectorEqFunc)(const uint32_t* a, uint32_t* out, int size);
+extern VP8LAddVectorEqFunc VP8LAddVectorEq;
+void VP8LHistogramAdd(const VP8LHistogram* const a,
+ const VP8LHistogram* const b,
+ VP8LHistogram* const out);
// -----------------------------------------------------------------------------
// PrefixEncode()
diff --git a/thirdparty/libwebp/src/dsp/lossless_enc.c b/thirdparty/libwebp/src/dsp/lossless_enc.c
index d608326fef..1408fbf580 100644
--- a/thirdparty/libwebp/src/dsp/lossless_enc.c
+++ b/thirdparty/libwebp/src/dsp/lossless_enc.c
@@ -632,38 +632,67 @@ static double ExtraCostCombined_C(const uint32_t* X, const uint32_t* Y,
//------------------------------------------------------------------------------
-static void HistogramAdd_C(const VP8LHistogram* const a,
- const VP8LHistogram* const b,
- VP8LHistogram* const out) {
+static void AddVector_C(const uint32_t* a, const uint32_t* b, uint32_t* out,
+ int size) {
+ int i;
+ for (i = 0; i < size; ++i) out[i] = a[i] + b[i];
+}
+
+static void AddVectorEq_C(const uint32_t* a, uint32_t* out, int size) {
+ int i;
+ for (i = 0; i < size; ++i) out[i] += a[i];
+}
+
+#define ADD(X, ARG, LEN) do { \
+ if (a->is_used_[X]) { \
+ if (b->is_used_[X]) { \
+ VP8LAddVector(a->ARG, b->ARG, out->ARG, (LEN)); \
+ } else { \
+ memcpy(&out->ARG[0], &a->ARG[0], (LEN) * sizeof(out->ARG[0])); \
+ } \
+ } else if (b->is_used_[X]) { \
+ memcpy(&out->ARG[0], &b->ARG[0], (LEN) * sizeof(out->ARG[0])); \
+ } else { \
+ memset(&out->ARG[0], 0, (LEN) * sizeof(out->ARG[0])); \
+ } \
+} while (0)
+
+#define ADD_EQ(X, ARG, LEN) do { \
+ if (a->is_used_[X]) { \
+ if (out->is_used_[X]) { \
+ VP8LAddVectorEq(a->ARG, out->ARG, (LEN)); \
+ } else { \
+ memcpy(&out->ARG[0], &a->ARG[0], (LEN) * sizeof(out->ARG[0])); \
+ } \
+ } \
+} while (0)
+
+void VP8LHistogramAdd(const VP8LHistogram* const a,
+ const VP8LHistogram* const b, VP8LHistogram* const out) {
int i;
const int literal_size = VP8LHistogramNumCodes(a->palette_code_bits_);
assert(a->palette_code_bits_ == b->palette_code_bits_);
+
if (b != out) {
- for (i = 0; i < literal_size; ++i) {
- out->literal_[i] = a->literal_[i] + b->literal_[i];
- }
- for (i = 0; i < NUM_DISTANCE_CODES; ++i) {
- out->distance_[i] = a->distance_[i] + b->distance_[i];
- }
- for (i = 0; i < NUM_LITERAL_CODES; ++i) {
- out->red_[i] = a->red_[i] + b->red_[i];
- out->blue_[i] = a->blue_[i] + b->blue_[i];
- out->alpha_[i] = a->alpha_[i] + b->alpha_[i];
+ ADD(0, literal_, literal_size);
+ ADD(1, red_, NUM_LITERAL_CODES);
+ ADD(2, blue_, NUM_LITERAL_CODES);
+ ADD(3, alpha_, NUM_LITERAL_CODES);
+ ADD(4, distance_, NUM_DISTANCE_CODES);
+ for (i = 0; i < 5; ++i) {
+ out->is_used_[i] = (a->is_used_[i] | b->is_used_[i]);
}
} else {
- for (i = 0; i < literal_size; ++i) {
- out->literal_[i] += a->literal_[i];
- }
- for (i = 0; i < NUM_DISTANCE_CODES; ++i) {
- out->distance_[i] += a->distance_[i];
- }
- for (i = 0; i < NUM_LITERAL_CODES; ++i) {
- out->red_[i] += a->red_[i];
- out->blue_[i] += a->blue_[i];
- out->alpha_[i] += a->alpha_[i];
- }
+ ADD_EQ(0, literal_, literal_size);
+ ADD_EQ(1, red_, NUM_LITERAL_CODES);
+ ADD_EQ(2, blue_, NUM_LITERAL_CODES);
+ ADD_EQ(3, alpha_, NUM_LITERAL_CODES);
+ ADD_EQ(4, distance_, NUM_DISTANCE_CODES);
+ for (i = 0; i < 5; ++i) out->is_used_[i] |= a->is_used_[i];
}
}
+#undef ADD
+#undef ADD_EQ
//------------------------------------------------------------------------------
// Image transforms.
@@ -848,7 +877,8 @@ VP8LCombinedShannonEntropyFunc VP8LCombinedShannonEntropy;
VP8LGetEntropyUnrefinedFunc VP8LGetEntropyUnrefined;
VP8LGetCombinedEntropyUnrefinedFunc VP8LGetCombinedEntropyUnrefined;
-VP8LHistogramAddFunc VP8LHistogramAdd;
+VP8LAddVectorFunc VP8LAddVector;
+VP8LAddVectorEqFunc VP8LAddVectorEq;
VP8LVectorMismatchFunc VP8LVectorMismatch;
VP8LBundleColorMapFunc VP8LBundleColorMap;
@@ -885,7 +915,8 @@ WEBP_DSP_INIT_FUNC(VP8LEncDspInit) {
VP8LGetEntropyUnrefined = GetEntropyUnrefined_C;
VP8LGetCombinedEntropyUnrefined = GetCombinedEntropyUnrefined_C;
- VP8LHistogramAdd = HistogramAdd_C;
+ VP8LAddVector = AddVector_C;
+ VP8LAddVectorEq = AddVectorEq_C;
VP8LVectorMismatch = VectorMismatch_C;
VP8LBundleColorMap = VP8LBundleColorMap_C;
@@ -971,7 +1002,8 @@ WEBP_DSP_INIT_FUNC(VP8LEncDspInit) {
assert(VP8LCombinedShannonEntropy != NULL);
assert(VP8LGetEntropyUnrefined != NULL);
assert(VP8LGetCombinedEntropyUnrefined != NULL);
- assert(VP8LHistogramAdd != NULL);
+ assert(VP8LAddVector != NULL);
+ assert(VP8LAddVectorEq != NULL);
assert(VP8LVectorMismatch != NULL);
assert(VP8LBundleColorMap != NULL);
assert(VP8LPredictorsSub[0] != NULL);
diff --git a/thirdparty/libwebp/src/dsp/lossless_enc_mips32.c b/thirdparty/libwebp/src/dsp/lossless_enc_mips32.c
index e7b58f4e8c..0412a093cf 100644
--- a/thirdparty/libwebp/src/dsp/lossless_enc_mips32.c
+++ b/thirdparty/libwebp/src/dsp/lossless_enc_mips32.c
@@ -344,65 +344,29 @@ static void GetCombinedEntropyUnrefined_MIPS32(const uint32_t X[],
ASM_END_COMMON_0 \
ASM_END_COMMON_1
-#define ADD_VECTOR(A, B, OUT, SIZE, EXTRA_SIZE) do { \
- const uint32_t* pa = (const uint32_t*)(A); \
- const uint32_t* pb = (const uint32_t*)(B); \
- uint32_t* pout = (uint32_t*)(OUT); \
- const uint32_t* const LoopEnd = pa + (SIZE); \
- assert((SIZE) % 4 == 0); \
- ASM_START \
- ADD_TO_OUT(0, 4, 8, 12, 1, pa, pb, pout) \
- ASM_END_0 \
- if ((EXTRA_SIZE) > 0) { \
- const int last = (EXTRA_SIZE); \
- int i; \
- for (i = 0; i < last; ++i) pout[i] = pa[i] + pb[i]; \
- } \
-} while (0)
-
-#define ADD_VECTOR_EQ(A, OUT, SIZE, EXTRA_SIZE) do { \
- const uint32_t* pa = (const uint32_t*)(A); \
- uint32_t* pout = (uint32_t*)(OUT); \
- const uint32_t* const LoopEnd = pa + (SIZE); \
- assert((SIZE) % 4 == 0); \
- ASM_START \
- ADD_TO_OUT(0, 4, 8, 12, 0, pa, pout, pout) \
- ASM_END_1 \
- if ((EXTRA_SIZE) > 0) { \
- const int last = (EXTRA_SIZE); \
- int i; \
- for (i = 0; i < last; ++i) pout[i] += pa[i]; \
- } \
-} while (0)
-
-static void HistogramAdd_MIPS32(const VP8LHistogram* const a,
- const VP8LHistogram* const b,
- VP8LHistogram* const out) {
+static void AddVector_MIPS32(const uint32_t* pa, const uint32_t* pb,
+ uint32_t* pout, int size) {
uint32_t temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7;
- const int extra_cache_size = VP8LHistogramNumCodes(a->palette_code_bits_)
- - (NUM_LITERAL_CODES + NUM_LENGTH_CODES);
- assert(a->palette_code_bits_ == b->palette_code_bits_);
-
- if (b != out) {
- ADD_VECTOR(a->literal_, b->literal_, out->literal_,
- NUM_LITERAL_CODES + NUM_LENGTH_CODES, extra_cache_size);
- ADD_VECTOR(a->distance_, b->distance_, out->distance_,
- NUM_DISTANCE_CODES, 0);
- ADD_VECTOR(a->red_, b->red_, out->red_, NUM_LITERAL_CODES, 0);
- ADD_VECTOR(a->blue_, b->blue_, out->blue_, NUM_LITERAL_CODES, 0);
- ADD_VECTOR(a->alpha_, b->alpha_, out->alpha_, NUM_LITERAL_CODES, 0);
- } else {
- ADD_VECTOR_EQ(a->literal_, out->literal_,
- NUM_LITERAL_CODES + NUM_LENGTH_CODES, extra_cache_size);
- ADD_VECTOR_EQ(a->distance_, out->distance_, NUM_DISTANCE_CODES, 0);
- ADD_VECTOR_EQ(a->red_, out->red_, NUM_LITERAL_CODES, 0);
- ADD_VECTOR_EQ(a->blue_, out->blue_, NUM_LITERAL_CODES, 0);
- ADD_VECTOR_EQ(a->alpha_, out->alpha_, NUM_LITERAL_CODES, 0);
- }
+ const uint32_t end = ((size) / 4) * 4;
+ const uint32_t* const LoopEnd = pa + end;
+ int i;
+ ASM_START
+ ADD_TO_OUT(0, 4, 8, 12, 1, pa, pb, pout)
+ ASM_END_0
+ for (i = end; i < size; ++i) pout[i] = pa[i] + pb[i];
+}
+
+static void AddVectorEq_MIPS32(const uint32_t* pa, uint32_t* pout, int size) {
+ uint32_t temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7;
+ const uint32_t end = ((size) / 4) * 4;
+ const uint32_t* const LoopEnd = pa + end;
+ int i;
+ ASM_START
+ ADD_TO_OUT(0, 4, 8, 12, 0, pa, pout, pout)
+ ASM_END_1
+ for (i = end; i < size; ++i) pout[i] += pa[i];
}
-#undef ADD_VECTOR_EQ
-#undef ADD_VECTOR
#undef ASM_END_1
#undef ASM_END_0
#undef ASM_END_COMMON_1
@@ -422,7 +386,8 @@ WEBP_TSAN_IGNORE_FUNCTION void VP8LEncDspInitMIPS32(void) {
VP8LExtraCostCombined = ExtraCostCombined_MIPS32;
VP8LGetEntropyUnrefined = GetEntropyUnrefined_MIPS32;
VP8LGetCombinedEntropyUnrefined = GetCombinedEntropyUnrefined_MIPS32;
- VP8LHistogramAdd = HistogramAdd_MIPS32;
+ VP8LAddVector = AddVector_MIPS32;
+ VP8LAddVectorEq = AddVectorEq_MIPS32;
}
#else // !WEBP_USE_MIPS32
diff --git a/thirdparty/libwebp/src/dsp/lossless_enc_sse2.c b/thirdparty/libwebp/src/dsp/lossless_enc_sse2.c
index f84a9909e1..36478c4912 100644
--- a/thirdparty/libwebp/src/dsp/lossless_enc_sse2.c
+++ b/thirdparty/libwebp/src/dsp/lossless_enc_sse2.c
@@ -170,12 +170,13 @@ static void CollectColorRedTransforms_SSE2(const uint32_t* argb, int stride,
//------------------------------------------------------------------------------
+// Note we are adding uint32_t's as *signed* int32's (using _mm_add_epi32). But
+// that's ok since the histogram values are less than 1<<28 (max picture size).
#define LINE_SIZE 16 // 8 or 16
static void AddVector_SSE2(const uint32_t* a, const uint32_t* b, uint32_t* out,
int size) {
int i;
- assert(size % LINE_SIZE == 0);
- for (i = 0; i < size; i += LINE_SIZE) {
+ for (i = 0; i + LINE_SIZE <= size; i += LINE_SIZE) {
const __m128i a0 = _mm_loadu_si128((const __m128i*)&a[i + 0]);
const __m128i a1 = _mm_loadu_si128((const __m128i*)&a[i + 4]);
#if (LINE_SIZE == 16)
@@ -195,12 +196,14 @@ static void AddVector_SSE2(const uint32_t* a, const uint32_t* b, uint32_t* out,
_mm_storeu_si128((__m128i*)&out[i + 12], _mm_add_epi32(a3, b3));
#endif
}
+ for (; i < size; ++i) {
+ out[i] = a[i] + b[i];
+ }
}
static void AddVectorEq_SSE2(const uint32_t* a, uint32_t* out, int size) {
int i;
- assert(size % LINE_SIZE == 0);
- for (i = 0; i < size; i += LINE_SIZE) {
+ for (i = 0; i + LINE_SIZE <= size; i += LINE_SIZE) {
const __m128i a0 = _mm_loadu_si128((const __m128i*)&a[i + 0]);
const __m128i a1 = _mm_loadu_si128((const __m128i*)&a[i + 4]);
#if (LINE_SIZE == 16)
@@ -220,35 +223,11 @@ static void AddVectorEq_SSE2(const uint32_t* a, uint32_t* out, int size) {
_mm_storeu_si128((__m128i*)&out[i + 12], _mm_add_epi32(a3, b3));
#endif
}
-}
-#undef LINE_SIZE
-
-// Note we are adding uint32_t's as *signed* int32's (using _mm_add_epi32). But
-// that's ok since the histogram values are less than 1<<28 (max picture size).
-static void HistogramAdd_SSE2(const VP8LHistogram* const a,
- const VP8LHistogram* const b,
- VP8LHistogram* const out) {
- int i;
- const int literal_size = VP8LHistogramNumCodes(a->palette_code_bits_);
- assert(a->palette_code_bits_ == b->palette_code_bits_);
- if (b != out) {
- AddVector_SSE2(a->literal_, b->literal_, out->literal_, NUM_LITERAL_CODES);
- AddVector_SSE2(a->red_, b->red_, out->red_, NUM_LITERAL_CODES);
- AddVector_SSE2(a->blue_, b->blue_, out->blue_, NUM_LITERAL_CODES);
- AddVector_SSE2(a->alpha_, b->alpha_, out->alpha_, NUM_LITERAL_CODES);
- } else {
- AddVectorEq_SSE2(a->literal_, out->literal_, NUM_LITERAL_CODES);
- AddVectorEq_SSE2(a->red_, out->red_, NUM_LITERAL_CODES);
- AddVectorEq_SSE2(a->blue_, out->blue_, NUM_LITERAL_CODES);
- AddVectorEq_SSE2(a->alpha_, out->alpha_, NUM_LITERAL_CODES);
- }
- for (i = NUM_LITERAL_CODES; i < literal_size; ++i) {
- out->literal_[i] = a->literal_[i] + b->literal_[i];
- }
- for (i = 0; i < NUM_DISTANCE_CODES; ++i) {
- out->distance_[i] = a->distance_[i] + b->distance_[i];
+ for (; i < size; ++i) {
+ out[i] += a[i];
}
}
+#undef LINE_SIZE
//------------------------------------------------------------------------------
// Entropy
@@ -675,7 +654,8 @@ WEBP_TSAN_IGNORE_FUNCTION void VP8LEncDspInitSSE2(void) {
VP8LTransformColor = TransformColor_SSE2;
VP8LCollectColorBlueTransforms = CollectColorBlueTransforms_SSE2;
VP8LCollectColorRedTransforms = CollectColorRedTransforms_SSE2;
- VP8LHistogramAdd = HistogramAdd_SSE2;
+ VP8LAddVector = AddVector_SSE2;
+ VP8LAddVectorEq = AddVectorEq_SSE2;
VP8LCombinedShannonEntropy = CombinedShannonEntropy_SSE2;
VP8LVectorMismatch = VectorMismatch_SSE2;
VP8LBundleColorMap = BundleColorMap_SSE2;
diff --git a/thirdparty/libwebp/src/dsp/msa_macro.h b/thirdparty/libwebp/src/dsp/msa_macro.h
index dfacda6ccd..de026a1d9e 100644
--- a/thirdparty/libwebp/src/dsp/msa_macro.h
+++ b/thirdparty/libwebp/src/dsp/msa_macro.h
@@ -1389,4 +1389,4 @@ static WEBP_INLINE uint32_t func_hadd_uh_u32(v8u16 in) {
} while (0)
#define AVER_UB2_UB(...) AVER_UB2(v16u8, __VA_ARGS__)
-#endif /* WEBP_DSP_MSA_MACRO_H_ */
+#endif // WEBP_DSP_MSA_MACRO_H_
diff --git a/thirdparty/libwebp/src/dsp/rescaler.c b/thirdparty/libwebp/src/dsp/rescaler.c
index f307d35056..753f84fcf4 100644
--- a/thirdparty/libwebp/src/dsp/rescaler.c
+++ b/thirdparty/libwebp/src/dsp/rescaler.c
@@ -21,6 +21,7 @@
#define ROUNDER (WEBP_RESCALER_ONE >> 1)
#define MULT_FIX(x, y) (((uint64_t)(x) * (y) + ROUNDER) >> WEBP_RESCALER_RFIX)
+#define MULT_FIX_FLOOR(x, y) (((uint64_t)(x) * (y)) >> WEBP_RESCALER_RFIX)
//------------------------------------------------------------------------------
// Row import
@@ -138,7 +139,7 @@ void WebPRescalerExportRowShrink_C(WebPRescaler* const wrk) {
if (yscale) {
for (x_out = 0; x_out < x_out_max; ++x_out) {
const uint32_t frac = (uint32_t)MULT_FIX(frow[x_out], yscale);
- const int v = (int)MULT_FIX(irow[x_out] - frac, wrk->fxy_scale);
+ const int v = (int)MULT_FIX_FLOOR(irow[x_out] - frac, wrk->fxy_scale);
assert(v >= 0 && v <= 255);
dst[x_out] = v;
irow[x_out] = frac; // new fractional start
@@ -153,6 +154,7 @@ void WebPRescalerExportRowShrink_C(WebPRescaler* const wrk) {
}
}
+#undef MULT_FIX_FLOOR
#undef MULT_FIX
#undef ROUNDER
diff --git a/thirdparty/libwebp/src/dsp/rescaler_mips32.c b/thirdparty/libwebp/src/dsp/rescaler_mips32.c
index 542f7e5970..61f63c616c 100644
--- a/thirdparty/libwebp/src/dsp/rescaler_mips32.c
+++ b/thirdparty/libwebp/src/dsp/rescaler_mips32.c
@@ -209,6 +209,7 @@ static void ExportRowExpand_MIPS32(WebPRescaler* const wrk) {
}
}
+#if 0 // disabled for now. TODO(skal): make match the C-code
static void ExportRowShrink_MIPS32(WebPRescaler* const wrk) {
const int x_out_max = wrk->dst_width * wrk->num_channels;
uint8_t* dst = wrk->dst;
@@ -273,6 +274,7 @@ static void ExportRowShrink_MIPS32(WebPRescaler* const wrk) {
);
}
}
+#endif // 0
//------------------------------------------------------------------------------
// Entry point
@@ -283,7 +285,7 @@ WEBP_TSAN_IGNORE_FUNCTION void WebPRescalerDspInitMIPS32(void) {
WebPRescalerImportRowExpand = ImportRowExpand_MIPS32;
WebPRescalerImportRowShrink = ImportRowShrink_MIPS32;
WebPRescalerExportRowExpand = ExportRowExpand_MIPS32;
- WebPRescalerExportRowShrink = ExportRowShrink_MIPS32;
+// WebPRescalerExportRowShrink = ExportRowShrink_MIPS32;
}
#else // !WEBP_USE_MIPS32
diff --git a/thirdparty/libwebp/src/dsp/rescaler_mips_dsp_r2.c b/thirdparty/libwebp/src/dsp/rescaler_mips_dsp_r2.c
index b78aac15e6..ce9e64862e 100644
--- a/thirdparty/libwebp/src/dsp/rescaler_mips_dsp_r2.c
+++ b/thirdparty/libwebp/src/dsp/rescaler_mips_dsp_r2.c
@@ -20,10 +20,12 @@
#define ROUNDER (WEBP_RESCALER_ONE >> 1)
#define MULT_FIX(x, y) (((uint64_t)(x) * (y) + ROUNDER) >> WEBP_RESCALER_RFIX)
+#define MULT_FIX_FLOOR(x, y) (((uint64_t)(x) * (y)) >> WEBP_RESCALER_RFIX)
//------------------------------------------------------------------------------
// Row export
+#if 0 // disabled for now. TODO(skal): make match the C-code
static void ExportRowShrink_MIPSdspR2(WebPRescaler* const wrk) {
int i;
const int x_out_max = wrk->dst_width * wrk->num_channels;
@@ -106,7 +108,7 @@ static void ExportRowShrink_MIPSdspR2(WebPRescaler* const wrk) {
}
for (i = 0; i < (x_out_max & 0x3); ++i) {
const uint32_t frac = (uint32_t)MULT_FIX(*frow++, yscale);
- const int v = (int)MULT_FIX(*irow - frac, wrk->fxy_scale);
+ const int v = (int)MULT_FIX_FLOOR(*irow - frac, wrk->fxy_scale);
assert(v >= 0 && v <= 255);
*dst++ = v;
*irow++ = frac; // new fractional start
@@ -154,13 +156,14 @@ static void ExportRowShrink_MIPSdspR2(WebPRescaler* const wrk) {
);
}
for (i = 0; i < (x_out_max & 0x3); ++i) {
- const int v = (int)MULT_FIX(*irow, wrk->fxy_scale);
+ const int v = (int)MULT_FIX_FLOOR(*irow, wrk->fxy_scale);
assert(v >= 0 && v <= 255);
*dst++ = v;
*irow++ = 0;
}
}
}
+#endif // 0
static void ExportRowExpand_MIPSdspR2(WebPRescaler* const wrk) {
int i;
@@ -294,6 +297,7 @@ static void ExportRowExpand_MIPSdspR2(WebPRescaler* const wrk) {
}
}
+#undef MULT_FIX_FLOOR
#undef MULT_FIX
#undef ROUNDER
@@ -304,7 +308,7 @@ extern void WebPRescalerDspInitMIPSdspR2(void);
WEBP_TSAN_IGNORE_FUNCTION void WebPRescalerDspInitMIPSdspR2(void) {
WebPRescalerExportRowExpand = ExportRowExpand_MIPSdspR2;
- WebPRescalerExportRowShrink = ExportRowShrink_MIPSdspR2;
+// WebPRescalerExportRowShrink = ExportRowShrink_MIPSdspR2;
}
#else // !WEBP_USE_MIPS_DSP_R2
diff --git a/thirdparty/libwebp/src/dsp/rescaler_msa.c b/thirdparty/libwebp/src/dsp/rescaler_msa.c
index f3bc99f1cd..c559254836 100644
--- a/thirdparty/libwebp/src/dsp/rescaler_msa.c
+++ b/thirdparty/libwebp/src/dsp/rescaler_msa.c
@@ -22,6 +22,7 @@
#define ROUNDER (WEBP_RESCALER_ONE >> 1)
#define MULT_FIX(x, y) (((uint64_t)(x) * (y) + ROUNDER) >> WEBP_RESCALER_RFIX)
+#define MULT_FIX_FLOOR(x, y) (((uint64_t)(x) * (y)) >> WEBP_RESCALER_RFIX)
#define CALC_MULT_FIX_16(in0, in1, in2, in3, scale, shift, dst) do { \
v4u32 tmp0, tmp1, tmp2, tmp3; \
@@ -262,6 +263,7 @@ static void RescalerExportRowExpand_MIPSdspR2(WebPRescaler* const wrk) {
}
}
+#if 0 // disabled for now. TODO(skal): make match the C-code
static WEBP_INLINE void ExportRowShrink_0(const uint32_t* frow, uint32_t* irow,
uint8_t* dst, int length,
const uint32_t yscale,
@@ -341,7 +343,7 @@ static WEBP_INLINE void ExportRowShrink_0(const uint32_t* frow, uint32_t* irow,
}
for (x_out = 0; x_out < length; ++x_out) {
const uint32_t frac = (uint32_t)MULT_FIX(frow[x_out], yscale);
- const int v = (int)MULT_FIX(irow[x_out] - frac, wrk->fxy_scale);
+ const int v = (int)MULT_FIX_FLOOR(irow[x_out] - frac, wrk->fxy_scale);
assert(v >= 0 && v <= 255);
dst[x_out] = v;
irow[x_out] = frac;
@@ -426,6 +428,7 @@ static void RescalerExportRowShrink_MIPSdspR2(WebPRescaler* const wrk) {
ExportRowShrink_1(irow, dst, x_out_max, wrk);
}
}
+#endif // 0
//------------------------------------------------------------------------------
// Entry point
@@ -434,7 +437,7 @@ extern void WebPRescalerDspInitMSA(void);
WEBP_TSAN_IGNORE_FUNCTION void WebPRescalerDspInitMSA(void) {
WebPRescalerExportRowExpand = RescalerExportRowExpand_MIPSdspR2;
- WebPRescalerExportRowShrink = RescalerExportRowShrink_MIPSdspR2;
+// WebPRescalerExportRowShrink = RescalerExportRowShrink_MIPSdspR2;
}
#else // !WEBP_USE_MSA
diff --git a/thirdparty/libwebp/src/dsp/rescaler_neon.c b/thirdparty/libwebp/src/dsp/rescaler_neon.c
index 3eff9fbaf4..a553f06f79 100644
--- a/thirdparty/libwebp/src/dsp/rescaler_neon.c
+++ b/thirdparty/libwebp/src/dsp/rescaler_neon.c
@@ -22,6 +22,7 @@
#define ROUNDER (WEBP_RESCALER_ONE >> 1)
#define MULT_FIX_C(x, y) (((uint64_t)(x) * (y) + ROUNDER) >> WEBP_RESCALER_RFIX)
+#define MULT_FIX_FLOOR_C(x, y) (((uint64_t)(x) * (y)) >> WEBP_RESCALER_RFIX)
#define LOAD_32x4(SRC, DST) const uint32x4_t DST = vld1q_u32((SRC))
#define LOAD_32x8(SRC, DST0, DST1) \
@@ -35,8 +36,11 @@
#if (WEBP_RESCALER_RFIX == 32)
#define MAKE_HALF_CST(C) vdupq_n_s32((int32_t)((C) >> 1))
-#define MULT_FIX(A, B) /* note: B is actualy scale>>1. See MAKE_HALF_CST */ \
+// note: B is actualy scale>>1. See MAKE_HALF_CST
+#define MULT_FIX(A, B) \
vreinterpretq_u32_s32(vqrdmulhq_s32(vreinterpretq_s32_u32((A)), (B)))
+#define MULT_FIX_FLOOR(A, B) \
+ vreinterpretq_u32_s32(vqdmulhq_s32(vreinterpretq_s32_u32((A)), (B)))
#else
#error "MULT_FIX/WEBP_RESCALER_RFIX need some more work"
#endif
@@ -135,8 +139,8 @@ static void RescalerExportRowShrink_NEON(WebPRescaler* const wrk) {
const uint32x4_t A1 = MULT_FIX(in1, yscale_half);
const uint32x4_t B0 = vqsubq_u32(in2, A0);
const uint32x4_t B1 = vqsubq_u32(in3, A1);
- const uint32x4_t C0 = MULT_FIX(B0, fxy_scale_half);
- const uint32x4_t C1 = MULT_FIX(B1, fxy_scale_half);
+ const uint32x4_t C0 = MULT_FIX_FLOOR(B0, fxy_scale_half);
+ const uint32x4_t C1 = MULT_FIX_FLOOR(B1, fxy_scale_half);
const uint16x4_t D0 = vmovn_u32(C0);
const uint16x4_t D1 = vmovn_u32(C1);
const uint8x8_t E = vmovn_u16(vcombine_u16(D0, D1));
@@ -145,7 +149,7 @@ static void RescalerExportRowShrink_NEON(WebPRescaler* const wrk) {
}
for (; x_out < x_out_max; ++x_out) {
const uint32_t frac = (uint32_t)MULT_FIX_C(frow[x_out], yscale);
- const int v = (int)MULT_FIX_C(irow[x_out] - frac, wrk->fxy_scale);
+ const int v = (int)MULT_FIX_FLOOR_C(irow[x_out] - frac, fxy_scale);
assert(v >= 0 && v <= 255);
dst[x_out] = v;
irow[x_out] = frac; // new fractional start
@@ -170,6 +174,12 @@ static void RescalerExportRowShrink_NEON(WebPRescaler* const wrk) {
}
}
+#undef MULT_FIX_FLOOR_C
+#undef MULT_FIX_C
+#undef MULT_FIX_FLOOR
+#undef MULT_FIX
+#undef ROUNDER
+
//------------------------------------------------------------------------------
extern void WebPRescalerDspInitNEON(void);
diff --git a/thirdparty/libwebp/src/dsp/rescaler_sse2.c b/thirdparty/libwebp/src/dsp/rescaler_sse2.c
index 64c50deab5..f7461a452c 100644
--- a/thirdparty/libwebp/src/dsp/rescaler_sse2.c
+++ b/thirdparty/libwebp/src/dsp/rescaler_sse2.c
@@ -25,6 +25,7 @@
#define ROUNDER (WEBP_RESCALER_ONE >> 1)
#define MULT_FIX(x, y) (((uint64_t)(x) * (y) + ROUNDER) >> WEBP_RESCALER_RFIX)
+#define MULT_FIX_FLOOR(x, y) (((uint64_t)(x) * (y)) >> WEBP_RESCALER_RFIX)
// input: 8 bytes ABCDEFGH -> output: A0E0B0F0C0G0D0H0
static void LoadTwoPixels_SSE2(const uint8_t* const src, __m128i* out) {
@@ -224,6 +225,35 @@ static WEBP_INLINE void ProcessRow_SSE2(const __m128i* const A0,
_mm_storel_epi64((__m128i*)dst, G);
}
+static WEBP_INLINE void ProcessRow_Floor_SSE2(const __m128i* const A0,
+ const __m128i* const A1,
+ const __m128i* const A2,
+ const __m128i* const A3,
+ const __m128i* const mult,
+ uint8_t* const dst) {
+ const __m128i mask = _mm_set_epi32(0xffffffffu, 0, 0xffffffffu, 0);
+ const __m128i B0 = _mm_mul_epu32(*A0, *mult);
+ const __m128i B1 = _mm_mul_epu32(*A1, *mult);
+ const __m128i B2 = _mm_mul_epu32(*A2, *mult);
+ const __m128i B3 = _mm_mul_epu32(*A3, *mult);
+ const __m128i D0 = _mm_srli_epi64(B0, WEBP_RESCALER_RFIX);
+ const __m128i D1 = _mm_srli_epi64(B1, WEBP_RESCALER_RFIX);
+#if (WEBP_RESCALER_RFIX < 32)
+ const __m128i D2 =
+ _mm_and_si128(_mm_slli_epi64(B2, 32 - WEBP_RESCALER_RFIX), mask);
+ const __m128i D3 =
+ _mm_and_si128(_mm_slli_epi64(B3, 32 - WEBP_RESCALER_RFIX), mask);
+#else
+ const __m128i D2 = _mm_and_si128(B2, mask);
+ const __m128i D3 = _mm_and_si128(B3, mask);
+#endif
+ const __m128i E0 = _mm_or_si128(D0, D2);
+ const __m128i E1 = _mm_or_si128(D1, D3);
+ const __m128i F = _mm_packs_epi32(E0, E1);
+ const __m128i G = _mm_packus_epi16(F, F);
+ _mm_storel_epi64((__m128i*)dst, G);
+}
+
static void RescalerExportRowExpand_SSE2(WebPRescaler* const wrk) {
int x_out;
uint8_t* const dst = wrk->dst;
@@ -322,12 +352,12 @@ static void RescalerExportRowShrink_SSE2(WebPRescaler* const wrk) {
const __m128i G1 = _mm_or_si128(D1, F3);
_mm_storeu_si128((__m128i*)(irow + x_out + 0), G0);
_mm_storeu_si128((__m128i*)(irow + x_out + 4), G1);
- ProcessRow_SSE2(&E0, &E1, &E2, &E3, &mult_xy, dst + x_out);
+ ProcessRow_Floor_SSE2(&E0, &E1, &E2, &E3, &mult_xy, dst + x_out);
}
}
for (; x_out < x_out_max; ++x_out) {
const uint32_t frac = (int)MULT_FIX(frow[x_out], yscale);
- const int v = (int)MULT_FIX(irow[x_out] - frac, wrk->fxy_scale);
+ const int v = (int)MULT_FIX_FLOOR(irow[x_out] - frac, wrk->fxy_scale);
assert(v >= 0 && v <= 255);
dst[x_out] = v;
irow[x_out] = frac; // new fractional start
@@ -352,6 +382,7 @@ static void RescalerExportRowShrink_SSE2(WebPRescaler* const wrk) {
}
}
+#undef MULT_FIX_FLOOR
#undef MULT_FIX
#undef ROUNDER
diff --git a/thirdparty/libwebp/src/dsp/yuv.h b/thirdparty/libwebp/src/dsp/yuv.h
index eb787270d2..c12be1d094 100644
--- a/thirdparty/libwebp/src/dsp/yuv.h
+++ b/thirdparty/libwebp/src/dsp/yuv.h
@@ -207,4 +207,4 @@ static WEBP_INLINE int VP8RGBToV(int r, int g, int b, int rounding) {
} // extern "C"
#endif
-#endif /* WEBP_DSP_YUV_H_ */
+#endif // WEBP_DSP_YUV_H_
diff --git a/thirdparty/libwebp/src/enc/analysis_enc.c b/thirdparty/libwebp/src/enc/analysis_enc.c
index a47ff7d4e8..687757ae03 100644
--- a/thirdparty/libwebp/src/enc/analysis_enc.c
+++ b/thirdparty/libwebp/src/enc/analysis_enc.c
@@ -458,7 +458,7 @@ static void MergeJobs(const SegmentJob* const src, SegmentJob* const dst) {
dst->uv_alpha += src->uv_alpha;
}
-// initialize the job struct with some TODOs
+// initialize the job struct with some tasks to perform
static void InitSegmentJob(VP8Encoder* const enc, SegmentJob* const job,
int start_row, int end_row) {
WebPGetWorkerInterface()->Init(&job->worker);
diff --git a/thirdparty/libwebp/src/enc/backward_references_cost_enc.c b/thirdparty/libwebp/src/enc/backward_references_cost_enc.c
index 7175496c7f..516abd73eb 100644
--- a/thirdparty/libwebp/src/enc/backward_references_cost_enc.c
+++ b/thirdparty/libwebp/src/enc/backward_references_cost_enc.c
@@ -67,7 +67,7 @@ static int CostModelBuild(CostModel* const m, int xsize, int cache_bits,
// The following code is similar to VP8LHistogramCreate but converts the
// distance to plane code.
- VP8LHistogramInit(histo, cache_bits);
+ VP8LHistogramInit(histo, cache_bits, /*init_arrays=*/ 1);
while (VP8LRefsCursorOk(&c)) {
VP8LHistogramAddSinglePixOrCopy(histo, c.cur_pos, VP8LDistanceToPlaneCode,
xsize);
diff --git a/thirdparty/libwebp/src/enc/backward_references_enc.c b/thirdparty/libwebp/src/enc/backward_references_enc.c
index 39230188b9..3ab7b0ac7d 100644
--- a/thirdparty/libwebp/src/enc/backward_references_enc.c
+++ b/thirdparty/libwebp/src/enc/backward_references_enc.c
@@ -715,6 +715,7 @@ static int CalculateBestCacheSize(const uint32_t* argb, int quality,
for (i = 0; i <= cache_bits_max; ++i) {
histos[i] = VP8LAllocateHistogram(i);
if (histos[i] == NULL) goto Error;
+ VP8LHistogramInit(histos[i], i, /*init_arrays=*/ 1);
if (i == 0) continue;
cc_init[i] = VP8LColorCacheInit(&hashers[i], i);
if (!cc_init[i]) goto Error;
diff --git a/thirdparty/libwebp/src/enc/cost_enc.h b/thirdparty/libwebp/src/enc/cost_enc.h
index bdce1e6a3b..a4b177b342 100644
--- a/thirdparty/libwebp/src/enc/cost_enc.h
+++ b/thirdparty/libwebp/src/enc/cost_enc.h
@@ -79,4 +79,4 @@ extern const uint16_t VP8FixedCostsI4[NUM_BMODES][NUM_BMODES][NUM_BMODES];
} // extern "C"
#endif
-#endif /* WEBP_ENC_COST_ENC_H_ */
+#endif // WEBP_ENC_COST_ENC_H_
diff --git a/thirdparty/libwebp/src/enc/delta_palettization_enc.c b/thirdparty/libwebp/src/enc/delta_palettization_enc.c
deleted file mode 100644
index a61c8e6c93..0000000000
--- a/thirdparty/libwebp/src/enc/delta_palettization_enc.c
+++ /dev/null
@@ -1,455 +0,0 @@
-// Copyright 2015 Google Inc. All Rights Reserved.
-//
-// Use of this source code is governed by a BSD-style license
-// that can be found in the COPYING file in the root of the source
-// tree. An additional intellectual property rights grant can be found
-// in the file PATENTS. All contributing project authors may
-// be found in the AUTHORS file in the root of the source tree.
-// -----------------------------------------------------------------------------
-//
-// Author: Mislav Bradac (mislavm@google.com)
-//
-
-#include "src/enc/delta_palettization_enc.h"
-
-#ifdef WEBP_EXPERIMENTAL_FEATURES
-#include "src/webp/types.h"
-#include "src/dsp/lossless.h"
-
-#define MK_COL(r, g, b) (((r) << 16) + ((g) << 8) + (b))
-
-// Format allows palette up to 256 entries, but more palette entries produce
-// bigger entropy. In the future it will probably be useful to add more entries
-// that are far from the origin of the palette or choose remaining entries
-// dynamically.
-#define DELTA_PALETTE_SIZE 226
-
-// Palette used for delta_palettization. Entries are roughly sorted by distance
-// of their signed equivalents from the origin.
-static const uint32_t kDeltaPalette[DELTA_PALETTE_SIZE] = {
- MK_COL(0u, 0u, 0u),
- MK_COL(255u, 255u, 255u),
- MK_COL(1u, 1u, 1u),
- MK_COL(254u, 254u, 254u),
- MK_COL(2u, 2u, 2u),
- MK_COL(4u, 4u, 4u),
- MK_COL(252u, 252u, 252u),
- MK_COL(250u, 0u, 0u),
- MK_COL(0u, 250u, 0u),
- MK_COL(0u, 0u, 250u),
- MK_COL(6u, 0u, 0u),
- MK_COL(0u, 6u, 0u),
- MK_COL(0u, 0u, 6u),
- MK_COL(0u, 0u, 248u),
- MK_COL(0u, 0u, 8u),
- MK_COL(0u, 248u, 0u),
- MK_COL(0u, 248u, 248u),
- MK_COL(0u, 248u, 8u),
- MK_COL(0u, 8u, 0u),
- MK_COL(0u, 8u, 248u),
- MK_COL(0u, 8u, 8u),
- MK_COL(8u, 8u, 8u),
- MK_COL(248u, 0u, 0u),
- MK_COL(248u, 0u, 248u),
- MK_COL(248u, 0u, 8u),
- MK_COL(248u, 248u, 0u),
- MK_COL(248u, 8u, 0u),
- MK_COL(8u, 0u, 0u),
- MK_COL(8u, 0u, 248u),
- MK_COL(8u, 0u, 8u),
- MK_COL(8u, 248u, 0u),
- MK_COL(8u, 8u, 0u),
- MK_COL(23u, 23u, 23u),
- MK_COL(13u, 13u, 13u),
- MK_COL(232u, 232u, 232u),
- MK_COL(244u, 244u, 244u),
- MK_COL(245u, 245u, 250u),
- MK_COL(50u, 50u, 50u),
- MK_COL(204u, 204u, 204u),
- MK_COL(236u, 236u, 236u),
- MK_COL(16u, 16u, 16u),
- MK_COL(240u, 16u, 16u),
- MK_COL(16u, 240u, 16u),
- MK_COL(240u, 240u, 16u),
- MK_COL(16u, 16u, 240u),
- MK_COL(240u, 16u, 240u),
- MK_COL(16u, 240u, 240u),
- MK_COL(240u, 240u, 240u),
- MK_COL(0u, 0u, 232u),
- MK_COL(0u, 232u, 0u),
- MK_COL(232u, 0u, 0u),
- MK_COL(0u, 0u, 24u),
- MK_COL(0u, 24u, 0u),
- MK_COL(24u, 0u, 0u),
- MK_COL(32u, 32u, 32u),
- MK_COL(224u, 32u, 32u),
- MK_COL(32u, 224u, 32u),
- MK_COL(224u, 224u, 32u),
- MK_COL(32u, 32u, 224u),
- MK_COL(224u, 32u, 224u),
- MK_COL(32u, 224u, 224u),
- MK_COL(224u, 224u, 224u),
- MK_COL(0u, 0u, 176u),
- MK_COL(0u, 0u, 80u),
- MK_COL(0u, 176u, 0u),
- MK_COL(0u, 176u, 176u),
- MK_COL(0u, 176u, 80u),
- MK_COL(0u, 80u, 0u),
- MK_COL(0u, 80u, 176u),
- MK_COL(0u, 80u, 80u),
- MK_COL(176u, 0u, 0u),
- MK_COL(176u, 0u, 176u),
- MK_COL(176u, 0u, 80u),
- MK_COL(176u, 176u, 0u),
- MK_COL(176u, 80u, 0u),
- MK_COL(80u, 0u, 0u),
- MK_COL(80u, 0u, 176u),
- MK_COL(80u, 0u, 80u),
- MK_COL(80u, 176u, 0u),
- MK_COL(80u, 80u, 0u),
- MK_COL(0u, 0u, 152u),
- MK_COL(0u, 0u, 104u),
- MK_COL(0u, 152u, 0u),
- MK_COL(0u, 152u, 152u),
- MK_COL(0u, 152u, 104u),
- MK_COL(0u, 104u, 0u),
- MK_COL(0u, 104u, 152u),
- MK_COL(0u, 104u, 104u),
- MK_COL(152u, 0u, 0u),
- MK_COL(152u, 0u, 152u),
- MK_COL(152u, 0u, 104u),
- MK_COL(152u, 152u, 0u),
- MK_COL(152u, 104u, 0u),
- MK_COL(104u, 0u, 0u),
- MK_COL(104u, 0u, 152u),
- MK_COL(104u, 0u, 104u),
- MK_COL(104u, 152u, 0u),
- MK_COL(104u, 104u, 0u),
- MK_COL(216u, 216u, 216u),
- MK_COL(216u, 216u, 40u),
- MK_COL(216u, 216u, 176u),
- MK_COL(216u, 216u, 80u),
- MK_COL(216u, 40u, 216u),
- MK_COL(216u, 40u, 40u),
- MK_COL(216u, 40u, 176u),
- MK_COL(216u, 40u, 80u),
- MK_COL(216u, 176u, 216u),
- MK_COL(216u, 176u, 40u),
- MK_COL(216u, 176u, 176u),
- MK_COL(216u, 176u, 80u),
- MK_COL(216u, 80u, 216u),
- MK_COL(216u, 80u, 40u),
- MK_COL(216u, 80u, 176u),
- MK_COL(216u, 80u, 80u),
- MK_COL(40u, 216u, 216u),
- MK_COL(40u, 216u, 40u),
- MK_COL(40u, 216u, 176u),
- MK_COL(40u, 216u, 80u),
- MK_COL(40u, 40u, 216u),
- MK_COL(40u, 40u, 40u),
- MK_COL(40u, 40u, 176u),
- MK_COL(40u, 40u, 80u),
- MK_COL(40u, 176u, 216u),
- MK_COL(40u, 176u, 40u),
- MK_COL(40u, 176u, 176u),
- MK_COL(40u, 176u, 80u),
- MK_COL(40u, 80u, 216u),
- MK_COL(40u, 80u, 40u),
- MK_COL(40u, 80u, 176u),
- MK_COL(40u, 80u, 80u),
- MK_COL(80u, 216u, 216u),
- MK_COL(80u, 216u, 40u),
- MK_COL(80u, 216u, 176u),
- MK_COL(80u, 216u, 80u),
- MK_COL(80u, 40u, 216u),
- MK_COL(80u, 40u, 40u),
- MK_COL(80u, 40u, 176u),
- MK_COL(80u, 40u, 80u),
- MK_COL(80u, 176u, 216u),
- MK_COL(80u, 176u, 40u),
- MK_COL(80u, 176u, 176u),
- MK_COL(80u, 176u, 80u),
- MK_COL(80u, 80u, 216u),
- MK_COL(80u, 80u, 40u),
- MK_COL(80u, 80u, 176u),
- MK_COL(80u, 80u, 80u),
- MK_COL(0u, 0u, 192u),
- MK_COL(0u, 0u, 64u),
- MK_COL(0u, 0u, 128u),
- MK_COL(0u, 192u, 0u),
- MK_COL(0u, 192u, 192u),
- MK_COL(0u, 192u, 64u),
- MK_COL(0u, 192u, 128u),
- MK_COL(0u, 64u, 0u),
- MK_COL(0u, 64u, 192u),
- MK_COL(0u, 64u, 64u),
- MK_COL(0u, 64u, 128u),
- MK_COL(0u, 128u, 0u),
- MK_COL(0u, 128u, 192u),
- MK_COL(0u, 128u, 64u),
- MK_COL(0u, 128u, 128u),
- MK_COL(176u, 216u, 216u),
- MK_COL(176u, 216u, 40u),
- MK_COL(176u, 216u, 176u),
- MK_COL(176u, 216u, 80u),
- MK_COL(176u, 40u, 216u),
- MK_COL(176u, 40u, 40u),
- MK_COL(176u, 40u, 176u),
- MK_COL(176u, 40u, 80u),
- MK_COL(176u, 176u, 216u),
- MK_COL(176u, 176u, 40u),
- MK_COL(176u, 176u, 176u),
- MK_COL(176u, 176u, 80u),
- MK_COL(176u, 80u, 216u),
- MK_COL(176u, 80u, 40u),
- MK_COL(176u, 80u, 176u),
- MK_COL(176u, 80u, 80u),
- MK_COL(192u, 0u, 0u),
- MK_COL(192u, 0u, 192u),
- MK_COL(192u, 0u, 64u),
- MK_COL(192u, 0u, 128u),
- MK_COL(192u, 192u, 0u),
- MK_COL(192u, 192u, 192u),
- MK_COL(192u, 192u, 64u),
- MK_COL(192u, 192u, 128u),
- MK_COL(192u, 64u, 0u),
- MK_COL(192u, 64u, 192u),
- MK_COL(192u, 64u, 64u),
- MK_COL(192u, 64u, 128u),
- MK_COL(192u, 128u, 0u),
- MK_COL(192u, 128u, 192u),
- MK_COL(192u, 128u, 64u),
- MK_COL(192u, 128u, 128u),
- MK_COL(64u, 0u, 0u),
- MK_COL(64u, 0u, 192u),
- MK_COL(64u, 0u, 64u),
- MK_COL(64u, 0u, 128u),
- MK_COL(64u, 192u, 0u),
- MK_COL(64u, 192u, 192u),
- MK_COL(64u, 192u, 64u),
- MK_COL(64u, 192u, 128u),
- MK_COL(64u, 64u, 0u),
- MK_COL(64u, 64u, 192u),
- MK_COL(64u, 64u, 64u),
- MK_COL(64u, 64u, 128u),
- MK_COL(64u, 128u, 0u),
- MK_COL(64u, 128u, 192u),
- MK_COL(64u, 128u, 64u),
- MK_COL(64u, 128u, 128u),
- MK_COL(128u, 0u, 0u),
- MK_COL(128u, 0u, 192u),
- MK_COL(128u, 0u, 64u),
- MK_COL(128u, 0u, 128u),
- MK_COL(128u, 192u, 0u),
- MK_COL(128u, 192u, 192u),
- MK_COL(128u, 192u, 64u),
- MK_COL(128u, 192u, 128u),
- MK_COL(128u, 64u, 0u),
- MK_COL(128u, 64u, 192u),
- MK_COL(128u, 64u, 64u),
- MK_COL(128u, 64u, 128u),
- MK_COL(128u, 128u, 0u),
- MK_COL(128u, 128u, 192u),
- MK_COL(128u, 128u, 64u),
- MK_COL(128u, 128u, 128u),
-};
-
-#undef MK_COL
-
-//------------------------------------------------------------------------------
-// TODO(skal): move the functions to dsp/lossless.c when the correct
-// granularity is found. For now, we'll just copy-paste some useful bits
-// here instead.
-
-// In-place sum of each component with mod 256.
-static WEBP_INLINE void AddPixelsEq(uint32_t* a, uint32_t b) {
- const uint32_t alpha_and_green = (*a & 0xff00ff00u) + (b & 0xff00ff00u);
- const uint32_t red_and_blue = (*a & 0x00ff00ffu) + (b & 0x00ff00ffu);
- *a = (alpha_and_green & 0xff00ff00u) | (red_and_blue & 0x00ff00ffu);
-}
-
-static WEBP_INLINE uint32_t Clip255(uint32_t a) {
- if (a < 256) {
- return a;
- }
- // return 0, when a is a negative integer.
- // return 255, when a is positive.
- return ~a >> 24;
-}
-
-// Delta palettization functions.
-static WEBP_INLINE int Square(int x) {
- return x * x;
-}
-
-static WEBP_INLINE uint32_t Intensity(uint32_t a) {
- return
- 30 * ((a >> 16) & 0xff) +
- 59 * ((a >> 8) & 0xff) +
- 11 * ((a >> 0) & 0xff);
-}
-
-static uint32_t CalcDist(uint32_t predicted_value, uint32_t actual_value,
- uint32_t palette_entry) {
- int i;
- uint32_t distance = 0;
- AddPixelsEq(&predicted_value, palette_entry);
- for (i = 0; i < 32; i += 8) {
- const int32_t av = (actual_value >> i) & 0xff;
- const int32_t pv = (predicted_value >> i) & 0xff;
- distance += Square(pv - av);
- }
- // We sum square of intensity difference with factor 10, but because Intensity
- // returns 100 times real intensity we need to multiply differences of colors
- // by 1000.
- distance *= 1000u;
- distance += Square(Intensity(predicted_value)
- - Intensity(actual_value));
- return distance;
-}
-
-static uint32_t Predict(int x, int y, uint32_t* image) {
- const uint32_t t = (y == 0) ? ARGB_BLACK : image[x];
- const uint32_t l = (x == 0) ? ARGB_BLACK : image[x - 1];
- const uint32_t p =
- (((((t >> 24) & 0xff) + ((l >> 24) & 0xff)) / 2) << 24) +
- (((((t >> 16) & 0xff) + ((l >> 16) & 0xff)) / 2) << 16) +
- (((((t >> 8) & 0xff) + ((l >> 8) & 0xff)) / 2) << 8) +
- (((((t >> 0) & 0xff) + ((l >> 0) & 0xff)) / 2) << 0);
- if (x == 0 && y == 0) return ARGB_BLACK;
- if (x == 0) return t;
- if (y == 0) return l;
- return p;
-}
-
-static WEBP_INLINE int AddSubtractComponentFullWithCoefficient(
- int a, int b, int c) {
- return Clip255(a + ((b - c) >> 2));
-}
-
-static WEBP_INLINE uint32_t ClampedAddSubtractFullWithCoefficient(
- uint32_t c0, uint32_t c1, uint32_t c2) {
- const int a = AddSubtractComponentFullWithCoefficient(
- c0 >> 24, c1 >> 24, c2 >> 24);
- const int r = AddSubtractComponentFullWithCoefficient((c0 >> 16) & 0xff,
- (c1 >> 16) & 0xff,
- (c2 >> 16) & 0xff);
- const int g = AddSubtractComponentFullWithCoefficient((c0 >> 8) & 0xff,
- (c1 >> 8) & 0xff,
- (c2 >> 8) & 0xff);
- const int b = AddSubtractComponentFullWithCoefficient(
- c0 & 0xff, c1 & 0xff, c2 & 0xff);
- return ((uint32_t)a << 24) | (r << 16) | (g << 8) | b;
-}
-
-//------------------------------------------------------------------------------
-
-// Find palette entry with minimum error from difference of actual pixel value
-// and predicted pixel value. Propagate error of pixel to its top and left pixel
-// in src array. Write predicted_value + palette_entry to new_image. Return
-// index of best palette entry.
-static int FindBestPaletteEntry(uint32_t src, uint32_t predicted_value,
- const uint32_t palette[], int palette_size) {
- int i;
- int idx = 0;
- uint32_t best_distance = CalcDist(predicted_value, src, palette[0]);
- for (i = 1; i < palette_size; ++i) {
- const uint32_t distance = CalcDist(predicted_value, src, palette[i]);
- if (distance < best_distance) {
- best_distance = distance;
- idx = i;
- }
- }
- return idx;
-}
-
-static void ApplyBestPaletteEntry(int x, int y,
- uint32_t new_value, uint32_t palette_value,
- uint32_t* src, int src_stride,
- uint32_t* new_image) {
- AddPixelsEq(&new_value, palette_value);
- if (x > 0) {
- src[x - 1] = ClampedAddSubtractFullWithCoefficient(src[x - 1],
- new_value, src[x]);
- }
- if (y > 0) {
- src[x - src_stride] =
- ClampedAddSubtractFullWithCoefficient(src[x - src_stride],
- new_value, src[x]);
- }
- new_image[x] = new_value;
-}
-
-//------------------------------------------------------------------------------
-// Main entry point
-
-static WebPEncodingError ApplyDeltaPalette(uint32_t* src, uint32_t* dst,
- uint32_t src_stride,
- uint32_t dst_stride,
- const uint32_t* palette,
- int palette_size,
- int width, int height,
- int num_passes) {
- int x, y;
- WebPEncodingError err = VP8_ENC_OK;
- uint32_t* new_image = (uint32_t*)WebPSafeMalloc(width, sizeof(*new_image));
- uint8_t* const tmp_row = (uint8_t*)WebPSafeMalloc(width, sizeof(*tmp_row));
- if (new_image == NULL || tmp_row == NULL) {
- err = VP8_ENC_ERROR_OUT_OF_MEMORY;
- goto Error;
- }
-
- while (num_passes--) {
- uint32_t* cur_src = src;
- uint32_t* cur_dst = dst;
- for (y = 0; y < height; ++y) {
- for (x = 0; x < width; ++x) {
- const uint32_t predicted_value = Predict(x, y, new_image);
- tmp_row[x] = FindBestPaletteEntry(cur_src[x], predicted_value,
- palette, palette_size);
- ApplyBestPaletteEntry(x, y, predicted_value, palette[tmp_row[x]],
- cur_src, src_stride, new_image);
- }
- for (x = 0; x < width; ++x) {
- cur_dst[x] = palette[tmp_row[x]];
- }
- cur_src += src_stride;
- cur_dst += dst_stride;
- }
- }
- Error:
- WebPSafeFree(new_image);
- WebPSafeFree(tmp_row);
- return err;
-}
-
-// replaces enc->argb_ by a palettizable approximation of it,
-// and generates optimal enc->palette_[]
-WebPEncodingError WebPSearchOptimalDeltaPalette(VP8LEncoder* const enc) {
- const WebPPicture* const pic = enc->pic_;
- uint32_t* src = pic->argb;
- uint32_t* dst = enc->argb_;
- const int width = pic->width;
- const int height = pic->height;
-
- WebPEncodingError err = VP8_ENC_OK;
- memcpy(enc->palette_, kDeltaPalette, sizeof(kDeltaPalette));
- enc->palette_[DELTA_PALETTE_SIZE - 1] = src[0] - 0xff000000u;
- enc->palette_size_ = DELTA_PALETTE_SIZE;
- err = ApplyDeltaPalette(src, dst, pic->argb_stride, enc->current_width_,
- enc->palette_, enc->palette_size_,
- width, height, 2);
- if (err != VP8_ENC_OK) goto Error;
-
- Error:
- return err;
-}
-
-#else // !WEBP_EXPERIMENTAL_FEATURES
-
-WebPEncodingError WebPSearchOptimalDeltaPalette(VP8LEncoder* const enc) {
- (void)enc;
- return VP8_ENC_ERROR_INVALID_CONFIGURATION;
-}
-
-#endif // WEBP_EXPERIMENTAL_FEATURES
diff --git a/thirdparty/libwebp/src/enc/delta_palettization_enc.h b/thirdparty/libwebp/src/enc/delta_palettization_enc.h
deleted file mode 100644
index b15e2cd487..0000000000
--- a/thirdparty/libwebp/src/enc/delta_palettization_enc.h
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2015 Google Inc. All Rights Reserved.
-//
-// Use of this source code is governed by a BSD-style license
-// that can be found in the COPYING file in the root of the source
-// tree. An additional intellectual property rights grant can be found
-// in the file PATENTS. All contributing project authors may
-// be found in the AUTHORS file in the root of the source tree.
-// -----------------------------------------------------------------------------
-//
-// Author: Mislav Bradac (mislavm@google.com)
-//
-
-#ifndef WEBP_ENC_DELTA_PALETTIZATION_ENC_H_
-#define WEBP_ENC_DELTA_PALETTIZATION_ENC_H_
-
-#include "src/webp/encode.h"
-#include "src/enc/vp8li_enc.h"
-
-// Replaces enc->argb_[] input by a palettizable approximation of it,
-// and generates optimal enc->palette_[].
-// This function can revert enc->use_palette_ / enc->use_predict_ flag
-// if delta-palettization is not producing expected saving.
-WebPEncodingError WebPSearchOptimalDeltaPalette(VP8LEncoder* const enc);
-
-#endif // WEBP_ENC_DELTA_PALETTIZATION_ENC_H_
diff --git a/thirdparty/libwebp/src/enc/histogram_enc.c b/thirdparty/libwebp/src/enc/histogram_enc.c
index 9fdbc627a1..4e49e0a201 100644
--- a/thirdparty/libwebp/src/enc/histogram_enc.c
+++ b/thirdparty/libwebp/src/enc/histogram_enc.c
@@ -51,10 +51,12 @@ static void HistogramCopy(const VP8LHistogram* const src,
VP8LHistogram* const dst) {
uint32_t* const dst_literal = dst->literal_;
const int dst_cache_bits = dst->palette_code_bits_;
+ const int literal_size = VP8LHistogramNumCodes(dst_cache_bits);
const int histo_size = VP8LGetHistogramSize(dst_cache_bits);
assert(src->palette_code_bits_ == dst_cache_bits);
memcpy(dst, src, histo_size);
dst->literal_ = dst_literal;
+ memcpy(dst->literal_, src->literal_, literal_size * sizeof(*dst->literal_));
}
int VP8LGetHistogramSize(int cache_bits) {
@@ -91,9 +93,19 @@ void VP8LHistogramCreate(VP8LHistogram* const p,
VP8LHistogramStoreRefs(refs, p);
}
-void VP8LHistogramInit(VP8LHistogram* const p, int palette_code_bits) {
+void VP8LHistogramInit(VP8LHistogram* const p, int palette_code_bits,
+ int init_arrays) {
p->palette_code_bits_ = palette_code_bits;
- HistogramClear(p);
+ if (init_arrays) {
+ HistogramClear(p);
+ } else {
+ p->trivial_symbol_ = 0;
+ p->bit_cost_ = 0.;
+ p->literal_cost_ = 0.;
+ p->red_cost_ = 0.;
+ p->blue_cost_ = 0.;
+ memset(p->is_used_, 0, sizeof(p->is_used_));
+ }
}
VP8LHistogram* VP8LAllocateHistogram(int cache_bits) {
@@ -104,37 +116,70 @@ VP8LHistogram* VP8LAllocateHistogram(int cache_bits) {
histo = (VP8LHistogram*)memory;
// literal_ won't necessary be aligned.
histo->literal_ = (uint32_t*)(memory + sizeof(VP8LHistogram));
- VP8LHistogramInit(histo, cache_bits);
+ VP8LHistogramInit(histo, cache_bits, /*init_arrays=*/ 0);
return histo;
}
+// Resets the pointers of the histograms to point to the bit buffer in the set.
+static void HistogramSetResetPointers(VP8LHistogramSet* const set,
+ int cache_bits) {
+ int i;
+ const int histo_size = VP8LGetHistogramSize(cache_bits);
+ uint8_t* memory = (uint8_t*) (set->histograms);
+ memory += set->max_size * sizeof(*set->histograms);
+ for (i = 0; i < set->max_size; ++i) {
+ memory = (uint8_t*) WEBP_ALIGN(memory);
+ set->histograms[i] = (VP8LHistogram*) memory;
+ // literal_ won't necessary be aligned.
+ set->histograms[i]->literal_ = (uint32_t*)(memory + sizeof(VP8LHistogram));
+ memory += histo_size;
+ }
+}
+
+// Returns the total size of the VP8LHistogramSet.
+static size_t HistogramSetTotalSize(int size, int cache_bits) {
+ const int histo_size = VP8LGetHistogramSize(cache_bits);
+ return (sizeof(VP8LHistogramSet) + size * (sizeof(VP8LHistogram*) +
+ histo_size + WEBP_ALIGN_CST));
+}
+
VP8LHistogramSet* VP8LAllocateHistogramSet(int size, int cache_bits) {
int i;
VP8LHistogramSet* set;
- const int histo_size = VP8LGetHistogramSize(cache_bits);
- const size_t total_size =
- sizeof(*set) + size * (sizeof(*set->histograms) +
- histo_size + WEBP_ALIGN_CST);
+ const size_t total_size = HistogramSetTotalSize(size, cache_bits);
uint8_t* memory = (uint8_t*)WebPSafeMalloc(total_size, sizeof(*memory));
if (memory == NULL) return NULL;
set = (VP8LHistogramSet*)memory;
memory += sizeof(*set);
set->histograms = (VP8LHistogram**)memory;
- memory += size * sizeof(*set->histograms);
set->max_size = size;
set->size = size;
+ HistogramSetResetPointers(set, cache_bits);
for (i = 0; i < size; ++i) {
- memory = (uint8_t*)WEBP_ALIGN(memory);
- set->histograms[i] = (VP8LHistogram*)memory;
- // literal_ won't necessary be aligned.
- set->histograms[i]->literal_ = (uint32_t*)(memory + sizeof(VP8LHistogram));
- VP8LHistogramInit(set->histograms[i], cache_bits);
- memory += histo_size;
+ VP8LHistogramInit(set->histograms[i], cache_bits, /*init_arrays=*/ 0);
}
return set;
}
+void VP8LHistogramSetClear(VP8LHistogramSet* const set) {
+ int i;
+ const int cache_bits = set->histograms[0]->palette_code_bits_;
+ const int size = set->size;
+ const size_t total_size = HistogramSetTotalSize(size, cache_bits);
+ uint8_t* memory = (uint8_t*)set;
+
+ memset(memory, 0, total_size);
+ memory += sizeof(*set);
+ set->histograms = (VP8LHistogram**)memory;
+ set->max_size = size;
+ set->size = size;
+ HistogramSetResetPointers(set, cache_bits);
+ for (i = 0; i < size; ++i) {
+ set->histograms[i]->palette_code_bits_ = cache_bits;
+ }
+}
+
// -----------------------------------------------------------------------------
void VP8LHistogramAddSinglePixOrCopy(VP8LHistogram* const histo,
@@ -237,7 +282,8 @@ static double FinalHuffmanCost(const VP8LStreaks* const stats) {
// Get the symbol entropy for the distribution 'population'.
// Set 'trivial_sym', if there's only one symbol present in the distribution.
static double PopulationCost(const uint32_t* const population, int length,
- uint32_t* const trivial_sym) {
+ uint32_t* const trivial_sym,
+ uint8_t* const is_used) {
VP8LBitEntropy bit_entropy;
VP8LStreaks stats;
VP8LGetEntropyUnrefined(population, length, &bit_entropy, &stats);
@@ -245,6 +291,8 @@ static double PopulationCost(const uint32_t* const population, int length,
*trivial_sym = (bit_entropy.nonzeros == 1) ? bit_entropy.nonzero_code
: VP8L_NON_TRIVIAL_SYM;
}
+ // The histogram is used if there is at least one non-zero streak.
+ *is_used = (stats.streaks[1][0] != 0 || stats.streaks[1][1] != 0);
return BitsEntropyRefine(&bit_entropy) + FinalHuffmanCost(&stats);
}
@@ -253,7 +301,9 @@ static double PopulationCost(const uint32_t* const population, int length,
// non-zero: both the zero-th one, or both the last one.
static WEBP_INLINE double GetCombinedEntropy(const uint32_t* const X,
const uint32_t* const Y,
- int length, int trivial_at_end) {
+ int length, int is_X_used,
+ int is_Y_used,
+ int trivial_at_end) {
VP8LStreaks stats;
if (trivial_at_end) {
// This configuration is due to palettization that transforms an indexed
@@ -262,28 +312,43 @@ static WEBP_INLINE double GetCombinedEntropy(const uint32_t* const X,
// Only FinalHuffmanCost needs to be evaluated.
memset(&stats, 0, sizeof(stats));
// Deal with the non-zero value at index 0 or length-1.
- stats.streaks[1][0] += 1;
+ stats.streaks[1][0] = 1;
// Deal with the following/previous zero streak.
- stats.counts[0] += 1;
- stats.streaks[0][1] += length - 1;
+ stats.counts[0] = 1;
+ stats.streaks[0][1] = length - 1;
return FinalHuffmanCost(&stats);
} else {
VP8LBitEntropy bit_entropy;
- VP8LGetCombinedEntropyUnrefined(X, Y, length, &bit_entropy, &stats);
+ if (is_X_used) {
+ if (is_Y_used) {
+ VP8LGetCombinedEntropyUnrefined(X, Y, length, &bit_entropy, &stats);
+ } else {
+ VP8LGetEntropyUnrefined(X, length, &bit_entropy, &stats);
+ }
+ } else {
+ if (is_Y_used) {
+ VP8LGetEntropyUnrefined(Y, length, &bit_entropy, &stats);
+ } else {
+ memset(&stats, 0, sizeof(stats));
+ stats.counts[0] = 1;
+ stats.streaks[0][length > 3] = length;
+ VP8LBitEntropyInit(&bit_entropy);
+ }
+ }
return BitsEntropyRefine(&bit_entropy) + FinalHuffmanCost(&stats);
}
}
// Estimates the Entropy + Huffman + other block overhead size cost.
-double VP8LHistogramEstimateBits(const VP8LHistogram* const p) {
+double VP8LHistogramEstimateBits(VP8LHistogram* const p) {
return
- PopulationCost(
- p->literal_, VP8LHistogramNumCodes(p->palette_code_bits_), NULL)
- + PopulationCost(p->red_, NUM_LITERAL_CODES, NULL)
- + PopulationCost(p->blue_, NUM_LITERAL_CODES, NULL)
- + PopulationCost(p->alpha_, NUM_LITERAL_CODES, NULL)
- + PopulationCost(p->distance_, NUM_DISTANCE_CODES, NULL)
+ PopulationCost(p->literal_, VP8LHistogramNumCodes(p->palette_code_bits_),
+ NULL, &p->is_used_[0])
+ + PopulationCost(p->red_, NUM_LITERAL_CODES, NULL, &p->is_used_[1])
+ + PopulationCost(p->blue_, NUM_LITERAL_CODES, NULL, &p->is_used_[2])
+ + PopulationCost(p->alpha_, NUM_LITERAL_CODES, NULL, &p->is_used_[3])
+ + PopulationCost(p->distance_, NUM_DISTANCE_CODES, NULL, &p->is_used_[4])
+ VP8LExtraCost(p->literal_ + NUM_LITERAL_CODES, NUM_LENGTH_CODES)
+ VP8LExtraCost(p->distance_, NUM_DISTANCE_CODES);
}
@@ -299,7 +364,8 @@ static int GetCombinedHistogramEntropy(const VP8LHistogram* const a,
int trivial_at_end = 0;
assert(a->palette_code_bits_ == b->palette_code_bits_);
*cost += GetCombinedEntropy(a->literal_, b->literal_,
- VP8LHistogramNumCodes(palette_code_bits), 0);
+ VP8LHistogramNumCodes(palette_code_bits),
+ a->is_used_[0], b->is_used_[0], 0);
*cost += VP8LExtraCostCombined(a->literal_ + NUM_LITERAL_CODES,
b->literal_ + NUM_LITERAL_CODES,
NUM_LENGTH_CODES);
@@ -319,19 +385,23 @@ static int GetCombinedHistogramEntropy(const VP8LHistogram* const a,
}
*cost +=
- GetCombinedEntropy(a->red_, b->red_, NUM_LITERAL_CODES, trivial_at_end);
+ GetCombinedEntropy(a->red_, b->red_, NUM_LITERAL_CODES, a->is_used_[1],
+ b->is_used_[1], trivial_at_end);
if (*cost > cost_threshold) return 0;
*cost +=
- GetCombinedEntropy(a->blue_, b->blue_, NUM_LITERAL_CODES, trivial_at_end);
+ GetCombinedEntropy(a->blue_, b->blue_, NUM_LITERAL_CODES, a->is_used_[2],
+ b->is_used_[2], trivial_at_end);
if (*cost > cost_threshold) return 0;
- *cost += GetCombinedEntropy(a->alpha_, b->alpha_, NUM_LITERAL_CODES,
- trivial_at_end);
+ *cost +=
+ GetCombinedEntropy(a->alpha_, b->alpha_, NUM_LITERAL_CODES,
+ a->is_used_[3], b->is_used_[3], trivial_at_end);
if (*cost > cost_threshold) return 0;
*cost +=
- GetCombinedEntropy(a->distance_, b->distance_, NUM_DISTANCE_CODES, 0);
+ GetCombinedEntropy(a->distance_, b->distance_, NUM_DISTANCE_CODES,
+ a->is_used_[4], b->is_used_[4], 0);
*cost +=
VP8LExtraCostCombined(a->distance_, b->distance_, NUM_DISTANCE_CODES);
if (*cost > cost_threshold) return 0;
@@ -419,16 +489,19 @@ static void UpdateDominantCostRange(
static void UpdateHistogramCost(VP8LHistogram* const h) {
uint32_t alpha_sym, red_sym, blue_sym;
const double alpha_cost =
- PopulationCost(h->alpha_, NUM_LITERAL_CODES, &alpha_sym);
+ PopulationCost(h->alpha_, NUM_LITERAL_CODES, &alpha_sym,
+ &h->is_used_[3]);
const double distance_cost =
- PopulationCost(h->distance_, NUM_DISTANCE_CODES, NULL) +
+ PopulationCost(h->distance_, NUM_DISTANCE_CODES, NULL, &h->is_used_[4]) +
VP8LExtraCost(h->distance_, NUM_DISTANCE_CODES);
const int num_codes = VP8LHistogramNumCodes(h->palette_code_bits_);
- h->literal_cost_ = PopulationCost(h->literal_, num_codes, NULL) +
- VP8LExtraCost(h->literal_ + NUM_LITERAL_CODES,
- NUM_LENGTH_CODES);
- h->red_cost_ = PopulationCost(h->red_, NUM_LITERAL_CODES, &red_sym);
- h->blue_cost_ = PopulationCost(h->blue_, NUM_LITERAL_CODES, &blue_sym);
+ h->literal_cost_ =
+ PopulationCost(h->literal_, num_codes, NULL, &h->is_used_[0]) +
+ VP8LExtraCost(h->literal_ + NUM_LITERAL_CODES, NUM_LENGTH_CODES);
+ h->red_cost_ =
+ PopulationCost(h->red_, NUM_LITERAL_CODES, &red_sym, &h->is_used_[1]);
+ h->blue_cost_ =
+ PopulationCost(h->blue_, NUM_LITERAL_CODES, &blue_sym, &h->is_used_[2]);
h->bit_cost_ = h->literal_cost_ + h->red_cost_ + h->blue_cost_ +
alpha_cost + distance_cost;
if ((alpha_sym | red_sym | blue_sym) == VP8L_NON_TRIVIAL_SYM) {
@@ -473,6 +546,7 @@ static void HistogramBuild(
VP8LHistogram** const histograms = image_histo->histograms;
VP8LRefsCursor c = VP8LRefsCursorInit(backward_refs);
assert(histo_bits > 0);
+ VP8LHistogramSetClear(image_histo);
while (VP8LRefsCursorOk(&c)) {
const PixOrCopy* const v = c.cur_pos;
const int ix = (y >> histo_bits) * histo_xsize + (x >> histo_bits);
@@ -493,11 +567,19 @@ static void HistogramCopyAndAnalyze(
const int histo_size = orig_histo->size;
VP8LHistogram** const orig_histograms = orig_histo->histograms;
VP8LHistogram** const histograms = image_histo->histograms;
+ image_histo->size = 0;
for (i = 0; i < histo_size; ++i) {
VP8LHistogram* const histo = orig_histograms[i];
UpdateHistogramCost(histo);
+
+ // Skip the histogram if it is completely empty, which can happen for tiles
+ // with no information (when they are skipped because of LZ77).
+ if (!histo->is_used_[0] && !histo->is_used_[1] && !histo->is_used_[2]
+ && !histo->is_used_[3] && !histo->is_used_[4]) {
+ continue;
+ }
// Copy histograms from orig_histo[] to image_histo[].
- HistogramCopy(histo, histograms[i]);
+ HistogramCopy(histo, histograms[image_histo->size++]);
}
}
@@ -674,6 +756,18 @@ static void HistoQueueUpdateHead(HistoQueue* const histo_queue,
}
}
+// Update the cost diff and combo of a pair of histograms. This needs to be
+// called when the the histograms have been merged with a third one.
+static void HistoQueueUpdatePair(const VP8LHistogram* const h1,
+ const VP8LHistogram* const h2,
+ double threshold,
+ HistogramPair* const pair) {
+ const double sum_cost = h1->bit_cost_ + h2->bit_cost_;
+ pair->cost_combo = 0.;
+ GetCombinedHistogramEntropy(h1, h2, sum_cost + threshold, &pair->cost_combo);
+ pair->cost_diff = pair->cost_combo - sum_cost;
+}
+
// Create a pair from indices "idx1" and "idx2" provided its cost
// is inferior to "threshold", a negative entropy.
// It returns the cost of the pair, or 0. if it superior to threshold.
@@ -683,7 +777,6 @@ static double HistoQueuePush(HistoQueue* const histo_queue,
const VP8LHistogram* h1;
const VP8LHistogram* h2;
HistogramPair pair;
- double sum_cost;
assert(threshold <= 0.);
if (idx1 > idx2) {
@@ -695,10 +788,8 @@ static double HistoQueuePush(HistoQueue* const histo_queue,
pair.idx2 = idx2;
h1 = histograms[idx1];
h2 = histograms[idx2];
- sum_cost = h1->bit_cost_ + h2->bit_cost_;
- pair.cost_combo = 0.;
- GetCombinedHistogramEntropy(h1, h2, sum_cost + threshold, &pair.cost_combo);
- pair.cost_diff = pair.cost_combo - sum_cost;
+
+ HistoQueueUpdatePair(h1, h2, threshold, &pair);
// Do not even consider the pair if it does not improve the entropy.
if (pair.cost_diff >= threshold) return 0.;
@@ -891,8 +982,7 @@ static int HistogramCombineStochastic(VP8LHistogramSet* const image_histo,
}
if (do_eval) {
// Re-evaluate the cost of an updated pair.
- GetCombinedHistogramEntropy(histograms[p->idx1], histograms[p->idx2], 0,
- &p->cost_diff);
+ HistoQueueUpdatePair(histograms[p->idx1], histograms[p->idx2], 0., p);
if (p->cost_diff >= 0.) {
HistoQueuePopPair(&histo_queue, p);
continue;
@@ -987,8 +1077,7 @@ int VP8LGetHistoImageSymbols(int xsize, int ysize,
// histograms of small sizes (as bin_map will be very sparse) and
// maximum quality q==100 (to preserve the compression gains at that level).
const int entropy_combine_num_bins = low_effort ? NUM_PARTITIONS : BIN_SIZE;
- const int entropy_combine =
- (orig_histo->size > entropy_combine_num_bins * 2) && (quality < 100);
+ int entropy_combine;
if (orig_histo == NULL) goto Error;
@@ -996,15 +1085,16 @@ int VP8LGetHistoImageSymbols(int xsize, int ysize,
HistogramBuild(xsize, histo_bits, refs, orig_histo);
// Copies the histograms and computes its bit_cost.
HistogramCopyAndAnalyze(orig_histo, image_histo);
-
+ entropy_combine =
+ (image_histo->size > entropy_combine_num_bins * 2) && (quality < 100);
if (entropy_combine) {
- const int bin_map_size = orig_histo->size;
+ const int bin_map_size = image_histo->size;
// Reuse histogram_symbols storage. By definition, it's guaranteed to be ok.
uint16_t* const bin_map = histogram_symbols;
const double combine_cost_factor =
GetCombineCostFactor(image_histo_raw_size, quality);
- HistogramAnalyzeEntropyBin(orig_histo, bin_map, low_effort);
+ HistogramAnalyzeEntropyBin(image_histo, bin_map, low_effort);
// Collapse histograms with similar entropy.
HistogramCombineEntropyBin(image_histo, tmp_histo, bin_map, bin_map_size,
entropy_combine_num_bins, combine_cost_factor,
diff --git a/thirdparty/libwebp/src/enc/histogram_enc.h b/thirdparty/libwebp/src/enc/histogram_enc.h
index e8c4c83f6f..54c2d21783 100644
--- a/thirdparty/libwebp/src/enc/histogram_enc.h
+++ b/thirdparty/libwebp/src/enc/histogram_enc.h
@@ -44,6 +44,7 @@ typedef struct {
double literal_cost_; // Cached values of dominant entropy costs:
double red_cost_; // literal, red & blue.
double blue_cost_;
+ uint8_t is_used_[5]; // 5 for literal, red, blue, alpha, distance
} VP8LHistogram;
// Collection of histograms with fixed capacity, allocated as one
@@ -67,7 +68,9 @@ void VP8LHistogramCreate(VP8LHistogram* const p,
int VP8LGetHistogramSize(int palette_code_bits);
// Set the palette_code_bits and reset the stats.
-void VP8LHistogramInit(VP8LHistogram* const p, int palette_code_bits);
+// If init_arrays is true, the arrays are also filled with 0's.
+void VP8LHistogramInit(VP8LHistogram* const p, int palette_code_bits,
+ int init_arrays);
// Collect all the references into a histogram (without reset)
void VP8LHistogramStoreRefs(const VP8LBackwardRefs* const refs,
@@ -83,6 +86,9 @@ void VP8LFreeHistogramSet(VP8LHistogramSet* const histo);
// using 'cache_bits'. Return NULL in case of memory error.
VP8LHistogramSet* VP8LAllocateHistogramSet(int size, int cache_bits);
+// Set the histograms in set to 0.
+void VP8LHistogramSetClear(VP8LHistogramSet* const set);
+
// Allocate and initialize histogram object with specified 'cache_bits'.
// Returns NULL in case of memory error.
// Special case of VP8LAllocateHistogramSet, with size equals 1.
@@ -113,7 +119,7 @@ double VP8LBitsEntropy(const uint32_t* const array, int n);
// Estimate how many bits the combined entropy of literals and distance
// approximately maps to.
-double VP8LHistogramEstimateBits(const VP8LHistogram* const p);
+double VP8LHistogramEstimateBits(VP8LHistogram* const p);
#ifdef __cplusplus
}
diff --git a/thirdparty/libwebp/src/enc/iterator_enc.c b/thirdparty/libwebp/src/enc/iterator_enc.c
index 7c47d51272..29f91d8315 100644
--- a/thirdparty/libwebp/src/enc/iterator_enc.c
+++ b/thirdparty/libwebp/src/enc/iterator_enc.c
@@ -128,7 +128,7 @@ static void ImportLine(const uint8_t* src, int src_stride,
for (; i < total_len; ++i) dst[i] = dst[len - 1];
}
-void VP8IteratorImport(VP8EncIterator* const it, uint8_t* tmp_32) {
+void VP8IteratorImport(VP8EncIterator* const it, uint8_t* const tmp_32) {
const VP8Encoder* const enc = it->enc_;
const int x = it->x_, y = it->y_;
const WebPPicture* const pic = enc->pic_;
diff --git a/thirdparty/libwebp/src/enc/picture_tools_enc.c b/thirdparty/libwebp/src/enc/picture_tools_enc.c
index be292d4391..d0e8a495da 100644
--- a/thirdparty/libwebp/src/enc/picture_tools_enc.c
+++ b/thirdparty/libwebp/src/enc/picture_tools_enc.c
@@ -16,10 +16,6 @@
#include "src/enc/vp8i_enc.h"
#include "src/dsp/yuv.h"
-static WEBP_INLINE uint32_t MakeARGB32(int r, int g, int b) {
- return (0xff000000u | (r << 16) | (g << 8) | b);
-}
-
//------------------------------------------------------------------------------
// Helper: clean up fully transparent area to help compressibility.
@@ -195,6 +191,10 @@ void WebPCleanupTransparentAreaLossless(WebPPicture* const pic) {
#define BLEND_10BIT(V0, V1, ALPHA) \
((((V0) * (1020 - (ALPHA)) + (V1) * (ALPHA)) * 0x101 + 1024) >> 18)
+static WEBP_INLINE uint32_t MakeARGB32(int r, int g, int b) {
+ return (0xff000000u | (r << 16) | (g << 8) | b);
+}
+
void WebPBlendAlpha(WebPPicture* pic, uint32_t background_rgb) {
const int red = (background_rgb >> 16) & 0xff;
const int green = (background_rgb >> 8) & 0xff;
@@ -208,39 +208,44 @@ void WebPBlendAlpha(WebPPicture* pic, uint32_t background_rgb) {
const int U0 = VP8RGBToU(4 * red, 4 * green, 4 * blue, 4 * YUV_HALF);
const int V0 = VP8RGBToV(4 * red, 4 * green, 4 * blue, 4 * YUV_HALF);
const int has_alpha = pic->colorspace & WEBP_CSP_ALPHA_BIT;
- if (!has_alpha || pic->a == NULL) return; // nothing to do
+ uint8_t* y_ptr = pic->y;
+ uint8_t* u_ptr = pic->u;
+ uint8_t* v_ptr = pic->v;
+ uint8_t* a_ptr = pic->a;
+ if (!has_alpha || a_ptr == NULL) return; // nothing to do
for (y = 0; y < pic->height; ++y) {
// Luma blending
- uint8_t* const y_ptr = pic->y + y * pic->y_stride;
- uint8_t* const a_ptr = pic->a + y * pic->a_stride;
for (x = 0; x < pic->width; ++x) {
- const int alpha = a_ptr[x];
+ const uint8_t alpha = a_ptr[x];
if (alpha < 0xff) {
- y_ptr[x] = BLEND(Y0, y_ptr[x], a_ptr[x]);
+ y_ptr[x] = BLEND(Y0, y_ptr[x], alpha);
}
}
// Chroma blending every even line
if ((y & 1) == 0) {
- uint8_t* const u = pic->u + (y >> 1) * pic->uv_stride;
- uint8_t* const v = pic->v + (y >> 1) * pic->uv_stride;
uint8_t* const a_ptr2 =
(y + 1 == pic->height) ? a_ptr : a_ptr + pic->a_stride;
for (x = 0; x < uv_width; ++x) {
// Average four alpha values into a single blending weight.
// TODO(skal): might lead to visible contouring. Can we do better?
- const int alpha =
+ const uint32_t alpha =
a_ptr[2 * x + 0] + a_ptr[2 * x + 1] +
a_ptr2[2 * x + 0] + a_ptr2[2 * x + 1];
- u[x] = BLEND_10BIT(U0, u[x], alpha);
- v[x] = BLEND_10BIT(V0, v[x], alpha);
+ u_ptr[x] = BLEND_10BIT(U0, u_ptr[x], alpha);
+ v_ptr[x] = BLEND_10BIT(V0, v_ptr[x], alpha);
}
if (pic->width & 1) { // rightmost pixel
- const int alpha = 2 * (a_ptr[2 * x + 0] + a_ptr2[2 * x + 0]);
- u[x] = BLEND_10BIT(U0, u[x], alpha);
- v[x] = BLEND_10BIT(V0, v[x], alpha);
+ const uint32_t alpha = 2 * (a_ptr[2 * x + 0] + a_ptr2[2 * x + 0]);
+ u_ptr[x] = BLEND_10BIT(U0, u_ptr[x], alpha);
+ v_ptr[x] = BLEND_10BIT(V0, v_ptr[x], alpha);
}
+ } else {
+ u_ptr += pic->uv_stride;
+ v_ptr += pic->uv_stride;
}
- memset(a_ptr, 0xff, pic->width);
+ memset(a_ptr, 0xff, pic->width); // reset alpha value to opaque
+ a_ptr += pic->a_stride;
+ y_ptr += pic->y_stride;
}
} else {
uint32_t* argb = pic->argb;
diff --git a/thirdparty/libwebp/src/enc/vp8i_enc.h b/thirdparty/libwebp/src/enc/vp8i_enc.h
index 624e8f8e66..92439febb8 100644
--- a/thirdparty/libwebp/src/enc/vp8i_enc.h
+++ b/thirdparty/libwebp/src/enc/vp8i_enc.h
@@ -32,7 +32,7 @@ extern "C" {
// version numbers
#define ENC_MAJ_VERSION 1
#define ENC_MIN_VERSION 0
-#define ENC_REV_VERSION 0
+#define ENC_REV_VERSION 1
enum { MAX_LF_LEVELS = 64, // Maximum loop filter level
MAX_VARIABLE_LEVEL = 67, // last (inclusive) level with variable cost
@@ -278,7 +278,7 @@ int VP8IteratorIsDone(const VP8EncIterator* const it);
// Import uncompressed samples from source.
// If tmp_32 is not NULL, import boundary samples too.
// tmp_32 is a 32-bytes scratch buffer that must be aligned in memory.
-void VP8IteratorImport(VP8EncIterator* const it, uint8_t* tmp_32);
+void VP8IteratorImport(VP8EncIterator* const it, uint8_t* const tmp_32);
// export decimated samples
void VP8IteratorExport(const VP8EncIterator* const it);
// go to next macroblock. Returns false if not finished.
@@ -515,4 +515,4 @@ void WebPCleanupTransparentAreaLossless(WebPPicture* const pic);
} // extern "C"
#endif
-#endif /* WEBP_ENC_VP8I_ENC_H_ */
+#endif // WEBP_ENC_VP8I_ENC_H_
diff --git a/thirdparty/libwebp/src/enc/vp8l_enc.c b/thirdparty/libwebp/src/enc/vp8l_enc.c
index a89184eb08..2713edcd95 100644
--- a/thirdparty/libwebp/src/enc/vp8l_enc.c
+++ b/thirdparty/libwebp/src/enc/vp8l_enc.c
@@ -809,6 +809,7 @@ static WebPEncodingError EncodeImageNoHuffman(VP8LBitWriter* const bw,
err = VP8_ENC_ERROR_OUT_OF_MEMORY;
goto Error;
}
+ VP8LHistogramSetClear(histogram_image);
// Build histogram image and symbols from backward references.
VP8LHistogramStoreRefs(refs, histogram_image->histograms[0]);
@@ -1248,14 +1249,20 @@ static WebPEncodingError MakeInputImageCopy(VP8LEncoder* const enc) {
const WebPPicture* const picture = enc->pic_;
const int width = picture->width;
const int height = picture->height;
- int y;
+
err = AllocateTransformBuffer(enc, width, height);
if (err != VP8_ENC_OK) return err;
if (enc->argb_content_ == kEncoderARGB) return VP8_ENC_OK;
- for (y = 0; y < height; ++y) {
- memcpy(enc->argb_ + y * width,
- picture->argb + y * picture->argb_stride,
- width * sizeof(*enc->argb_));
+
+ {
+ uint32_t* dst = enc->argb_;
+ const uint32_t* src = picture->argb;
+ int y;
+ for (y = 0; y < height; ++y) {
+ memcpy(dst, src, width * sizeof(*dst));
+ dst += width;
+ src += picture->argb_stride;
+ }
}
enc->argb_content_ = kEncoderARGB;
assert(enc->current_width_ == width);
diff --git a/thirdparty/libwebp/src/enc/vp8li_enc.h b/thirdparty/libwebp/src/enc/vp8li_enc.h
index 298a4a0014..d2d0fc509c 100644
--- a/thirdparty/libwebp/src/enc/vp8li_enc.h
+++ b/thirdparty/libwebp/src/enc/vp8li_enc.h
@@ -115,4 +115,4 @@ void VP8LColorSpaceTransform(int width, int height, int bits, int quality,
} // extern "C"
#endif
-#endif /* WEBP_ENC_VP8LI_ENC_H_ */
+#endif // WEBP_ENC_VP8LI_ENC_H_
diff --git a/thirdparty/libwebp/src/mux/animi.h b/thirdparty/libwebp/src/mux/animi.h
index 88899532aa..34c45ba4da 100644
--- a/thirdparty/libwebp/src/mux/animi.h
+++ b/thirdparty/libwebp/src/mux/animi.h
@@ -40,4 +40,4 @@ int WebPAnimEncoderRefineRect(
} // extern "C"
#endif
-#endif /* WEBP_MUX_ANIMI_H_ */
+#endif // WEBP_MUX_ANIMI_H_
diff --git a/thirdparty/libwebp/src/mux/muxedit.c b/thirdparty/libwebp/src/mux/muxedit.c
index 7a027b3cb4..ccf14b2a0c 100644
--- a/thirdparty/libwebp/src/mux/muxedit.c
+++ b/thirdparty/libwebp/src/mux/muxedit.c
@@ -69,12 +69,12 @@ void WebPMuxDelete(WebPMux* mux) {
if (idx == (INDEX)) { \
err = ChunkAssignData(&chunk, data, copy_data, tag); \
if (err == WEBP_MUX_OK) { \
- err = ChunkSetNth(&chunk, (LIST), nth); \
+ err = ChunkSetHead(&chunk, (LIST)); \
} \
return err; \
}
-static WebPMuxError MuxSet(WebPMux* const mux, uint32_t tag, uint32_t nth,
+static WebPMuxError MuxSet(WebPMux* const mux, uint32_t tag,
const WebPData* const data, int copy_data) {
WebPChunk chunk;
WebPMuxError err = WEBP_MUX_NOT_FOUND;
@@ -190,7 +190,7 @@ WebPMuxError WebPMuxSetChunk(WebPMux* mux, const char fourcc[4],
if (err != WEBP_MUX_OK && err != WEBP_MUX_NOT_FOUND) return err;
// Add the given chunk.
- return MuxSet(mux, tag, 1, chunk_data, copy_data);
+ return MuxSet(mux, tag, chunk_data, copy_data);
}
// Creates a chunk from given 'data' and sets it as 1st chunk in 'chunk_list'.
@@ -202,7 +202,7 @@ static WebPMuxError AddDataToChunkList(
ChunkInit(&chunk);
err = ChunkAssignData(&chunk, data, copy_data, tag);
if (err != WEBP_MUX_OK) goto Err;
- err = ChunkSetNth(&chunk, chunk_list, 1);
+ err = ChunkSetHead(&chunk, chunk_list);
if (err != WEBP_MUX_OK) goto Err;
return WEBP_MUX_OK;
Err:
@@ -266,14 +266,14 @@ WebPMuxError WebPMuxPushFrame(WebPMux* mux, const WebPMuxFrameInfo* info,
int copy_data) {
WebPMuxImage wpi;
WebPMuxError err;
- const WebPData* const bitstream = &info->bitstream;
// Sanity checks.
if (mux == NULL || info == NULL) return WEBP_MUX_INVALID_ARGUMENT;
if (info->id != WEBP_CHUNK_ANMF) return WEBP_MUX_INVALID_ARGUMENT;
- if (bitstream->bytes == NULL || bitstream->size > MAX_CHUNK_PAYLOAD) {
+ if (info->bitstream.bytes == NULL ||
+ info->bitstream.size > MAX_CHUNK_PAYLOAD) {
return WEBP_MUX_INVALID_ARGUMENT;
}
@@ -287,7 +287,7 @@ WebPMuxError WebPMuxPushFrame(WebPMux* mux, const WebPMuxFrameInfo* info,
}
MuxImageInit(&wpi);
- err = SetAlphaAndImageChunks(bitstream, copy_data, &wpi);
+ err = SetAlphaAndImageChunks(&info->bitstream, copy_data, &wpi);
if (err != WEBP_MUX_OK) goto Err;
assert(wpi.img_ != NULL); // As SetAlphaAndImageChunks() was successful.
@@ -342,7 +342,7 @@ WebPMuxError WebPMuxSetAnimationParams(WebPMux* mux,
// Set the animation parameters.
PutLE32(data, params->bgcolor);
PutLE16(data + 4, params->loop_count);
- return MuxSet(mux, kChunks[IDX_ANIM].tag, 1, &anim, 1);
+ return MuxSet(mux, kChunks[IDX_ANIM].tag, &anim, 1);
}
WebPMuxError WebPMuxSetCanvasSize(WebPMux* mux,
@@ -540,7 +540,7 @@ static WebPMuxError CreateVP8XChunk(WebPMux* const mux) {
PutLE24(data + 4, width - 1); // canvas width.
PutLE24(data + 7, height - 1); // canvas height.
- return MuxSet(mux, kChunks[IDX_VP8X].tag, 1, &vp8x, 1);
+ return MuxSet(mux, kChunks[IDX_VP8X].tag, &vp8x, 1);
}
// Cleans up 'mux' by removing any unnecessary chunks.
diff --git a/thirdparty/libwebp/src/mux/muxi.h b/thirdparty/libwebp/src/mux/muxi.h
index 6b57eea30f..df9f74c63c 100644
--- a/thirdparty/libwebp/src/mux/muxi.h
+++ b/thirdparty/libwebp/src/mux/muxi.h
@@ -14,6 +14,7 @@
#ifndef WEBP_MUX_MUXI_H_
#define WEBP_MUX_MUXI_H_
+#include <assert.h>
#include <stdlib.h>
#include "src/dec/vp8i_dec.h"
#include "src/dec/vp8li_dec.h"
@@ -28,7 +29,7 @@ extern "C" {
#define MUX_MAJ_VERSION 1
#define MUX_MIN_VERSION 0
-#define MUX_REV_VERSION 0
+#define MUX_REV_VERSION 1
// Chunk object.
typedef struct WebPChunk WebPChunk;
@@ -126,11 +127,14 @@ WebPChunk* ChunkSearchList(WebPChunk* first, uint32_t nth, uint32_t tag);
WebPMuxError ChunkAssignData(WebPChunk* chunk, const WebPData* const data,
int copy_data, uint32_t tag);
-// Sets 'chunk' at nth position in the 'chunk_list'.
-// nth = 0 has the special meaning "last of the list".
+// Sets 'chunk' as the only element in 'chunk_list' if it is empty.
// On success ownership is transferred from 'chunk' to the 'chunk_list'.
-WebPMuxError ChunkSetNth(WebPChunk* chunk, WebPChunk** chunk_list,
- uint32_t nth);
+WebPMuxError ChunkSetHead(WebPChunk* const chunk, WebPChunk** const chunk_list);
+// Sets 'chunk' at last position in the 'chunk_list'.
+// On success ownership is transferred from 'chunk' to the 'chunk_list'.
+// *chunk_list also points towards the last valid element of the initial
+// *chunk_list.
+WebPMuxError ChunkAppend(WebPChunk* const chunk, WebPChunk*** const chunk_list);
// Releases chunk and returns chunk->next_.
WebPChunk* ChunkRelease(WebPChunk* const chunk);
@@ -143,13 +147,13 @@ void ChunkListDelete(WebPChunk** const chunk_list);
// Returns size of the chunk including chunk header and padding byte (if any).
static WEBP_INLINE size_t SizeWithPadding(size_t chunk_size) {
+ assert(chunk_size <= MAX_CHUNK_PAYLOAD);
return CHUNK_HEADER_SIZE + ((chunk_size + 1) & ~1U);
}
// Size of a chunk including header and padding.
static WEBP_INLINE size_t ChunkDiskSize(const WebPChunk* chunk) {
const size_t data_size = chunk->data_.size;
- assert(data_size < MAX_CHUNK_PAYLOAD);
return SizeWithPadding(data_size);
}
@@ -227,4 +231,4 @@ WebPMuxError MuxValidate(const WebPMux* const mux);
} // extern "C"
#endif
-#endif /* WEBP_MUX_MUXI_H_ */
+#endif // WEBP_MUX_MUXI_H_
diff --git a/thirdparty/libwebp/src/mux/muxinternal.c b/thirdparty/libwebp/src/mux/muxinternal.c
index 1473f100e5..b9ee6717d3 100644
--- a/thirdparty/libwebp/src/mux/muxinternal.c
+++ b/thirdparty/libwebp/src/mux/muxinternal.c
@@ -111,27 +111,6 @@ WebPChunk* ChunkSearchList(WebPChunk* first, uint32_t nth, uint32_t tag) {
return ((nth > 0) && (iter > 0)) ? NULL : first;
}
-// Outputs a pointer to 'prev_chunk->next_',
-// where 'prev_chunk' is the pointer to the chunk at position (nth - 1).
-// Returns true if nth chunk was found.
-static int ChunkSearchListToSet(WebPChunk** chunk_list, uint32_t nth,
- WebPChunk*** const location) {
- uint32_t count = 0;
- assert(chunk_list != NULL);
- *location = chunk_list;
-
- while (*chunk_list != NULL) {
- WebPChunk* const cur_chunk = *chunk_list;
- ++count;
- if (count == nth) return 1; // Found.
- chunk_list = &cur_chunk->next_;
- *location = chunk_list;
- }
-
- // *chunk_list is ok to be NULL if adding at last location.
- return (nth == 0 || (count == nth - 1)) ? 1 : 0;
-}
-
//------------------------------------------------------------------------------
// Chunk writer methods.
@@ -156,11 +135,12 @@ WebPMuxError ChunkAssignData(WebPChunk* chunk, const WebPData* const data,
return WEBP_MUX_OK;
}
-WebPMuxError ChunkSetNth(WebPChunk* chunk, WebPChunk** chunk_list,
- uint32_t nth) {
+WebPMuxError ChunkSetHead(WebPChunk* const chunk,
+ WebPChunk** const chunk_list) {
WebPChunk* new_chunk;
- if (!ChunkSearchListToSet(chunk_list, nth, &chunk_list)) {
+ assert(chunk_list != NULL);
+ if (*chunk_list != NULL) {
return WEBP_MUX_NOT_FOUND;
}
@@ -168,11 +148,26 @@ WebPMuxError ChunkSetNth(WebPChunk* chunk, WebPChunk** chunk_list,
if (new_chunk == NULL) return WEBP_MUX_MEMORY_ERROR;
*new_chunk = *chunk;
chunk->owner_ = 0;
- new_chunk->next_ = *chunk_list;
+ new_chunk->next_ = NULL;
*chunk_list = new_chunk;
return WEBP_MUX_OK;
}
+WebPMuxError ChunkAppend(WebPChunk* const chunk,
+ WebPChunk*** const chunk_list) {
+ assert(chunk_list != NULL && *chunk_list != NULL);
+
+ if (**chunk_list == NULL) {
+ ChunkSetHead(chunk, *chunk_list);
+ } else {
+ WebPChunk* last_chunk = **chunk_list;
+ while (last_chunk->next_ != NULL) last_chunk = last_chunk->next_;
+ ChunkSetHead(chunk, &last_chunk->next_);
+ *chunk_list = &last_chunk->next_;
+ }
+ return WEBP_MUX_OK;
+}
+
//------------------------------------------------------------------------------
// Chunk deletion method(s).
@@ -232,9 +227,11 @@ void MuxImageInit(WebPMuxImage* const wpi) {
WebPMuxImage* MuxImageRelease(WebPMuxImage* const wpi) {
WebPMuxImage* next;
if (wpi == NULL) return NULL;
- ChunkDelete(wpi->header_);
- ChunkDelete(wpi->alpha_);
- ChunkDelete(wpi->img_);
+ // There should be at most one chunk of header_, alpha_, img_ but we call
+ // ChunkListDelete to be safe
+ ChunkListDelete(&wpi->header_);
+ ChunkListDelete(&wpi->alpha_);
+ ChunkListDelete(&wpi->img_);
ChunkListDelete(&wpi->unknown_);
next = wpi->next_;
diff --git a/thirdparty/libwebp/src/mux/muxread.c b/thirdparty/libwebp/src/mux/muxread.c
index 0b55286862..268f6acb53 100644
--- a/thirdparty/libwebp/src/mux/muxread.c
+++ b/thirdparty/libwebp/src/mux/muxread.c
@@ -59,6 +59,7 @@ static WebPMuxError ChunkVerifyAndAssign(WebPChunk* chunk,
// Sanity checks.
if (data_size < CHUNK_HEADER_SIZE) return WEBP_MUX_NOT_ENOUGH_DATA;
chunk_size = GetLE32(data + TAG_SIZE);
+ if (chunk_size > MAX_CHUNK_PAYLOAD) return WEBP_MUX_BAD_DATA;
{
const size_t chunk_disk_size = SizeWithPadding(chunk_size);
@@ -102,6 +103,7 @@ static int MuxImageParse(const WebPChunk* const chunk, int copy_data,
const uint8_t* const last = bytes + size;
WebPChunk subchunk;
size_t subchunk_size;
+ WebPChunk** unknown_chunk_list = &wpi->unknown_;
ChunkInit(&subchunk);
assert(chunk->tag_ == kChunks[IDX_ANMF].tag);
@@ -116,7 +118,7 @@ static int MuxImageParse(const WebPChunk* const chunk, int copy_data,
if (size < hdr_size) goto Fail;
ChunkAssignData(&subchunk, &temp, copy_data, chunk->tag_);
}
- ChunkSetNth(&subchunk, &wpi->header_, 1);
+ ChunkSetHead(&subchunk, &wpi->header_);
wpi->is_partial_ = 1; // Waiting for ALPH and/or VP8/VP8L chunks.
// Rest of the chunks.
@@ -133,18 +135,23 @@ static int MuxImageParse(const WebPChunk* const chunk, int copy_data,
switch (ChunkGetIdFromTag(subchunk.tag_)) {
case WEBP_CHUNK_ALPHA:
if (wpi->alpha_ != NULL) goto Fail; // Consecutive ALPH chunks.
- if (ChunkSetNth(&subchunk, &wpi->alpha_, 1) != WEBP_MUX_OK) goto Fail;
+ if (ChunkSetHead(&subchunk, &wpi->alpha_) != WEBP_MUX_OK) goto Fail;
wpi->is_partial_ = 1; // Waiting for a VP8 chunk.
break;
case WEBP_CHUNK_IMAGE:
- if (ChunkSetNth(&subchunk, &wpi->img_, 1) != WEBP_MUX_OK) goto Fail;
+ if (wpi->img_ != NULL) goto Fail; // Only 1 image chunk allowed.
+ if (ChunkSetHead(&subchunk, &wpi->img_) != WEBP_MUX_OK) goto Fail;
if (!MuxImageFinalize(wpi)) goto Fail;
wpi->is_partial_ = 0; // wpi is completely filled.
break;
case WEBP_CHUNK_UNKNOWN:
- if (wpi->is_partial_) goto Fail; // Encountered an unknown chunk
- // before some image chunks.
- if (ChunkSetNth(&subchunk, &wpi->unknown_, 0) != WEBP_MUX_OK) goto Fail;
+ if (wpi->is_partial_) {
+ goto Fail; // Encountered an unknown chunk
+ // before some image chunks.
+ }
+ if (ChunkAppend(&subchunk, &unknown_chunk_list) != WEBP_MUX_OK) {
+ goto Fail;
+ }
break;
default:
goto Fail;
@@ -175,6 +182,9 @@ WebPMux* WebPMuxCreateInternal(const WebPData* bitstream, int copy_data,
const uint8_t* data;
size_t size;
WebPChunk chunk;
+ // Stores the end of the chunk lists so that it is faster to append data to
+ // their ends.
+ WebPChunk** chunk_list_ends[WEBP_CHUNK_NIL + 1] = { NULL };
ChunkInit(&chunk);
// Sanity checks.
@@ -187,7 +197,7 @@ WebPMux* WebPMuxCreateInternal(const WebPData* bitstream, int copy_data,
size = bitstream->size;
if (data == NULL) return NULL;
- if (size < RIFF_HEADER_SIZE) return NULL;
+ if (size < RIFF_HEADER_SIZE + CHUNK_HEADER_SIZE) return NULL;
if (GetLE32(data + 0) != MKFOURCC('R', 'I', 'F', 'F') ||
GetLE32(data + CHUNK_HEADER_SIZE) != MKFOURCC('W', 'E', 'B', 'P')) {
return NULL;
@@ -196,8 +206,6 @@ WebPMux* WebPMuxCreateInternal(const WebPData* bitstream, int copy_data,
mux = WebPMuxNew();
if (mux == NULL) return NULL;
- if (size < RIFF_HEADER_SIZE + TAG_SIZE) goto Err;
-
tag = GetLE32(data + RIFF_HEADER_SIZE);
if (tag != kChunks[IDX_VP8].tag &&
tag != kChunks[IDX_VP8L].tag &&
@@ -205,13 +213,17 @@ WebPMux* WebPMuxCreateInternal(const WebPData* bitstream, int copy_data,
goto Err; // First chunk should be VP8, VP8L or VP8X.
}
- riff_size = SizeWithPadding(GetLE32(data + TAG_SIZE));
- if (riff_size > MAX_CHUNK_PAYLOAD || riff_size > size) {
- goto Err;
- } else {
- if (riff_size < size) { // Redundant data after last chunk.
- size = riff_size; // To make sure we don't read any data beyond mux_size.
- }
+ riff_size = GetLE32(data + TAG_SIZE);
+ if (riff_size > MAX_CHUNK_PAYLOAD) goto Err;
+
+ // Note this padding is historical and differs from demux.c which does not
+ // pad the file size.
+ riff_size = SizeWithPadding(riff_size);
+ if (riff_size < CHUNK_HEADER_SIZE) goto Err;
+ if (riff_size > size) goto Err;
+ // There's no point in reading past the end of the RIFF chunk.
+ if (size > riff_size + CHUNK_HEADER_SIZE) {
+ size = riff_size + CHUNK_HEADER_SIZE;
}
end = data + size;
@@ -226,7 +238,6 @@ WebPMux* WebPMuxCreateInternal(const WebPData* bitstream, int copy_data,
while (data != end) {
size_t data_size;
WebPChunkId id;
- WebPChunk** chunk_list;
if (ChunkVerifyAndAssign(&chunk, data, size, riff_size,
copy_data) != WEBP_MUX_OK) {
goto Err;
@@ -236,11 +247,11 @@ WebPMux* WebPMuxCreateInternal(const WebPData* bitstream, int copy_data,
switch (id) {
case WEBP_CHUNK_ALPHA:
if (wpi->alpha_ != NULL) goto Err; // Consecutive ALPH chunks.
- if (ChunkSetNth(&chunk, &wpi->alpha_, 1) != WEBP_MUX_OK) goto Err;
+ if (ChunkSetHead(&chunk, &wpi->alpha_) != WEBP_MUX_OK) goto Err;
wpi->is_partial_ = 1; // Waiting for a VP8 chunk.
break;
case WEBP_CHUNK_IMAGE:
- if (ChunkSetNth(&chunk, &wpi->img_, 1) != WEBP_MUX_OK) goto Err;
+ if (ChunkSetHead(&chunk, &wpi->img_) != WEBP_MUX_OK) goto Err;
if (!MuxImageFinalize(wpi)) goto Err;
wpi->is_partial_ = 0; // wpi is completely filled.
PushImage:
@@ -257,9 +268,13 @@ WebPMux* WebPMuxCreateInternal(const WebPData* bitstream, int copy_data,
default: // A non-image chunk.
if (wpi->is_partial_) goto Err; // Encountered a non-image chunk before
// getting all chunks of an image.
- chunk_list = MuxGetChunkListFromId(mux, id); // List to add this chunk.
- if (ChunkSetNth(&chunk, chunk_list, 0) != WEBP_MUX_OK) goto Err;
+ if (chunk_list_ends[id] == NULL) {
+ chunk_list_ends[id] =
+ MuxGetChunkListFromId(mux, id); // List to add this chunk.
+ }
+ if (ChunkAppend(&chunk, &chunk_list_ends[id]) != WEBP_MUX_OK) goto Err;
if (id == WEBP_CHUNK_VP8X) { // grab global specs
+ if (data_size < CHUNK_HEADER_SIZE + VP8X_CHUNK_SIZE) goto Err;
mux->canvas_width_ = GetLE24(data + 12) + 1;
mux->canvas_height_ = GetLE24(data + 15) + 1;
}
@@ -385,6 +400,10 @@ static WebPMuxError SynthesizeBitstream(const WebPMuxImage* const wpi,
uint8_t* const data = (uint8_t*)WebPSafeMalloc(1ULL, size);
if (data == NULL) return WEBP_MUX_MEMORY_ERROR;
+ // There should be at most one alpha_ chunk and exactly one img_ chunk.
+ assert(wpi->alpha_ == NULL || wpi->alpha_->next_ == NULL);
+ assert(wpi->img_ != NULL && wpi->img_->next_ == NULL);
+
// Main RIFF header.
dst = MuxEmitRiffHeader(data, size);
diff --git a/thirdparty/libwebp/src/utils/bit_reader_inl_utils.h b/thirdparty/libwebp/src/utils/bit_reader_inl_utils.h
index 2ccc6ed326..7e607f370a 100644
--- a/thirdparty/libwebp/src/utils/bit_reader_inl_utils.h
+++ b/thirdparty/libwebp/src/utils/bit_reader_inl_utils.h
@@ -187,4 +187,4 @@ static WEBP_INLINE int VP8GetBitAlt(VP8BitReader* const br, int prob) {
} // extern "C"
#endif
-#endif // WEBP_UTILS_BIT_READER_INL_UTILS_H_
+#endif // WEBP_UTILS_BIT_READER_INL_UTILS_H_
diff --git a/thirdparty/libwebp/src/utils/bit_reader_utils.h b/thirdparty/libwebp/src/utils/bit_reader_utils.h
index 04f9804409..de810d402a 100644
--- a/thirdparty/libwebp/src/utils/bit_reader_utils.h
+++ b/thirdparty/libwebp/src/utils/bit_reader_utils.h
@@ -182,4 +182,4 @@ static WEBP_INLINE void VP8LFillBitWindow(VP8LBitReader* const br) {
} // extern "C"
#endif
-#endif /* WEBP_UTILS_BIT_READER_UTILS_H_ */
+#endif // WEBP_UTILS_BIT_READER_UTILS_H_
diff --git a/thirdparty/libwebp/src/utils/bit_writer_utils.h b/thirdparty/libwebp/src/utils/bit_writer_utils.h
index 2cf5976fe3..b9d5102a5a 100644
--- a/thirdparty/libwebp/src/utils/bit_writer_utils.h
+++ b/thirdparty/libwebp/src/utils/bit_writer_utils.h
@@ -151,4 +151,4 @@ static WEBP_INLINE void VP8LPutBits(VP8LBitWriter* const bw,
} // extern "C"
#endif
-#endif /* WEBP_UTILS_BIT_WRITER_UTILS_H_ */
+#endif // WEBP_UTILS_BIT_WRITER_UTILS_H_
diff --git a/thirdparty/libwebp/src/utils/filters_utils.h b/thirdparty/libwebp/src/utils/filters_utils.h
index 410f2fcdf2..61da66e212 100644
--- a/thirdparty/libwebp/src/utils/filters_utils.h
+++ b/thirdparty/libwebp/src/utils/filters_utils.h
@@ -29,4 +29,4 @@ WEBP_FILTER_TYPE WebPEstimateBestFilter(const uint8_t* data,
} // extern "C"
#endif
-#endif /* WEBP_UTILS_FILTERS_UTILS_H_ */
+#endif // WEBP_UTILS_FILTERS_UTILS_H_
diff --git a/thirdparty/libwebp/src/utils/quant_levels_dec_utils.c b/thirdparty/libwebp/src/utils/quant_levels_dec_utils.c
index 3818a78b93..f65b6cdbb6 100644
--- a/thirdparty/libwebp/src/utils/quant_levels_dec_utils.c
+++ b/thirdparty/libwebp/src/utils/quant_levels_dec_utils.c
@@ -261,9 +261,15 @@ static void CleanupParams(SmoothParams* const p) {
int WebPDequantizeLevels(uint8_t* const data, int width, int height, int stride,
int strength) {
- const int radius = 4 * strength / 100;
+ int radius = 4 * strength / 100;
+
if (strength < 0 || strength > 100) return 0;
if (data == NULL || width <= 0 || height <= 0) return 0; // bad params
+
+ // limit the filter size to not exceed the image dimensions
+ if (2 * radius + 1 > width) radius = (width - 1) >> 1;
+ if (2 * radius + 1 > height) radius = (height - 1) >> 1;
+
if (radius > 0) {
SmoothParams p;
memset(&p, 0, sizeof(p));
diff --git a/thirdparty/libwebp/src/utils/quant_levels_dec_utils.h b/thirdparty/libwebp/src/utils/quant_levels_dec_utils.h
index f822107a72..327f19f336 100644
--- a/thirdparty/libwebp/src/utils/quant_levels_dec_utils.h
+++ b/thirdparty/libwebp/src/utils/quant_levels_dec_utils.h
@@ -32,4 +32,4 @@ int WebPDequantizeLevels(uint8_t* const data, int width, int height, int stride,
} // extern "C"
#endif
-#endif /* WEBP_UTILS_QUANT_LEVELS_DEC_UTILS_H_ */
+#endif // WEBP_UTILS_QUANT_LEVELS_DEC_UTILS_H_
diff --git a/thirdparty/libwebp/src/utils/quant_levels_utils.h b/thirdparty/libwebp/src/utils/quant_levels_utils.h
index 75df2ba6a4..9ee3ea0075 100644
--- a/thirdparty/libwebp/src/utils/quant_levels_utils.h
+++ b/thirdparty/libwebp/src/utils/quant_levels_utils.h
@@ -33,4 +33,4 @@ int QuantizeLevels(uint8_t* const data, int width, int height, int num_levels,
} // extern "C"
#endif
-#endif /* WEBP_UTILS_QUANT_LEVELS_UTILS_H_ */
+#endif // WEBP_UTILS_QUANT_LEVELS_UTILS_H_
diff --git a/thirdparty/libwebp/src/utils/random_utils.h b/thirdparty/libwebp/src/utils/random_utils.h
index 6d36c667e7..a5006f84f7 100644
--- a/thirdparty/libwebp/src/utils/random_utils.h
+++ b/thirdparty/libwebp/src/utils/random_utils.h
@@ -60,4 +60,4 @@ static WEBP_INLINE int VP8RandomBits(VP8Random* const rg, int num_bits) {
} // extern "C"
#endif
-#endif /* WEBP_UTILS_RANDOM_UTILS_H_ */
+#endif // WEBP_UTILS_RANDOM_UTILS_H_
diff --git a/thirdparty/libwebp/src/utils/rescaler_utils.h b/thirdparty/libwebp/src/utils/rescaler_utils.h
index 8890e6fa13..ca41e42c4a 100644
--- a/thirdparty/libwebp/src/utils/rescaler_utils.h
+++ b/thirdparty/libwebp/src/utils/rescaler_utils.h
@@ -98,4 +98,4 @@ int WebPRescalerHasPendingOutput(const WebPRescaler* const rescaler) {
} // extern "C"
#endif
-#endif /* WEBP_UTILS_RESCALER_UTILS_H_ */
+#endif // WEBP_UTILS_RESCALER_UTILS_H_
diff --git a/thirdparty/libwebp/src/utils/thread_utils.h b/thirdparty/libwebp/src/utils/thread_utils.h
index c8ae6c9033..29ad49f74b 100644
--- a/thirdparty/libwebp/src/utils/thread_utils.h
+++ b/thirdparty/libwebp/src/utils/thread_utils.h
@@ -87,4 +87,4 @@ WEBP_EXTERN const WebPWorkerInterface* WebPGetWorkerInterface(void);
} // extern "C"
#endif
-#endif /* WEBP_UTILS_THREAD_UTILS_H_ */
+#endif // WEBP_UTILS_THREAD_UTILS_H_
diff --git a/thirdparty/libwebp/src/utils/utils.h b/thirdparty/libwebp/src/utils/utils.h
index 52921bf24e..da97b5d38f 100644
--- a/thirdparty/libwebp/src/utils/utils.h
+++ b/thirdparty/libwebp/src/utils/utils.h
@@ -175,4 +175,4 @@ WEBP_EXTERN int WebPGetColorPalette(const struct WebPPicture* const pic,
} // extern "C"
#endif
-#endif /* WEBP_UTILS_UTILS_H_ */
+#endif // WEBP_UTILS_UTILS_H_
diff --git a/thirdparty/libwebp/src/webp/decode.h b/thirdparty/libwebp/src/webp/decode.h
index 2165e96c95..95d31e7619 100644
--- a/thirdparty/libwebp/src/webp/decode.h
+++ b/thirdparty/libwebp/src/webp/decode.h
@@ -491,4 +491,4 @@ WEBP_EXTERN VP8StatusCode WebPDecode(const uint8_t* data, size_t data_size,
} // extern "C"
#endif
-#endif /* WEBP_WEBP_DECODE_H_ */
+#endif // WEBP_WEBP_DECODE_H_
diff --git a/thirdparty/libwebp/src/webp/demux.h b/thirdparty/libwebp/src/webp/demux.h
index 555d641338..846eeb15a9 100644
--- a/thirdparty/libwebp/src/webp/demux.h
+++ b/thirdparty/libwebp/src/webp/demux.h
@@ -360,4 +360,4 @@ WEBP_EXTERN void WebPAnimDecoderDelete(WebPAnimDecoder* dec);
} // extern "C"
#endif
-#endif /* WEBP_WEBP_DEMUX_H_ */
+#endif // WEBP_WEBP_DEMUX_H_
diff --git a/thirdparty/libwebp/src/webp/encode.h b/thirdparty/libwebp/src/webp/encode.h
index 7ec3543dc2..549cf07730 100644
--- a/thirdparty/libwebp/src/webp/encode.h
+++ b/thirdparty/libwebp/src/webp/encode.h
@@ -542,4 +542,4 @@ WEBP_EXTERN int WebPEncode(const WebPConfig* config, WebPPicture* picture);
} // extern "C"
#endif
-#endif /* WEBP_WEBP_ENCODE_H_ */
+#endif // WEBP_WEBP_ENCODE_H_
diff --git a/thirdparty/libwebp/src/webp/format_constants.h b/thirdparty/libwebp/src/webp/format_constants.h
index 329fc8a3b0..eca6981a47 100644
--- a/thirdparty/libwebp/src/webp/format_constants.h
+++ b/thirdparty/libwebp/src/webp/format_constants.h
@@ -84,4 +84,4 @@ typedef enum {
// overflow a uint32_t.
#define MAX_CHUNK_PAYLOAD (~0U - CHUNK_HEADER_SIZE - 1)
-#endif /* WEBP_WEBP_FORMAT_CONSTANTS_H_ */
+#endif // WEBP_WEBP_FORMAT_CONSTANTS_H_
diff --git a/thirdparty/libwebp/src/webp/mux.h b/thirdparty/libwebp/src/webp/mux.h
index 28bb4a41c9..66096a92e0 100644
--- a/thirdparty/libwebp/src/webp/mux.h
+++ b/thirdparty/libwebp/src/webp/mux.h
@@ -527,4 +527,4 @@ WEBP_EXTERN void WebPAnimEncoderDelete(WebPAnimEncoder* enc);
} // extern "C"
#endif
-#endif /* WEBP_WEBP_MUX_H_ */
+#endif // WEBP_WEBP_MUX_H_
diff --git a/thirdparty/libwebp/src/webp/mux_types.h b/thirdparty/libwebp/src/webp/mux_types.h
index b37e2c67aa..ceea77dfc6 100644
--- a/thirdparty/libwebp/src/webp/mux_types.h
+++ b/thirdparty/libwebp/src/webp/mux_types.h
@@ -95,4 +95,4 @@ static WEBP_INLINE int WebPDataCopy(const WebPData* src, WebPData* dst) {
} // extern "C"
#endif
-#endif /* WEBP_WEBP_MUX_TYPES_H_ */
+#endif // WEBP_WEBP_MUX_TYPES_H_
diff --git a/thirdparty/libwebp/src/webp/types.h b/thirdparty/libwebp/src/webp/types.h
index 989a763f0d..0ce2622e41 100644
--- a/thirdparty/libwebp/src/webp/types.h
+++ b/thirdparty/libwebp/src/webp/types.h
@@ -49,4 +49,4 @@ typedef long long int int64_t;
// Macro to check ABI compatibility (same major revision number)
#define WEBP_ABI_IS_INCOMPATIBLE(a, b) (((a) >> 8) != ((b) >> 8))
-#endif /* WEBP_WEBP_TYPES_H_ */
+#endif // WEBP_WEBP_TYPES_H_
diff --git a/thirdparty/libwebsockets/core/context.c b/thirdparty/libwebsockets/core/context.c
index db9151b95f..7be004df33 100644
--- a/thirdparty/libwebsockets/core/context.c
+++ b/thirdparty/libwebsockets/core/context.c
@@ -134,7 +134,7 @@ lws_protocol_vh_priv_get(struct lws_vhost *vhost,
{
int n = 0;
- if (!vhost || !vhost->protocol_vh_privs)
+ if (!vhost || !vhost->protocol_vh_privs || !prot)
return NULL;
while (n < vhost->count_protocols && &vhost->protocols[n] != prot)
@@ -808,7 +808,7 @@ lws_create_vhost(struct lws_context *context,
#ifdef LWS_WITH_ACCESS_LOG
if (info->log_filepath) {
- vh->log_fd = open(info->log_filepath,
+ vh->log_fd = lws_open(info->log_filepath,
O_CREAT | O_APPEND | O_RDWR, 0600);
if (vh->log_fd == (int)LWS_INVALID_FILE) {
lwsl_err("unable to open log filepath %s\n",
@@ -936,24 +936,29 @@ lws_create_event_pipes(struct lws_context *context)
wsi->tsi = n;
wsi->vhost = NULL;
wsi->event_pipe = 1;
+ wsi->desc.sockfd = LWS_SOCK_INVALID;
+ context->pt[n].pipe_wsi = wsi;
+ context->count_wsi_allocated++;
- if (lws_plat_pipe_create(wsi)) {
- lws_free(wsi);
+ if (lws_plat_pipe_create(wsi))
+ /*
+ * platform code returns 0 if it actually created pipes
+ * and initialized pt->dummy_pipe_fds[]. If it used
+ * some other mechanism outside of signaling in the
+ * normal event loop, we skip treating the pipe as
+ * related to dummy_pipe_fds[], adding it to the fds,
+ * etc.
+ */
continue;
- }
+
wsi->desc.sockfd = context->pt[n].dummy_pipe_fds[0];
lwsl_debug("event pipe fd %d\n", wsi->desc.sockfd);
- context->pt[n].pipe_wsi = wsi;
-
if (context->event_loop_ops->accept)
context->event_loop_ops->accept(wsi);
if (__insert_wsi_socket_into_fds(context, wsi))
return 1;
-
- //lws_change_pollfd(context->pt[n].pipe_wsi, 0, LWS_POLLIN);
- context->count_wsi_allocated++;
}
return 0;
diff --git a/thirdparty/libwebsockets/core/libwebsockets.c b/thirdparty/libwebsockets/core/libwebsockets.c
index 0da02b17e4..58f00226f6 100644
--- a/thirdparty/libwebsockets/core/libwebsockets.c
+++ b/thirdparty/libwebsockets/core/libwebsockets.c
@@ -28,7 +28,7 @@
#ifdef LWS_WITH_IPV6
#if defined(WIN32) || defined(_WIN32)
#include <wincrypt.h>
-#include <Iphlpapi.h>
+#include <iphlpapi.h>
#else
#include <net/if.h>
#endif
@@ -58,6 +58,28 @@ static const char * const log_level_names[] = {
};
#endif
+int lws_open(const char *__file, int __oflag, ...)
+{
+ va_list ap;
+ int n;
+
+ va_start(ap, __oflag);
+ if (((__oflag & O_CREAT) == O_CREAT)
+#if defined(O_TMPFILE)
+ || ((__oflag & O_TMPFILE) == O_TMPFILE)
+#endif
+ )
+ /* last arg is really a mode_t. But windows... */
+ n = open(__file, __oflag, va_arg(ap, uint32_t));
+ else
+ n = open(__file, __oflag);
+ va_end(ap);
+
+ lws_plat_apply_FD_CLOEXEC(n);
+
+ return n;
+}
+
#if defined (_DEBUG)
void lwsi_set_role(struct lws *wsi, lws_wsi_state_t role)
{
@@ -826,7 +848,15 @@ just_kill_connection:
if (!wsi->protocol)
pro = &wsi->vhost->protocols[0];
- pro->callback(wsi,
+ if (!wsi->upgraded_to_http2 || !lwsi_role_client(wsi))
+ /*
+ * The network wsi for a client h2 connection shouldn't
+ * call back for its role: the child stream connections
+ * own the role. Otherwise h2 will call back closed
+ * one too many times as the children do it and then
+ * the closing network stream.
+ */
+ pro->callback(wsi,
wsi->role_ops->close_cb[lwsi_role_server(wsi)],
wsi->user_space, NULL, 0);
wsi->told_user_closed = 1;
@@ -1453,7 +1483,7 @@ lws_vfs_select_fops(const struct lws_plat_file_ops *fops, const char *vfs_path,
pf = fops->next;
while (pf) {
n = 0;
- while (n < (int)ARRAY_SIZE(pf->fi) && pf->fi[n].sig) {
+ while (n < (int)LWS_ARRAY_SIZE(pf->fi) && pf->fi[n].sig) {
if (p >= vfs_path + pf->fi[n].len)
if (!strncmp(p - (pf->fi[n].len - 1),
pf->fi[n].sig,
@@ -1935,9 +1965,9 @@ static const char * const colours[] = {
"[32;1m", /* LLL_INFO */
"[34;1m", /* LLL_DEBUG */
"[33;1m", /* LLL_PARSER */
- "[33;1m", /* LLL_HEADER */
- "[33;1m", /* LLL_EXT */
- "[33;1m", /* LLL_CLIENT */
+ "[33m", /* LLL_HEADER */
+ "[33m", /* LLL_EXT */
+ "[33m", /* LLL_CLIENT */
"[33;1m", /* LLL_LATENCY */
"[30;1m", /* LLL_USER */
};
@@ -1946,14 +1976,14 @@ LWS_VISIBLE void lwsl_emit_stderr(int level, const char *line)
{
char buf[50];
static char tty = 3;
- int n, m = ARRAY_SIZE(colours) - 1;
+ int n, m = LWS_ARRAY_SIZE(colours) - 1;
if (!tty)
tty = isatty(2) | 2;
lwsl_timestamp(level, buf, sizeof(buf));
if (tty == 3) {
- n = 1 << (ARRAY_SIZE(colours) - 1);
+ n = 1 << (LWS_ARRAY_SIZE(colours) - 1);
while (n) {
if (level & n)
break;
@@ -2060,7 +2090,9 @@ lwsl_hexdump_level(int hexdump_level, const void *vbuf, size_t len)
LWS_VISIBLE void
lwsl_hexdump(const void *vbuf, size_t len)
{
+#if defined(_DEBUG)
lwsl_hexdump_level(LLL_DEBUG, vbuf, len);
+#endif
}
LWS_VISIBLE int
@@ -2091,6 +2123,8 @@ lws_partial_buffered(struct lws *wsi)
LWS_VISIBLE lws_fileofs_t
lws_get_peer_write_allowance(struct lws *wsi)
{
+ if (!wsi->role_ops->tx_credit)
+ return -1;
return wsi->role_ops->tx_credit(wsi);
}
@@ -3364,7 +3398,7 @@ lws_stats_log_dump(struct lws_context *context)
wl = pt->http.ah_wait_list;
while (wl) {
m++;
- wl = wl->ah_wait_list;
+ wl = wl->http.ah_wait_list;
}
lwsl_notice(" AH wait list count / actual: %d / %d\n",
@@ -3401,7 +3435,8 @@ lws_stats_log_dump(struct lws_context *context)
strcpy(buf, "unknown");
#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
lwsl_notice(" peer %s: count wsi: %d, count ah: %d\n",
- buf, df->count_wsi, df->count_ah);
+ buf, df->count_wsi,
+ df->http.count_ah);
#else
lwsl_notice(" peer %s: count wsi: %d\n",
buf, df->count_wsi);
diff --git a/thirdparty/libwebsockets/core/output.c b/thirdparty/libwebsockets/core/output.c
index e2ff18ef27..11965a06b9 100644
--- a/thirdparty/libwebsockets/core/output.c
+++ b/thirdparty/libwebsockets/core/output.c
@@ -126,6 +126,18 @@ int lws_issue_raw(struct lws *wsi, unsigned char *buf, size_t len)
lwsl_info("** %p signalling to close now\n", wsi);
return -1; /* retry closing now */
}
+
+#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
+#if !defined(LWS_WITHOUT_SERVER)
+ if (wsi->http.deferred_transaction_completed) {
+ lwsl_notice("%s: partial completed, doing "
+ "deferred transaction completed\n",
+ __func__);
+ wsi->http.deferred_transaction_completed = 0;
+ return lws_http_transaction_completed(wsi);
+ }
+#endif
+#endif
}
/* always callback on writeable */
lws_callback_on_writable(wsi);
diff --git a/thirdparty/libwebsockets/core/private.h b/thirdparty/libwebsockets/core/private.h
index d6b494ac8c..73748b0498 100644
--- a/thirdparty/libwebsockets/core/private.h
+++ b/thirdparty/libwebsockets/core/private.h
@@ -232,7 +232,7 @@
#endif
#else /* not windows */
- static inline int compatible_close(int fd) { return close(fd); }
+ static LWS_INLINE int compatible_close(int fd) { return close(fd); }
#include <sys/stat.h>
#include <sys/time.h>
@@ -351,7 +351,15 @@ extern "C" {
#define LWS_H2_RX_SCRATCH_SIZE 512
-
+#if defined(WIN32) || defined(_WIN32)
+ // Visual studio older than 2015 and WIN_CE has only _stricmp
+ #if (defined(_MSC_VER) && _MSC_VER < 1900) || defined(_WIN32_WCE)
+ #define strcasecmp _stricmp
+ #elif !defined(__MINGW32__)
+ #define strcasecmp stricmp
+ #endif
+ #define getdtablesize() 30000
+#endif
/*
* All lws_tls...() functions must return this type, converting the
@@ -863,6 +871,7 @@ struct lws_context {
unsigned int timeout_secs;
unsigned int pt_serv_buf_size;
int max_http_header_data;
+ int max_http_header_pool;
int simultaneous_ssl_restriction;
int simultaneous_ssl;
#if defined(LWS_WITH_PEER_LIMITS)
@@ -889,7 +898,6 @@ struct lws_context {
volatile int service_tid;
int service_tid_detected;
- short max_http_header_pool;
short count_threads;
short plugin_protocol_count;
short plugin_extension_count;
@@ -1216,7 +1224,7 @@ LWS_EXTERN int
lws_rxflow_cache(struct lws *wsi, unsigned char *buf, int n, int len);
#ifndef LWS_LATENCY
-static inline void
+static LWS_INLINE void
lws_latency(struct lws_context *context, struct lws *wsi, const char *action,
int ret, int completion) {
do {
@@ -1224,7 +1232,7 @@ lws_latency(struct lws_context *context, struct lws *wsi, const char *action,
(void)completion;
} while (0);
}
-static inline void
+static LWS_INLINE void
lws_latency_pre(struct lws_context *context, struct lws *wsi) {
do { (void)context; (void)wsi; } while (0);
}
@@ -1597,6 +1605,9 @@ void lws_free(void *p);
#define lws_free_set_NULL(P) do { lws_realloc(P, 0, "free"); (P) = NULL; } while(0)
#endif
+char *
+lws_strdup(const char *s);
+
int
lws_plat_pipe_create(struct lws *wsi);
int
@@ -1606,6 +1617,9 @@ lws_plat_pipe_close(struct lws *wsi);
int
lws_create_event_pipes(struct lws_context *context);
+int lws_open(const char *__file, int __oflag, ...);
+void lws_plat_apply_FD_CLOEXEC(int n);
+
const struct lws_plat_file_ops *
lws_vfs_select_fops(const struct lws_plat_file_ops *fops, const char *vfs_path,
const char **vpath);
@@ -1673,10 +1687,10 @@ lws_broadcast(struct lws_context *context, int reason, void *in, size_t len);
lws_stats_atomic_max(struct lws_context * context,
struct lws_context_per_thread *pt, int index, uint64_t val);
#else
- static inline uint64_t lws_stats_atomic_bump(struct lws_context * context,
+ static LWS_INLINE uint64_t lws_stats_atomic_bump(struct lws_context * context,
struct lws_context_per_thread *pt, int index, uint64_t bump) {
(void)context; (void)pt; (void)index; (void)bump; return 0; }
- static inline uint64_t lws_stats_atomic_max(struct lws_context * context,
+ static LWS_INLINE uint64_t lws_stats_atomic_max(struct lws_context * context,
struct lws_context_per_thread *pt, int index, uint64_t val) {
(void)context; (void)pt; (void)index; (void)val; return 0; }
#endif
@@ -1703,6 +1717,11 @@ void
lws_peer_dump_from_wsi(struct lws *wsi);
#endif
+#ifdef LWS_WITH_HTTP_PROXY
+hubbub_error
+html_parser_cb(const hubbub_token *token, void *pw);
+#endif
+
void
__lws_remove_from_timeout_list(struct lws *wsi);
diff --git a/thirdparty/libwebsockets/libwebsockets.h b/thirdparty/libwebsockets/libwebsockets.h
index 7ae563d582..2c01696404 100644
--- a/thirdparty/libwebsockets/libwebsockets.h
+++ b/thirdparty/libwebsockets/libwebsockets.h
@@ -66,14 +66,6 @@ typedef unsigned long long lws_intptr_t;
#define O_RDONLY _O_RDONLY
#endif
-// Visual studio older than 2015 and WIN_CE has only _stricmp
-#if (defined(_MSC_VER) && _MSC_VER < 1900) || defined(_WIN32_WCE)
-#define strcasecmp _stricmp
-#elif !defined(__MINGW32__)
-#define strcasecmp stricmp
-#endif
-#define getdtablesize() 30000
-
#define LWS_INLINE __inline
#define LWS_VISIBLE
#define LWS_WARN_UNUSED_RESULT
@@ -150,6 +142,7 @@ typedef unsigned long long lws_intptr_t;
#endif
#if defined(__ANDROID__)
+#include <netinet/in.h>
#include <unistd.h>
#define getdtablesize() sysconf(_SC_OPEN_MAX)
#endif
@@ -164,6 +157,9 @@ typedef unsigned long long lws_intptr_t;
#ifdef LWS_HAVE_UV_VERSION_H
#include <uv-version.h>
#endif
+#ifdef LWS_HAVE_NEW_UV_VERSION_H
+#include <uv/version.h>
+#endif
#endif /* LWS_WITH_LIBUV */
#if defined(LWS_WITH_LIBEVENT)
#include <event2/event.h>
@@ -456,9 +452,6 @@ lwsl_visible(int level);
#endif
struct lws;
-#ifndef ARRAY_SIZE
-#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
-#endif
typedef int64_t lws_usec_t;
@@ -540,7 +533,7 @@ struct timer_mapping {
#define lws_uv_getloop(a, b) (NULL)
-static inline void uv_timer_init(void *l, uv_timer_t *t)
+static LWS_INLINE void uv_timer_init(void *l, uv_timer_t *t)
{
(void)l;
*t = NULL;
@@ -548,7 +541,7 @@ static inline void uv_timer_init(void *l, uv_timer_t *t)
extern void esp32_uvtimer_cb(TimerHandle_t t);
-static inline void uv_timer_start(uv_timer_t *t, uv_cb_t *cb, int first, int rep)
+static LWS_INLINE void uv_timer_start(uv_timer_t *t, uv_cb_t *cb, int first, int rep)
{
struct timer_mapping *tm = (struct timer_mapping *)malloc(sizeof(*tm));
@@ -563,12 +556,12 @@ static inline void uv_timer_start(uv_timer_t *t, uv_cb_t *cb, int first, int rep
xTimerStart(*t, 0);
}
-static inline void uv_timer_stop(uv_timer_t *t)
+static LWS_INLINE void uv_timer_stop(uv_timer_t *t)
{
xTimerStop(*t, 0);
}
-static inline void uv_close(uv_handle_t *h, void *v)
+static LWS_INLINE void uv_close(uv_handle_t *h, void *v)
{
free(pvTimerGetTimerID((uv_timer_t)h));
xTimerDelete(*(uv_timer_t *)h, 0);
@@ -1757,7 +1750,7 @@ lws_genhash_destroy(struct lws_genhash_ctx *ctx, void *result);
* If the return is nonzero, it failed and there is nothing needing to be
* destroyed.
*/
-int
+LWS_VISIBLE LWS_EXTERN int LWS_WARN_UNUSED_RESULT
lws_genhmac_init(struct lws_genhmac_ctx *ctx, enum lws_genhmac_types type,
const uint8_t *key, size_t key_len);
@@ -1771,7 +1764,7 @@ lws_genhmac_init(struct lws_genhmac_ctx *ctx, enum lws_genhmac_types type,
*
* If the return is nonzero, it failed and needs destroying.
*/
-int
+LWS_VISIBLE LWS_EXTERN int LWS_WARN_UNUSED_RESULT
lws_genhmac_update(struct lws_genhmac_ctx *ctx, const void *in, size_t len);
/** lws_genhmac_destroy() - copy out the result digest and destroy the ctx
@@ -1785,7 +1778,7 @@ lws_genhmac_update(struct lws_genhmac_ctx *ctx, const void *in, size_t len);
* NULL result is supported so that you can destroy the ctx cleanly on error
* conditions, where there is no valid result.
*/
-int
+LWS_VISIBLE LWS_EXTERN int
lws_genhmac_destroy(struct lws_genhmac_ctx *ctx, void *result);
///@}
@@ -2812,7 +2805,7 @@ struct lws_context_creation_info {
/**< VHOST: pointer to optional linked list of per-vhost
* options made accessible to protocols */
int keepalive_timeout;
- /**< VHOST: (default = 0 = 60s) seconds to allow remote
+ /**< VHOST: (default = 0 = 5s) seconds to allow remote
* client to hold on to an idle HTTP/1.1 connection */
const char *log_filepath;
/**< VHOST: filepath to append logs to... this is opened before
@@ -4943,7 +4936,7 @@ lws_write(struct lws *wsi, unsigned char *buf, size_t len,
lws_write(wsi, (unsigned char *)(buf), len, LWS_WRITE_HTTP)
/* helper for multi-frame ws message flags */
-static inline int
+static LWS_INLINE int
lws_write_ws_flags(int initial, int is_start, int is_end)
{
int r;
@@ -5621,13 +5614,13 @@ struct lws_dll_lws { /* typed as struct lws * */
#define lws_dll_is_null(___dll) (!(___dll)->prev && !(___dll)->next)
-static inline void
+static LWS_INLINE void
lws_dll_lws_add_front(struct lws_dll_lws *_a, struct lws_dll_lws *_head)
{
lws_dll_add_front((struct lws_dll *)_a, (struct lws_dll *)_head);
}
-static inline void
+static LWS_INLINE void
lws_dll_lws_remove(struct lws_dll_lws *_a)
{
lws_dll_remove((struct lws_dll *)_a);
@@ -7064,9 +7057,6 @@ lws_email_destroy(struct lws_email *email);
//@{
struct lejp_ctx;
-#ifndef ARRAY_SIZE
-#define ARRAY_SIZE(_x) (sizeof(_x) / sizeof(_x[0]))
-#endif
#define LWS_ARRAY_SIZE(_x) (sizeof(_x) / sizeof(_x[0]))
#define LEJP_FLAG_WS_KEEP 64
#define LEJP_FLAG_WS_COMMENTLINE 32
@@ -7219,7 +7209,7 @@ typedef signed char (*lejp_callback)(struct lejp_ctx *ctx, char reason);
#endif
#ifndef LEJP_STRING_CHUNK
/* must be >= 30 to assemble floats */
-#define LEJP_STRING_CHUNK 255
+#define LEJP_STRING_CHUNK 254
#endif
enum num_flags {
@@ -7253,7 +7243,7 @@ struct lejp_ctx {
uint16_t i[LEJP_MAX_INDEX_DEPTH]; /* index array */
uint16_t wild[LEJP_MAX_INDEX_DEPTH]; /* index array */
char path[LEJP_MAX_PATH];
- char buf[LEJP_STRING_CHUNK];
+ char buf[LEJP_STRING_CHUNK + 1];
/* int */
diff --git a/thirdparty/libwebsockets/lws_config.h b/thirdparty/libwebsockets/lws_config.h
index 7185a806a5..86ce9ac38a 100644
--- a/thirdparty/libwebsockets/lws_config.h
+++ b/thirdparty/libwebsockets/lws_config.h
@@ -174,7 +174,7 @@
#define LWS_HAVE_MALLOC_H
#endif
-#if !defined(IPHONE_ENABLED) && !defined(OSX_ENABLED)
+#if !defined(__APPLE__) && !defined(__HAIKU__)
#define LWS_HAVE_PIPE2
#endif
diff --git a/thirdparty/libwebsockets/lws_config_private.h b/thirdparty/libwebsockets/lws_config_private.h
index 9d04078fef..e531777624 100644
--- a/thirdparty/libwebsockets/lws_config_private.h
+++ b/thirdparty/libwebsockets/lws_config_private.h
@@ -81,7 +81,7 @@
/* Define to 1 if you have the <sys/prctl.h> header file. */
#define LWS_HAVE_SYS_PRCTL_H
-#if defined(OSX_ENABLED) || defined(IPHONE_ENABLED) || defined(__FreeBSD__) || defined(__OpenBSD__)
+#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__)
#undef LWS_HAVE_SYS_PRCTL_H
#endif
diff --git a/thirdparty/libwebsockets/misc/lejp.c b/thirdparty/libwebsockets/misc/lejp.c
index 00d350f81e..99142b9553 100644
--- a/thirdparty/libwebsockets/misc/lejp.c
+++ b/thirdparty/libwebsockets/misc/lejp.c
@@ -20,6 +20,7 @@
*/
#include <libwebsockets.h>
+#include "core/private.h"
#include <string.h>
#include <stdio.h>
@@ -30,7 +31,7 @@
* \param callback: your user callback which will received parsed tokens
* \param user: optional user data pointer untouched by lejp
* \param paths: your array of name elements you are interested in
- * \param count_paths: ARRAY_SIZE() of @paths
+ * \param count_paths: LWS_ARRAY_SIZE() of @paths
*
* Prepares your context struct for use with lejp
*/
@@ -250,7 +251,7 @@ lejp_parse(struct lejp_ctx *ctx, const unsigned char *json, int len)
case LEJP_MP_STRING:
if (c == '\"') {
- if (!ctx->sp) {
+ if (!ctx->sp) { /* JSON can't end on quote */
ret = LEJP_REJECT_MP_STRING_UNDERRUN;
goto reject;
}
@@ -417,7 +418,7 @@ lejp_parse(struct lejp_ctx *ctx, const unsigned char *json, int len)
goto reject;
}
ctx->i[ctx->ipos++] = 0;
- if (ctx->ipos > ARRAY_SIZE(ctx->i)) {
+ if (ctx->ipos > LWS_ARRAY_SIZE(ctx->i)) {
ret = LEJP_REJECT_MP_DELIM_ISTACK;
goto reject;
}
@@ -425,17 +426,23 @@ lejp_parse(struct lejp_ctx *ctx, const unsigned char *json, int len)
case ']':
/* pop */
+ if (!ctx->sp) { /* JSON can't end on ] */
+ ret = LEJP_REJECT_MP_C_OR_E_UNDERF;
+ goto reject;
+ }
ctx->sp--;
if (ctx->st[ctx->sp].s != LEJP_MP_ARRAY_END) {
ret = LEJP_REJECT_MP_C_OR_E_NOTARRAY;
goto reject;
}
/* drop the path [n] bit */
- ctx->ppos = ctx->st[ctx->sp - 1].p;
- ctx->ipos = ctx->st[ctx->sp - 1].i;
+ if (ctx->sp) {
+ ctx->ppos = ctx->st[ctx->sp - 1].p;
+ ctx->ipos = ctx->st[ctx->sp - 1].i;
+ }
ctx->path[ctx->ppos] = '\0';
if (ctx->path_match &&
- ctx->ppos <= ctx->path_match_len)
+ ctx->ppos <= ctx->path_match_len)
/*
* we shrank the path to be
* smaller than the matching point
@@ -603,7 +610,7 @@ lejp_parse(struct lejp_ctx *ctx, const unsigned char *json, int len)
break;
}
if (c == ']') {
- if (!ctx->sp) {
+ if (!ctx->sp) { /* JSON can't end on ] */
ret = LEJP_REJECT_MP_C_OR_E_UNDERF;
goto reject;
}
@@ -631,7 +638,7 @@ lejp_parse(struct lejp_ctx *ctx, const unsigned char *json, int len)
goto redo_character;
}
if (c == '}') {
- if (ctx->sp == 0) {
+ if (!ctx->sp) {
lejp_check_path_match(ctx);
if (ctx->callback(ctx, LEJPCB_OBJECT_END)) {
ret = LEJP_REJECT_CALLBACK;
@@ -716,7 +723,7 @@ add_stack_level:
ctx->st[ctx->sp].p = ctx->ppos;
ctx->st[ctx->sp].i = ctx->ipos;
- if (++ctx->sp == ARRAY_SIZE(ctx->st)) {
+ if (++ctx->sp == LWS_ARRAY_SIZE(ctx->st)) {
ret = LEJP_REJECT_STACK_OVERFLOW;
goto reject;
}
diff --git a/thirdparty/libwebsockets/plat/lws-plat-unix.c b/thirdparty/libwebsockets/plat/lws-plat-unix.c
index bacc6af647..7dba3bd82f 100644
--- a/thirdparty/libwebsockets/plat/lws-plat-unix.c
+++ b/thirdparty/libwebsockets/plat/lws-plat-unix.c
@@ -30,6 +30,12 @@
#endif
#include <dirent.h>
+void lws_plat_apply_FD_CLOEXEC(int n)
+{
+ if (n != -1)
+ fcntl(n, F_SETFD, FD_CLOEXEC );
+}
+
int
lws_plat_socket_offset(void)
{
@@ -330,6 +336,8 @@ lws_plat_set_socket_options(struct lws_vhost *vhost, int fd)
struct protoent *tcp_proto;
#endif
+ fcntl(fd, F_SETFD, FD_CLOEXEC);
+
if (vhost->ka_time) {
/* enable keepalive on this socket */
optval = 1;
@@ -952,7 +960,7 @@ lws_plat_write_file(const char *filename, void *buf, int len)
LWS_VISIBLE int
lws_plat_read_file(const char *filename, void *buf, int len)
{
- int n, fd = open(filename, O_RDONLY);
+ int n, fd = lws_open(filename, O_RDONLY);
if (fd == -1)
return -1;
diff --git a/thirdparty/libwebsockets/plat/lws-plat-win.c b/thirdparty/libwebsockets/plat/lws-plat-win.c
index 948db62896..1850b64250 100644
--- a/thirdparty/libwebsockets/plat/lws-plat-win.c
+++ b/thirdparty/libwebsockets/plat/lws-plat-win.c
@@ -3,6 +3,10 @@
#endif
#include "core/private.h"
+void lws_plat_apply_FD_CLOEXEC(int n)
+{
+}
+
int
lws_plat_socket_offset(void)
{
@@ -54,7 +58,7 @@ time_in_microseconds()
memcpy(&datetime, &filetime, sizeof(datetime));
/* Windows file times are in 100s of nanoseconds. */
- return (datetime.QuadPart - DELTA_EPOCH_IN_MICROSECS) / 10;
+ return (datetime.QuadPart / 10) - DELTA_EPOCH_IN_MICROSECS;
}
#ifdef _WIN32_WCE
@@ -229,23 +233,21 @@ _lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi)
continue;
wsi = wsi_from_fd(context, pfd->fd);
- if (wsi->listener)
+ if (!wsi || wsi->listener)
continue;
- if (!wsi || wsi->sock_send_blocking)
+ if (wsi->sock_send_blocking)
continue;
pfd->revents = LWS_POLLOUT;
n = lws_service_fd(context, pfd);
if (n < 0)
return -1;
+
+ /* Force WSAWaitForMultipleEvents() to check events and then return immediately. */
+ timeout_ms = 0;
+
/* if something closed, retry this slot */
if (n)
i--;
-
- /*
- * any wsi has truncated, force him signalled
- */
- if (wsi->trunc_len)
- WSASetEvent(pt->events[0]);
}
/*
@@ -261,9 +263,11 @@ _lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi)
}
if (timeout_ms) {
+ lws_usec_t t;
+
lws_pt_lock(pt, __func__);
/* don't stay in poll wait longer than next hr timeout */
- lws_usec_t t = __lws_hrtimer_service(pt);
+ t = __lws_hrtimer_service(pt);
if ((lws_usec_t)timeout_ms * 1000 > t)
timeout_ms = (int)(t / 1000);
@@ -310,8 +314,10 @@ _lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi)
if (pfd->revents & LWS_POLLHUP)
--eIdx;
- if (pfd->revents)
+ if (pfd->revents) {
+ recv(pfd->fd, NULL, 0, 0);
lws_service_fd_tsi(context, pfd, tsi);
+ }
}
}
@@ -635,9 +641,20 @@ _lws_plat_file_open(const struct lws_plat_file_ops *fops, const char *filename,
HANDLE ret;
WCHAR buf[MAX_PATH];
lws_fop_fd_t fop_fd;
- LARGE_INTEGER llFileSize = {0};
+ FILE_STANDARD_INFO fInfo = {0};
+
+ MultiByteToWideChar(CP_UTF8, 0, filename, -1, buf, LWS_ARRAY_SIZE(buf));
+
+#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0602 // Windows 8 (minimum when UWP_ENABLED, but can be used in Windows builds)
+ CREATEFILE2_EXTENDED_PARAMETERS extParams = {0};
+ extParams.dwFileAttributes = FILE_ATTRIBUTE_NORMAL;
- MultiByteToWideChar(CP_UTF8, 0, filename, -1, buf, ARRAY_SIZE(buf));
+ if (((*flags) & 7) == _O_RDONLY) {
+ ret = CreateFile2(buf, GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, &extParams);
+ } else {
+ ret = CreateFile2(buf, GENERIC_WRITE, 0, CREATE_ALWAYS, &extParams);
+ }
+#else
if (((*flags) & 7) == _O_RDONLY) {
ret = CreateFileW(buf, GENERIC_READ, FILE_SHARE_READ,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
@@ -645,6 +662,7 @@ _lws_plat_file_open(const struct lws_plat_file_ops *fops, const char *filename,
ret = CreateFileW(buf, GENERIC_WRITE, 0, NULL,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
}
+#endif
if (ret == LWS_INVALID_FILE)
goto bail;
@@ -657,9 +675,9 @@ _lws_plat_file_open(const struct lws_plat_file_ops *fops, const char *filename,
fop_fd->fd = ret;
fop_fd->filesystem_priv = NULL; /* we don't use it */
fop_fd->flags = *flags;
- fop_fd->len = GetFileSize(ret, NULL);
- if(GetFileSizeEx(ret, &llFileSize))
- fop_fd->len = llFileSize.QuadPart;
+ fop_fd->len = 0;
+ if(GetFileInformationByHandleEx(ret, FileStandardInfo, &fInfo, sizeof(fInfo)))
+ fop_fd->len = fInfo.EndOfFile.QuadPart;
fop_fd->pos = 0;
@@ -798,7 +816,7 @@ lws_plat_write_file(const char *filename, void *buf, int len)
{
int m, fd;
- fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600);
+ fd = lws_open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600);
if (fd == -1)
return -1;
@@ -812,7 +830,7 @@ lws_plat_write_file(const char *filename, void *buf, int len)
LWS_VISIBLE int
lws_plat_read_file(const char *filename, void *buf, int len)
{
- int n, fd = open(filename, O_RDONLY);
+ int n, fd = lws_open(filename, O_RDONLY);
if (fd == -1)
return -1;
diff --git a/thirdparty/libwebsockets/roles/h1/ops-h1.c b/thirdparty/libwebsockets/roles/h1/ops-h1.c
index d3b16f4d1f..9001c864ea 100644
--- a/thirdparty/libwebsockets/roles/h1/ops-h1.c
+++ b/thirdparty/libwebsockets/roles/h1/ops-h1.c
@@ -195,6 +195,7 @@ postbody_completion:
}
break;
+ case LRS_RETURNED_CLOSE:
case LRS_AWAITING_CLOSE_ACK:
case LRS_WAITING_TO_SEND_CLOSE:
case LRS_SHUTDOWN:
@@ -444,6 +445,16 @@ try_pollout:
if (lwsi_state(wsi) != LRS_ISSUING_FILE) {
+ if (wsi->trunc_len) {
+ //lwsl_notice("%s: completing partial\n", __func__);
+ if (lws_issue_raw(wsi, wsi->trunc_alloc + wsi->trunc_offset,
+ wsi->trunc_len) < 0) {
+ lwsl_info("%s signalling to close\n", __func__);
+ goto fail;
+ }
+ return LWS_HPI_RET_HANDLED;
+ }
+
lws_stats_atomic_bump(wsi->context, pt,
LWSSTATS_C_WRITEABLE_CB, 1);
#if defined(LWS_WITH_STATS)
@@ -655,6 +666,9 @@ rops_destroy_role_h1(struct lws *wsi)
ah = ah->next;
}
+#ifdef LWS_ROLE_WS
+ lws_free_set_NULL(wsi->ws);
+#endif
return 0;
}
diff --git a/thirdparty/libwebsockets/roles/http/client/client-handshake.c b/thirdparty/libwebsockets/roles/http/client/client-handshake.c
index 4830fc9eca..0095c79a69 100644
--- a/thirdparty/libwebsockets/roles/http/client/client-handshake.c
+++ b/thirdparty/libwebsockets/roles/http/client/client-handshake.c
@@ -162,7 +162,7 @@ create_new_conn:
if (!wsi->client_hostname_copy)
wsi->client_hostname_copy =
- strdup(lws_hdr_simple_ptr(wsi,
+ lws_strdup(lws_hdr_simple_ptr(wsi,
_WSI_TOKEN_CLIENT_PEER_ADDRESS));
/*
@@ -654,13 +654,13 @@ lws_client_reset(struct lws **pwsi, int ssl, const char *address, int port,
lws_ssl_close(wsi);
#endif
+ __remove_wsi_socket_from_fds(wsi);
+
if (wsi->context->event_loop_ops->close_handle_manually)
wsi->context->event_loop_ops->close_handle_manually(wsi);
else
compatible_close(wsi->desc.sockfd);
- __remove_wsi_socket_from_fds(wsi);
-
#if defined(LWS_WITH_TLS)
wsi->tls.use_ssl = ssl;
#else
@@ -717,7 +717,7 @@ lws_client_reset(struct lws **pwsi, int ssl, const char *address, int port,
}
#ifdef LWS_WITH_HTTP_PROXY
-static hubbub_error
+hubbub_error
html_parser_cb(const hubbub_token *token, void *pw)
{
struct lws_rewrite *r = (struct lws_rewrite *)pw;
@@ -846,7 +846,7 @@ html_parser_cb(const hubbub_token *token, void *pw)
#endif
-static char *
+char *
lws_strdup(const char *s)
{
char *d = lws_malloc(strlen(s) + 1, "strdup");
diff --git a/thirdparty/libwebsockets/roles/http/client/client.c b/thirdparty/libwebsockets/roles/http/client/client.c
index ce42dc6cd3..5645fa2b7a 100644
--- a/thirdparty/libwebsockets/roles/http/client/client.c
+++ b/thirdparty/libwebsockets/roles/http/client/client.c
@@ -93,7 +93,7 @@ lws_client_socket_service(struct lws *wsi, struct lws_pollfd *pollfd,
char *sb = p;
int n = 0;
#if defined(LWS_WITH_SOCKS5)
- char conn_mode = 0, pending_timeout = 0;
+ int conn_mode = 0, pending_timeout = 0;
#endif
if ((pollfd->revents & LWS_POLLOUT) &&
@@ -252,6 +252,8 @@ socks_reply_fail:
/* clear his proxy connection timeout */
lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
goto start_ws_handshake;
+ default:
+ break;
}
break;
#endif
@@ -578,6 +580,8 @@ lws_http_transaction_completed_client(struct lws *wsi)
"queued client done");
}
+ _lws_header_table_reset(wsi->http.ah);
+
/* after the first one, they can only be coming from the queue */
wsi->transaction_from_pipeline_queue = 1;
@@ -629,12 +633,20 @@ lws_http_transaction_completed_client(struct lws *wsi)
}
LWS_VISIBLE LWS_EXTERN unsigned int
-lws_http_client_http_response(struct lws *wsi)
+lws_http_client_http_response(struct lws *_wsi)
{
- if (!wsi->http.ah)
- return 0;
+ struct lws *wsi;
+ unsigned int resp;
+
+ if (_wsi->http.ah && _wsi->http.ah->http_response)
+ return _wsi->http.ah->http_response;
- return wsi->http.ah->http_response;
+ lws_vhost_lock(_wsi->vhost);
+ wsi = _lws_client_wsi_master(_wsi);
+ resp = wsi->http.ah->http_response;
+ lws_vhost_unlock(_wsi->vhost);
+
+ return resp;
}
#endif
#if defined(LWS_PLAT_OPTEE)
@@ -781,7 +793,7 @@ lws_client_interpret_server_handshake(struct lws *wsi)
q = strrchr(new_path, '/');
if (q)
lws_strncpy(q + 1, p, sizeof(new_path) -
- (q - new_path));
+ (q - new_path) - 1);
else
path = p;
}
@@ -910,9 +922,9 @@ lws_client_interpret_server_handshake(struct lws *wsi)
* we seem to be good to go, give client last chance to check
* headers and OK it
*/
- if (wsi->protocol->callback(wsi,
+ if (w->protocol->callback(w,
LWS_CALLBACK_CLIENT_FILTER_PRE_ESTABLISH,
- wsi->user_space, NULL, 0)) {
+ w->user_space, NULL, 0)) {
cce = "HS: disallowed by client filter";
goto bail2;
@@ -924,9 +936,9 @@ lws_client_interpret_server_handshake(struct lws *wsi)
wsi->rxflow_change_to = LWS_RXFLOW_ALLOW;
/* call him back to inform him he is up */
- if (wsi->protocol->callback(wsi,
+ if (w->protocol->callback(w,
LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP,
- wsi->user_space, NULL, 0)) {
+ w->user_space, NULL, 0)) {
cce = "HS: disallowed at ESTABLISHED";
goto bail3;
}
@@ -964,9 +976,9 @@ bail2:
n = 0;
if (cce)
n = (int)strlen(cce);
- wsi->protocol->callback(wsi,
+ w->protocol->callback(w,
LWS_CALLBACK_CLIENT_CONNECTION_ERROR,
- wsi->user_space, (void *)cce,
+ w->user_space, (void *)cce,
(unsigned int)n);
}
wsi->already_did_cce = 1;
@@ -1228,4 +1240,4 @@ completed:
return 0;
}
-#endif \ No newline at end of file
+#endif
diff --git a/thirdparty/libwebsockets/roles/http/header.c b/thirdparty/libwebsockets/roles/http/header.c
index 99e56f7564..dbcf27cbd1 100644
--- a/thirdparty/libwebsockets/roles/http/header.c
+++ b/thirdparty/libwebsockets/roles/http/header.c
@@ -26,7 +26,7 @@
const unsigned char *
lws_token_to_string(enum lws_token_indexes token)
{
- if ((unsigned int)token >= ARRAY_SIZE(set))
+ if ((unsigned int)token >= LWS_ARRAY_SIZE(set))
return NULL;
return (unsigned char *)set[token];
@@ -149,9 +149,17 @@ lws_add_http_common_headers(struct lws *wsi, unsigned int code,
(int)strlen(content_type), p, end))
return 1;
- if (content_len != LWS_ILLEGAL_HTTP_CONTENT_LEN &&
- lws_add_http_header_content_length(wsi, content_len, p, end))
- return 1;
+ if (content_len != LWS_ILLEGAL_HTTP_CONTENT_LEN) {
+ if (lws_add_http_header_content_length(wsi, content_len, p, end))
+ return 1;
+ } else {
+ if (lws_add_http_header_by_token(wsi, WSI_TOKEN_CONNECTION,
+ (unsigned char *)"close", 5,
+ p, end))
+ return 1;
+
+ wsi->http.connection_type = HTTP_CONNECTION_CLOSE;
+ }
return 0;
}
@@ -204,34 +212,40 @@ lws_add_http_header_status(struct lws *wsi, unsigned int _code,
#endif
#ifdef LWS_WITH_HTTP2
- if (lwsi_role_h2(wsi) || lwsi_role_h2_ENCAPSULATION(wsi))
- return lws_add_http2_header_status(wsi, code, p, end);
+ if (lwsi_role_h2(wsi) || lwsi_role_h2_ENCAPSULATION(wsi)) {
+ n = lws_add_http2_header_status(wsi, code, p, end);
+ if (n)
+ return n;
+ } else
#endif
- if (code >= 400 && code < (400 + ARRAY_SIZE(err400)))
- description = err400[code - 400];
- if (code >= 500 && code < (500 + ARRAY_SIZE(err500)))
- description = err500[code - 500];
-
- if (code == 100)
- description = "Continue";
- if (code == 200)
- description = "OK";
- if (code == 304)
- description = "Not Modified";
- else
- if (code >= 300 && code < 400)
- description = "Redirect";
-
- if (wsi->http.request_version < ARRAY_SIZE(hver))
- p1 = hver[wsi->http.request_version];
- else
- p1 = hver[0];
-
- n = sprintf((char *)code_and_desc, "%s %u %s", p1, code, description);
-
- if (lws_add_http_header_by_name(wsi, NULL, code_and_desc, n, p, end))
- return 1;
-
+ {
+ if (code >= 400 && code < (400 + LWS_ARRAY_SIZE(err400)))
+ description = err400[code - 400];
+ if (code >= 500 && code < (500 + LWS_ARRAY_SIZE(err500)))
+ description = err500[code - 500];
+
+ if (code == 100)
+ description = "Continue";
+ if (code == 200)
+ description = "OK";
+ if (code == 304)
+ description = "Not Modified";
+ else
+ if (code >= 300 && code < 400)
+ description = "Redirect";
+
+ if (wsi->http.request_version < LWS_ARRAY_SIZE(hver))
+ p1 = hver[wsi->http.request_version];
+ else
+ p1 = hver[0];
+
+ n = sprintf((char *)code_and_desc, "%s %u %s", p1, code,
+ description);
+
+ if (lws_add_http_header_by_name(wsi, NULL, code_and_desc, n, p,
+ end))
+ return 1;
+ }
headers = wsi->vhost->headers;
while (headers) {
if (lws_add_http_header_by_name(wsi,
diff --git a/thirdparty/libwebsockets/roles/http/private.h b/thirdparty/libwebsockets/roles/http/private.h
index 2aa7a92f75..5699914742 100644
--- a/thirdparty/libwebsockets/roles/http/private.h
+++ b/thirdparty/libwebsockets/roles/http/private.h
@@ -227,6 +227,7 @@ struct _lws_http_mode_related {
#if defined(LWS_WITH_HTTP_PROXY)
unsigned int perform_rewrite:1;
#endif
+ unsigned int deferred_transaction_completed:1;
};
diff --git a/thirdparty/libwebsockets/roles/http/server/lejp-conf.c b/thirdparty/libwebsockets/roles/http/server/lejp-conf.c
index e9ce854cfc..fbf10c288e 100644
--- a/thirdparty/libwebsockets/roles/http/server/lejp-conf.c
+++ b/thirdparty/libwebsockets/roles/http/server/lejp-conf.c
@@ -205,6 +205,7 @@ struct jpargs {
unsigned int enable_client_ssl:1;
unsigned int fresh_mount:1;
unsigned int any_vhosts:1;
+ unsigned int chunk:1;
};
static void *
@@ -213,6 +214,8 @@ lwsws_align(struct jpargs *a)
if ((lws_intptr_t)(a->p) & 15)
a->p += 16 - ((lws_intptr_t)(a->p) & 15);
+ a->chunk = 0;
+
return a->p;
}
@@ -225,7 +228,7 @@ arg_to_bool(const char *s)
if (n)
return 1;
- for (n = 0; n < (int)ARRAY_SIZE(on); n++)
+ for (n = 0; n < (int)LWS_ARRAY_SIZE(on); n++)
if (!strcasecmp(s, on[n]))
return 1;
@@ -413,25 +416,30 @@ lejp_vhosts_cb(struct lejp_ctx *ctx, char reason)
}
/* this catches, eg, vhosts[].headers[].xxx */
- if (reason == LEJPCB_VAL_STR_END &&
+ if ((reason == LEJPCB_VAL_STR_END || reason == LEJPCB_VAL_STR_CHUNK) &&
ctx->path_match == LEJPVP_HEADERS_NAME + 1) {
- headers = lwsws_align(a);
- a->p += sizeof(*headers);
-
- n = lejp_get_wildcard(ctx, 0, a->p, a->end - a->p);
- /* ie, enable this protocol, no options yet */
- headers->next = a->info->headers;
- a->info->headers = headers;
- headers->name = a->p;
- // lwsl_notice(" adding header %s=%s\n", a->p, ctx->buf);
- a->p += n - 1;
- *(a->p++) = ':';
- if (a->p < a->end)
- *(a->p++) = '\0';
- else
- *(a->p - 1) = '\0';
- headers->value = a->p;
- headers->options = NULL;
+ if (!a->chunk) {
+ headers = lwsws_align(a);
+ a->p += sizeof(*headers);
+
+ n = lejp_get_wildcard(ctx, 0, a->p,
+ lws_ptr_diff(a->end, a->p));
+ /* ie, add this header */
+ headers->next = a->info->headers;
+ a->info->headers = headers;
+ headers->name = a->p;
+
+ lwsl_notice(" adding header %s=%s\n", a->p, ctx->buf);
+ a->p += n - 1;
+ *(a->p++) = ':';
+ if (a->p < a->end)
+ *(a->p++) = '\0';
+ else
+ *(a->p - 1) = '\0';
+ headers->value = a->p;
+ headers->options = NULL;
+ }
+ a->chunk = reason == LEJPCB_VAL_STR_CHUNK;
goto dostring;
}
@@ -502,7 +510,7 @@ lejp_vhosts_cb(struct lejp_ctx *ctx, char reason)
if (a->last)
a->last->mount_next = m;
- for (n = 0; n < (int)ARRAY_SIZE(mount_protocols); n++)
+ for (n = 0; n < (int)LWS_ARRAY_SIZE(mount_protocols); n++)
if (!strncmp(a->m.origin, mount_protocols[n],
strlen(mount_protocols[n]))) {
lwsl_info("----%s\n", a->m.origin);
@@ -512,7 +520,7 @@ lejp_vhosts_cb(struct lejp_ctx *ctx, char reason)
break;
}
- if (n == (int)ARRAY_SIZE(mount_protocols)) {
+ if (n == (int)LWS_ARRAY_SIZE(mount_protocols)) {
lwsl_err("unsupported protocol:// %s\n", a->m.origin);
return 1;
}
@@ -750,6 +758,7 @@ lejp_vhosts_cb(struct lejp_ctx *ctx, char reason)
dostring:
p = ctx->buf;
+ p[LEJP_STRING_CHUNK] = '\0';
p1 = strstr(p, ESC_INSTALL_DATADIR);
if (p1) {
n = p1 - p;
@@ -762,7 +771,8 @@ dostring:
}
a->p += lws_snprintf(a->p, a->end - a->p, "%s", p);
- *(a->p)++ = '\0';
+ if (reason == LEJPCB_VAL_STR_END)
+ *(a->p)++ = '\0';
return 0;
}
@@ -779,7 +789,7 @@ lwsws_get_config(void *user, const char *f, const char * const *paths,
struct lejp_ctx ctx;
int n, m, fd;
- fd = open(f, O_RDONLY);
+ fd = lws_open(f, O_RDONLY);
if (fd < 0) {
lwsl_err("Cannot open %s\n", f);
return 2;
@@ -927,11 +937,11 @@ lwsws_get_config_globals(struct lws_context_creation_info *info, const char *d,
lws_snprintf(dd, sizeof(dd) - 1, "%s/conf", d);
if (lwsws_get_config(&a, dd, paths_global,
- ARRAY_SIZE(paths_global), lejp_globals_cb) > 1)
+ LWS_ARRAY_SIZE(paths_global), lejp_globals_cb) > 1)
return 1;
lws_snprintf(dd, sizeof(dd) - 1, "%s/conf.d", d);
if (lwsws_get_config_d(&a, dd, paths_global,
- ARRAY_SIZE(paths_global), lejp_globals_cb) > 1)
+ LWS_ARRAY_SIZE(paths_global), lejp_globals_cb) > 1)
return 1;
a.plugin_dirs[a.count_plugin_dirs] = NULL;
@@ -962,11 +972,11 @@ lwsws_get_config_vhosts(struct lws_context *context,
lws_snprintf(dd, sizeof(dd) - 1, "%s/conf", d);
if (lwsws_get_config(&a, dd, paths_vhosts,
- ARRAY_SIZE(paths_vhosts), lejp_vhosts_cb) > 1)
+ LWS_ARRAY_SIZE(paths_vhosts), lejp_vhosts_cb) > 1)
return 1;
lws_snprintf(dd, sizeof(dd) - 1, "%s/conf.d", d);
if (lwsws_get_config_d(&a, dd, paths_vhosts,
- ARRAY_SIZE(paths_vhosts), lejp_vhosts_cb) > 1)
+ LWS_ARRAY_SIZE(paths_vhosts), lejp_vhosts_cb) > 1)
return 1;
*cs = a.p;
diff --git a/thirdparty/libwebsockets/roles/http/server/parsers.c b/thirdparty/libwebsockets/roles/http/server/parsers.c
index cb022e362b..482bdc676a 100644
--- a/thirdparty/libwebsockets/roles/http/server/parsers.c
+++ b/thirdparty/libwebsockets/roles/http/server/parsers.c
@@ -563,7 +563,7 @@ int LWS_WARN_UNUSED_RESULT
lws_hdr_simple_create(struct lws *wsi, enum lws_token_indexes h, const char *s)
{
wsi->http.ah->nfrag++;
- if (wsi->http.ah->nfrag == ARRAY_SIZE(wsi->http.ah->frags)) {
+ if (wsi->http.ah->nfrag == LWS_ARRAY_SIZE(wsi->http.ah->frags)) {
lwsl_warn("More hdr frags than we can deal with, dropping\n");
return -1;
}
@@ -677,18 +677,16 @@ lws_parse_urldecode(struct lws *wsi, uint8_t *_c)
return -1;
/* genuine delimiter */
if ((c == '&' || c == ';') && !enc) {
- if (issue_char(wsi, c) < 0)
+ if (issue_char(wsi, '\0') < 0)
return -1;
- /* swallow the terminator */
- ah->frags[ah->nfrag].len--;
/* link to next fragment */
ah->frags[ah->nfrag].nfrag = ah->nfrag + 1;
ah->nfrag++;
- if (ah->nfrag >= ARRAY_SIZE(ah->frags))
+ if (ah->nfrag >= LWS_ARRAY_SIZE(ah->frags))
goto excessive;
/* start next fragment after the & */
ah->post_literal_equal = 0;
- ah->frags[ah->nfrag].offset = ah->pos;
+ ah->frags[ah->nfrag].offset = ++ah->pos;
ah->frags[ah->nfrag].len = 0;
ah->frags[ah->nfrag].nfrag = 0;
goto swallow;
@@ -787,9 +785,9 @@ lws_parse_urldecode(struct lws *wsi, uint8_t *_c)
/* move to using WSI_TOKEN_HTTP_URI_ARGS */
ah->nfrag++;
- if (ah->nfrag >= ARRAY_SIZE(ah->frags))
+ if (ah->nfrag >= LWS_ARRAY_SIZE(ah->frags))
goto excessive;
- ah->frags[ah->nfrag].offset = ah->pos;
+ ah->frags[ah->nfrag].offset = ++ah->pos;
ah->frags[ah->nfrag].len = 0;
ah->frags[ah->nfrag].nfrag = 0;
@@ -852,10 +850,10 @@ lws_parse(struct lws *wsi, unsigned char *buf, int *len)
c == ' ')
break;
- for (m = 0; m < ARRAY_SIZE(methods); m++)
+ for (m = 0; m < LWS_ARRAY_SIZE(methods); m++)
if (ah->parser_state == methods[m])
break;
- if (m == ARRAY_SIZE(methods))
+ if (m == LWS_ARRAY_SIZE(methods))
/* it was not any of the methods */
goto check_eol;
@@ -983,7 +981,7 @@ nope:
if (ah->lextable_pos < 0 && lwsi_role_h1(wsi) &&
lwsi_role_server(wsi)) {
/* this is not a header we know about */
- for (m = 0; m < ARRAY_SIZE(methods); m++)
+ for (m = 0; m < LWS_ARRAY_SIZE(methods); m++)
if (ah->frag_index[methods[m]]) {
/*
* already had the method, no idea what
@@ -996,7 +994,7 @@ nope:
* hm it's an unknown http method from a client in fact,
* it cannot be valid http
*/
- if (m == ARRAY_SIZE(methods)) {
+ if (m == LWS_ARRAY_SIZE(methods)) {
/*
* are we set up to accept raw in these cases?
*/
@@ -1025,7 +1023,7 @@ nope:
lextable[ah->lextable_pos + 1];
lwsl_parser("known hdr %d\n", n);
- for (m = 0; m < ARRAY_SIZE(methods); m++)
+ for (m = 0; m < LWS_ARRAY_SIZE(methods); m++)
if (n == methods[m] &&
ah->frag_index[methods[m]]) {
lwsl_warn("Duplicated method\n");
@@ -1061,7 +1059,7 @@ nope:
start_fragment:
ah->nfrag++;
excessive:
- if (ah->nfrag == ARRAY_SIZE(ah->frags)) {
+ if (ah->nfrag == LWS_ARRAY_SIZE(ah->frags)) {
lwsl_warn("More hdr frags than we can deal with\n");
return -1;
}
diff --git a/thirdparty/libwebsockets/roles/http/server/server.c b/thirdparty/libwebsockets/roles/http/server/server.c
index 350af3cd7e..abd86dc9b5 100644
--- a/thirdparty/libwebsockets/roles/http/server/server.c
+++ b/thirdparty/libwebsockets/roles/http/server/server.c
@@ -131,6 +131,17 @@ done_list:
(void)n;
#if defined(__linux__)
+#ifdef LWS_WITH_UNIX_SOCK
+ /*
+ * A Unix domain sockets cannot be bound for several times, even if we set
+ * the SO_REUSE* options on.
+ * However, fortunately, each thread is able to independently listen when
+ * running on a reasonably new Linux kernel. So we can safely assume
+ * creating just one listening socket for a multi-threaded environment won't
+ * fail in most cases.
+ */
+ if (!LWS_UNIX_SOCK_ENABLED(vhost))
+#endif
limit = vhost->context->count_threads;
#endif
@@ -694,7 +705,7 @@ lws_find_string_in_file(const char *filename, const char *string, int stringlen)
char buf[128];
int fd, match = 0, pos = 0, n = 0, hit = 0;
- fd = open(filename, O_RDONLY);
+ fd = lws_open(filename, O_RDONLY);
if (fd < 0) {
lwsl_err("can't open auth file: %s\n", filename);
return 0;
@@ -812,7 +823,7 @@ lws_http_get_uri_and_method(struct lws *wsi, char **puri_ptr, int *puri_len)
{
int n, count = 0;
- for (n = 0; n < (int)ARRAY_SIZE(methods); n++)
+ for (n = 0; n < (int)LWS_ARRAY_SIZE(methods); n++)
if (lws_hdr_total_length(wsi, methods[n]))
count++;
if (!count) {
@@ -827,7 +838,7 @@ lws_http_get_uri_and_method(struct lws *wsi, char **puri_ptr, int *puri_len)
return -1;
}
- for (n = 0; n < (int)ARRAY_SIZE(methods); n++)
+ for (n = 0; n < (int)LWS_ARRAY_SIZE(methods); n++)
if (lws_hdr_total_length(wsi, methods[n])) {
*puri_ptr = lws_hdr_simple_ptr(wsi, methods[n]);
*puri_len = lws_hdr_total_length(wsi, methods[n]);
@@ -857,7 +868,7 @@ lws_http_action(struct lws *wsi)
};
meth = lws_http_get_uri_and_method(wsi, &uri_ptr, &uri_len);
- if (meth < 0 || meth >= (int)ARRAY_SIZE(method_names))
+ if (meth < 0 || meth >= (int)LWS_ARRAY_SIZE(method_names))
goto bail_nuke_ah;
/* we insist on absolute paths */
@@ -1128,7 +1139,7 @@ lws_http_action(struct lws *wsi)
}
if (pcolon > pslash)
pcolon = NULL;
-
+
if (pcolon)
n = pcolon - hit->origin;
else
@@ -1142,13 +1153,13 @@ lws_http_action(struct lws *wsi)
i.address = ads;
i.port = 80;
- if (hit->origin_protocol == LWSMPRO_HTTPS) {
+ if (hit->origin_protocol == LWSMPRO_HTTPS) {
i.port = 443;
i.ssl_connection = 1;
}
if (pcolon)
i.port = atoi(pcolon + 1);
-
+
lws_snprintf(rpath, sizeof(rpath) - 1, "/%s/%s", pslash + 1,
uri_ptr + hit->mountpoint_len);
lws_clean_url(rpath);
@@ -1164,7 +1175,7 @@ lws_http_action(struct lws *wsi)
p++;
}
}
-
+
i.path = rpath;
i.host = i.address;
@@ -1178,7 +1189,7 @@ lws_http_action(struct lws *wsi)
"from %s, to %s\n",
i.address, i.port, i.path, i.ssl_connection,
i.uri_replace_from, i.uri_replace_to);
-
+
if (!lws_client_connect_via_info(&i)) {
lwsl_err("proxy connect fail\n");
return 1;
@@ -1714,12 +1725,31 @@ lws_http_transaction_completed(struct lws *wsi)
{
int n = NO_PENDING_TIMEOUT;
+ if (wsi->trunc_len) {
+ /*
+ * ...so he tried to send something large as the http reply,
+ * it went as a partial, but he immediately said the
+ * transaction was completed.
+ *
+ * Defer the transaction completed until the last part of the
+ * partial is sent.
+ */
+ lwsl_notice("%s: deferring due to partial\n", __func__);
+ wsi->http.deferred_transaction_completed = 1;
+
+ return 0;
+ }
+
lwsl_info("%s: wsi %p\n", __func__, wsi);
lws_access_log(wsi);
if (!wsi->hdr_parsing_completed) {
- lwsl_notice("%s: ignoring, ah parsing incomplete\n", __func__);
+ char peer[64];
+ lws_get_peer_simple(wsi, peer, sizeof(peer) - 1);
+ peer[sizeof(peer) - 1] = '\0';
+ lwsl_notice("%s: (from %s) ignoring, ah parsing incomplete\n",
+ __func__, peer);
return 0;
}
diff --git a/thirdparty/libwebsockets/roles/ws/client-parser-ws.c b/thirdparty/libwebsockets/roles/ws/client-parser-ws.c
index aa561ce034..7287fb1590 100644
--- a/thirdparty/libwebsockets/roles/ws/client-parser-ws.c
+++ b/thirdparty/libwebsockets/roles/ws/client-parser-ws.c
@@ -450,7 +450,7 @@ ping_drop:
break;
case LWSWSOPC_PONG:
- lwsl_info("client receied pong\n");
+ lwsl_info("client received pong\n");
lwsl_hexdump(&wsi->ws->rx_ubuf[LWS_PRE],
wsi->ws->rx_ubuf_head);
@@ -488,9 +488,6 @@ ping_drop:
ebuf.token = &wsi->ws->rx_ubuf[LWS_PRE];
ebuf.len = wsi->ws->rx_ubuf_head;
- if (wsi->ws->opcode == LWSWSOPC_PONG && !ebuf.len)
- goto already_done;
-
#if !defined(LWS_WITHOUT_EXTENSIONS)
drain_extension:
lwsl_ext("%s: passing %d to ext\n", __func__, ebuf.len);
@@ -504,14 +501,12 @@ drain_extension:
#endif
lwsl_debug("post inflate ebuf len %d\n", ebuf.len);
- if (
#if !defined(LWS_WITHOUT_EXTENSIONS)
- rx_draining_ext &&
-#endif
- !ebuf.len) {
+ if (rx_draining_ext && !ebuf.len) {
lwsl_debug(" --- ending drain on 0 read result\n");
goto already_done;
}
+#endif
if (wsi->ws->check_utf8 && !wsi->ws->defeat_check_utf8) {
if (lws_check_utf8(&wsi->ws->utf8,
diff --git a/thirdparty/libwebsockets/roles/ws/ops-ws.c b/thirdparty/libwebsockets/roles/ws/ops-ws.c
index 5ddaba9e18..665b2c9b74 100644
--- a/thirdparty/libwebsockets/roles/ws/ops-ws.c
+++ b/thirdparty/libwebsockets/roles/ws/ops-ws.c
@@ -1246,8 +1246,7 @@ int rops_handle_POLLOUT_ws(struct lws *wsi)
return LWS_HP_RET_BAIL_OK;
}
- if (lwsi_role_client(wsi) && !wsi->socket_is_permanently_unusable &&
- wsi->ws->send_check_ping) {
+ if (!wsi->socket_is_permanently_unusable && wsi->ws->send_check_ping) {
lwsl_info("issuing ping on wsi %p\n", wsi);
wsi->ws->send_check_ping = 0;
@@ -1282,7 +1281,7 @@ int rops_handle_POLLOUT_ws(struct lws *wsi)
* payload ordering, but since they are always complete
* fragments control packets can interleave OK.
*/
- if (lwsi_role_client(wsi) && wsi->ws->tx_draining_ext) {
+ if (wsi->ws->tx_draining_ext) {
lwsl_ext("SERVICING TX EXT DRAINING\n");
if (lws_write(wsi, NULL, 0, LWS_WRITE_CONTINUATION) < 0)
return LWS_HP_RET_BAIL_DIE;
@@ -1292,8 +1291,10 @@ int rops_handle_POLLOUT_ws(struct lws *wsi)
/* Priority 6: extensions
*/
- if (!wsi->ws->extension_data_pending)
+ if (!wsi->ws->extension_data_pending && !wsi->ws->tx_draining_ext) {
+ lwsl_ext("%s: !wsi->ws->extension_data_pending\n", __func__);
return LWS_HP_RET_USER_SERVICE;
+ }
/*
* check in on the active extensions, see if they
@@ -1412,15 +1413,13 @@ rops_periodic_checks_ws(struct lws_context *context, int tsi, time_t now)
wsi->ws->time_next_ping_check) >
context->ws_ping_pong_interval) {
- lwsl_info("req pp on wsi %p\n",
- wsi);
+ lwsl_info("req pp on wsi %p\n", wsi);
wsi->ws->send_check_ping = 1;
lws_set_timeout(wsi,
PENDING_TIMEOUT_WS_PONG_CHECK_SEND_PING,
context->timeout_secs);
lws_callback_on_writable(wsi);
- wsi->ws->time_next_ping_check =
- now;
+ wsi->ws->time_next_ping_check = now;
}
wsi = wsi->same_vh_protocol_next;
}
@@ -1466,6 +1465,9 @@ rops_service_flag_pending_ws(struct lws_context *context, int tsi)
static int
rops_close_via_role_protocol_ws(struct lws *wsi, enum lws_close_status reason)
{
+ if (!wsi->ws)
+ return 0;
+
if (!wsi->ws->close_in_ping_buffer_len && /* already a reason */
(reason == LWS_CLOSE_STATUS_NOSTATUS ||
reason == LWS_CLOSE_STATUS_NOSTATUS_CONTEXT_DESTROY))
@@ -1512,7 +1514,7 @@ rops_close_role_ws(struct lws_context_per_thread *pt, struct lws *wsi)
if (wsi->ws->tx_draining_ext) {
struct lws **w = &pt->ws.tx_draining_ext_list;
- lwsl_notice("%s: CLEARING tx_draining_ext\n", __func__);
+ lwsl_ext("%s: CLEARING tx_draining_ext\n", __func__);
wsi->ws->tx_draining_ext = 0;
/* remove us from context draining ext list */
while (*w) {
@@ -1563,7 +1565,7 @@ rops_write_role_protocol_ws(struct lws *wsi, unsigned char *buf, size_t len,
/* remove us from the list */
struct lws **w = &pt->ws.tx_draining_ext_list;
- lwsl_notice("%s: CLEARING tx_draining_ext\n", __func__);
+ lwsl_ext("%s: CLEARING tx_draining_ext\n", __func__);
wsi->ws->tx_draining_ext = 0;
/* remove us from context draining ext list */
while (*w) {
@@ -1588,7 +1590,7 @@ rops_write_role_protocol_ws(struct lws *wsi, unsigned char *buf, size_t len,
if (!(wpt & LWS_WRITE_NO_FIN) && len)
*wp &= ~LWS_WRITE_NO_FIN;
- lwsl_notice("FORCED draining wp to 0x%02X (stashed 0x%02X, incoming 0x%02X)\n", *wp,
+ lwsl_ext("FORCED draining wp to 0x%02X (stashed 0x%02X, incoming 0x%02X)\n", *wp,
wsi->ws->tx_draining_stashed_wp, wpt);
// assert(0);
}
@@ -1644,7 +1646,7 @@ rops_write_role_protocol_ws(struct lws *wsi, unsigned char *buf, size_t len,
// lwsl_notice("ext processed %d plaintext into %d compressed (wp 0x%x)\n", m, (int)ebuf.len, *wp);
if (n && ebuf.len) {
- lwsl_notice("write drain len %d (wp 0x%x) SETTING tx_draining_ext\n", (int)ebuf.len, *wp);
+ lwsl_ext("write drain len %d (wp 0x%x) SETTING tx_draining_ext\n", (int)ebuf.len, *wp);
/* extension requires further draining */
wsi->ws->tx_draining_ext = 1;
wsi->ws->tx_draining_ext_list = pt->ws.tx_draining_ext_list;
diff --git a/thirdparty/libwebsockets/tls/mbedtls/mbedtls-server.c b/thirdparty/libwebsockets/tls/mbedtls/mbedtls-server.c
index 2de6d422e3..f17c7e5494 100644
--- a/thirdparty/libwebsockets/tls/mbedtls/mbedtls-server.c
+++ b/thirdparty/libwebsockets/tls/mbedtls/mbedtls-server.c
@@ -631,7 +631,7 @@ lws_tls_acme_sni_csr_create(struct lws_context *context, const char *elements[],
/* subject must be formatted like "C=TW,O=warmcat,CN=myserver" */
- for (n = 0; n < (int)ARRAY_SIZE(x5); n++) {
+ for (n = 0; n < (int)LWS_ARRAY_SIZE(x5); n++) {
if (p != subject)
*p++ = ',';
if (elements[n])
diff --git a/thirdparty/libwebsockets/tls/mbedtls/ssl.c b/thirdparty/libwebsockets/tls/mbedtls/ssl.c
index 6ae9d2556b..f311ef50e3 100644
--- a/thirdparty/libwebsockets/tls/mbedtls/ssl.c
+++ b/thirdparty/libwebsockets/tls/mbedtls/ssl.c
@@ -121,8 +121,6 @@ lws_ssl_capable_read(struct lws *wsi, unsigned char *buf, int len)
if (wsi->vhost)
wsi->vhost->conn_stats.rx += n;
- lws_restart_ws_ping_pong_timer(wsi);
-
/*
* if it was our buffer that limited what we read,
* check if SSL has additional data pending inside SSL buffers.
diff --git a/thirdparty/libwebsockets/tls/mbedtls/wrapper/include/internal/ssl_types.h b/thirdparty/libwebsockets/tls/mbedtls/wrapper/include/internal/ssl_types.h
index ba19663d9e..68ac748a28 100644
--- a/thirdparty/libwebsockets/tls/mbedtls/wrapper/include/internal/ssl_types.h
+++ b/thirdparty/libwebsockets/tls/mbedtls/wrapper/include/internal/ssl_types.h
@@ -37,7 +37,11 @@ typedef void RSA;
typedef void STACK;
typedef void BIO;
+#if defined(WIN32) || defined(_WIN32)
+#define ossl_inline __inline
+#else
#define ossl_inline inline
+#endif
#define SSL_METHOD_CALL(f, s, ...) s->method->func->ssl_##f(s, ##__VA_ARGS__)
#define X509_METHOD_CALL(f, x, ...) x->method->x509_##f(x, ##__VA_ARGS__)
diff --git a/thirdparty/libwebsockets/uwp_fixes.diff b/thirdparty/libwebsockets/uwp_fixes.diff
new file mode 100644
index 0000000000..21c3275bba
--- /dev/null
+++ b/thirdparty/libwebsockets/uwp_fixes.diff
@@ -0,0 +1,47 @@
+diff --git a/thirdparty/libwebsockets/plat/lws-plat-win.c b/thirdparty/libwebsockets/plat/lws-plat-win.c
+index bd513b494..1850b6425 100644
+--- a/thirdparty/libwebsockets/plat/lws-plat-win.c
++++ b/thirdparty/libwebsockets/plat/lws-plat-win.c
+@@ -641,9 +641,20 @@ _lws_plat_file_open(const struct lws_plat_file_ops *fops, const char *filename,
+ HANDLE ret;
+ WCHAR buf[MAX_PATH];
+ lws_fop_fd_t fop_fd;
+- LARGE_INTEGER llFileSize = {0};
++ FILE_STANDARD_INFO fInfo = {0};
+
+ MultiByteToWideChar(CP_UTF8, 0, filename, -1, buf, LWS_ARRAY_SIZE(buf));
++
++#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0602 // Windows 8 (minimum when UWP_ENABLED, but can be used in Windows builds)
++ CREATEFILE2_EXTENDED_PARAMETERS extParams = {0};
++ extParams.dwFileAttributes = FILE_ATTRIBUTE_NORMAL;
++
++ if (((*flags) & 7) == _O_RDONLY) {
++ ret = CreateFile2(buf, GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, &extParams);
++ } else {
++ ret = CreateFile2(buf, GENERIC_WRITE, 0, CREATE_ALWAYS, &extParams);
++ }
++#else
+ if (((*flags) & 7) == _O_RDONLY) {
+ ret = CreateFileW(buf, GENERIC_READ, FILE_SHARE_READ,
+ NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+@@ -651,6 +662,7 @@ _lws_plat_file_open(const struct lws_plat_file_ops *fops, const char *filename,
+ ret = CreateFileW(buf, GENERIC_WRITE, 0, NULL,
+ CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+ }
++#endif
+
+ if (ret == LWS_INVALID_FILE)
+ goto bail;
+@@ -663,9 +675,9 @@ _lws_plat_file_open(const struct lws_plat_file_ops *fops, const char *filename,
+ fop_fd->fd = ret;
+ fop_fd->filesystem_priv = NULL; /* we don't use it */
+ fop_fd->flags = *flags;
+- fop_fd->len = GetFileSize(ret, NULL);
+- if(GetFileSizeEx(ret, &llFileSize))
+- fop_fd->len = llFileSize.QuadPart;
++ fop_fd->len = 0;
++ if(GetFileInformationByHandleEx(ret, FileStandardInfo, &fInfo, sizeof(fInfo)))
++ fop_fd->len = fInfo.EndOfFile.QuadPart;
+
+ fop_fd->pos = 0;
+
diff --git a/thirdparty/libwebsockets/win32helpers/getopt.c b/thirdparty/libwebsockets/win32helpers/getopt.c
index 2181f1cb12..3bb21f6f28 100644
--- a/thirdparty/libwebsockets/win32helpers/getopt.c
+++ b/thirdparty/libwebsockets/win32helpers/getopt.c
@@ -1,153 +1,153 @@
-/* $NetBSD: getopt.c,v 1.16 1999/12/02 13:15:56 kleink Exp $ */
-
-/*
- * Copyright (c) 1987, 1993, 1994
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#if 0
-static char sccsid[] = "@(#)getopt.c 8.3 (Berkeley) 4/27/95";
-#endif
-
-#include <assert.h>
-#include <errno.h>
-#include <stdio.h>
-#include <string.h>
-
-#define __P(x) x
-#define _DIAGASSERT(x) assert(x)
-
-#ifdef __weak_alias
-__weak_alias(getopt,_getopt);
-#endif
-
-
-int opterr = 1, /* if error message should be printed */
- optind = 1, /* index into parent argv vector */
- optopt, /* character checked for validity */
- optreset; /* reset getopt */
-char *optarg; /* argument associated with option */
-
-static char * _progname __P((char *));
-int getopt_internal __P((int, char * const *, const char *));
-
-static char *
-_progname(nargv0)
- char * nargv0;
-{
- char * tmp;
-
- _DIAGASSERT(nargv0 != NULL);
-
- tmp = strrchr(nargv0, '/');
- if (tmp)
- tmp++;
- else
- tmp = nargv0;
- return(tmp);
-}
-
-#define BADCH (int)'?'
-#define BADARG (int)':'
-#define EMSG ""
-
-/*
- * getopt --
- * Parse argc/argv argument vector.
- */
-int
-getopt(nargc, nargv, ostr)
- int nargc;
- char * const nargv[];
- const char *ostr;
-{
- static char *__progname = 0;
- static char *place = EMSG; /* option letter processing */
- char *oli; /* option letter list index */
- __progname = __progname?__progname:_progname(*nargv);
-
- _DIAGASSERT(nargv != NULL);
- _DIAGASSERT(ostr != NULL);
-
- if (optreset || !*place) { /* update scanning pointer */
- optreset = 0;
- if (optind >= nargc || *(place = nargv[optind]) != '-') {
- place = EMSG;
- return (-1);
- }
- if (place[1] && *++place == '-' /* found "--" */
- && place[1] == '\0') {
- ++optind;
- place = EMSG;
- return (-1);
- }
- } /* option letter okay? */
- if ((optopt = (int)*place++) == (int)':' ||
- !(oli = strchr(ostr, optopt))) {
- /*
- * if the user didn't specify '-' as an option,
- * assume it means -1.
- */
- if (optopt == (int)'-')
- return (-1);
- if (!*place)
- ++optind;
- if (opterr && *ostr != ':')
- (void)fprintf(stderr,
- "%s: illegal option -- %c\n", __progname, optopt);
- return (BADCH);
- }
- if (*++oli != ':') { /* don't need argument */
- optarg = NULL;
- if (!*place)
- ++optind;
- }
- else { /* need an argument */
- if (*place) /* no white space */
- optarg = place;
- else if (nargc <= ++optind) { /* no arg */
- place = EMSG;
- if (*ostr == ':')
- return (BADARG);
- if (opterr)
- (void)fprintf(stderr,
- "%s: option requires an argument -- %c\n",
- __progname, optopt);
- return (BADCH);
- }
- else /* white space */
- optarg = nargv[optind];
- place = EMSG;
- ++optind;
- }
- return (optopt); /* dump back option letter */
-}
-
+/* $NetBSD: getopt.c,v 1.16 1999/12/02 13:15:56 kleink Exp $ */
+
+/*
+ * Copyright (c) 1987, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+static char sccsid[] = "@(#)getopt.c 8.3 (Berkeley) 4/27/95";
+#endif
+
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+#define __P(x) x
+#define _DIAGASSERT(x) assert(x)
+
+#ifdef __weak_alias
+__weak_alias(getopt,_getopt);
+#endif
+
+
+int opterr = 1, /* if error message should be printed */
+ optind = 1, /* index into parent argv vector */
+ optopt, /* character checked for validity */
+ optreset; /* reset getopt */
+char *optarg; /* argument associated with option */
+
+static char * _progname __P((char *));
+int getopt_internal __P((int, char * const *, const char *));
+
+static char *
+_progname(nargv0)
+ char * nargv0;
+{
+ char * tmp;
+
+ _DIAGASSERT(nargv0 != NULL);
+
+ tmp = strrchr(nargv0, '/');
+ if (tmp)
+ tmp++;
+ else
+ tmp = nargv0;
+ return(tmp);
+}
+
+#define BADCH (int)'?'
+#define BADARG (int)':'
+#define EMSG ""
+
+/*
+ * getopt --
+ * Parse argc/argv argument vector.
+ */
+int
+getopt(nargc, nargv, ostr)
+ int nargc;
+ char * const nargv[];
+ const char *ostr;
+{
+ static char *__progname = 0;
+ static char *place = EMSG; /* option letter processing */
+ char *oli; /* option letter list index */
+ __progname = __progname?__progname:_progname(*nargv);
+
+ _DIAGASSERT(nargv != NULL);
+ _DIAGASSERT(ostr != NULL);
+
+ if (optreset || !*place) { /* update scanning pointer */
+ optreset = 0;
+ if (optind >= nargc || *(place = nargv[optind]) != '-') {
+ place = EMSG;
+ return (-1);
+ }
+ if (place[1] && *++place == '-' /* found "--" */
+ && place[1] == '\0') {
+ ++optind;
+ place = EMSG;
+ return (-1);
+ }
+ } /* option letter okay? */
+ if ((optopt = (int)*place++) == (int)':' ||
+ !(oli = strchr(ostr, optopt))) {
+ /*
+ * if the user didn't specify '-' as an option,
+ * assume it means -1.
+ */
+ if (optopt == (int)'-')
+ return (-1);
+ if (!*place)
+ ++optind;
+ if (opterr && *ostr != ':')
+ (void)fprintf(stderr,
+ "%s: illegal option -- %c\n", __progname, optopt);
+ return (BADCH);
+ }
+ if (*++oli != ':') { /* don't need argument */
+ optarg = NULL;
+ if (!*place)
+ ++optind;
+ }
+ else { /* need an argument */
+ if (*place) /* no white space */
+ optarg = place;
+ else if (nargc <= ++optind) { /* no arg */
+ place = EMSG;
+ if (*ostr == ':')
+ return (BADARG);
+ if (opterr)
+ (void)fprintf(stderr,
+ "%s: option requires an argument -- %c\n",
+ __progname, optopt);
+ return (BADCH);
+ }
+ else /* white space */
+ optarg = nargv[optind];
+ place = EMSG;
+ ++optind;
+ }
+ return (optopt); /* dump back option letter */
+}
+
diff --git a/thirdparty/libwebsockets/win32helpers/getopt_long.c b/thirdparty/libwebsockets/win32helpers/getopt_long.c
index 22e5fa8945..6dfccf367d 100644
--- a/thirdparty/libwebsockets/win32helpers/getopt_long.c
+++ b/thirdparty/libwebsockets/win32helpers/getopt_long.c
@@ -1,240 +1,240 @@
-
-/*
- * Copyright (c) 1987, 1993, 1994, 1996
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-#include <assert.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include "getopt.h"
-
-#define lws_ptr_diff(head, tail) \
- ((int)((char *)(head) - (char *)(tail)))
-
-extern int opterr; /* if error message should be printed */
-extern int optind; /* index into parent argv vector */
-extern int optopt; /* character checked for validity */
-extern int optreset; /* reset getopt */
-extern char *optarg; /* argument associated with option */
-
-#define __P(x) x
-#define _DIAGASSERT(x) assert(x)
-
-static char * __progname __P((char *));
-int getopt_internal __P((int, char * const *, const char *));
-
-static char *
-__progname(nargv0)
- char * nargv0;
-{
- char * tmp;
-
- _DIAGASSERT(nargv0 != NULL);
-
- tmp = strrchr(nargv0, '/');
- if (tmp)
- tmp++;
- else
- tmp = nargv0;
- return(tmp);
-}
-
-#define BADCH (int)'?'
-#define BADARG (int)':'
-#define EMSG ""
-
-/*
- * getopt --
- * Parse argc/argv argument vector.
- */
-int
-getopt_internal(nargc, nargv, ostr)
- int nargc;
- char * const *nargv;
- const char *ostr;
-{
- static char *place = EMSG; /* option letter processing */
- char *oli; /* option letter list index */
-
- _DIAGASSERT(nargv != NULL);
- _DIAGASSERT(ostr != NULL);
-
- if (optreset || !*place) { /* update scanning pointer */
- optreset = 0;
- if (optind >= nargc || *(place = nargv[optind]) != '-') {
- place = EMSG;
- return (-1);
- }
- if (place[1] && *++place == '-') { /* found "--" */
- /* ++optind; */
- place = EMSG;
- return (-2);
- }
- } /* option letter okay? */
- if ((optopt = (int)*place++) == (int)':' ||
- !(oli = strchr(ostr, optopt))) {
- /*
- * if the user didn't specify '-' as an option,
- * assume it means -1.
- */
- if (optopt == (int)'-')
- return (-1);
- if (!*place)
- ++optind;
- if (opterr && *ostr != ':')
- (void)fprintf(stderr,
- "%s: illegal option -- %c\n", __progname(nargv[0]), optopt);
- return (BADCH);
- }
- if (*++oli != ':') { /* don't need argument */
- optarg = NULL;
- if (!*place)
- ++optind;
- } else { /* need an argument */
- if (*place) /* no white space */
- optarg = place;
- else if (nargc <= ++optind) { /* no arg */
- place = EMSG;
- if ((opterr) && (*ostr != ':'))
- (void)fprintf(stderr,
- "%s: option requires an argument -- %c\n",
- __progname(nargv[0]), optopt);
- return (BADARG);
- } else /* white space */
- optarg = nargv[optind];
- place = EMSG;
- ++optind;
- }
- return (optopt); /* dump back option letter */
-}
-
-#if 0
-/*
- * getopt --
- * Parse argc/argv argument vector.
- */
-int
-getopt2(nargc, nargv, ostr)
- int nargc;
- char * const *nargv;
- const char *ostr;
-{
- int retval;
-
- if ((retval = getopt_internal(nargc, nargv, ostr)) == -2) {
- retval = -1;
- ++optind;
- }
- return(retval);
-}
-#endif
-
-/*
- * getopt_long --
- * Parse argc/argv argument vector.
- */
-int
-getopt_long(nargc, nargv, options, long_options, index)
- int nargc;
- char ** nargv;
- char * options;
- struct option * long_options;
- int * index;
-{
- int retval;
-
- _DIAGASSERT(nargv != NULL);
- _DIAGASSERT(options != NULL);
- _DIAGASSERT(long_options != NULL);
- /* index may be NULL */
-
- if ((retval = getopt_internal(nargc, nargv, options)) == -2) {
- char *current_argv = nargv[optind++] + 2, *has_equal;
- int i, current_argv_len, match = -1;
-
- if (*current_argv == '\0') {
- return(-1);
- }
- if ((has_equal = strchr(current_argv, '=')) != NULL) {
- current_argv_len = lws_ptr_diff(has_equal, current_argv);
- has_equal++;
- } else
- current_argv_len = (int)strlen(current_argv);
-
- for (i = 0; long_options[i].name; i++) {
- if (strncmp(current_argv, long_options[i].name, current_argv_len))
- continue;
-
- if (strlen(long_options[i].name) == (unsigned)current_argv_len) {
- match = i;
- break;
- }
- if (match == -1)
- match = i;
- }
- if (match != -1) {
- if (long_options[match].has_arg == required_argument ||
- long_options[match].has_arg == optional_argument) {
- if (has_equal)
- optarg = has_equal;
- else
- optarg = nargv[optind++];
- }
- if ((long_options[match].has_arg == required_argument)
- && (optarg == NULL)) {
- /*
- * Missing argument, leading :
- * indicates no error should be generated
- */
- if ((opterr) && (*options != ':'))
- (void)fprintf(stderr,
- "%s: option requires an argument -- %s\n",
- __progname(nargv[0]), current_argv);
- return (BADARG);
- }
- } else { /* No matching argument */
- if ((opterr) && (*options != ':'))
- (void)fprintf(stderr,
- "%s: illegal option -- %s\n", __progname(nargv[0]), current_argv);
- return (BADCH);
- }
- if (long_options[match].flag) {
- *long_options[match].flag = long_options[match].val;
- retval = 0;
- } else
- retval = long_options[match].val;
- if (index)
- *index = match;
- }
- return(retval);
-}
+
+/*
+ * Copyright (c) 1987, 1993, 1994, 1996
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "getopt.h"
+
+#define lws_ptr_diff(head, tail) \
+ ((int)((char *)(head) - (char *)(tail)))
+
+extern int opterr; /* if error message should be printed */
+extern int optind; /* index into parent argv vector */
+extern int optopt; /* character checked for validity */
+extern int optreset; /* reset getopt */
+extern char *optarg; /* argument associated with option */
+
+#define __P(x) x
+#define _DIAGASSERT(x) assert(x)
+
+static char * __progname __P((char *));
+int getopt_internal __P((int, char * const *, const char *));
+
+static char *
+__progname(nargv0)
+ char * nargv0;
+{
+ char * tmp;
+
+ _DIAGASSERT(nargv0 != NULL);
+
+ tmp = strrchr(nargv0, '/');
+ if (tmp)
+ tmp++;
+ else
+ tmp = nargv0;
+ return(tmp);
+}
+
+#define BADCH (int)'?'
+#define BADARG (int)':'
+#define EMSG ""
+
+/*
+ * getopt --
+ * Parse argc/argv argument vector.
+ */
+int
+getopt_internal(nargc, nargv, ostr)
+ int nargc;
+ char * const *nargv;
+ const char *ostr;
+{
+ static char *place = EMSG; /* option letter processing */
+ char *oli; /* option letter list index */
+
+ _DIAGASSERT(nargv != NULL);
+ _DIAGASSERT(ostr != NULL);
+
+ if (optreset || !*place) { /* update scanning pointer */
+ optreset = 0;
+ if (optind >= nargc || *(place = nargv[optind]) != '-') {
+ place = EMSG;
+ return (-1);
+ }
+ if (place[1] && *++place == '-') { /* found "--" */
+ /* ++optind; */
+ place = EMSG;
+ return (-2);
+ }
+ } /* option letter okay? */
+ if ((optopt = (int)*place++) == (int)':' ||
+ !(oli = strchr(ostr, optopt))) {
+ /*
+ * if the user didn't specify '-' as an option,
+ * assume it means -1.
+ */
+ if (optopt == (int)'-')
+ return (-1);
+ if (!*place)
+ ++optind;
+ if (opterr && *ostr != ':')
+ (void)fprintf(stderr,
+ "%s: illegal option -- %c\n", __progname(nargv[0]), optopt);
+ return (BADCH);
+ }
+ if (*++oli != ':') { /* don't need argument */
+ optarg = NULL;
+ if (!*place)
+ ++optind;
+ } else { /* need an argument */
+ if (*place) /* no white space */
+ optarg = place;
+ else if (nargc <= ++optind) { /* no arg */
+ place = EMSG;
+ if ((opterr) && (*ostr != ':'))
+ (void)fprintf(stderr,
+ "%s: option requires an argument -- %c\n",
+ __progname(nargv[0]), optopt);
+ return (BADARG);
+ } else /* white space */
+ optarg = nargv[optind];
+ place = EMSG;
+ ++optind;
+ }
+ return (optopt); /* dump back option letter */
+}
+
+#if 0
+/*
+ * getopt --
+ * Parse argc/argv argument vector.
+ */
+int
+getopt2(nargc, nargv, ostr)
+ int nargc;
+ char * const *nargv;
+ const char *ostr;
+{
+ int retval;
+
+ if ((retval = getopt_internal(nargc, nargv, ostr)) == -2) {
+ retval = -1;
+ ++optind;
+ }
+ return(retval);
+}
+#endif
+
+/*
+ * getopt_long --
+ * Parse argc/argv argument vector.
+ */
+int
+getopt_long(nargc, nargv, options, long_options, index)
+ int nargc;
+ char ** nargv;
+ char * options;
+ struct option * long_options;
+ int * index;
+{
+ int retval;
+
+ _DIAGASSERT(nargv != NULL);
+ _DIAGASSERT(options != NULL);
+ _DIAGASSERT(long_options != NULL);
+ /* index may be NULL */
+
+ if ((retval = getopt_internal(nargc, nargv, options)) == -2) {
+ char *current_argv = nargv[optind++] + 2, *has_equal;
+ int i, current_argv_len, match = -1;
+
+ if (*current_argv == '\0') {
+ return(-1);
+ }
+ if ((has_equal = strchr(current_argv, '=')) != NULL) {
+ current_argv_len = lws_ptr_diff(has_equal, current_argv);
+ has_equal++;
+ } else
+ current_argv_len = (int)strlen(current_argv);
+
+ for (i = 0; long_options[i].name; i++) {
+ if (strncmp(current_argv, long_options[i].name, current_argv_len))
+ continue;
+
+ if (strlen(long_options[i].name) == (unsigned)current_argv_len) {
+ match = i;
+ break;
+ }
+ if (match == -1)
+ match = i;
+ }
+ if (match != -1) {
+ if (long_options[match].has_arg == required_argument ||
+ long_options[match].has_arg == optional_argument) {
+ if (has_equal)
+ optarg = has_equal;
+ else
+ optarg = nargv[optind++];
+ }
+ if ((long_options[match].has_arg == required_argument)
+ && (optarg == NULL)) {
+ /*
+ * Missing argument, leading :
+ * indicates no error should be generated
+ */
+ if ((opterr) && (*options != ':'))
+ (void)fprintf(stderr,
+ "%s: option requires an argument -- %s\n",
+ __progname(nargv[0]), current_argv);
+ return (BADARG);
+ }
+ } else { /* No matching argument */
+ if ((opterr) && (*options != ':'))
+ (void)fprintf(stderr,
+ "%s: illegal option -- %s\n", __progname(nargv[0]), current_argv);
+ return (BADCH);
+ }
+ if (long_options[match].flag) {
+ *long_options[match].flag = long_options[match].val;
+ retval = 0;
+ } else
+ retval = long_options[match].val;
+ if (index)
+ *index = match;
+ }
+ return(retval);
+}
diff --git a/thirdparty/libwebsockets/win32helpers/gettimeofday.c b/thirdparty/libwebsockets/win32helpers/gettimeofday.c
index 08385c2320..35dd73531d 100644
--- a/thirdparty/libwebsockets/win32helpers/gettimeofday.c
+++ b/thirdparty/libwebsockets/win32helpers/gettimeofday.c
@@ -1,36 +1,36 @@
-#include <time.h>
-#include <windows.h> //I've omitted context line
-
-#include "gettimeofday.h"
-
-int gettimeofday(struct timeval *tv, struct timezone *tz)
-{
- FILETIME ft;
- unsigned __int64 tmpres = 0;
- static int tzflag;
-
- if (NULL != tv) {
- GetSystemTimeAsFileTime(&ft);
-
- tmpres |= ft.dwHighDateTime;
- tmpres <<= 32;
- tmpres |= ft.dwLowDateTime;
-
- /*converting file time to unix epoch*/
- tmpres /= 10; /*convert into microseconds*/
+#include <time.h>
+#include <windows.h> //I've omitted context line
+
+#include "gettimeofday.h"
+
+int gettimeofday(struct timeval *tv, struct timezone *tz)
+{
+ FILETIME ft;
+ unsigned __int64 tmpres = 0;
+ static int tzflag;
+
+ if (NULL != tv) {
+ GetSystemTimeAsFileTime(&ft);
+
+ tmpres |= ft.dwHighDateTime;
+ tmpres <<= 32;
+ tmpres |= ft.dwLowDateTime;
+
+ /*converting file time to unix epoch*/
+ tmpres /= 10; /*convert into microseconds*/
tmpres -= DELTA_EPOCH_IN_MICROSECS;
- tv->tv_sec = (long)(tmpres / 1000000UL);
- tv->tv_usec = (long)(tmpres % 1000000UL);
- }
-
- if (NULL != tz) {
- if (!tzflag) {
- _tzset();
- tzflag++;
- }
- tz->tz_minuteswest = _timezone / 60;
- tz->tz_dsttime = _daylight;
- }
-
- return 0;
-}
+ tv->tv_sec = (long)(tmpres / 1000000UL);
+ tv->tv_usec = (long)(tmpres % 1000000UL);
+ }
+
+ if (NULL != tz) {
+ if (!tzflag) {
+ _tzset();
+ tzflag++;
+ }
+ tz->tz_minuteswest = _timezone / 60;
+ tz->tz_dsttime = _daylight;
+ }
+
+ return 0;
+}
diff --git a/thirdparty/miniupnpc/minissdpc.c b/thirdparty/miniupnpc/minissdpc.c
index d76b242ad0..1d29b4ba5b 100644
--- a/thirdparty/miniupnpc/minissdpc.c
+++ b/thirdparty/miniupnpc/minissdpc.c
@@ -494,7 +494,6 @@ ssdpDiscoverDevices(const char * const deviceTypes[],
struct addrinfo hints, *servinfo, *p;
#endif
#ifdef _WIN32
- MIB_IPFORWARDROW ip_forward;
unsigned long _ttl = (unsigned long)ttl;
#endif
int linklocal = 1;
@@ -538,61 +537,103 @@ ssdpDiscoverDevices(const char * const deviceTypes[],
* SSDP multicast traffic */
/* Get IP associated with the index given in the ip_forward struct
* in order to give this ip to setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF) */
- if(!ipv6
- && (GetBestRoute(inet_addr("223.255.255.255"), 0, &ip_forward) == NO_ERROR)) {
- DWORD dwRetVal = 0;
- PMIB_IPADDRTABLE pIPAddrTable;
- DWORD dwSize = 0;
-#ifdef DEBUG
- IN_ADDR IPAddr;
-#endif
- int i;
-#ifdef DEBUG
- printf("ifIndex=%lu nextHop=%lx \n", ip_forward.dwForwardIfIndex, ip_forward.dwForwardNextHop);
-#endif
- pIPAddrTable = (MIB_IPADDRTABLE *) malloc(sizeof (MIB_IPADDRTABLE));
- if(pIPAddrTable) {
- if (GetIpAddrTable(pIPAddrTable, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER) {
- free(pIPAddrTable);
- pIPAddrTable = (MIB_IPADDRTABLE *) malloc(dwSize);
- }
- }
- if(pIPAddrTable) {
- dwRetVal = GetIpAddrTable( pIPAddrTable, &dwSize, 0 );
+ if(!ipv6) {
+ DWORD ifbestidx;
+ SOCKADDR_IN destAddr;
+ memset(&destAddr, 0, sizeof(destAddr));
+ destAddr.sin_family = AF_INET;
+ destAddr.sin_addr.s_addr = inet_addr("223.255.255.255");
+ destAddr.sin_port = 0;
+ if (GetBestInterfaceEx((struct sockaddr *)&destAddr, &ifbestidx) == NO_ERROR) {
+ DWORD dwSize = 0;
+ DWORD dwRetVal = 0;
+ unsigned int i = 0;
+ ULONG flags = GAA_FLAG_INCLUDE_PREFIX;
+ ULONG family = AF_INET;
+ LPVOID lpMsgBuf = NULL;
+ PIP_ADAPTER_ADDRESSES pAddresses = NULL;
+ ULONG outBufLen = 0;
+ ULONG Iterations = 0;
+ PIP_ADAPTER_ADDRESSES pCurrAddresses = NULL;
+ PIP_ADAPTER_UNICAST_ADDRESS pUnicast = NULL;
+ PIP_ADAPTER_ANYCAST_ADDRESS pAnycast = NULL;
+ PIP_ADAPTER_MULTICAST_ADDRESS pMulticast = NULL;
+ IP_ADAPTER_DNS_SERVER_ADDRESS *pDnServer = NULL;
+ IP_ADAPTER_PREFIX *pPrefix = NULL;
+
+ outBufLen = 15360;
+ do {
+ pAddresses = (IP_ADAPTER_ADDRESSES *) HeapAlloc(GetProcessHeap(), 0, outBufLen);
+ if (pAddresses == NULL) {
+ break;
+ }
+
+ dwRetVal = GetAdaptersAddresses(family, flags, NULL, pAddresses, &outBufLen);
+
+ if (dwRetVal == ERROR_BUFFER_OVERFLOW) {
+ HeapFree(GetProcessHeap(), 0, pAddresses);
+ pAddresses = NULL;
+ } else {
+ break;
+ }
+ Iterations++;
+ } while ((dwRetVal == ERROR_BUFFER_OVERFLOW) && (Iterations < 3));
+
if (dwRetVal == NO_ERROR) {
+ pCurrAddresses = pAddresses;
+ while (pCurrAddresses) {
#ifdef DEBUG
- printf("\tNum Entries: %ld\n", pIPAddrTable->dwNumEntries);
-#endif
- for (i=0; i < (int) pIPAddrTable->dwNumEntries; i++) {
-#ifdef DEBUG
- printf("\n\tInterface Index[%d]:\t%ld\n", i, pIPAddrTable->table[i].dwIndex);
- IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwAddr;
- printf("\tIP Address[%d]: \t%s\n", i, inet_ntoa(IPAddr) );
- IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwMask;
- printf("\tSubnet Mask[%d]: \t%s\n", i, inet_ntoa(IPAddr) );
- IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwBCastAddr;
- printf("\tBroadCast[%d]: \t%s (%ld)\n", i, inet_ntoa(IPAddr), pIPAddrTable->table[i].dwBCastAddr);
- printf("\tReassembly size[%d]:\t%ld\n", i, pIPAddrTable->table[i].dwReasmSize);
- printf("\tType and State[%d]:", i);
+ printf("\tIfIndex (IPv4 interface): %u\n", pCurrAddresses->IfIndex);
+ printf("\tAdapter name: %s\n", pCurrAddresses->AdapterName);
+ pUnicast = pCurrAddresses->FirstUnicastAddress;
+ if (pUnicast != NULL) {
+ for (i = 0; pUnicast != NULL; i++) {
+ IPAddr.S_un.S_addr = (u_long) pUnicast->Address;
+ printf("\tIP Address[%d]: \t%s\n", i, inet_ntoa(IPAddr) );
+ pUnicast = pUnicast->Next;
+ }
+ printf("\tNumber of Unicast Addresses: %d\n", i);
+ }
+ pAnycast = pCurrAddresses->FirstAnycastAddress;
+ if (pAnycast) {
+ for (i = 0; pAnycast != NULL; i++) {
+ IPAddr.S_un.S_addr = (u_long) pAnyCast->Address;
+ printf("\tAnycast Address[%d]: \t%s\n", i, inet_ntoa(IPAddr) );
+ pAnycast = pAnycast->Next;
+ }
+ printf("\tNumber of Anycast Addresses: %d\n", i);
+ }
+ pMulticast = pCurrAddresses->FirstMulticastAddress;
+ if (pMulticast) {
+ for (i = 0; pMulticast != NULL; i++) {
+ IPAddr.S_un.S_addr = (u_long) pMultiCast->Address;
+ printf("\tMulticast Address[%d]: \t%s\n", i, inet_ntoa(IPAddr) );
+ }
+ }
printf("\n");
#endif
- if (pIPAddrTable->table[i].dwIndex == ip_forward.dwForwardIfIndex) {
+ pUnicast = pCurrAddresses->FirstUnicastAddress;
+ if (pCurrAddresses->IfIndex == ifbestidx && pUnicast != NULL) {
+ SOCKADDR_IN *ipv4 = (SOCKADDR_IN *)(pUnicast->Address.lpSockaddr);
/* Set the address of this interface to be used */
struct in_addr mc_if;
memset(&mc_if, 0, sizeof(mc_if));
- mc_if.s_addr = pIPAddrTable->table[i].dwAddr;
+ mc_if.s_addr = ipv4->sin_addr.s_addr;
if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&mc_if, sizeof(mc_if)) < 0) {
PRINT_SOCKET_ERROR("setsockopt");
}
- ((struct sockaddr_in *)&sockudp_r)->sin_addr.s_addr = pIPAddrTable->table[i].dwAddr;
+ ((struct sockaddr_in *)&sockudp_r)->sin_addr.s_addr = ipv4->sin_addr.s_addr;
#ifndef DEBUG
break;
#endif
}
+ pCurrAddresses = pCurrAddresses->Next;
}
}
- free(pIPAddrTable);
- pIPAddrTable = NULL;
+ if (pAddresses != NULL) {
+ HeapFree(GetProcessHeap(), 0, pAddresses);
+ pAddresses = NULL;
+ }
}
}
#endif /* _WIN32 */
diff --git a/thirdparty/miniupnpc/miniupnpcstrings.h b/thirdparty/miniupnpc/miniupnpcstrings.h
index 1d5c5882fd..a718cc7bbf 100644
--- a/thirdparty/miniupnpc/miniupnpcstrings.h
+++ b/thirdparty/miniupnpc/miniupnpcstrings.h
@@ -1,7 +1,7 @@
#ifndef MINIUPNPCSTRINGS_H_INCLUDED
#define MINIUPNPCSTRINGS_H_INCLUDED
-#include <version.h>
+#include "core/version.h"
#define OS_STRING VERSION_NAME "/1.0"
#define MINIUPNPC_VERSION_STRING "2.1"
diff --git a/thirdparty/misc/aes256.h b/thirdparty/misc/aes256.h
index 8fcc25a4de..150a0670f5 100644
--- a/thirdparty/misc/aes256.h
+++ b/thirdparty/misc/aes256.h
@@ -21,7 +21,7 @@
#ifndef AES_256_H
#define AES_256_H
-#include "typedefs.h"
+#include "core/typedefs.h"
#ifdef __cplusplus
extern "C" {
diff --git a/thirdparty/misc/easing_equations.cpp b/thirdparty/misc/easing_equations.cpp
new file mode 100644
index 0000000000..bc84564b19
--- /dev/null
+++ b/thirdparty/misc/easing_equations.cpp
@@ -0,0 +1,308 @@
+/**
+ * Adapted from Penner Easing equations' C++ port.
+ * Source: https://github.com/jesusgollonet/ofpennereasing
+ * License: BSD-3-clause
+ */
+
+#include "scene/animation/tween.h"
+
+const real_t pi = 3.1415926535898;
+
+///////////////////////////////////////////////////////////////////////////
+// linear
+///////////////////////////////////////////////////////////////////////////
+namespace linear {
+static real_t in(real_t t, real_t b, real_t c, real_t d) {
+ return c * t / d + b;
+}
+
+static real_t out(real_t t, real_t b, real_t c, real_t d) {
+ return c * t / d + b;
+}
+
+static real_t in_out(real_t t, real_t b, real_t c, real_t d) {
+ return c * t / d + b;
+}
+
+static real_t out_in(real_t t, real_t b, real_t c, real_t d) {
+ return c * t / d + b;
+}
+}; // namespace linear
+///////////////////////////////////////////////////////////////////////////
+// sine
+///////////////////////////////////////////////////////////////////////////
+namespace sine {
+static real_t in(real_t t, real_t b, real_t c, real_t d) {
+ return -c * cos(t / d * (pi / 2)) + c + b;
+}
+
+static real_t out(real_t t, real_t b, real_t c, real_t d) {
+ return c * sin(t / d * (pi / 2)) + b;
+}
+
+static real_t in_out(real_t t, real_t b, real_t c, real_t d) {
+ return -c / 2 * (cos(pi * t / d) - 1) + b;
+}
+
+static real_t out_in(real_t t, real_t b, real_t c, real_t d) {
+ return (t < d / 2) ? out(t * 2, b, c / 2, d) : in((t * 2) - d, b + c / 2, c / 2, d);
+}
+}; // namespace sine
+///////////////////////////////////////////////////////////////////////////
+// quint
+///////////////////////////////////////////////////////////////////////////
+namespace quint {
+static real_t in(real_t t, real_t b, real_t c, real_t d) {
+ return c * pow(t / d, 5) + b;
+}
+
+static real_t out(real_t t, real_t b, real_t c, real_t d) {
+ return c * (pow(t / d - 1, 5) + 1) + b;
+}
+
+static real_t in_out(real_t t, real_t b, real_t c, real_t d) {
+ t = t / d * 2;
+ if (t < 1) return c / 2 * pow(t, 5) + b;
+ return c / 2 * (pow(t - 2, 5) + 2) + b;
+}
+
+static real_t out_in(real_t t, real_t b, real_t c, real_t d) {
+ return (t < d / 2) ? out(t * 2, b, c / 2, d) : in((t * 2) - d, b + c / 2, c / 2, d);
+}
+}; // namespace quint
+///////////////////////////////////////////////////////////////////////////
+// quart
+///////////////////////////////////////////////////////////////////////////
+namespace quart {
+static real_t in(real_t t, real_t b, real_t c, real_t d) {
+ return c * pow(t / d, 4) + b;
+}
+
+static real_t out(real_t t, real_t b, real_t c, real_t d) {
+ return -c * (pow(t / d - 1, 4) - 1) + b;
+}
+
+static real_t in_out(real_t t, real_t b, real_t c, real_t d) {
+ t = t / d * 2;
+ if (t < 1) return c / 2 * pow(t, 4) + b;
+ return -c / 2 * (pow(t - 2, 4) - 2) + b;
+}
+
+static real_t out_in(real_t t, real_t b, real_t c, real_t d) {
+ return (t < d / 2) ? out(t * 2, b, c / 2, d) : in((t * 2) - d, b + c / 2, c / 2, d);
+}
+}; // namespace quart
+///////////////////////////////////////////////////////////////////////////
+// quad
+///////////////////////////////////////////////////////////////////////////
+namespace quad {
+static real_t in(real_t t, real_t b, real_t c, real_t d) {
+ return c * pow(t / d, 2) + b;
+}
+
+static real_t out(real_t t, real_t b, real_t c, real_t d) {
+ t = t / d;
+ return -c * t * (t - 2) + b;
+}
+
+static real_t in_out(real_t t, real_t b, real_t c, real_t d) {
+ t = t / d * 2;
+ if (t < 1) return c / 2 * pow(t, 2) + b;
+ return -c / 2 * ((t - 1) * (t - 3) - 1) + b;
+}
+
+static real_t out_in(real_t t, real_t b, real_t c, real_t d) {
+ return (t < d / 2) ? out(t * 2, b, c / 2, d) : in((t * 2) - d, b + c / 2, c / 2, d);
+}
+}; // namespace quad
+///////////////////////////////////////////////////////////////////////////
+// expo
+///////////////////////////////////////////////////////////////////////////
+namespace expo {
+static real_t in(real_t t, real_t b, real_t c, real_t d) {
+ if (t == 0) return b;
+ return c * pow(2, 10 * (t / d - 1)) + b - c * 0.001;
+}
+
+static real_t out(real_t t, real_t b, real_t c, real_t d) {
+ if (t == d) return b + c;
+ return c * 1.001 * (-pow(2, -10 * t / d) + 1) + b;
+}
+
+static real_t in_out(real_t t, real_t b, real_t c, real_t d) {
+ if (t == 0) return b;
+ if (t == d) return b + c;
+ t = t / d * 2;
+ if (t < 1) return c / 2 * pow(2, 10 * (t - 1)) + b - c * 0.0005;
+ return c / 2 * 1.0005 * (-pow(2, -10 * (t - 1)) + 2) + b;
+}
+
+static real_t out_in(real_t t, real_t b, real_t c, real_t d) {
+ return (t < d / 2) ? out(t * 2, b, c / 2, d) : in((t * 2) - d, b + c / 2, c / 2, d);
+}
+}; // namespace expo
+///////////////////////////////////////////////////////////////////////////
+// elastic
+///////////////////////////////////////////////////////////////////////////
+namespace elastic {
+static real_t in(real_t t, real_t b, real_t c, real_t d) {
+ if (t == 0) return b;
+ if ((t /= d) == 1) return b + c;
+ float p = d * 0.3f;
+ float a = c;
+ float s = p / 4;
+ float postFix = a * pow(2, 10 * (t -= 1)); // this is a fix, again, with post-increment operators
+ return -(postFix * sin((t * d - s) * (2 * pi) / p)) + b;
+}
+
+static real_t out(real_t t, real_t b, real_t c, real_t d) {
+ if (t == 0) return b;
+ if ((t /= d) == 1) return b + c;
+ float p = d * 0.3f;
+ float a = c;
+ float s = p / 4;
+ return (a * pow(2, -10 * t) * sin((t * d - s) * (2 * pi) / p) + c + b);
+}
+
+static real_t in_out(real_t t, real_t b, real_t c, real_t d) {
+ if (t == 0) return b;
+ if ((t /= d / 2) == 2) return b + c;
+ float p = d * (0.3f * 1.5f);
+ float a = c;
+ float s = p / 4;
+
+ if (t < 1) {
+ float postFix = a * pow(2, 10 * (t -= 1)); // postIncrement is evil
+ return -0.5f * (postFix * sin((t * d - s) * (2 * pi) / p)) + b;
+ }
+ float postFix = a * pow(2, -10 * (t -= 1)); // postIncrement is evil
+ return postFix * sin((t * d - s) * (2 * pi) / p) * 0.5f + c + b;
+}
+
+static real_t out_in(real_t t, real_t b, real_t c, real_t d) {
+ return (t < d / 2) ? out(t * 2, b, c / 2, d) : in((t * 2) - d, b + c / 2, c / 2, d);
+}
+}; // namespace elastic
+///////////////////////////////////////////////////////////////////////////
+// cubic
+///////////////////////////////////////////////////////////////////////////
+namespace cubic {
+static real_t in(real_t t, real_t b, real_t c, real_t d) {
+ return c * (t /= d) * t * t + b;
+}
+
+static real_t out(real_t t, real_t b, real_t c, real_t d) {
+ t = t / d - 1;
+ return c * (t * t * t + 1) + b;
+}
+
+static real_t in_out(real_t t, real_t b, real_t c, real_t d) {
+ if ((t /= d / 2) < 1) return c / 2 * t * t * t + b;
+ return c / 2 * ((t -= 2) * t * t + 2) + b;
+}
+
+static real_t out_in(real_t t, real_t b, real_t c, real_t d) {
+ return (t < d / 2) ? out(t * 2, b, c / 2, d) : in((t * 2) - d, b + c / 2, c / 2, d);
+}
+}; // namespace cubic
+///////////////////////////////////////////////////////////////////////////
+// circ
+///////////////////////////////////////////////////////////////////////////
+namespace circ {
+static real_t in(real_t t, real_t b, real_t c, real_t d) {
+ return -c * (sqrt(1 - (t /= d) * t) - 1) + b; // TODO: ehrich: operation with t is undefined
+}
+
+static real_t out(real_t t, real_t b, real_t c, real_t d) {
+ return c * sqrt(1 - (t = t / d - 1) * t) + b; // TODO: ehrich: operation with t is undefined
+}
+
+static real_t in_out(real_t t, real_t b, real_t c, real_t d) {
+ if ((t /= d / 2) < 1) return -c / 2 * (sqrt(1 - t * t) - 1) + b;
+ return c / 2 * (sqrt(1 - t * (t -= 2)) + 1) + b; // TODO: ehrich: operation with t is undefined
+}
+
+static real_t out_in(real_t t, real_t b, real_t c, real_t d) {
+ return (t < d / 2) ? out(t * 2, b, c / 2, d) : in((t * 2) - d, b + c / 2, c / 2, d);
+}
+}; // namespace circ
+///////////////////////////////////////////////////////////////////////////
+// bounce
+///////////////////////////////////////////////////////////////////////////
+namespace bounce {
+static real_t out(real_t t, real_t b, real_t c, real_t d);
+
+static real_t in(real_t t, real_t b, real_t c, real_t d) {
+ return c - out(d - t, 0, c, d) + b;
+}
+
+static real_t out(real_t t, real_t b, real_t c, real_t d) {
+ if ((t /= d) < (1 / 2.75f)) {
+ return c * (7.5625f * t * t) + b;
+ } else if (t < (2 / 2.75f)) {
+ float postFix = t -= (1.5f / 2.75f);
+ return c * (7.5625f * (postFix)*t + .75f) + b;
+ } else if (t < (2.5 / 2.75)) {
+ float postFix = t -= (2.25f / 2.75f);
+ return c * (7.5625f * (postFix)*t + .9375f) + b;
+ } else {
+ float postFix = t -= (2.625f / 2.75f);
+ return c * (7.5625f * (postFix)*t + .984375f) + b;
+ }
+}
+
+static real_t in_out(real_t t, real_t b, real_t c, real_t d) {
+ return (t < d / 2) ? in(t * 2, b, c / 2, d) : out((t * 2) - d, b + c / 2, c / 2, d);
+}
+
+static real_t out_in(real_t t, real_t b, real_t c, real_t d) {
+ return (t < d / 2) ? out(t * 2, b, c / 2, d) : in((t * 2) - d, b + c / 2, c / 2, d);
+}
+}; // namespace bounce
+///////////////////////////////////////////////////////////////////////////
+// back
+///////////////////////////////////////////////////////////////////////////
+namespace back {
+static real_t in(real_t t, real_t b, real_t c, real_t d) {
+ float s = 1.70158f;
+ float postFix = t /= d;
+ return c * (postFix)*t * ((s + 1) * t - s) + b;
+}
+
+static real_t out(real_t t, real_t b, real_t c, real_t d) {
+ float s = 1.70158f;
+ return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b; // TODO: ehrich: operation with t is undefined
+}
+
+static real_t in_out(real_t t, real_t b, real_t c, real_t d) {
+ float s = 1.70158f;
+ if ((t /= d / 2) < 1) return c / 2 * (t * t * (((s *= (1.525f)) + 1) * t - s)) + b; // TODO: ehrich: operation with s is undefined
+ float postFix = t -= 2;
+ return c / 2 * ((postFix)*t * (((s *= (1.525f)) + 1) * t + s) + 2) + b; // TODO: ehrich: operation with s is undefined
+}
+
+static real_t out_in(real_t t, real_t b, real_t c, real_t d) {
+ return (t < d / 2) ? out(t * 2, b, c / 2, d) : in((t * 2) - d, b + c / 2, c / 2, d);
+}
+}; // namespace back
+
+Tween::interpolater Tween::interpolaters[Tween::TRANS_COUNT][Tween::EASE_COUNT] = {
+ { &linear::in, &linear::out, &linear::in_out, &linear::out_in },
+ { &sine::in, &sine::out, &sine::in_out, &sine::out_in },
+ { &quint::in, &quint::out, &quint::in_out, &quint::out_in },
+ { &quart::in, &quart::out, &quart::in_out, &quart::out_in },
+ { &quad::in, &quad::out, &quad::in_out, &quad::out_in },
+ { &expo::in, &expo::out, &expo::in_out, &expo::out_in },
+ { &elastic::in, &elastic::out, &elastic::in_out, &elastic::out_in },
+ { &cubic::in, &cubic::out, &cubic::in_out, &cubic::out_in },
+ { &circ::in, &circ::out, &circ::in_out, &circ::out_in },
+ { &bounce::in, &bounce::out, &bounce::in_out, &bounce::out_in },
+ { &back::in, &back::out, &back::in_out, &back::out_in },
+};
+
+real_t Tween::_run_equation(TransitionType p_trans_type, EaseType p_ease_type, real_t t, real_t b, real_t c, real_t d) {
+
+ interpolater cb = interpolaters[p_trans_type][p_ease_type];
+ ERR_FAIL_COND_V(cb == NULL, b);
+ return cb(t, b, c, d);
+}
diff --git a/thirdparty/misc/hq2x.cpp b/thirdparty/misc/hq2x.cpp
index 7ebb505d64..9c089ba85c 100644
--- a/thirdparty/misc/hq2x.cpp
+++ b/thirdparty/misc/hq2x.cpp
@@ -16,8 +16,8 @@
#include "hq2x.h"
-#include "math_funcs.h"
+#include "core/math/math_funcs.h"
static const uint32_t AMASK = 0xFF000000;
static const uint32_t YMASK = 0x00FF0000;
diff --git a/thirdparty/misc/hq2x.h b/thirdparty/misc/hq2x.h
index 8f119d2a01..bebd917950 100644
--- a/thirdparty/misc/hq2x.h
+++ b/thirdparty/misc/hq2x.h
@@ -1,7 +1,7 @@
#ifndef HQ2X_H
#define HQ2X_H
-#include "typedefs.h"
+#include "core/typedefs.h"
uint32_t *hq2x_resize(
diff --git a/thirdparty/misc/md5.h b/thirdparty/misc/md5.h
index e99d58b443..14b3cd3ddf 100644
--- a/thirdparty/misc/md5.h
+++ b/thirdparty/misc/md5.h
@@ -42,7 +42,7 @@
/* NOT typedef a 32 bit type */
-#include "typedefs.h"
+#include "core/typedefs.h"
/* Data structure for MD5 (Message Digest) computation */
typedef struct {
diff --git a/thirdparty/misc/open-simplex-noise-LICENSE b/thirdparty/misc/open-simplex-noise-LICENSE
new file mode 100644
index 0000000000..a84c395662
--- /dev/null
+++ b/thirdparty/misc/open-simplex-noise-LICENSE
@@ -0,0 +1,25 @@
+This is free and unencumbered software released into the public domain.
+
+Anyone is free to copy, modify, publish, use, compile, sell, or
+distribute this software, either in source code form or as a compiled
+binary, for any purpose, commercial or non-commercial, and by any
+means.
+
+In jurisdictions that recognize copyright laws, the author or authors
+of this software dedicate any and all copyright interest in the
+software to the public domain. We make this dedication for the benefit
+of the public at large and to the detriment of our heirs and
+successors. We intend this dedication to be an overt act of
+relinquishment in perpetuity of all present and future rights to this
+software under copyright law.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+For more information, please refer to <http://unlicense.org>
+
diff --git a/thirdparty/misc/open-simplex-noise-no-allocate.patch b/thirdparty/misc/open-simplex-noise-no-allocate.patch
new file mode 100644
index 0000000000..fc3abe7d00
--- /dev/null
+++ b/thirdparty/misc/open-simplex-noise-no-allocate.patch
@@ -0,0 +1,133 @@
+diff -u orig/open-simplex-noise.c misc/open-simplex-noise.c
+--- orig/open-simplex-noise.c 2018-09-14 11:11:40.049810000 +0200
++++ misc/open-simplex-noise.c 2018-09-14 11:09:39.726457000 +0200
+@@ -13,6 +13,11 @@
+ * of any particular randomization library, so results
+ * will be the same when ported to other languages.
+ */
++
++// -- GODOT start --
++// Modified to work without allocating memory, also removed some unused function.
++// -- GODOT end --
++
+ #include <math.h>
+ #include <stdlib.h>
+ #include <stdint.h>
+@@ -34,11 +39,12 @@
+
+ #define DEFAULT_SEED (0LL)
+
+-struct osn_context {
++// -- GODOT start --
++/*struct osn_context {
+ int16_t *perm;
+ int16_t *permGradIndex3D;
+-};
+-
++};*/
++// -- GODOT end --
+ #define ARRAYSIZE(x) (sizeof((x)) / sizeof((x)[0]))
+
+ /*
+@@ -126,7 +132,9 @@
+ int xi = (int) x;
+ return x < xi ? xi - 1 : xi;
+ }
+-
++
++// -- GODOT start --
++/*
+ static int allocate_perm(struct osn_context *ctx, int nperm, int ngrad)
+ {
+ if (ctx->perm)
+@@ -154,18 +162,21 @@
+ memcpy(ctx->perm, p, sizeof(*ctx->perm) * nelements);
+
+ for (i = 0; i < 256; i++) {
+- /* Since 3D has 24 gradients, simple bitmask won't work, so precompute modulo array. */
++ // Since 3D has 24 gradients, simple bitmask won't work, so precompute modulo array.
+ ctx->permGradIndex3D[i] = (int16_t)((ctx->perm[i] % (ARRAYSIZE(gradients3D) / 3)) * 3);
+ }
+ return 0;
+ }
++*/
++// -- GODOT end --
+
+ /*
+ * Initializes using a permutation array generated from a 64-bit seed.
+ * Generates a proper permutation (i.e. doesn't merely perform N successive pair
+ * swaps on a base array). Uses a simple 64-bit LCG.
+ */
+-int open_simplex_noise(int64_t seed, struct osn_context **ctx)
++// -- GODOT start --
++int open_simplex_noise(int64_t seed, struct osn_context *ctx)
+ {
+ int rc;
+ int16_t source[256];
+@@ -174,20 +185,9 @@
+ int16_t *permGradIndex3D;
+ int r;
+
+- *ctx = (struct osn_context *) malloc(sizeof(**ctx));
+- if (!(*ctx))
+- return -ENOMEM;
+- (*ctx)->perm = NULL;
+- (*ctx)->permGradIndex3D = NULL;
+-
+- rc = allocate_perm(*ctx, 256, 256);
+- if (rc) {
+- free(*ctx);
+- return rc;
+- }
+-
+- perm = (*ctx)->perm;
+- permGradIndex3D = (*ctx)->permGradIndex3D;
++ perm = ctx->perm;
++ permGradIndex3D = ctx->permGradIndex3D;
++// -- GODOT end --
+
+ for (i = 0; i < 256; i++)
+ source[i] = (int16_t) i;
+@@ -206,6 +206,8 @@
+ return 0;
+ }
+
++// -- GODOT start --
++/*
+ void open_simplex_noise_free(struct osn_context *ctx)
+ {
+ if (!ctx)
+@@ -220,6 +222,8 @@
+ }
+ free(ctx);
+ }
++*/
++// -- GODOT end --
+
+ /* 2D OpenSimplex (Simplectic) Noise. */
+ double open_simplex_noise2(struct osn_context *ctx, double x, double y)
+diff -u orig/open-simplex-noise.h misc/open-simplex-noise.h
+--- orig/open-simplex-noise.h 2018-09-14 11:11:19.659807000 +0200
++++ misc/open-simplex-noise.h 2018-09-14 11:10:05.006460000 +0200
+@@ -35,11 +35,18 @@
+ extern "C" {
+ #endif
+
+-struct osn_context;
++// -- GODOT start --
++// Modified to work without allocating memory, also removed some unused function.
+
+-int open_simplex_noise(int64_t seed, struct osn_context **ctx);
++struct osn_context {
++ int16_t perm[256];
++ int16_t permGradIndex3D[256];
++};
++
++int open_simplex_noise(int64_t seed, struct osn_context *ctx);
++//int open_simplex_noise_init_perm(struct osn_context *ctx, int16_t p[], int nelements);
++// -- GODOT end --
+ void open_simplex_noise_free(struct osn_context *ctx);
+-int open_simplex_noise_init_perm(struct osn_context *ctx, int16_t p[], int nelements);
+ double open_simplex_noise2(struct osn_context *ctx, double x, double y);
+ double open_simplex_noise3(struct osn_context *ctx, double x, double y, double z);
+ double open_simplex_noise4(struct osn_context *ctx, double x, double y, double z, double w);
diff --git a/thirdparty/misc/open-simplex-noise.c b/thirdparty/misc/open-simplex-noise.c
new file mode 100644
index 0000000000..42f2fbb5be
--- /dev/null
+++ b/thirdparty/misc/open-simplex-noise.c
@@ -0,0 +1,2254 @@
+/*
+ * OpenSimplex (Simplectic) Noise in C.
+ * Ported by Stephen M. Cameron from Kurt Spencer's java implementation
+ *
+ * v1.1 (October 5, 2014)
+ * - Added 2D and 4D implementations.
+ * - Proper gradient sets for all dimensions, from a
+ * dimensionally-generalizable scheme with an actual
+ * rhyme and reason behind it.
+ * - Removed default permutation array in favor of
+ * default seed.
+ * - Changed seed-based constructor to be independent
+ * of any particular randomization library, so results
+ * will be the same when ported to other languages.
+ */
+
+// -- GODOT start --
+// Modified to work without allocating memory, also removed some unused function.
+// -- GODOT end --
+
+#include <math.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+
+#include "open-simplex-noise.h"
+
+#define STRETCH_CONSTANT_2D (-0.211324865405187) /* (1 / sqrt(2 + 1) - 1 ) / 2; */
+#define SQUISH_CONSTANT_2D (0.366025403784439) /* (sqrt(2 + 1) -1) / 2; */
+#define STRETCH_CONSTANT_3D (-1.0 / 6.0) /* (1 / sqrt(3 + 1) - 1) / 3; */
+#define SQUISH_CONSTANT_3D (1.0 / 3.0) /* (sqrt(3+1)-1)/3; */
+#define STRETCH_CONSTANT_4D (-0.138196601125011) /* (1 / sqrt(4 + 1) - 1) / 4; */
+#define SQUISH_CONSTANT_4D (0.309016994374947) /* (sqrt(4 + 1) - 1) / 4; */
+
+#define NORM_CONSTANT_2D (47.0)
+#define NORM_CONSTANT_3D (103.0)
+#define NORM_CONSTANT_4D (30.0)
+
+#define DEFAULT_SEED (0LL)
+
+// -- GODOT start --
+/*struct osn_context {
+ int16_t *perm;
+ int16_t *permGradIndex3D;
+};*/
+// -- GODOT end --
+#define ARRAYSIZE(x) (sizeof((x)) / sizeof((x)[0]))
+
+/*
+ * Gradients for 2D. They approximate the directions to the
+ * vertices of an octagon from the center.
+ */
+static const int8_t gradients2D[] = {
+ 5, 2, 2, 5,
+ -5, 2, -2, 5,
+ 5, -2, 2, -5,
+ -5, -2, -2, -5,
+};
+
+/*
+ * Gradients for 3D. They approximate the directions to the
+ * vertices of a rhombicuboctahedron from the center, skewed so
+ * that the triangular and square facets can be inscribed inside
+ * circles of the same radius.
+ */
+static const signed char gradients3D[] = {
+ -11, 4, 4, -4, 11, 4, -4, 4, 11,
+ 11, 4, 4, 4, 11, 4, 4, 4, 11,
+ -11, -4, 4, -4, -11, 4, -4, -4, 11,
+ 11, -4, 4, 4, -11, 4, 4, -4, 11,
+ -11, 4, -4, -4, 11, -4, -4, 4, -11,
+ 11, 4, -4, 4, 11, -4, 4, 4, -11,
+ -11, -4, -4, -4, -11, -4, -4, -4, -11,
+ 11, -4, -4, 4, -11, -4, 4, -4, -11,
+};
+
+/*
+ * Gradients for 4D. They approximate the directions to the
+ * vertices of a disprismatotesseractihexadecachoron from the center,
+ * skewed so that the tetrahedral and cubic facets can be inscribed inside
+ * spheres of the same radius.
+ */
+static const signed char gradients4D[] = {
+ 3, 1, 1, 1, 1, 3, 1, 1, 1, 1, 3, 1, 1, 1, 1, 3,
+ -3, 1, 1, 1, -1, 3, 1, 1, -1, 1, 3, 1, -1, 1, 1, 3,
+ 3, -1, 1, 1, 1, -3, 1, 1, 1, -1, 3, 1, 1, -1, 1, 3,
+ -3, -1, 1, 1, -1, -3, 1, 1, -1, -1, 3, 1, -1, -1, 1, 3,
+ 3, 1, -1, 1, 1, 3, -1, 1, 1, 1, -3, 1, 1, 1, -1, 3,
+ -3, 1, -1, 1, -1, 3, -1, 1, -1, 1, -3, 1, -1, 1, -1, 3,
+ 3, -1, -1, 1, 1, -3, -1, 1, 1, -1, -3, 1, 1, -1, -1, 3,
+ -3, -1, -1, 1, -1, -3, -1, 1, -1, -1, -3, 1, -1, -1, -1, 3,
+ 3, 1, 1, -1, 1, 3, 1, -1, 1, 1, 3, -1, 1, 1, 1, -3,
+ -3, 1, 1, -1, -1, 3, 1, -1, -1, 1, 3, -1, -1, 1, 1, -3,
+ 3, -1, 1, -1, 1, -3, 1, -1, 1, -1, 3, -1, 1, -1, 1, -3,
+ -3, -1, 1, -1, -1, -3, 1, -1, -1, -1, 3, -1, -1, -1, 1, -3,
+ 3, 1, -1, -1, 1, 3, -1, -1, 1, 1, -3, -1, 1, 1, -1, -3,
+ -3, 1, -1, -1, -1, 3, -1, -1, -1, 1, -3, -1, -1, 1, -1, -3,
+ 3, -1, -1, -1, 1, -3, -1, -1, 1, -1, -3, -1, 1, -1, -1, -3,
+ -3, -1, -1, -1, -1, -3, -1, -1, -1, -1, -3, -1, -1, -1, -1, -3,
+};
+
+static double extrapolate2(struct osn_context *ctx, int xsb, int ysb, double dx, double dy)
+{
+ int16_t *perm = ctx->perm;
+ int index = perm[(perm[xsb & 0xFF] + ysb) & 0xFF] & 0x0E;
+ return gradients2D[index] * dx
+ + gradients2D[index + 1] * dy;
+}
+
+static double extrapolate3(struct osn_context *ctx, int xsb, int ysb, int zsb, double dx, double dy, double dz)
+{
+ int16_t *perm = ctx->perm;
+ int16_t *permGradIndex3D = ctx->permGradIndex3D;
+ int index = permGradIndex3D[(perm[(perm[xsb & 0xFF] + ysb) & 0xFF] + zsb) & 0xFF];
+ return gradients3D[index] * dx
+ + gradients3D[index + 1] * dy
+ + gradients3D[index + 2] * dz;
+}
+
+static double extrapolate4(struct osn_context *ctx, int xsb, int ysb, int zsb, int wsb, double dx, double dy, double dz, double dw)
+{
+ int16_t *perm = ctx->perm;
+ int index = perm[(perm[(perm[(perm[xsb & 0xFF] + ysb) & 0xFF] + zsb) & 0xFF] + wsb) & 0xFF] & 0xFC;
+ return gradients4D[index] * dx
+ + gradients4D[index + 1] * dy
+ + gradients4D[index + 2] * dz
+ + gradients4D[index + 3] * dw;
+}
+
+static INLINE int fastFloor(double x) {
+ int xi = (int) x;
+ return x < xi ? xi - 1 : xi;
+}
+
+// -- GODOT start --
+/*
+static int allocate_perm(struct osn_context *ctx, int nperm, int ngrad)
+{
+ if (ctx->perm)
+ free(ctx->perm);
+ if (ctx->permGradIndex3D)
+ free(ctx->permGradIndex3D);
+ ctx->perm = (int16_t *) malloc(sizeof(*ctx->perm) * nperm);
+ if (!ctx->perm)
+ return -ENOMEM;
+ ctx->permGradIndex3D = (int16_t *) malloc(sizeof(*ctx->permGradIndex3D) * ngrad);
+ if (!ctx->permGradIndex3D) {
+ free(ctx->perm);
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+int open_simplex_noise_init_perm(struct osn_context *ctx, int16_t p[], int nelements)
+{
+ int i, rc;
+
+ rc = allocate_perm(ctx, nelements, 256);
+ if (rc)
+ return rc;
+ memcpy(ctx->perm, p, sizeof(*ctx->perm) * nelements);
+
+ for (i = 0; i < 256; i++) {
+ // Since 3D has 24 gradients, simple bitmask won't work, so precompute modulo array.
+ ctx->permGradIndex3D[i] = (int16_t)((ctx->perm[i] % (ARRAYSIZE(gradients3D) / 3)) * 3);
+ }
+ return 0;
+}
+*/
+// -- GODOT end --
+
+/*
+ * Initializes using a permutation array generated from a 64-bit seed.
+ * Generates a proper permutation (i.e. doesn't merely perform N successive pair
+ * swaps on a base array). Uses a simple 64-bit LCG.
+ */
+// -- GODOT start --
+int open_simplex_noise(int64_t seed, struct osn_context *ctx)
+{
+ int rc;
+ int16_t source[256];
+ int i;
+ int16_t *perm;
+ int16_t *permGradIndex3D;
+ int r;
+
+ perm = ctx->perm;
+ permGradIndex3D = ctx->permGradIndex3D;
+// -- GODOT end --
+
+ for (i = 0; i < 256; i++)
+ source[i] = (int16_t) i;
+ seed = seed * 6364136223846793005LL + 1442695040888963407LL;
+ seed = seed * 6364136223846793005LL + 1442695040888963407LL;
+ seed = seed * 6364136223846793005LL + 1442695040888963407LL;
+ for (i = 255; i >= 0; i--) {
+ seed = seed * 6364136223846793005LL + 1442695040888963407LL;
+ r = (int)((seed + 31) % (i + 1));
+ if (r < 0)
+ r += (i + 1);
+ perm[i] = source[r];
+ permGradIndex3D[i] = (short)((perm[i] % (ARRAYSIZE(gradients3D) / 3)) * 3);
+ source[r] = source[i];
+ }
+ return 0;
+}
+
+// -- GODOT start --
+/*
+void open_simplex_noise_free(struct osn_context *ctx)
+{
+ if (!ctx)
+ return;
+ if (ctx->perm) {
+ free(ctx->perm);
+ ctx->perm = NULL;
+ }
+ if (ctx->permGradIndex3D) {
+ free(ctx->permGradIndex3D);
+ ctx->permGradIndex3D = NULL;
+ }
+ free(ctx);
+}
+*/
+// -- GODOT end --
+
+/* 2D OpenSimplex (Simplectic) Noise. */
+double open_simplex_noise2(struct osn_context *ctx, double x, double y)
+{
+
+ /* Place input coordinates onto grid. */
+ double stretchOffset = (x + y) * STRETCH_CONSTANT_2D;
+ double xs = x + stretchOffset;
+ double ys = y + stretchOffset;
+
+ /* Floor to get grid coordinates of rhombus (stretched square) super-cell origin. */
+ int xsb = fastFloor(xs);
+ int ysb = fastFloor(ys);
+
+ /* Skew out to get actual coordinates of rhombus origin. We'll need these later. */
+ double squishOffset = (xsb + ysb) * SQUISH_CONSTANT_2D;
+ double xb = xsb + squishOffset;
+ double yb = ysb + squishOffset;
+
+ /* Compute grid coordinates relative to rhombus origin. */
+ double xins = xs - xsb;
+ double yins = ys - ysb;
+
+ /* Sum those together to get a value that determines which region we're in. */
+ double inSum = xins + yins;
+
+ /* Positions relative to origin point. */
+ double dx0 = x - xb;
+ double dy0 = y - yb;
+
+ /* We'll be defining these inside the next block and using them afterwards. */
+ double dx_ext, dy_ext;
+ int xsv_ext, ysv_ext;
+
+ double dx1;
+ double dy1;
+ double attn1;
+ double dx2;
+ double dy2;
+ double attn2;
+ double zins;
+ double attn0;
+ double attn_ext;
+
+ double value = 0;
+
+ /* Contribution (1,0) */
+ dx1 = dx0 - 1 - SQUISH_CONSTANT_2D;
+ dy1 = dy0 - 0 - SQUISH_CONSTANT_2D;
+ attn1 = 2 - dx1 * dx1 - dy1 * dy1;
+ if (attn1 > 0) {
+ attn1 *= attn1;
+ value += attn1 * attn1 * extrapolate2(ctx, xsb + 1, ysb + 0, dx1, dy1);
+ }
+
+ /* Contribution (0,1) */
+ dx2 = dx0 - 0 - SQUISH_CONSTANT_2D;
+ dy2 = dy0 - 1 - SQUISH_CONSTANT_2D;
+ attn2 = 2 - dx2 * dx2 - dy2 * dy2;
+ if (attn2 > 0) {
+ attn2 *= attn2;
+ value += attn2 * attn2 * extrapolate2(ctx, xsb + 0, ysb + 1, dx2, dy2);
+ }
+
+ if (inSum <= 1) { /* We're inside the triangle (2-Simplex) at (0,0) */
+ zins = 1 - inSum;
+ if (zins > xins || zins > yins) { /* (0,0) is one of the closest two triangular vertices */
+ if (xins > yins) {
+ xsv_ext = xsb + 1;
+ ysv_ext = ysb - 1;
+ dx_ext = dx0 - 1;
+ dy_ext = dy0 + 1;
+ } else {
+ xsv_ext = xsb - 1;
+ ysv_ext = ysb + 1;
+ dx_ext = dx0 + 1;
+ dy_ext = dy0 - 1;
+ }
+ } else { /* (1,0) and (0,1) are the closest two vertices. */
+ xsv_ext = xsb + 1;
+ ysv_ext = ysb + 1;
+ dx_ext = dx0 - 1 - 2 * SQUISH_CONSTANT_2D;
+ dy_ext = dy0 - 1 - 2 * SQUISH_CONSTANT_2D;
+ }
+ } else { /* We're inside the triangle (2-Simplex) at (1,1) */
+ zins = 2 - inSum;
+ if (zins < xins || zins < yins) { /* (0,0) is one of the closest two triangular vertices */
+ if (xins > yins) {
+ xsv_ext = xsb + 2;
+ ysv_ext = ysb + 0;
+ dx_ext = dx0 - 2 - 2 * SQUISH_CONSTANT_2D;
+ dy_ext = dy0 + 0 - 2 * SQUISH_CONSTANT_2D;
+ } else {
+ xsv_ext = xsb + 0;
+ ysv_ext = ysb + 2;
+ dx_ext = dx0 + 0 - 2 * SQUISH_CONSTANT_2D;
+ dy_ext = dy0 - 2 - 2 * SQUISH_CONSTANT_2D;
+ }
+ } else { /* (1,0) and (0,1) are the closest two vertices. */
+ dx_ext = dx0;
+ dy_ext = dy0;
+ xsv_ext = xsb;
+ ysv_ext = ysb;
+ }
+ xsb += 1;
+ ysb += 1;
+ dx0 = dx0 - 1 - 2 * SQUISH_CONSTANT_2D;
+ dy0 = dy0 - 1 - 2 * SQUISH_CONSTANT_2D;
+ }
+
+ /* Contribution (0,0) or (1,1) */
+ attn0 = 2 - dx0 * dx0 - dy0 * dy0;
+ if (attn0 > 0) {
+ attn0 *= attn0;
+ value += attn0 * attn0 * extrapolate2(ctx, xsb, ysb, dx0, dy0);
+ }
+
+ /* Extra Vertex */
+ attn_ext = 2 - dx_ext * dx_ext - dy_ext * dy_ext;
+ if (attn_ext > 0) {
+ attn_ext *= attn_ext;
+ value += attn_ext * attn_ext * extrapolate2(ctx, xsv_ext, ysv_ext, dx_ext, dy_ext);
+ }
+
+ return value / NORM_CONSTANT_2D;
+}
+
+/*
+ * 3D OpenSimplex (Simplectic) Noise
+ */
+double open_simplex_noise3(struct osn_context *ctx, double x, double y, double z)
+{
+
+ /* Place input coordinates on simplectic honeycomb. */
+ double stretchOffset = (x + y + z) * STRETCH_CONSTANT_3D;
+ double xs = x + stretchOffset;
+ double ys = y + stretchOffset;
+ double zs = z + stretchOffset;
+
+ /* Floor to get simplectic honeycomb coordinates of rhombohedron (stretched cube) super-cell origin. */
+ int xsb = fastFloor(xs);
+ int ysb = fastFloor(ys);
+ int zsb = fastFloor(zs);
+
+ /* Skew out to get actual coordinates of rhombohedron origin. We'll need these later. */
+ double squishOffset = (xsb + ysb + zsb) * SQUISH_CONSTANT_3D;
+ double xb = xsb + squishOffset;
+ double yb = ysb + squishOffset;
+ double zb = zsb + squishOffset;
+
+ /* Compute simplectic honeycomb coordinates relative to rhombohedral origin. */
+ double xins = xs - xsb;
+ double yins = ys - ysb;
+ double zins = zs - zsb;
+
+ /* Sum those together to get a value that determines which region we're in. */
+ double inSum = xins + yins + zins;
+
+ /* Positions relative to origin point. */
+ double dx0 = x - xb;
+ double dy0 = y - yb;
+ double dz0 = z - zb;
+
+ /* We'll be defining these inside the next block and using them afterwards. */
+ double dx_ext0, dy_ext0, dz_ext0;
+ double dx_ext1, dy_ext1, dz_ext1;
+ int xsv_ext0, ysv_ext0, zsv_ext0;
+ int xsv_ext1, ysv_ext1, zsv_ext1;
+
+ double wins;
+ int8_t c, c1, c2;
+ int8_t aPoint, bPoint;
+ double aScore, bScore;
+ int aIsFurtherSide;
+ int bIsFurtherSide;
+ double p1, p2, p3;
+ double score;
+ double attn0, attn1, attn2, attn3, attn4, attn5, attn6;
+ double dx1, dy1, dz1;
+ double dx2, dy2, dz2;
+ double dx3, dy3, dz3;
+ double dx4, dy4, dz4;
+ double dx5, dy5, dz5;
+ double dx6, dy6, dz6;
+ double attn_ext0, attn_ext1;
+
+ double value = 0;
+ if (inSum <= 1) { /* We're inside the tetrahedron (3-Simplex) at (0,0,0) */
+
+ /* Determine which two of (0,0,1), (0,1,0), (1,0,0) are closest. */
+ aPoint = 0x01;
+ aScore = xins;
+ bPoint = 0x02;
+ bScore = yins;
+ if (aScore >= bScore && zins > bScore) {
+ bScore = zins;
+ bPoint = 0x04;
+ } else if (aScore < bScore && zins > aScore) {
+ aScore = zins;
+ aPoint = 0x04;
+ }
+
+ /* Now we determine the two lattice points not part of the tetrahedron that may contribute.
+ This depends on the closest two tetrahedral vertices, including (0,0,0) */
+ wins = 1 - inSum;
+ if (wins > aScore || wins > bScore) { /* (0,0,0) is one of the closest two tetrahedral vertices. */
+ c = (bScore > aScore ? bPoint : aPoint); /* Our other closest vertex is the closest out of a and b. */
+
+ if ((c & 0x01) == 0) {
+ xsv_ext0 = xsb - 1;
+ xsv_ext1 = xsb;
+ dx_ext0 = dx0 + 1;
+ dx_ext1 = dx0;
+ } else {
+ xsv_ext0 = xsv_ext1 = xsb + 1;
+ dx_ext0 = dx_ext1 = dx0 - 1;
+ }
+
+ if ((c & 0x02) == 0) {
+ ysv_ext0 = ysv_ext1 = ysb;
+ dy_ext0 = dy_ext1 = dy0;
+ if ((c & 0x01) == 0) {
+ ysv_ext1 -= 1;
+ dy_ext1 += 1;
+ } else {
+ ysv_ext0 -= 1;
+ dy_ext0 += 1;
+ }
+ } else {
+ ysv_ext0 = ysv_ext1 = ysb + 1;
+ dy_ext0 = dy_ext1 = dy0 - 1;
+ }
+
+ if ((c & 0x04) == 0) {
+ zsv_ext0 = zsb;
+ zsv_ext1 = zsb - 1;
+ dz_ext0 = dz0;
+ dz_ext1 = dz0 + 1;
+ } else {
+ zsv_ext0 = zsv_ext1 = zsb + 1;
+ dz_ext0 = dz_ext1 = dz0 - 1;
+ }
+ } else { /* (0,0,0) is not one of the closest two tetrahedral vertices. */
+ c = (int8_t)(aPoint | bPoint); /* Our two extra vertices are determined by the closest two. */
+
+ if ((c & 0x01) == 0) {
+ xsv_ext0 = xsb;
+ xsv_ext1 = xsb - 1;
+ dx_ext0 = dx0 - 2 * SQUISH_CONSTANT_3D;
+ dx_ext1 = dx0 + 1 - SQUISH_CONSTANT_3D;
+ } else {
+ xsv_ext0 = xsv_ext1 = xsb + 1;
+ dx_ext0 = dx0 - 1 - 2 * SQUISH_CONSTANT_3D;
+ dx_ext1 = dx0 - 1 - SQUISH_CONSTANT_3D;
+ }
+
+ if ((c & 0x02) == 0) {
+ ysv_ext0 = ysb;
+ ysv_ext1 = ysb - 1;
+ dy_ext0 = dy0 - 2 * SQUISH_CONSTANT_3D;
+ dy_ext1 = dy0 + 1 - SQUISH_CONSTANT_3D;
+ } else {
+ ysv_ext0 = ysv_ext1 = ysb + 1;
+ dy_ext0 = dy0 - 1 - 2 * SQUISH_CONSTANT_3D;
+ dy_ext1 = dy0 - 1 - SQUISH_CONSTANT_3D;
+ }
+
+ if ((c & 0x04) == 0) {
+ zsv_ext0 = zsb;
+ zsv_ext1 = zsb - 1;
+ dz_ext0 = dz0 - 2 * SQUISH_CONSTANT_3D;
+ dz_ext1 = dz0 + 1 - SQUISH_CONSTANT_3D;
+ } else {
+ zsv_ext0 = zsv_ext1 = zsb + 1;
+ dz_ext0 = dz0 - 1 - 2 * SQUISH_CONSTANT_3D;
+ dz_ext1 = dz0 - 1 - SQUISH_CONSTANT_3D;
+ }
+ }
+
+ /* Contribution (0,0,0) */
+ attn0 = 2 - dx0 * dx0 - dy0 * dy0 - dz0 * dz0;
+ if (attn0 > 0) {
+ attn0 *= attn0;
+ value += attn0 * attn0 * extrapolate3(ctx, xsb + 0, ysb + 0, zsb + 0, dx0, dy0, dz0);
+ }
+
+ /* Contribution (1,0,0) */
+ dx1 = dx0 - 1 - SQUISH_CONSTANT_3D;
+ dy1 = dy0 - 0 - SQUISH_CONSTANT_3D;
+ dz1 = dz0 - 0 - SQUISH_CONSTANT_3D;
+ attn1 = 2 - dx1 * dx1 - dy1 * dy1 - dz1 * dz1;
+ if (attn1 > 0) {
+ attn1 *= attn1;
+ value += attn1 * attn1 * extrapolate3(ctx, xsb + 1, ysb + 0, zsb + 0, dx1, dy1, dz1);
+ }
+
+ /* Contribution (0,1,0) */
+ dx2 = dx0 - 0 - SQUISH_CONSTANT_3D;
+ dy2 = dy0 - 1 - SQUISH_CONSTANT_3D;
+ dz2 = dz1;
+ attn2 = 2 - dx2 * dx2 - dy2 * dy2 - dz2 * dz2;
+ if (attn2 > 0) {
+ attn2 *= attn2;
+ value += attn2 * attn2 * extrapolate3(ctx, xsb + 0, ysb + 1, zsb + 0, dx2, dy2, dz2);
+ }
+
+ /* Contribution (0,0,1) */
+ dx3 = dx2;
+ dy3 = dy1;
+ dz3 = dz0 - 1 - SQUISH_CONSTANT_3D;
+ attn3 = 2 - dx3 * dx3 - dy3 * dy3 - dz3 * dz3;
+ if (attn3 > 0) {
+ attn3 *= attn3;
+ value += attn3 * attn3 * extrapolate3(ctx, xsb + 0, ysb + 0, zsb + 1, dx3, dy3, dz3);
+ }
+ } else if (inSum >= 2) { /* We're inside the tetrahedron (3-Simplex) at (1,1,1) */
+
+ /* Determine which two tetrahedral vertices are the closest, out of (1,1,0), (1,0,1), (0,1,1) but not (1,1,1). */
+ aPoint = 0x06;
+ aScore = xins;
+ bPoint = 0x05;
+ bScore = yins;
+ if (aScore <= bScore && zins < bScore) {
+ bScore = zins;
+ bPoint = 0x03;
+ } else if (aScore > bScore && zins < aScore) {
+ aScore = zins;
+ aPoint = 0x03;
+ }
+
+ /* Now we determine the two lattice points not part of the tetrahedron that may contribute.
+ This depends on the closest two tetrahedral vertices, including (1,1,1) */
+ wins = 3 - inSum;
+ if (wins < aScore || wins < bScore) { /* (1,1,1) is one of the closest two tetrahedral vertices. */
+ c = (bScore < aScore ? bPoint : aPoint); /* Our other closest vertex is the closest out of a and b. */
+
+ if ((c & 0x01) != 0) {
+ xsv_ext0 = xsb + 2;
+ xsv_ext1 = xsb + 1;
+ dx_ext0 = dx0 - 2 - 3 * SQUISH_CONSTANT_3D;
+ dx_ext1 = dx0 - 1 - 3 * SQUISH_CONSTANT_3D;
+ } else {
+ xsv_ext0 = xsv_ext1 = xsb;
+ dx_ext0 = dx_ext1 = dx0 - 3 * SQUISH_CONSTANT_3D;
+ }
+
+ if ((c & 0x02) != 0) {
+ ysv_ext0 = ysv_ext1 = ysb + 1;
+ dy_ext0 = dy_ext1 = dy0 - 1 - 3 * SQUISH_CONSTANT_3D;
+ if ((c & 0x01) != 0) {
+ ysv_ext1 += 1;
+ dy_ext1 -= 1;
+ } else {
+ ysv_ext0 += 1;
+ dy_ext0 -= 1;
+ }
+ } else {
+ ysv_ext0 = ysv_ext1 = ysb;
+ dy_ext0 = dy_ext1 = dy0 - 3 * SQUISH_CONSTANT_3D;
+ }
+
+ if ((c & 0x04) != 0) {
+ zsv_ext0 = zsb + 1;
+ zsv_ext1 = zsb + 2;
+ dz_ext0 = dz0 - 1 - 3 * SQUISH_CONSTANT_3D;
+ dz_ext1 = dz0 - 2 - 3 * SQUISH_CONSTANT_3D;
+ } else {
+ zsv_ext0 = zsv_ext1 = zsb;
+ dz_ext0 = dz_ext1 = dz0 - 3 * SQUISH_CONSTANT_3D;
+ }
+ } else { /* (1,1,1) is not one of the closest two tetrahedral vertices. */
+ c = (int8_t)(aPoint & bPoint); /* Our two extra vertices are determined by the closest two. */
+
+ if ((c & 0x01) != 0) {
+ xsv_ext0 = xsb + 1;
+ xsv_ext1 = xsb + 2;
+ dx_ext0 = dx0 - 1 - SQUISH_CONSTANT_3D;
+ dx_ext1 = dx0 - 2 - 2 * SQUISH_CONSTANT_3D;
+ } else {
+ xsv_ext0 = xsv_ext1 = xsb;
+ dx_ext0 = dx0 - SQUISH_CONSTANT_3D;
+ dx_ext1 = dx0 - 2 * SQUISH_CONSTANT_3D;
+ }
+
+ if ((c & 0x02) != 0) {
+ ysv_ext0 = ysb + 1;
+ ysv_ext1 = ysb + 2;
+ dy_ext0 = dy0 - 1 - SQUISH_CONSTANT_3D;
+ dy_ext1 = dy0 - 2 - 2 * SQUISH_CONSTANT_3D;
+ } else {
+ ysv_ext0 = ysv_ext1 = ysb;
+ dy_ext0 = dy0 - SQUISH_CONSTANT_3D;
+ dy_ext1 = dy0 - 2 * SQUISH_CONSTANT_3D;
+ }
+
+ if ((c & 0x04) != 0) {
+ zsv_ext0 = zsb + 1;
+ zsv_ext1 = zsb + 2;
+ dz_ext0 = dz0 - 1 - SQUISH_CONSTANT_3D;
+ dz_ext1 = dz0 - 2 - 2 * SQUISH_CONSTANT_3D;
+ } else {
+ zsv_ext0 = zsv_ext1 = zsb;
+ dz_ext0 = dz0 - SQUISH_CONSTANT_3D;
+ dz_ext1 = dz0 - 2 * SQUISH_CONSTANT_3D;
+ }
+ }
+
+ /* Contribution (1,1,0) */
+ dx3 = dx0 - 1 - 2 * SQUISH_CONSTANT_3D;
+ dy3 = dy0 - 1 - 2 * SQUISH_CONSTANT_3D;
+ dz3 = dz0 - 0 - 2 * SQUISH_CONSTANT_3D;
+ attn3 = 2 - dx3 * dx3 - dy3 * dy3 - dz3 * dz3;
+ if (attn3 > 0) {
+ attn3 *= attn3;
+ value += attn3 * attn3 * extrapolate3(ctx, xsb + 1, ysb + 1, zsb + 0, dx3, dy3, dz3);
+ }
+
+ /* Contribution (1,0,1) */
+ dx2 = dx3;
+ dy2 = dy0 - 0 - 2 * SQUISH_CONSTANT_3D;
+ dz2 = dz0 - 1 - 2 * SQUISH_CONSTANT_3D;
+ attn2 = 2 - dx2 * dx2 - dy2 * dy2 - dz2 * dz2;
+ if (attn2 > 0) {
+ attn2 *= attn2;
+ value += attn2 * attn2 * extrapolate3(ctx, xsb + 1, ysb + 0, zsb + 1, dx2, dy2, dz2);
+ }
+
+ /* Contribution (0,1,1) */
+ dx1 = dx0 - 0 - 2 * SQUISH_CONSTANT_3D;
+ dy1 = dy3;
+ dz1 = dz2;
+ attn1 = 2 - dx1 * dx1 - dy1 * dy1 - dz1 * dz1;
+ if (attn1 > 0) {
+ attn1 *= attn1;
+ value += attn1 * attn1 * extrapolate3(ctx, xsb + 0, ysb + 1, zsb + 1, dx1, dy1, dz1);
+ }
+
+ /* Contribution (1,1,1) */
+ dx0 = dx0 - 1 - 3 * SQUISH_CONSTANT_3D;
+ dy0 = dy0 - 1 - 3 * SQUISH_CONSTANT_3D;
+ dz0 = dz0 - 1 - 3 * SQUISH_CONSTANT_3D;
+ attn0 = 2 - dx0 * dx0 - dy0 * dy0 - dz0 * dz0;
+ if (attn0 > 0) {
+ attn0 *= attn0;
+ value += attn0 * attn0 * extrapolate3(ctx, xsb + 1, ysb + 1, zsb + 1, dx0, dy0, dz0);
+ }
+ } else { /* We're inside the octahedron (Rectified 3-Simplex) in between.
+ Decide between point (0,0,1) and (1,1,0) as closest */
+ p1 = xins + yins;
+ if (p1 > 1) {
+ aScore = p1 - 1;
+ aPoint = 0x03;
+ aIsFurtherSide = 1;
+ } else {
+ aScore = 1 - p1;
+ aPoint = 0x04;
+ aIsFurtherSide = 0;
+ }
+
+ /* Decide between point (0,1,0) and (1,0,1) as closest */
+ p2 = xins + zins;
+ if (p2 > 1) {
+ bScore = p2 - 1;
+ bPoint = 0x05;
+ bIsFurtherSide = 1;
+ } else {
+ bScore = 1 - p2;
+ bPoint = 0x02;
+ bIsFurtherSide = 0;
+ }
+
+ /* The closest out of the two (1,0,0) and (0,1,1) will replace the furthest out of the two decided above, if closer. */
+ p3 = yins + zins;
+ if (p3 > 1) {
+ score = p3 - 1;
+ if (aScore <= bScore && aScore < score) {
+ aScore = score;
+ aPoint = 0x06;
+ aIsFurtherSide = 1;
+ } else if (aScore > bScore && bScore < score) {
+ bScore = score;
+ bPoint = 0x06;
+ bIsFurtherSide = 1;
+ }
+ } else {
+ score = 1 - p3;
+ if (aScore <= bScore && aScore < score) {
+ aScore = score;
+ aPoint = 0x01;
+ aIsFurtherSide = 0;
+ } else if (aScore > bScore && bScore < score) {
+ bScore = score;
+ bPoint = 0x01;
+ bIsFurtherSide = 0;
+ }
+ }
+
+ /* Where each of the two closest points are determines how the extra two vertices are calculated. */
+ if (aIsFurtherSide == bIsFurtherSide) {
+ if (aIsFurtherSide) { /* Both closest points on (1,1,1) side */
+
+ /* One of the two extra points is (1,1,1) */
+ dx_ext0 = dx0 - 1 - 3 * SQUISH_CONSTANT_3D;
+ dy_ext0 = dy0 - 1 - 3 * SQUISH_CONSTANT_3D;
+ dz_ext0 = dz0 - 1 - 3 * SQUISH_CONSTANT_3D;
+ xsv_ext0 = xsb + 1;
+ ysv_ext0 = ysb + 1;
+ zsv_ext0 = zsb + 1;
+
+ /* Other extra point is based on the shared axis. */
+ c = (int8_t)(aPoint & bPoint);
+ if ((c & 0x01) != 0) {
+ dx_ext1 = dx0 - 2 - 2 * SQUISH_CONSTANT_3D;
+ dy_ext1 = dy0 - 2 * SQUISH_CONSTANT_3D;
+ dz_ext1 = dz0 - 2 * SQUISH_CONSTANT_3D;
+ xsv_ext1 = xsb + 2;
+ ysv_ext1 = ysb;
+ zsv_ext1 = zsb;
+ } else if ((c & 0x02) != 0) {
+ dx_ext1 = dx0 - 2 * SQUISH_CONSTANT_3D;
+ dy_ext1 = dy0 - 2 - 2 * SQUISH_CONSTANT_3D;
+ dz_ext1 = dz0 - 2 * SQUISH_CONSTANT_3D;
+ xsv_ext1 = xsb;
+ ysv_ext1 = ysb + 2;
+ zsv_ext1 = zsb;
+ } else {
+ dx_ext1 = dx0 - 2 * SQUISH_CONSTANT_3D;
+ dy_ext1 = dy0 - 2 * SQUISH_CONSTANT_3D;
+ dz_ext1 = dz0 - 2 - 2 * SQUISH_CONSTANT_3D;
+ xsv_ext1 = xsb;
+ ysv_ext1 = ysb;
+ zsv_ext1 = zsb + 2;
+ }
+ } else { /* Both closest points on (0,0,0) side */
+
+ /* One of the two extra points is (0,0,0) */
+ dx_ext0 = dx0;
+ dy_ext0 = dy0;
+ dz_ext0 = dz0;
+ xsv_ext0 = xsb;
+ ysv_ext0 = ysb;
+ zsv_ext0 = zsb;
+
+ /* Other extra point is based on the omitted axis. */
+ c = (int8_t)(aPoint | bPoint);
+ if ((c & 0x01) == 0) {
+ dx_ext1 = dx0 + 1 - SQUISH_CONSTANT_3D;
+ dy_ext1 = dy0 - 1 - SQUISH_CONSTANT_3D;
+ dz_ext1 = dz0 - 1 - SQUISH_CONSTANT_3D;
+ xsv_ext1 = xsb - 1;
+ ysv_ext1 = ysb + 1;
+ zsv_ext1 = zsb + 1;
+ } else if ((c & 0x02) == 0) {
+ dx_ext1 = dx0 - 1 - SQUISH_CONSTANT_3D;
+ dy_ext1 = dy0 + 1 - SQUISH_CONSTANT_3D;
+ dz_ext1 = dz0 - 1 - SQUISH_CONSTANT_3D;
+ xsv_ext1 = xsb + 1;
+ ysv_ext1 = ysb - 1;
+ zsv_ext1 = zsb + 1;
+ } else {
+ dx_ext1 = dx0 - 1 - SQUISH_CONSTANT_3D;
+ dy_ext1 = dy0 - 1 - SQUISH_CONSTANT_3D;
+ dz_ext1 = dz0 + 1 - SQUISH_CONSTANT_3D;
+ xsv_ext1 = xsb + 1;
+ ysv_ext1 = ysb + 1;
+ zsv_ext1 = zsb - 1;
+ }
+ }
+ } else { /* One point on (0,0,0) side, one point on (1,1,1) side */
+ if (aIsFurtherSide) {
+ c1 = aPoint;
+ c2 = bPoint;
+ } else {
+ c1 = bPoint;
+ c2 = aPoint;
+ }
+
+ /* One contribution is a permutation of (1,1,-1) */
+ if ((c1 & 0x01) == 0) {
+ dx_ext0 = dx0 + 1 - SQUISH_CONSTANT_3D;
+ dy_ext0 = dy0 - 1 - SQUISH_CONSTANT_3D;
+ dz_ext0 = dz0 - 1 - SQUISH_CONSTANT_3D;
+ xsv_ext0 = xsb - 1;
+ ysv_ext0 = ysb + 1;
+ zsv_ext0 = zsb + 1;
+ } else if ((c1 & 0x02) == 0) {
+ dx_ext0 = dx0 - 1 - SQUISH_CONSTANT_3D;
+ dy_ext0 = dy0 + 1 - SQUISH_CONSTANT_3D;
+ dz_ext0 = dz0 - 1 - SQUISH_CONSTANT_3D;
+ xsv_ext0 = xsb + 1;
+ ysv_ext0 = ysb - 1;
+ zsv_ext0 = zsb + 1;
+ } else {
+ dx_ext0 = dx0 - 1 - SQUISH_CONSTANT_3D;
+ dy_ext0 = dy0 - 1 - SQUISH_CONSTANT_3D;
+ dz_ext0 = dz0 + 1 - SQUISH_CONSTANT_3D;
+ xsv_ext0 = xsb + 1;
+ ysv_ext0 = ysb + 1;
+ zsv_ext0 = zsb - 1;
+ }
+
+ /* One contribution is a permutation of (0,0,2) */
+ dx_ext1 = dx0 - 2 * SQUISH_CONSTANT_3D;
+ dy_ext1 = dy0 - 2 * SQUISH_CONSTANT_3D;
+ dz_ext1 = dz0 - 2 * SQUISH_CONSTANT_3D;
+ xsv_ext1 = xsb;
+ ysv_ext1 = ysb;
+ zsv_ext1 = zsb;
+ if ((c2 & 0x01) != 0) {
+ dx_ext1 -= 2;
+ xsv_ext1 += 2;
+ } else if ((c2 & 0x02) != 0) {
+ dy_ext1 -= 2;
+ ysv_ext1 += 2;
+ } else {
+ dz_ext1 -= 2;
+ zsv_ext1 += 2;
+ }
+ }
+
+ /* Contribution (1,0,0) */
+ dx1 = dx0 - 1 - SQUISH_CONSTANT_3D;
+ dy1 = dy0 - 0 - SQUISH_CONSTANT_3D;
+ dz1 = dz0 - 0 - SQUISH_CONSTANT_3D;
+ attn1 = 2 - dx1 * dx1 - dy1 * dy1 - dz1 * dz1;
+ if (attn1 > 0) {
+ attn1 *= attn1;
+ value += attn1 * attn1 * extrapolate3(ctx, xsb + 1, ysb + 0, zsb + 0, dx1, dy1, dz1);
+ }
+
+ /* Contribution (0,1,0) */
+ dx2 = dx0 - 0 - SQUISH_CONSTANT_3D;
+ dy2 = dy0 - 1 - SQUISH_CONSTANT_3D;
+ dz2 = dz1;
+ attn2 = 2 - dx2 * dx2 - dy2 * dy2 - dz2 * dz2;
+ if (attn2 > 0) {
+ attn2 *= attn2;
+ value += attn2 * attn2 * extrapolate3(ctx, xsb + 0, ysb + 1, zsb + 0, dx2, dy2, dz2);
+ }
+
+ /* Contribution (0,0,1) */
+ dx3 = dx2;
+ dy3 = dy1;
+ dz3 = dz0 - 1 - SQUISH_CONSTANT_3D;
+ attn3 = 2 - dx3 * dx3 - dy3 * dy3 - dz3 * dz3;
+ if (attn3 > 0) {
+ attn3 *= attn3;
+ value += attn3 * attn3 * extrapolate3(ctx, xsb + 0, ysb + 0, zsb + 1, dx3, dy3, dz3);
+ }
+
+ /* Contribution (1,1,0) */
+ dx4 = dx0 - 1 - 2 * SQUISH_CONSTANT_3D;
+ dy4 = dy0 - 1 - 2 * SQUISH_CONSTANT_3D;
+ dz4 = dz0 - 0 - 2 * SQUISH_CONSTANT_3D;
+ attn4 = 2 - dx4 * dx4 - dy4 * dy4 - dz4 * dz4;
+ if (attn4 > 0) {
+ attn4 *= attn4;
+ value += attn4 * attn4 * extrapolate3(ctx, xsb + 1, ysb + 1, zsb + 0, dx4, dy4, dz4);
+ }
+
+ /* Contribution (1,0,1) */
+ dx5 = dx4;
+ dy5 = dy0 - 0 - 2 * SQUISH_CONSTANT_3D;
+ dz5 = dz0 - 1 - 2 * SQUISH_CONSTANT_3D;
+ attn5 = 2 - dx5 * dx5 - dy5 * dy5 - dz5 * dz5;
+ if (attn5 > 0) {
+ attn5 *= attn5;
+ value += attn5 * attn5 * extrapolate3(ctx, xsb + 1, ysb + 0, zsb + 1, dx5, dy5, dz5);
+ }
+
+ /* Contribution (0,1,1) */
+ dx6 = dx0 - 0 - 2 * SQUISH_CONSTANT_3D;
+ dy6 = dy4;
+ dz6 = dz5;
+ attn6 = 2 - dx6 * dx6 - dy6 * dy6 - dz6 * dz6;
+ if (attn6 > 0) {
+ attn6 *= attn6;
+ value += attn6 * attn6 * extrapolate3(ctx, xsb + 0, ysb + 1, zsb + 1, dx6, dy6, dz6);
+ }
+ }
+
+ /* First extra vertex */
+ attn_ext0 = 2 - dx_ext0 * dx_ext0 - dy_ext0 * dy_ext0 - dz_ext0 * dz_ext0;
+ if (attn_ext0 > 0)
+ {
+ attn_ext0 *= attn_ext0;
+ value += attn_ext0 * attn_ext0 * extrapolate3(ctx, xsv_ext0, ysv_ext0, zsv_ext0, dx_ext0, dy_ext0, dz_ext0);
+ }
+
+ /* Second extra vertex */
+ attn_ext1 = 2 - dx_ext1 * dx_ext1 - dy_ext1 * dy_ext1 - dz_ext1 * dz_ext1;
+ if (attn_ext1 > 0)
+ {
+ attn_ext1 *= attn_ext1;
+ value += attn_ext1 * attn_ext1 * extrapolate3(ctx, xsv_ext1, ysv_ext1, zsv_ext1, dx_ext1, dy_ext1, dz_ext1);
+ }
+
+ return value / NORM_CONSTANT_3D;
+}
+
+/*
+ * 4D OpenSimplex (Simplectic) Noise.
+ */
+double open_simplex_noise4(struct osn_context *ctx, double x, double y, double z, double w)
+{
+ double uins;
+ double dx1, dy1, dz1, dw1;
+ double dx2, dy2, dz2, dw2;
+ double dx3, dy3, dz3, dw3;
+ double dx4, dy4, dz4, dw4;
+ double dx5, dy5, dz5, dw5;
+ double dx6, dy6, dz6, dw6;
+ double dx7, dy7, dz7, dw7;
+ double dx8, dy8, dz8, dw8;
+ double dx9, dy9, dz9, dw9;
+ double dx10, dy10, dz10, dw10;
+ double attn0, attn1, attn2, attn3, attn4;
+ double attn5, attn6, attn7, attn8, attn9, attn10;
+ double attn_ext0, attn_ext1, attn_ext2;
+ int8_t c, c1, c2;
+ int8_t aPoint, bPoint;
+ double aScore, bScore;
+ int aIsBiggerSide;
+ int bIsBiggerSide;
+ double p1, p2, p3, p4;
+ double score;
+
+ /* Place input coordinates on simplectic honeycomb. */
+ double stretchOffset = (x + y + z + w) * STRETCH_CONSTANT_4D;
+ double xs = x + stretchOffset;
+ double ys = y + stretchOffset;
+ double zs = z + stretchOffset;
+ double ws = w + stretchOffset;
+
+ /* Floor to get simplectic honeycomb coordinates of rhombo-hypercube super-cell origin. */
+ int xsb = fastFloor(xs);
+ int ysb = fastFloor(ys);
+ int zsb = fastFloor(zs);
+ int wsb = fastFloor(ws);
+
+ /* Skew out to get actual coordinates of stretched rhombo-hypercube origin. We'll need these later. */
+ double squishOffset = (xsb + ysb + zsb + wsb) * SQUISH_CONSTANT_4D;
+ double xb = xsb + squishOffset;
+ double yb = ysb + squishOffset;
+ double zb = zsb + squishOffset;
+ double wb = wsb + squishOffset;
+
+ /* Compute simplectic honeycomb coordinates relative to rhombo-hypercube origin. */
+ double xins = xs - xsb;
+ double yins = ys - ysb;
+ double zins = zs - zsb;
+ double wins = ws - wsb;
+
+ /* Sum those together to get a value that determines which region we're in. */
+ double inSum = xins + yins + zins + wins;
+
+ /* Positions relative to origin point. */
+ double dx0 = x - xb;
+ double dy0 = y - yb;
+ double dz0 = z - zb;
+ double dw0 = w - wb;
+
+ /* We'll be defining these inside the next block and using them afterwards. */
+ double dx_ext0, dy_ext0, dz_ext0, dw_ext0;
+ double dx_ext1, dy_ext1, dz_ext1, dw_ext1;
+ double dx_ext2, dy_ext2, dz_ext2, dw_ext2;
+ int xsv_ext0, ysv_ext0, zsv_ext0, wsv_ext0;
+ int xsv_ext1, ysv_ext1, zsv_ext1, wsv_ext1;
+ int xsv_ext2, ysv_ext2, zsv_ext2, wsv_ext2;
+
+ double value = 0;
+ if (inSum <= 1) { /* We're inside the pentachoron (4-Simplex) at (0,0,0,0) */
+
+ /* Determine which two of (0,0,0,1), (0,0,1,0), (0,1,0,0), (1,0,0,0) are closest. */
+ aPoint = 0x01;
+ aScore = xins;
+ bPoint = 0x02;
+ bScore = yins;
+ if (aScore >= bScore && zins > bScore) {
+ bScore = zins;
+ bPoint = 0x04;
+ } else if (aScore < bScore && zins > aScore) {
+ aScore = zins;
+ aPoint = 0x04;
+ }
+ if (aScore >= bScore && wins > bScore) {
+ bScore = wins;
+ bPoint = 0x08;
+ } else if (aScore < bScore && wins > aScore) {
+ aScore = wins;
+ aPoint = 0x08;
+ }
+
+ /* Now we determine the three lattice points not part of the pentachoron that may contribute.
+ This depends on the closest two pentachoron vertices, including (0,0,0,0) */
+ uins = 1 - inSum;
+ if (uins > aScore || uins > bScore) { /* (0,0,0,0) is one of the closest two pentachoron vertices. */
+ c = (bScore > aScore ? bPoint : aPoint); /* Our other closest vertex is the closest out of a and b. */
+ if ((c & 0x01) == 0) {
+ xsv_ext0 = xsb - 1;
+ xsv_ext1 = xsv_ext2 = xsb;
+ dx_ext0 = dx0 + 1;
+ dx_ext1 = dx_ext2 = dx0;
+ } else {
+ xsv_ext0 = xsv_ext1 = xsv_ext2 = xsb + 1;
+ dx_ext0 = dx_ext1 = dx_ext2 = dx0 - 1;
+ }
+
+ if ((c & 0x02) == 0) {
+ ysv_ext0 = ysv_ext1 = ysv_ext2 = ysb;
+ dy_ext0 = dy_ext1 = dy_ext2 = dy0;
+ if ((c & 0x01) == 0x01) {
+ ysv_ext0 -= 1;
+ dy_ext0 += 1;
+ } else {
+ ysv_ext1 -= 1;
+ dy_ext1 += 1;
+ }
+ } else {
+ ysv_ext0 = ysv_ext1 = ysv_ext2 = ysb + 1;
+ dy_ext0 = dy_ext1 = dy_ext2 = dy0 - 1;
+ }
+
+ if ((c & 0x04) == 0) {
+ zsv_ext0 = zsv_ext1 = zsv_ext2 = zsb;
+ dz_ext0 = dz_ext1 = dz_ext2 = dz0;
+ if ((c & 0x03) != 0) {
+ if ((c & 0x03) == 0x03) {
+ zsv_ext0 -= 1;
+ dz_ext0 += 1;
+ } else {
+ zsv_ext1 -= 1;
+ dz_ext1 += 1;
+ }
+ } else {
+ zsv_ext2 -= 1;
+ dz_ext2 += 1;
+ }
+ } else {
+ zsv_ext0 = zsv_ext1 = zsv_ext2 = zsb + 1;
+ dz_ext0 = dz_ext1 = dz_ext2 = dz0 - 1;
+ }
+
+ if ((c & 0x08) == 0) {
+ wsv_ext0 = wsv_ext1 = wsb;
+ wsv_ext2 = wsb - 1;
+ dw_ext0 = dw_ext1 = dw0;
+ dw_ext2 = dw0 + 1;
+ } else {
+ wsv_ext0 = wsv_ext1 = wsv_ext2 = wsb + 1;
+ dw_ext0 = dw_ext1 = dw_ext2 = dw0 - 1;
+ }
+ } else { /* (0,0,0,0) is not one of the closest two pentachoron vertices. */
+ c = (int8_t)(aPoint | bPoint); /* Our three extra vertices are determined by the closest two. */
+
+ if ((c & 0x01) == 0) {
+ xsv_ext0 = xsv_ext2 = xsb;
+ xsv_ext1 = xsb - 1;
+ dx_ext0 = dx0 - 2 * SQUISH_CONSTANT_4D;
+ dx_ext1 = dx0 + 1 - SQUISH_CONSTANT_4D;
+ dx_ext2 = dx0 - SQUISH_CONSTANT_4D;
+ } else {
+ xsv_ext0 = xsv_ext1 = xsv_ext2 = xsb + 1;
+ dx_ext0 = dx0 - 1 - 2 * SQUISH_CONSTANT_4D;
+ dx_ext1 = dx_ext2 = dx0 - 1 - SQUISH_CONSTANT_4D;
+ }
+
+ if ((c & 0x02) == 0) {
+ ysv_ext0 = ysv_ext1 = ysv_ext2 = ysb;
+ dy_ext0 = dy0 - 2 * SQUISH_CONSTANT_4D;
+ dy_ext1 = dy_ext2 = dy0 - SQUISH_CONSTANT_4D;
+ if ((c & 0x01) == 0x01) {
+ ysv_ext1 -= 1;
+ dy_ext1 += 1;
+ } else {
+ ysv_ext2 -= 1;
+ dy_ext2 += 1;
+ }
+ } else {
+ ysv_ext0 = ysv_ext1 = ysv_ext2 = ysb + 1;
+ dy_ext0 = dy0 - 1 - 2 * SQUISH_CONSTANT_4D;
+ dy_ext1 = dy_ext2 = dy0 - 1 - SQUISH_CONSTANT_4D;
+ }
+
+ if ((c & 0x04) == 0) {
+ zsv_ext0 = zsv_ext1 = zsv_ext2 = zsb;
+ dz_ext0 = dz0 - 2 * SQUISH_CONSTANT_4D;
+ dz_ext1 = dz_ext2 = dz0 - SQUISH_CONSTANT_4D;
+ if ((c & 0x03) == 0x03) {
+ zsv_ext1 -= 1;
+ dz_ext1 += 1;
+ } else {
+ zsv_ext2 -= 1;
+ dz_ext2 += 1;
+ }
+ } else {
+ zsv_ext0 = zsv_ext1 = zsv_ext2 = zsb + 1;
+ dz_ext0 = dz0 - 1 - 2 * SQUISH_CONSTANT_4D;
+ dz_ext1 = dz_ext2 = dz0 - 1 - SQUISH_CONSTANT_4D;
+ }
+
+ if ((c & 0x08) == 0) {
+ wsv_ext0 = wsv_ext1 = wsb;
+ wsv_ext2 = wsb - 1;
+ dw_ext0 = dw0 - 2 * SQUISH_CONSTANT_4D;
+ dw_ext1 = dw0 - SQUISH_CONSTANT_4D;
+ dw_ext2 = dw0 + 1 - SQUISH_CONSTANT_4D;
+ } else {
+ wsv_ext0 = wsv_ext1 = wsv_ext2 = wsb + 1;
+ dw_ext0 = dw0 - 1 - 2 * SQUISH_CONSTANT_4D;
+ dw_ext1 = dw_ext2 = dw0 - 1 - SQUISH_CONSTANT_4D;
+ }
+ }
+
+ /* Contribution (0,0,0,0) */
+ attn0 = 2 - dx0 * dx0 - dy0 * dy0 - dz0 * dz0 - dw0 * dw0;
+ if (attn0 > 0) {
+ attn0 *= attn0;
+ value += attn0 * attn0 * extrapolate4(ctx, xsb + 0, ysb + 0, zsb + 0, wsb + 0, dx0, dy0, dz0, dw0);
+ }
+
+ /* Contribution (1,0,0,0) */
+ dx1 = dx0 - 1 - SQUISH_CONSTANT_4D;
+ dy1 = dy0 - 0 - SQUISH_CONSTANT_4D;
+ dz1 = dz0 - 0 - SQUISH_CONSTANT_4D;
+ dw1 = dw0 - 0 - SQUISH_CONSTANT_4D;
+ attn1 = 2 - dx1 * dx1 - dy1 * dy1 - dz1 * dz1 - dw1 * dw1;
+ if (attn1 > 0) {
+ attn1 *= attn1;
+ value += attn1 * attn1 * extrapolate4(ctx, xsb + 1, ysb + 0, zsb + 0, wsb + 0, dx1, dy1, dz1, dw1);
+ }
+
+ /* Contribution (0,1,0,0) */
+ dx2 = dx0 - 0 - SQUISH_CONSTANT_4D;
+ dy2 = dy0 - 1 - SQUISH_CONSTANT_4D;
+ dz2 = dz1;
+ dw2 = dw1;
+ attn2 = 2 - dx2 * dx2 - dy2 * dy2 - dz2 * dz2 - dw2 * dw2;
+ if (attn2 > 0) {
+ attn2 *= attn2;
+ value += attn2 * attn2 * extrapolate4(ctx, xsb + 0, ysb + 1, zsb + 0, wsb + 0, dx2, dy2, dz2, dw2);
+ }
+
+ /* Contribution (0,0,1,0) */
+ dx3 = dx2;
+ dy3 = dy1;
+ dz3 = dz0 - 1 - SQUISH_CONSTANT_4D;
+ dw3 = dw1;
+ attn3 = 2 - dx3 * dx3 - dy3 * dy3 - dz3 * dz3 - dw3 * dw3;
+ if (attn3 > 0) {
+ attn3 *= attn3;
+ value += attn3 * attn3 * extrapolate4(ctx, xsb + 0, ysb + 0, zsb + 1, wsb + 0, dx3, dy3, dz3, dw3);
+ }
+
+ /* Contribution (0,0,0,1) */
+ dx4 = dx2;
+ dy4 = dy1;
+ dz4 = dz1;
+ dw4 = dw0 - 1 - SQUISH_CONSTANT_4D;
+ attn4 = 2 - dx4 * dx4 - dy4 * dy4 - dz4 * dz4 - dw4 * dw4;
+ if (attn4 > 0) {
+ attn4 *= attn4;
+ value += attn4 * attn4 * extrapolate4(ctx, xsb + 0, ysb + 0, zsb + 0, wsb + 1, dx4, dy4, dz4, dw4);
+ }
+ } else if (inSum >= 3) { /* We're inside the pentachoron (4-Simplex) at (1,1,1,1)
+ Determine which two of (1,1,1,0), (1,1,0,1), (1,0,1,1), (0,1,1,1) are closest. */
+ aPoint = 0x0E;
+ aScore = xins;
+ bPoint = 0x0D;
+ bScore = yins;
+ if (aScore <= bScore && zins < bScore) {
+ bScore = zins;
+ bPoint = 0x0B;
+ } else if (aScore > bScore && zins < aScore) {
+ aScore = zins;
+ aPoint = 0x0B;
+ }
+ if (aScore <= bScore && wins < bScore) {
+ bScore = wins;
+ bPoint = 0x07;
+ } else if (aScore > bScore && wins < aScore) {
+ aScore = wins;
+ aPoint = 0x07;
+ }
+
+ /* Now we determine the three lattice points not part of the pentachoron that may contribute.
+ This depends on the closest two pentachoron vertices, including (0,0,0,0) */
+ uins = 4 - inSum;
+ if (uins < aScore || uins < bScore) { /* (1,1,1,1) is one of the closest two pentachoron vertices. */
+ c = (bScore < aScore ? bPoint : aPoint); /* Our other closest vertex is the closest out of a and b. */
+
+ if ((c & 0x01) != 0) {
+ xsv_ext0 = xsb + 2;
+ xsv_ext1 = xsv_ext2 = xsb + 1;
+ dx_ext0 = dx0 - 2 - 4 * SQUISH_CONSTANT_4D;
+ dx_ext1 = dx_ext2 = dx0 - 1 - 4 * SQUISH_CONSTANT_4D;
+ } else {
+ xsv_ext0 = xsv_ext1 = xsv_ext2 = xsb;
+ dx_ext0 = dx_ext1 = dx_ext2 = dx0 - 4 * SQUISH_CONSTANT_4D;
+ }
+
+ if ((c & 0x02) != 0) {
+ ysv_ext0 = ysv_ext1 = ysv_ext2 = ysb + 1;
+ dy_ext0 = dy_ext1 = dy_ext2 = dy0 - 1 - 4 * SQUISH_CONSTANT_4D;
+ if ((c & 0x01) != 0) {
+ ysv_ext1 += 1;
+ dy_ext1 -= 1;
+ } else {
+ ysv_ext0 += 1;
+ dy_ext0 -= 1;
+ }
+ } else {
+ ysv_ext0 = ysv_ext1 = ysv_ext2 = ysb;
+ dy_ext0 = dy_ext1 = dy_ext2 = dy0 - 4 * SQUISH_CONSTANT_4D;
+ }
+
+ if ((c & 0x04) != 0) {
+ zsv_ext0 = zsv_ext1 = zsv_ext2 = zsb + 1;
+ dz_ext0 = dz_ext1 = dz_ext2 = dz0 - 1 - 4 * SQUISH_CONSTANT_4D;
+ if ((c & 0x03) != 0x03) {
+ if ((c & 0x03) == 0) {
+ zsv_ext0 += 1;
+ dz_ext0 -= 1;
+ } else {
+ zsv_ext1 += 1;
+ dz_ext1 -= 1;
+ }
+ } else {
+ zsv_ext2 += 1;
+ dz_ext2 -= 1;
+ }
+ } else {
+ zsv_ext0 = zsv_ext1 = zsv_ext2 = zsb;
+ dz_ext0 = dz_ext1 = dz_ext2 = dz0 - 4 * SQUISH_CONSTANT_4D;
+ }
+
+ if ((c & 0x08) != 0) {
+ wsv_ext0 = wsv_ext1 = wsb + 1;
+ wsv_ext2 = wsb + 2;
+ dw_ext0 = dw_ext1 = dw0 - 1 - 4 * SQUISH_CONSTANT_4D;
+ dw_ext2 = dw0 - 2 - 4 * SQUISH_CONSTANT_4D;
+ } else {
+ wsv_ext0 = wsv_ext1 = wsv_ext2 = wsb;
+ dw_ext0 = dw_ext1 = dw_ext2 = dw0 - 4 * SQUISH_CONSTANT_4D;
+ }
+ } else { /* (1,1,1,1) is not one of the closest two pentachoron vertices. */
+ c = (int8_t)(aPoint & bPoint); /* Our three extra vertices are determined by the closest two. */
+
+ if ((c & 0x01) != 0) {
+ xsv_ext0 = xsv_ext2 = xsb + 1;
+ xsv_ext1 = xsb + 2;
+ dx_ext0 = dx0 - 1 - 2 * SQUISH_CONSTANT_4D;
+ dx_ext1 = dx0 - 2 - 3 * SQUISH_CONSTANT_4D;
+ dx_ext2 = dx0 - 1 - 3 * SQUISH_CONSTANT_4D;
+ } else {
+ xsv_ext0 = xsv_ext1 = xsv_ext2 = xsb;
+ dx_ext0 = dx0 - 2 * SQUISH_CONSTANT_4D;
+ dx_ext1 = dx_ext2 = dx0 - 3 * SQUISH_CONSTANT_4D;
+ }
+
+ if ((c & 0x02) != 0) {
+ ysv_ext0 = ysv_ext1 = ysv_ext2 = ysb + 1;
+ dy_ext0 = dy0 - 1 - 2 * SQUISH_CONSTANT_4D;
+ dy_ext1 = dy_ext2 = dy0 - 1 - 3 * SQUISH_CONSTANT_4D;
+ if ((c & 0x01) != 0) {
+ ysv_ext2 += 1;
+ dy_ext2 -= 1;
+ } else {
+ ysv_ext1 += 1;
+ dy_ext1 -= 1;
+ }
+ } else {
+ ysv_ext0 = ysv_ext1 = ysv_ext2 = ysb;
+ dy_ext0 = dy0 - 2 * SQUISH_CONSTANT_4D;
+ dy_ext1 = dy_ext2 = dy0 - 3 * SQUISH_CONSTANT_4D;
+ }
+
+ if ((c & 0x04) != 0) {
+ zsv_ext0 = zsv_ext1 = zsv_ext2 = zsb + 1;
+ dz_ext0 = dz0 - 1 - 2 * SQUISH_CONSTANT_4D;
+ dz_ext1 = dz_ext2 = dz0 - 1 - 3 * SQUISH_CONSTANT_4D;
+ if ((c & 0x03) != 0) {
+ zsv_ext2 += 1;
+ dz_ext2 -= 1;
+ } else {
+ zsv_ext1 += 1;
+ dz_ext1 -= 1;
+ }
+ } else {
+ zsv_ext0 = zsv_ext1 = zsv_ext2 = zsb;
+ dz_ext0 = dz0 - 2 * SQUISH_CONSTANT_4D;
+ dz_ext1 = dz_ext2 = dz0 - 3 * SQUISH_CONSTANT_4D;
+ }
+
+ if ((c & 0x08) != 0) {
+ wsv_ext0 = wsv_ext1 = wsb + 1;
+ wsv_ext2 = wsb + 2;
+ dw_ext0 = dw0 - 1 - 2 * SQUISH_CONSTANT_4D;
+ dw_ext1 = dw0 - 1 - 3 * SQUISH_CONSTANT_4D;
+ dw_ext2 = dw0 - 2 - 3 * SQUISH_CONSTANT_4D;
+ } else {
+ wsv_ext0 = wsv_ext1 = wsv_ext2 = wsb;
+ dw_ext0 = dw0 - 2 * SQUISH_CONSTANT_4D;
+ dw_ext1 = dw_ext2 = dw0 - 3 * SQUISH_CONSTANT_4D;
+ }
+ }
+
+ /* Contribution (1,1,1,0) */
+ dx4 = dx0 - 1 - 3 * SQUISH_CONSTANT_4D;
+ dy4 = dy0 - 1 - 3 * SQUISH_CONSTANT_4D;
+ dz4 = dz0 - 1 - 3 * SQUISH_CONSTANT_4D;
+ dw4 = dw0 - 3 * SQUISH_CONSTANT_4D;
+ attn4 = 2 - dx4 * dx4 - dy4 * dy4 - dz4 * dz4 - dw4 * dw4;
+ if (attn4 > 0) {
+ attn4 *= attn4;
+ value += attn4 * attn4 * extrapolate4(ctx, xsb + 1, ysb + 1, zsb + 1, wsb + 0, dx4, dy4, dz4, dw4);
+ }
+
+ /* Contribution (1,1,0,1) */
+ dx3 = dx4;
+ dy3 = dy4;
+ dz3 = dz0 - 3 * SQUISH_CONSTANT_4D;
+ dw3 = dw0 - 1 - 3 * SQUISH_CONSTANT_4D;
+ attn3 = 2 - dx3 * dx3 - dy3 * dy3 - dz3 * dz3 - dw3 * dw3;
+ if (attn3 > 0) {
+ attn3 *= attn3;
+ value += attn3 * attn3 * extrapolate4(ctx, xsb + 1, ysb + 1, zsb + 0, wsb + 1, dx3, dy3, dz3, dw3);
+ }
+
+ /* Contribution (1,0,1,1) */
+ dx2 = dx4;
+ dy2 = dy0 - 3 * SQUISH_CONSTANT_4D;
+ dz2 = dz4;
+ dw2 = dw3;
+ attn2 = 2 - dx2 * dx2 - dy2 * dy2 - dz2 * dz2 - dw2 * dw2;
+ if (attn2 > 0) {
+ attn2 *= attn2;
+ value += attn2 * attn2 * extrapolate4(ctx, xsb + 1, ysb + 0, zsb + 1, wsb + 1, dx2, dy2, dz2, dw2);
+ }
+
+ /* Contribution (0,1,1,1) */
+ dx1 = dx0 - 3 * SQUISH_CONSTANT_4D;
+ dz1 = dz4;
+ dy1 = dy4;
+ dw1 = dw3;
+ attn1 = 2 - dx1 * dx1 - dy1 * dy1 - dz1 * dz1 - dw1 * dw1;
+ if (attn1 > 0) {
+ attn1 *= attn1;
+ value += attn1 * attn1 * extrapolate4(ctx, xsb + 0, ysb + 1, zsb + 1, wsb + 1, dx1, dy1, dz1, dw1);
+ }
+
+ /* Contribution (1,1,1,1) */
+ dx0 = dx0 - 1 - 4 * SQUISH_CONSTANT_4D;
+ dy0 = dy0 - 1 - 4 * SQUISH_CONSTANT_4D;
+ dz0 = dz0 - 1 - 4 * SQUISH_CONSTANT_4D;
+ dw0 = dw0 - 1 - 4 * SQUISH_CONSTANT_4D;
+ attn0 = 2 - dx0 * dx0 - dy0 * dy0 - dz0 * dz0 - dw0 * dw0;
+ if (attn0 > 0) {
+ attn0 *= attn0;
+ value += attn0 * attn0 * extrapolate4(ctx, xsb + 1, ysb + 1, zsb + 1, wsb + 1, dx0, dy0, dz0, dw0);
+ }
+ } else if (inSum <= 2) { /* We're inside the first dispentachoron (Rectified 4-Simplex) */
+ aIsBiggerSide = 1;
+ bIsBiggerSide = 1;
+
+ /* Decide between (1,1,0,0) and (0,0,1,1) */
+ if (xins + yins > zins + wins) {
+ aScore = xins + yins;
+ aPoint = 0x03;
+ } else {
+ aScore = zins + wins;
+ aPoint = 0x0C;
+ }
+
+ /* Decide between (1,0,1,0) and (0,1,0,1) */
+ if (xins + zins > yins + wins) {
+ bScore = xins + zins;
+ bPoint = 0x05;
+ } else {
+ bScore = yins + wins;
+ bPoint = 0x0A;
+ }
+
+ /* Closer between (1,0,0,1) and (0,1,1,0) will replace the further of a and b, if closer. */
+ if (xins + wins > yins + zins) {
+ score = xins + wins;
+ if (aScore >= bScore && score > bScore) {
+ bScore = score;
+ bPoint = 0x09;
+ } else if (aScore < bScore && score > aScore) {
+ aScore = score;
+ aPoint = 0x09;
+ }
+ } else {
+ score = yins + zins;
+ if (aScore >= bScore && score > bScore) {
+ bScore = score;
+ bPoint = 0x06;
+ } else if (aScore < bScore && score > aScore) {
+ aScore = score;
+ aPoint = 0x06;
+ }
+ }
+
+ /* Decide if (1,0,0,0) is closer. */
+ p1 = 2 - inSum + xins;
+ if (aScore >= bScore && p1 > bScore) {
+ bScore = p1;
+ bPoint = 0x01;
+ bIsBiggerSide = 0;
+ } else if (aScore < bScore && p1 > aScore) {
+ aScore = p1;
+ aPoint = 0x01;
+ aIsBiggerSide = 0;
+ }
+
+ /* Decide if (0,1,0,0) is closer. */
+ p2 = 2 - inSum + yins;
+ if (aScore >= bScore && p2 > bScore) {
+ bScore = p2;
+ bPoint = 0x02;
+ bIsBiggerSide = 0;
+ } else if (aScore < bScore && p2 > aScore) {
+ aScore = p2;
+ aPoint = 0x02;
+ aIsBiggerSide = 0;
+ }
+
+ /* Decide if (0,0,1,0) is closer. */
+ p3 = 2 - inSum + zins;
+ if (aScore >= bScore && p3 > bScore) {
+ bScore = p3;
+ bPoint = 0x04;
+ bIsBiggerSide = 0;
+ } else if (aScore < bScore && p3 > aScore) {
+ aScore = p3;
+ aPoint = 0x04;
+ aIsBiggerSide = 0;
+ }
+
+ /* Decide if (0,0,0,1) is closer. */
+ p4 = 2 - inSum + wins;
+ if (aScore >= bScore && p4 > bScore) {
+ bScore = p4;
+ bPoint = 0x08;
+ bIsBiggerSide = 0;
+ } else if (aScore < bScore && p4 > aScore) {
+ aScore = p4;
+ aPoint = 0x08;
+ aIsBiggerSide = 0;
+ }
+
+ /* Where each of the two closest points are determines how the extra three vertices are calculated. */
+ if (aIsBiggerSide == bIsBiggerSide) {
+ if (aIsBiggerSide) { /* Both closest points on the bigger side */
+ c1 = (int8_t)(aPoint | bPoint);
+ c2 = (int8_t)(aPoint & bPoint);
+ if ((c1 & 0x01) == 0) {
+ xsv_ext0 = xsb;
+ xsv_ext1 = xsb - 1;
+ dx_ext0 = dx0 - 3 * SQUISH_CONSTANT_4D;
+ dx_ext1 = dx0 + 1 - 2 * SQUISH_CONSTANT_4D;
+ } else {
+ xsv_ext0 = xsv_ext1 = xsb + 1;
+ dx_ext0 = dx0 - 1 - 3 * SQUISH_CONSTANT_4D;
+ dx_ext1 = dx0 - 1 - 2 * SQUISH_CONSTANT_4D;
+ }
+
+ if ((c1 & 0x02) == 0) {
+ ysv_ext0 = ysb;
+ ysv_ext1 = ysb - 1;
+ dy_ext0 = dy0 - 3 * SQUISH_CONSTANT_4D;
+ dy_ext1 = dy0 + 1 - 2 * SQUISH_CONSTANT_4D;
+ } else {
+ ysv_ext0 = ysv_ext1 = ysb + 1;
+ dy_ext0 = dy0 - 1 - 3 * SQUISH_CONSTANT_4D;
+ dy_ext1 = dy0 - 1 - 2 * SQUISH_CONSTANT_4D;
+ }
+
+ if ((c1 & 0x04) == 0) {
+ zsv_ext0 = zsb;
+ zsv_ext1 = zsb - 1;
+ dz_ext0 = dz0 - 3 * SQUISH_CONSTANT_4D;
+ dz_ext1 = dz0 + 1 - 2 * SQUISH_CONSTANT_4D;
+ } else {
+ zsv_ext0 = zsv_ext1 = zsb + 1;
+ dz_ext0 = dz0 - 1 - 3 * SQUISH_CONSTANT_4D;
+ dz_ext1 = dz0 - 1 - 2 * SQUISH_CONSTANT_4D;
+ }
+
+ if ((c1 & 0x08) == 0) {
+ wsv_ext0 = wsb;
+ wsv_ext1 = wsb - 1;
+ dw_ext0 = dw0 - 3 * SQUISH_CONSTANT_4D;
+ dw_ext1 = dw0 + 1 - 2 * SQUISH_CONSTANT_4D;
+ } else {
+ wsv_ext0 = wsv_ext1 = wsb + 1;
+ dw_ext0 = dw0 - 1 - 3 * SQUISH_CONSTANT_4D;
+ dw_ext1 = dw0 - 1 - 2 * SQUISH_CONSTANT_4D;
+ }
+
+ /* One combination is a permutation of (0,0,0,2) based on c2 */
+ xsv_ext2 = xsb;
+ ysv_ext2 = ysb;
+ zsv_ext2 = zsb;
+ wsv_ext2 = wsb;
+ dx_ext2 = dx0 - 2 * SQUISH_CONSTANT_4D;
+ dy_ext2 = dy0 - 2 * SQUISH_CONSTANT_4D;
+ dz_ext2 = dz0 - 2 * SQUISH_CONSTANT_4D;
+ dw_ext2 = dw0 - 2 * SQUISH_CONSTANT_4D;
+ if ((c2 & 0x01) != 0) {
+ xsv_ext2 += 2;
+ dx_ext2 -= 2;
+ } else if ((c2 & 0x02) != 0) {
+ ysv_ext2 += 2;
+ dy_ext2 -= 2;
+ } else if ((c2 & 0x04) != 0) {
+ zsv_ext2 += 2;
+ dz_ext2 -= 2;
+ } else {
+ wsv_ext2 += 2;
+ dw_ext2 -= 2;
+ }
+
+ } else { /* Both closest points on the smaller side */
+ /* One of the two extra points is (0,0,0,0) */
+ xsv_ext2 = xsb;
+ ysv_ext2 = ysb;
+ zsv_ext2 = zsb;
+ wsv_ext2 = wsb;
+ dx_ext2 = dx0;
+ dy_ext2 = dy0;
+ dz_ext2 = dz0;
+ dw_ext2 = dw0;
+
+ /* Other two points are based on the omitted axes. */
+ c = (int8_t)(aPoint | bPoint);
+
+ if ((c & 0x01) == 0) {
+ xsv_ext0 = xsb - 1;
+ xsv_ext1 = xsb;
+ dx_ext0 = dx0 + 1 - SQUISH_CONSTANT_4D;
+ dx_ext1 = dx0 - SQUISH_CONSTANT_4D;
+ } else {
+ xsv_ext0 = xsv_ext1 = xsb + 1;
+ dx_ext0 = dx_ext1 = dx0 - 1 - SQUISH_CONSTANT_4D;
+ }
+
+ if ((c & 0x02) == 0) {
+ ysv_ext0 = ysv_ext1 = ysb;
+ dy_ext0 = dy_ext1 = dy0 - SQUISH_CONSTANT_4D;
+ if ((c & 0x01) == 0x01)
+ {
+ ysv_ext0 -= 1;
+ dy_ext0 += 1;
+ } else {
+ ysv_ext1 -= 1;
+ dy_ext1 += 1;
+ }
+ } else {
+ ysv_ext0 = ysv_ext1 = ysb + 1;
+ dy_ext0 = dy_ext1 = dy0 - 1 - SQUISH_CONSTANT_4D;
+ }
+
+ if ((c & 0x04) == 0) {
+ zsv_ext0 = zsv_ext1 = zsb;
+ dz_ext0 = dz_ext1 = dz0 - SQUISH_CONSTANT_4D;
+ if ((c & 0x03) == 0x03)
+ {
+ zsv_ext0 -= 1;
+ dz_ext0 += 1;
+ } else {
+ zsv_ext1 -= 1;
+ dz_ext1 += 1;
+ }
+ } else {
+ zsv_ext0 = zsv_ext1 = zsb + 1;
+ dz_ext0 = dz_ext1 = dz0 - 1 - SQUISH_CONSTANT_4D;
+ }
+
+ if ((c & 0x08) == 0)
+ {
+ wsv_ext0 = wsb;
+ wsv_ext1 = wsb - 1;
+ dw_ext0 = dw0 - SQUISH_CONSTANT_4D;
+ dw_ext1 = dw0 + 1 - SQUISH_CONSTANT_4D;
+ } else {
+ wsv_ext0 = wsv_ext1 = wsb + 1;
+ dw_ext0 = dw_ext1 = dw0 - 1 - SQUISH_CONSTANT_4D;
+ }
+
+ }
+ } else { /* One point on each "side" */
+ if (aIsBiggerSide) {
+ c1 = aPoint;
+ c2 = bPoint;
+ } else {
+ c1 = bPoint;
+ c2 = aPoint;
+ }
+
+ /* Two contributions are the bigger-sided point with each 0 replaced with -1. */
+ if ((c1 & 0x01) == 0) {
+ xsv_ext0 = xsb - 1;
+ xsv_ext1 = xsb;
+ dx_ext0 = dx0 + 1 - SQUISH_CONSTANT_4D;
+ dx_ext1 = dx0 - SQUISH_CONSTANT_4D;
+ } else {
+ xsv_ext0 = xsv_ext1 = xsb + 1;
+ dx_ext0 = dx_ext1 = dx0 - 1 - SQUISH_CONSTANT_4D;
+ }
+
+ if ((c1 & 0x02) == 0) {
+ ysv_ext0 = ysv_ext1 = ysb;
+ dy_ext0 = dy_ext1 = dy0 - SQUISH_CONSTANT_4D;
+ if ((c1 & 0x01) == 0x01) {
+ ysv_ext0 -= 1;
+ dy_ext0 += 1;
+ } else {
+ ysv_ext1 -= 1;
+ dy_ext1 += 1;
+ }
+ } else {
+ ysv_ext0 = ysv_ext1 = ysb + 1;
+ dy_ext0 = dy_ext1 = dy0 - 1 - SQUISH_CONSTANT_4D;
+ }
+
+ if ((c1 & 0x04) == 0) {
+ zsv_ext0 = zsv_ext1 = zsb;
+ dz_ext0 = dz_ext1 = dz0 - SQUISH_CONSTANT_4D;
+ if ((c1 & 0x03) == 0x03) {
+ zsv_ext0 -= 1;
+ dz_ext0 += 1;
+ } else {
+ zsv_ext1 -= 1;
+ dz_ext1 += 1;
+ }
+ } else {
+ zsv_ext0 = zsv_ext1 = zsb + 1;
+ dz_ext0 = dz_ext1 = dz0 - 1 - SQUISH_CONSTANT_4D;
+ }
+
+ if ((c1 & 0x08) == 0) {
+ wsv_ext0 = wsb;
+ wsv_ext1 = wsb - 1;
+ dw_ext0 = dw0 - SQUISH_CONSTANT_4D;
+ dw_ext1 = dw0 + 1 - SQUISH_CONSTANT_4D;
+ } else {
+ wsv_ext0 = wsv_ext1 = wsb + 1;
+ dw_ext0 = dw_ext1 = dw0 - 1 - SQUISH_CONSTANT_4D;
+ }
+
+ /* One contribution is a permutation of (0,0,0,2) based on the smaller-sided point */
+ xsv_ext2 = xsb;
+ ysv_ext2 = ysb;
+ zsv_ext2 = zsb;
+ wsv_ext2 = wsb;
+ dx_ext2 = dx0 - 2 * SQUISH_CONSTANT_4D;
+ dy_ext2 = dy0 - 2 * SQUISH_CONSTANT_4D;
+ dz_ext2 = dz0 - 2 * SQUISH_CONSTANT_4D;
+ dw_ext2 = dw0 - 2 * SQUISH_CONSTANT_4D;
+ if ((c2 & 0x01) != 0) {
+ xsv_ext2 += 2;
+ dx_ext2 -= 2;
+ } else if ((c2 & 0x02) != 0) {
+ ysv_ext2 += 2;
+ dy_ext2 -= 2;
+ } else if ((c2 & 0x04) != 0) {
+ zsv_ext2 += 2;
+ dz_ext2 -= 2;
+ } else {
+ wsv_ext2 += 2;
+ dw_ext2 -= 2;
+ }
+ }
+
+ /* Contribution (1,0,0,0) */
+ dx1 = dx0 - 1 - SQUISH_CONSTANT_4D;
+ dy1 = dy0 - 0 - SQUISH_CONSTANT_4D;
+ dz1 = dz0 - 0 - SQUISH_CONSTANT_4D;
+ dw1 = dw0 - 0 - SQUISH_CONSTANT_4D;
+ attn1 = 2 - dx1 * dx1 - dy1 * dy1 - dz1 * dz1 - dw1 * dw1;
+ if (attn1 > 0) {
+ attn1 *= attn1;
+ value += attn1 * attn1 * extrapolate4(ctx, xsb + 1, ysb + 0, zsb + 0, wsb + 0, dx1, dy1, dz1, dw1);
+ }
+
+ /* Contribution (0,1,0,0) */
+ dx2 = dx0 - 0 - SQUISH_CONSTANT_4D;
+ dy2 = dy0 - 1 - SQUISH_CONSTANT_4D;
+ dz2 = dz1;
+ dw2 = dw1;
+ attn2 = 2 - dx2 * dx2 - dy2 * dy2 - dz2 * dz2 - dw2 * dw2;
+ if (attn2 > 0) {
+ attn2 *= attn2;
+ value += attn2 * attn2 * extrapolate4(ctx, xsb + 0, ysb + 1, zsb + 0, wsb + 0, dx2, dy2, dz2, dw2);
+ }
+
+ /* Contribution (0,0,1,0) */
+ dx3 = dx2;
+ dy3 = dy1;
+ dz3 = dz0 - 1 - SQUISH_CONSTANT_4D;
+ dw3 = dw1;
+ attn3 = 2 - dx3 * dx3 - dy3 * dy3 - dz3 * dz3 - dw3 * dw3;
+ if (attn3 > 0) {
+ attn3 *= attn3;
+ value += attn3 * attn3 * extrapolate4(ctx, xsb + 0, ysb + 0, zsb + 1, wsb + 0, dx3, dy3, dz3, dw3);
+ }
+
+ /* Contribution (0,0,0,1) */
+ dx4 = dx2;
+ dy4 = dy1;
+ dz4 = dz1;
+ dw4 = dw0 - 1 - SQUISH_CONSTANT_4D;
+ attn4 = 2 - dx4 * dx4 - dy4 * dy4 - dz4 * dz4 - dw4 * dw4;
+ if (attn4 > 0) {
+ attn4 *= attn4;
+ value += attn4 * attn4 * extrapolate4(ctx, xsb + 0, ysb + 0, zsb + 0, wsb + 1, dx4, dy4, dz4, dw4);
+ }
+
+ /* Contribution (1,1,0,0) */
+ dx5 = dx0 - 1 - 2 * SQUISH_CONSTANT_4D;
+ dy5 = dy0 - 1 - 2 * SQUISH_CONSTANT_4D;
+ dz5 = dz0 - 0 - 2 * SQUISH_CONSTANT_4D;
+ dw5 = dw0 - 0 - 2 * SQUISH_CONSTANT_4D;
+ attn5 = 2 - dx5 * dx5 - dy5 * dy5 - dz5 * dz5 - dw5 * dw5;
+ if (attn5 > 0) {
+ attn5 *= attn5;
+ value += attn5 * attn5 * extrapolate4(ctx, xsb + 1, ysb + 1, zsb + 0, wsb + 0, dx5, dy5, dz5, dw5);
+ }
+
+ /* Contribution (1,0,1,0) */
+ dx6 = dx0 - 1 - 2 * SQUISH_CONSTANT_4D;
+ dy6 = dy0 - 0 - 2 * SQUISH_CONSTANT_4D;
+ dz6 = dz0 - 1 - 2 * SQUISH_CONSTANT_4D;
+ dw6 = dw0 - 0 - 2 * SQUISH_CONSTANT_4D;
+ attn6 = 2 - dx6 * dx6 - dy6 * dy6 - dz6 * dz6 - dw6 * dw6;
+ if (attn6 > 0) {
+ attn6 *= attn6;
+ value += attn6 * attn6 * extrapolate4(ctx, xsb + 1, ysb + 0, zsb + 1, wsb + 0, dx6, dy6, dz6, dw6);
+ }
+
+ /* Contribution (1,0,0,1) */
+ dx7 = dx0 - 1 - 2 * SQUISH_CONSTANT_4D;
+ dy7 = dy0 - 0 - 2 * SQUISH_CONSTANT_4D;
+ dz7 = dz0 - 0 - 2 * SQUISH_CONSTANT_4D;
+ dw7 = dw0 - 1 - 2 * SQUISH_CONSTANT_4D;
+ attn7 = 2 - dx7 * dx7 - dy7 * dy7 - dz7 * dz7 - dw7 * dw7;
+ if (attn7 > 0) {
+ attn7 *= attn7;
+ value += attn7 * attn7 * extrapolate4(ctx, xsb + 1, ysb + 0, zsb + 0, wsb + 1, dx7, dy7, dz7, dw7);
+ }
+
+ /* Contribution (0,1,1,0) */
+ dx8 = dx0 - 0 - 2 * SQUISH_CONSTANT_4D;
+ dy8 = dy0 - 1 - 2 * SQUISH_CONSTANT_4D;
+ dz8 = dz0 - 1 - 2 * SQUISH_CONSTANT_4D;
+ dw8 = dw0 - 0 - 2 * SQUISH_CONSTANT_4D;
+ attn8 = 2 - dx8 * dx8 - dy8 * dy8 - dz8 * dz8 - dw8 * dw8;
+ if (attn8 > 0) {
+ attn8 *= attn8;
+ value += attn8 * attn8 * extrapolate4(ctx, xsb + 0, ysb + 1, zsb + 1, wsb + 0, dx8, dy8, dz8, dw8);
+ }
+
+ /* Contribution (0,1,0,1) */
+ dx9 = dx0 - 0 - 2 * SQUISH_CONSTANT_4D;
+ dy9 = dy0 - 1 - 2 * SQUISH_CONSTANT_4D;
+ dz9 = dz0 - 0 - 2 * SQUISH_CONSTANT_4D;
+ dw9 = dw0 - 1 - 2 * SQUISH_CONSTANT_4D;
+ attn9 = 2 - dx9 * dx9 - dy9 * dy9 - dz9 * dz9 - dw9 * dw9;
+ if (attn9 > 0) {
+ attn9 *= attn9;
+ value += attn9 * attn9 * extrapolate4(ctx, xsb + 0, ysb + 1, zsb + 0, wsb + 1, dx9, dy9, dz9, dw9);
+ }
+
+ /* Contribution (0,0,1,1) */
+ dx10 = dx0 - 0 - 2 * SQUISH_CONSTANT_4D;
+ dy10 = dy0 - 0 - 2 * SQUISH_CONSTANT_4D;
+ dz10 = dz0 - 1 - 2 * SQUISH_CONSTANT_4D;
+ dw10 = dw0 - 1 - 2 * SQUISH_CONSTANT_4D;
+ attn10 = 2 - dx10 * dx10 - dy10 * dy10 - dz10 * dz10 - dw10 * dw10;
+ if (attn10 > 0) {
+ attn10 *= attn10;
+ value += attn10 * attn10 * extrapolate4(ctx, xsb + 0, ysb + 0, zsb + 1, wsb + 1, dx10, dy10, dz10, dw10);
+ }
+ } else { /* We're inside the second dispentachoron (Rectified 4-Simplex) */
+ aIsBiggerSide = 1;
+ bIsBiggerSide = 1;
+
+ /* Decide between (0,0,1,1) and (1,1,0,0) */
+ if (xins + yins < zins + wins) {
+ aScore = xins + yins;
+ aPoint = 0x0C;
+ } else {
+ aScore = zins + wins;
+ aPoint = 0x03;
+ }
+
+ /* Decide between (0,1,0,1) and (1,0,1,0) */
+ if (xins + zins < yins + wins) {
+ bScore = xins + zins;
+ bPoint = 0x0A;
+ } else {
+ bScore = yins + wins;
+ bPoint = 0x05;
+ }
+
+ /* Closer between (0,1,1,0) and (1,0,0,1) will replace the further of a and b, if closer. */
+ if (xins + wins < yins + zins) {
+ score = xins + wins;
+ if (aScore <= bScore && score < bScore) {
+ bScore = score;
+ bPoint = 0x06;
+ } else if (aScore > bScore && score < aScore) {
+ aScore = score;
+ aPoint = 0x06;
+ }
+ } else {
+ score = yins + zins;
+ if (aScore <= bScore && score < bScore) {
+ bScore = score;
+ bPoint = 0x09;
+ } else if (aScore > bScore && score < aScore) {
+ aScore = score;
+ aPoint = 0x09;
+ }
+ }
+
+ /* Decide if (0,1,1,1) is closer. */
+ p1 = 3 - inSum + xins;
+ if (aScore <= bScore && p1 < bScore) {
+ bScore = p1;
+ bPoint = 0x0E;
+ bIsBiggerSide = 0;
+ } else if (aScore > bScore && p1 < aScore) {
+ aScore = p1;
+ aPoint = 0x0E;
+ aIsBiggerSide = 0;
+ }
+
+ /* Decide if (1,0,1,1) is closer. */
+ p2 = 3 - inSum + yins;
+ if (aScore <= bScore && p2 < bScore) {
+ bScore = p2;
+ bPoint = 0x0D;
+ bIsBiggerSide = 0;
+ } else if (aScore > bScore && p2 < aScore) {
+ aScore = p2;
+ aPoint = 0x0D;
+ aIsBiggerSide = 0;
+ }
+
+ /* Decide if (1,1,0,1) is closer. */
+ p3 = 3 - inSum + zins;
+ if (aScore <= bScore && p3 < bScore) {
+ bScore = p3;
+ bPoint = 0x0B;
+ bIsBiggerSide = 0;
+ } else if (aScore > bScore && p3 < aScore) {
+ aScore = p3;
+ aPoint = 0x0B;
+ aIsBiggerSide = 0;
+ }
+
+ /* Decide if (1,1,1,0) is closer. */
+ p4 = 3 - inSum + wins;
+ if (aScore <= bScore && p4 < bScore) {
+ bScore = p4;
+ bPoint = 0x07;
+ bIsBiggerSide = 0;
+ } else if (aScore > bScore && p4 < aScore) {
+ aScore = p4;
+ aPoint = 0x07;
+ aIsBiggerSide = 0;
+ }
+
+ /* Where each of the two closest points are determines how the extra three vertices are calculated. */
+ if (aIsBiggerSide == bIsBiggerSide) {
+ if (aIsBiggerSide) { /* Both closest points on the bigger side */
+ c1 = (int8_t)(aPoint & bPoint);
+ c2 = (int8_t)(aPoint | bPoint);
+
+ /* Two contributions are permutations of (0,0,0,1) and (0,0,0,2) based on c1 */
+ xsv_ext0 = xsv_ext1 = xsb;
+ ysv_ext0 = ysv_ext1 = ysb;
+ zsv_ext0 = zsv_ext1 = zsb;
+ wsv_ext0 = wsv_ext1 = wsb;
+ dx_ext0 = dx0 - SQUISH_CONSTANT_4D;
+ dy_ext0 = dy0 - SQUISH_CONSTANT_4D;
+ dz_ext0 = dz0 - SQUISH_CONSTANT_4D;
+ dw_ext0 = dw0 - SQUISH_CONSTANT_4D;
+ dx_ext1 = dx0 - 2 * SQUISH_CONSTANT_4D;
+ dy_ext1 = dy0 - 2 * SQUISH_CONSTANT_4D;
+ dz_ext1 = dz0 - 2 * SQUISH_CONSTANT_4D;
+ dw_ext1 = dw0 - 2 * SQUISH_CONSTANT_4D;
+ if ((c1 & 0x01) != 0) {
+ xsv_ext0 += 1;
+ dx_ext0 -= 1;
+ xsv_ext1 += 2;
+ dx_ext1 -= 2;
+ } else if ((c1 & 0x02) != 0) {
+ ysv_ext0 += 1;
+ dy_ext0 -= 1;
+ ysv_ext1 += 2;
+ dy_ext1 -= 2;
+ } else if ((c1 & 0x04) != 0) {
+ zsv_ext0 += 1;
+ dz_ext0 -= 1;
+ zsv_ext1 += 2;
+ dz_ext1 -= 2;
+ } else {
+ wsv_ext0 += 1;
+ dw_ext0 -= 1;
+ wsv_ext1 += 2;
+ dw_ext1 -= 2;
+ }
+
+ /* One contribution is a permutation of (1,1,1,-1) based on c2 */
+ xsv_ext2 = xsb + 1;
+ ysv_ext2 = ysb + 1;
+ zsv_ext2 = zsb + 1;
+ wsv_ext2 = wsb + 1;
+ dx_ext2 = dx0 - 1 - 2 * SQUISH_CONSTANT_4D;
+ dy_ext2 = dy0 - 1 - 2 * SQUISH_CONSTANT_4D;
+ dz_ext2 = dz0 - 1 - 2 * SQUISH_CONSTANT_4D;
+ dw_ext2 = dw0 - 1 - 2 * SQUISH_CONSTANT_4D;
+ if ((c2 & 0x01) == 0) {
+ xsv_ext2 -= 2;
+ dx_ext2 += 2;
+ } else if ((c2 & 0x02) == 0) {
+ ysv_ext2 -= 2;
+ dy_ext2 += 2;
+ } else if ((c2 & 0x04) == 0) {
+ zsv_ext2 -= 2;
+ dz_ext2 += 2;
+ } else {
+ wsv_ext2 -= 2;
+ dw_ext2 += 2;
+ }
+ } else { /* Both closest points on the smaller side */
+ /* One of the two extra points is (1,1,1,1) */
+ xsv_ext2 = xsb + 1;
+ ysv_ext2 = ysb + 1;
+ zsv_ext2 = zsb + 1;
+ wsv_ext2 = wsb + 1;
+ dx_ext2 = dx0 - 1 - 4 * SQUISH_CONSTANT_4D;
+ dy_ext2 = dy0 - 1 - 4 * SQUISH_CONSTANT_4D;
+ dz_ext2 = dz0 - 1 - 4 * SQUISH_CONSTANT_4D;
+ dw_ext2 = dw0 - 1 - 4 * SQUISH_CONSTANT_4D;
+
+ /* Other two points are based on the shared axes. */
+ c = (int8_t)(aPoint & bPoint);
+
+ if ((c & 0x01) != 0) {
+ xsv_ext0 = xsb + 2;
+ xsv_ext1 = xsb + 1;
+ dx_ext0 = dx0 - 2 - 3 * SQUISH_CONSTANT_4D;
+ dx_ext1 = dx0 - 1 - 3 * SQUISH_CONSTANT_4D;
+ } else {
+ xsv_ext0 = xsv_ext1 = xsb;
+ dx_ext0 = dx_ext1 = dx0 - 3 * SQUISH_CONSTANT_4D;
+ }
+
+ if ((c & 0x02) != 0) {
+ ysv_ext0 = ysv_ext1 = ysb + 1;
+ dy_ext0 = dy_ext1 = dy0 - 1 - 3 * SQUISH_CONSTANT_4D;
+ if ((c & 0x01) == 0)
+ {
+ ysv_ext0 += 1;
+ dy_ext0 -= 1;
+ } else {
+ ysv_ext1 += 1;
+ dy_ext1 -= 1;
+ }
+ } else {
+ ysv_ext0 = ysv_ext1 = ysb;
+ dy_ext0 = dy_ext1 = dy0 - 3 * SQUISH_CONSTANT_4D;
+ }
+
+ if ((c & 0x04) != 0) {
+ zsv_ext0 = zsv_ext1 = zsb + 1;
+ dz_ext0 = dz_ext1 = dz0 - 1 - 3 * SQUISH_CONSTANT_4D;
+ if ((c & 0x03) == 0)
+ {
+ zsv_ext0 += 1;
+ dz_ext0 -= 1;
+ } else {
+ zsv_ext1 += 1;
+ dz_ext1 -= 1;
+ }
+ } else {
+ zsv_ext0 = zsv_ext1 = zsb;
+ dz_ext0 = dz_ext1 = dz0 - 3 * SQUISH_CONSTANT_4D;
+ }
+
+ if ((c & 0x08) != 0)
+ {
+ wsv_ext0 = wsb + 1;
+ wsv_ext1 = wsb + 2;
+ dw_ext0 = dw0 - 1 - 3 * SQUISH_CONSTANT_4D;
+ dw_ext1 = dw0 - 2 - 3 * SQUISH_CONSTANT_4D;
+ } else {
+ wsv_ext0 = wsv_ext1 = wsb;
+ dw_ext0 = dw_ext1 = dw0 - 3 * SQUISH_CONSTANT_4D;
+ }
+ }
+ } else { /* One point on each "side" */
+ if (aIsBiggerSide) {
+ c1 = aPoint;
+ c2 = bPoint;
+ } else {
+ c1 = bPoint;
+ c2 = aPoint;
+ }
+
+ /* Two contributions are the bigger-sided point with each 1 replaced with 2. */
+ if ((c1 & 0x01) != 0) {
+ xsv_ext0 = xsb + 2;
+ xsv_ext1 = xsb + 1;
+ dx_ext0 = dx0 - 2 - 3 * SQUISH_CONSTANT_4D;
+ dx_ext1 = dx0 - 1 - 3 * SQUISH_CONSTANT_4D;
+ } else {
+ xsv_ext0 = xsv_ext1 = xsb;
+ dx_ext0 = dx_ext1 = dx0 - 3 * SQUISH_CONSTANT_4D;
+ }
+
+ if ((c1 & 0x02) != 0) {
+ ysv_ext0 = ysv_ext1 = ysb + 1;
+ dy_ext0 = dy_ext1 = dy0 - 1 - 3 * SQUISH_CONSTANT_4D;
+ if ((c1 & 0x01) == 0) {
+ ysv_ext0 += 1;
+ dy_ext0 -= 1;
+ } else {
+ ysv_ext1 += 1;
+ dy_ext1 -= 1;
+ }
+ } else {
+ ysv_ext0 = ysv_ext1 = ysb;
+ dy_ext0 = dy_ext1 = dy0 - 3 * SQUISH_CONSTANT_4D;
+ }
+
+ if ((c1 & 0x04) != 0) {
+ zsv_ext0 = zsv_ext1 = zsb + 1;
+ dz_ext0 = dz_ext1 = dz0 - 1 - 3 * SQUISH_CONSTANT_4D;
+ if ((c1 & 0x03) == 0) {
+ zsv_ext0 += 1;
+ dz_ext0 -= 1;
+ } else {
+ zsv_ext1 += 1;
+ dz_ext1 -= 1;
+ }
+ } else {
+ zsv_ext0 = zsv_ext1 = zsb;
+ dz_ext0 = dz_ext1 = dz0 - 3 * SQUISH_CONSTANT_4D;
+ }
+
+ if ((c1 & 0x08) != 0) {
+ wsv_ext0 = wsb + 1;
+ wsv_ext1 = wsb + 2;
+ dw_ext0 = dw0 - 1 - 3 * SQUISH_CONSTANT_4D;
+ dw_ext1 = dw0 - 2 - 3 * SQUISH_CONSTANT_4D;
+ } else {
+ wsv_ext0 = wsv_ext1 = wsb;
+ dw_ext0 = dw_ext1 = dw0 - 3 * SQUISH_CONSTANT_4D;
+ }
+
+ /* One contribution is a permutation of (1,1,1,-1) based on the smaller-sided point */
+ xsv_ext2 = xsb + 1;
+ ysv_ext2 = ysb + 1;
+ zsv_ext2 = zsb + 1;
+ wsv_ext2 = wsb + 1;
+ dx_ext2 = dx0 - 1 - 2 * SQUISH_CONSTANT_4D;
+ dy_ext2 = dy0 - 1 - 2 * SQUISH_CONSTANT_4D;
+ dz_ext2 = dz0 - 1 - 2 * SQUISH_CONSTANT_4D;
+ dw_ext2 = dw0 - 1 - 2 * SQUISH_CONSTANT_4D;
+ if ((c2 & 0x01) == 0) {
+ xsv_ext2 -= 2;
+ dx_ext2 += 2;
+ } else if ((c2 & 0x02) == 0) {
+ ysv_ext2 -= 2;
+ dy_ext2 += 2;
+ } else if ((c2 & 0x04) == 0) {
+ zsv_ext2 -= 2;
+ dz_ext2 += 2;
+ } else {
+ wsv_ext2 -= 2;
+ dw_ext2 += 2;
+ }
+ }
+
+ /* Contribution (1,1,1,0) */
+ dx4 = dx0 - 1 - 3 * SQUISH_CONSTANT_4D;
+ dy4 = dy0 - 1 - 3 * SQUISH_CONSTANT_4D;
+ dz4 = dz0 - 1 - 3 * SQUISH_CONSTANT_4D;
+ dw4 = dw0 - 3 * SQUISH_CONSTANT_4D;
+ attn4 = 2 - dx4 * dx4 - dy4 * dy4 - dz4 * dz4 - dw4 * dw4;
+ if (attn4 > 0) {
+ attn4 *= attn4;
+ value += attn4 * attn4 * extrapolate4(ctx, xsb + 1, ysb + 1, zsb + 1, wsb + 0, dx4, dy4, dz4, dw4);
+ }
+
+ /* Contribution (1,1,0,1) */
+ dx3 = dx4;
+ dy3 = dy4;
+ dz3 = dz0 - 3 * SQUISH_CONSTANT_4D;
+ dw3 = dw0 - 1 - 3 * SQUISH_CONSTANT_4D;
+ attn3 = 2 - dx3 * dx3 - dy3 * dy3 - dz3 * dz3 - dw3 * dw3;
+ if (attn3 > 0) {
+ attn3 *= attn3;
+ value += attn3 * attn3 * extrapolate4(ctx, xsb + 1, ysb + 1, zsb + 0, wsb + 1, dx3, dy3, dz3, dw3);
+ }
+
+ /* Contribution (1,0,1,1) */
+ dx2 = dx4;
+ dy2 = dy0 - 3 * SQUISH_CONSTANT_4D;
+ dz2 = dz4;
+ dw2 = dw3;
+ attn2 = 2 - dx2 * dx2 - dy2 * dy2 - dz2 * dz2 - dw2 * dw2;
+ if (attn2 > 0) {
+ attn2 *= attn2;
+ value += attn2 * attn2 * extrapolate4(ctx, xsb + 1, ysb + 0, zsb + 1, wsb + 1, dx2, dy2, dz2, dw2);
+ }
+
+ /* Contribution (0,1,1,1) */
+ dx1 = dx0 - 3 * SQUISH_CONSTANT_4D;
+ dz1 = dz4;
+ dy1 = dy4;
+ dw1 = dw3;
+ attn1 = 2 - dx1 * dx1 - dy1 * dy1 - dz1 * dz1 - dw1 * dw1;
+ if (attn1 > 0) {
+ attn1 *= attn1;
+ value += attn1 * attn1 * extrapolate4(ctx, xsb + 0, ysb + 1, zsb + 1, wsb + 1, dx1, dy1, dz1, dw1);
+ }
+
+ /* Contribution (1,1,0,0) */
+ dx5 = dx0 - 1 - 2 * SQUISH_CONSTANT_4D;
+ dy5 = dy0 - 1 - 2 * SQUISH_CONSTANT_4D;
+ dz5 = dz0 - 0 - 2 * SQUISH_CONSTANT_4D;
+ dw5 = dw0 - 0 - 2 * SQUISH_CONSTANT_4D;
+ attn5 = 2 - dx5 * dx5 - dy5 * dy5 - dz5 * dz5 - dw5 * dw5;
+ if (attn5 > 0) {
+ attn5 *= attn5;
+ value += attn5 * attn5 * extrapolate4(ctx, xsb + 1, ysb + 1, zsb + 0, wsb + 0, dx5, dy5, dz5, dw5);
+ }
+
+ /* Contribution (1,0,1,0) */
+ dx6 = dx0 - 1 - 2 * SQUISH_CONSTANT_4D;
+ dy6 = dy0 - 0 - 2 * SQUISH_CONSTANT_4D;
+ dz6 = dz0 - 1 - 2 * SQUISH_CONSTANT_4D;
+ dw6 = dw0 - 0 - 2 * SQUISH_CONSTANT_4D;
+ attn6 = 2 - dx6 * dx6 - dy6 * dy6 - dz6 * dz6 - dw6 * dw6;
+ if (attn6 > 0) {
+ attn6 *= attn6;
+ value += attn6 * attn6 * extrapolate4(ctx, xsb + 1, ysb + 0, zsb + 1, wsb + 0, dx6, dy6, dz6, dw6);
+ }
+
+ /* Contribution (1,0,0,1) */
+ dx7 = dx0 - 1 - 2 * SQUISH_CONSTANT_4D;
+ dy7 = dy0 - 0 - 2 * SQUISH_CONSTANT_4D;
+ dz7 = dz0 - 0 - 2 * SQUISH_CONSTANT_4D;
+ dw7 = dw0 - 1 - 2 * SQUISH_CONSTANT_4D;
+ attn7 = 2 - dx7 * dx7 - dy7 * dy7 - dz7 * dz7 - dw7 * dw7;
+ if (attn7 > 0) {
+ attn7 *= attn7;
+ value += attn7 * attn7 * extrapolate4(ctx, xsb + 1, ysb + 0, zsb + 0, wsb + 1, dx7, dy7, dz7, dw7);
+ }
+
+ /* Contribution (0,1,1,0) */
+ dx8 = dx0 - 0 - 2 * SQUISH_CONSTANT_4D;
+ dy8 = dy0 - 1 - 2 * SQUISH_CONSTANT_4D;
+ dz8 = dz0 - 1 - 2 * SQUISH_CONSTANT_4D;
+ dw8 = dw0 - 0 - 2 * SQUISH_CONSTANT_4D;
+ attn8 = 2 - dx8 * dx8 - dy8 * dy8 - dz8 * dz8 - dw8 * dw8;
+ if (attn8 > 0) {
+ attn8 *= attn8;
+ value += attn8 * attn8 * extrapolate4(ctx, xsb + 0, ysb + 1, zsb + 1, wsb + 0, dx8, dy8, dz8, dw8);
+ }
+
+ /* Contribution (0,1,0,1) */
+ dx9 = dx0 - 0 - 2 * SQUISH_CONSTANT_4D;
+ dy9 = dy0 - 1 - 2 * SQUISH_CONSTANT_4D;
+ dz9 = dz0 - 0 - 2 * SQUISH_CONSTANT_4D;
+ dw9 = dw0 - 1 - 2 * SQUISH_CONSTANT_4D;
+ attn9 = 2 - dx9 * dx9 - dy9 * dy9 - dz9 * dz9 - dw9 * dw9;
+ if (attn9 > 0) {
+ attn9 *= attn9;
+ value += attn9 * attn9 * extrapolate4(ctx, xsb + 0, ysb + 1, zsb + 0, wsb + 1, dx9, dy9, dz9, dw9);
+ }
+
+ /* Contribution (0,0,1,1) */
+ dx10 = dx0 - 0 - 2 * SQUISH_CONSTANT_4D;
+ dy10 = dy0 - 0 - 2 * SQUISH_CONSTANT_4D;
+ dz10 = dz0 - 1 - 2 * SQUISH_CONSTANT_4D;
+ dw10 = dw0 - 1 - 2 * SQUISH_CONSTANT_4D;
+ attn10 = 2 - dx10 * dx10 - dy10 * dy10 - dz10 * dz10 - dw10 * dw10;
+ if (attn10 > 0) {
+ attn10 *= attn10;
+ value += attn10 * attn10 * extrapolate4(ctx, xsb + 0, ysb + 0, zsb + 1, wsb + 1, dx10, dy10, dz10, dw10);
+ }
+ }
+
+ /* First extra vertex */
+ attn_ext0 = 2 - dx_ext0 * dx_ext0 - dy_ext0 * dy_ext0 - dz_ext0 * dz_ext0 - dw_ext0 * dw_ext0;
+ if (attn_ext0 > 0)
+ {
+ attn_ext0 *= attn_ext0;
+ value += attn_ext0 * attn_ext0 * extrapolate4(ctx, xsv_ext0, ysv_ext0, zsv_ext0, wsv_ext0, dx_ext0, dy_ext0, dz_ext0, dw_ext0);
+ }
+
+ /* Second extra vertex */
+ attn_ext1 = 2 - dx_ext1 * dx_ext1 - dy_ext1 * dy_ext1 - dz_ext1 * dz_ext1 - dw_ext1 * dw_ext1;
+ if (attn_ext1 > 0)
+ {
+ attn_ext1 *= attn_ext1;
+ value += attn_ext1 * attn_ext1 * extrapolate4(ctx, xsv_ext1, ysv_ext1, zsv_ext1, wsv_ext1, dx_ext1, dy_ext1, dz_ext1, dw_ext1);
+ }
+
+ /* Third extra vertex */
+ attn_ext2 = 2 - dx_ext2 * dx_ext2 - dy_ext2 * dy_ext2 - dz_ext2 * dz_ext2 - dw_ext2 * dw_ext2;
+ if (attn_ext2 > 0)
+ {
+ attn_ext2 *= attn_ext2;
+ value += attn_ext2 * attn_ext2 * extrapolate4(ctx, xsv_ext2, ysv_ext2, zsv_ext2, wsv_ext2, dx_ext2, dy_ext2, dz_ext2, dw_ext2);
+ }
+
+ return value / NORM_CONSTANT_4D;
+}
+
diff --git a/thirdparty/misc/open-simplex-noise.h b/thirdparty/misc/open-simplex-noise.h
new file mode 100644
index 0000000000..89e0df8218
--- /dev/null
+++ b/thirdparty/misc/open-simplex-noise.h
@@ -0,0 +1,58 @@
+#ifndef OPEN_SIMPLEX_NOISE_H__
+#define OPEN_SIMPLEX_NOISE_H__
+
+/*
+ * OpenSimplex (Simplectic) Noise in C.
+ * Ported to C from Kurt Spencer's java implementation by Stephen M. Cameron
+ *
+ * v1.1 (October 6, 2014)
+ * - Ported to C
+ *
+ * v1.1 (October 5, 2014)
+ * - Added 2D and 4D implementations.
+ * - Proper gradient sets for all dimensions, from a
+ * dimensionally-generalizable scheme with an actual
+ * rhyme and reason behind it.
+ * - Removed default permutation array in favor of
+ * default seed.
+ * - Changed seed-based constructor to be independent
+ * of any particular randomization library, so results
+ * will be the same when ported to other languages.
+ */
+
+#if ((__GNUC_STDC_INLINE__) || (__STDC_VERSION__ >= 199901L))
+ #include <stdint.h>
+ #define INLINE inline
+#elif (defined (_MSC_VER) || defined (__GNUC_GNU_INLINE__))
+ #include <stdint.h>
+ #define INLINE __inline
+#else
+ /* ANSI C doesn't have inline or stdint.h. */
+ #define INLINE
+#endif
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+// -- GODOT start --
+// Modified to work without allocating memory, also removed some unused function.
+
+struct osn_context {
+ int16_t perm[256];
+ int16_t permGradIndex3D[256];
+};
+
+int open_simplex_noise(int64_t seed, struct osn_context *ctx);
+//int open_simplex_noise_init_perm(struct osn_context *ctx, int16_t p[], int nelements);
+// -- GODOT end --
+void open_simplex_noise_free(struct osn_context *ctx);
+double open_simplex_noise2(struct osn_context *ctx, double x, double y);
+double open_simplex_noise3(struct osn_context *ctx, double x, double y, double z);
+double open_simplex_noise4(struct osn_context *ctx, double x, double y, double z, double w);
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
diff --git a/thirdparty/misc/pcg.h b/thirdparty/misc/pcg.h
index 81f4c9770e..e2d66d51d5 100644
--- a/thirdparty/misc/pcg.h
+++ b/thirdparty/misc/pcg.h
@@ -4,7 +4,7 @@
#ifndef RANDOM_H
#define RANDOM_H
-#include "typedefs.h"
+#include "core/typedefs.h"
#define PCG_DEFAULT_INC_64 1442695040888963407ULL
diff --git a/thirdparty/misc/stb_vorbis.h b/thirdparty/misc/stb_vorbis.h
new file mode 100644
index 0000000000..357efcd5fc
--- /dev/null
+++ b/thirdparty/misc/stb_vorbis.h
@@ -0,0 +1,2 @@
+#define STB_VORBIS_HEADER_ONLY
+#include "stb_vorbis.c"
diff --git a/thirdparty/misc/triangulator.h b/thirdparty/misc/triangulator.h
index b6dd7e8236..c85792fd50 100644
--- a/thirdparty/misc/triangulator.h
+++ b/thirdparty/misc/triangulator.h
@@ -21,11 +21,11 @@
#ifndef TRIANGULATOR_H
#define TRIANGULATOR_H
-#include "math_2d.h"
-#include "list.h"
-#include "set.h"
-//2D point structure
+#include "core/list.h"
+#include "core/math/vector2.h"
+#include "core/set.h"
+//2D point structure
#define TRIANGULATOR_CCW 1
#define TRIANGULATOR_CW -1
diff --git a/thirdparty/misc/yuv2rgb.h b/thirdparty/misc/yuv2rgb.h
index d0c2813a75..3ec8388246 100644
--- a/thirdparty/misc/yuv2rgb.h
+++ b/thirdparty/misc/yuv2rgb.h
@@ -27,7 +27,7 @@ ship it.
#ifndef YUV2RGB_H
#define YUV2RGB_H
-#include "typedefs.h"
+#include "core/typedefs.h"
static const uint32_t tables[256*3] = {
/* y_table */
diff --git a/thirdparty/pvrtccompressor/BitScale.h b/thirdparty/pvrtccompressor/BitScale.h
index 36613aeeee..3ea7962f55 100644
--- a/thirdparty/pvrtccompressor/BitScale.h
+++ b/thirdparty/pvrtccompressor/BitScale.h
@@ -2,7 +2,7 @@
#pragma once
-#include "typedefs.h"
+#include "core/typedefs.h"
//============================================================================
diff --git a/thirdparty/squish/Add-Decompress-Bc5-to-Squish.patch b/thirdparty/squish/Add-Decompress-Bc5-to-Squish.patch
deleted file mode 100644
index 1e06a8d318..0000000000
--- a/thirdparty/squish/Add-Decompress-Bc5-to-Squish.patch
+++ /dev/null
@@ -1,143 +0,0 @@
-From 7b64cc4c8b0be0443741483bf65909f5140179c0 Mon Sep 17 00:00:00 2001
-From: Orkun <orkuntezerm@gmail.com>
-Date: Sun, 19 Nov 2017 02:24:31 +0300
-Subject: [PATCH] Fix #12220: Add Decompress Bc5 to Squish
-
-This Commit fixes the corrupted file preview described in #12220.
-Added DecompressColourBc5 function to squish.
----
- thirdparty/squish/colourblock.cpp | 85 +++++++++++++++++++++++++++++++++++++++
- thirdparty/squish/colourblock.h | 3 ++
- thirdparty/squish/squish.cpp | 8 +++-
- 3 files changed, 95 insertions(+), 1 deletion(-)
-
-diff --git a/thirdparty/squish/colourblock.cpp b/thirdparty/squish/colourblock.cpp
-index af8b98036..3de46382c 100644
---- a/thirdparty/squish/colourblock.cpp
-+++ b/thirdparty/squish/colourblock.cpp
-@@ -211,4 +211,89 @@ void DecompressColour( u8* rgba, void const* block, bool isDxt1 )
- }
- }
-
-+// -- Godot start --
-+void DecompressColourBc5( u8* rgba, void const* block)
-+{
-+ // get the block bytes
-+ u8 const* bytes = reinterpret_cast< u8 const* >( block );
-+
-+ // unpack the endpoints
-+ u8 codes[16];
-+ int red_0 = bytes[0];
-+ int red_1 = bytes[1];
-+
-+ codes[0] = red_0;
-+ codes[1] = red_1;
-+ codes[6] = 0.0f;
-+ codes[7] = 1.0f;
-+ // generate the midpoints
-+ if(red_0 > red_1)
-+ {
-+ for( int i = 2; i < 8; ++i )
-+ {
-+ codes[i] = ((8-i)*red_0 + (i-1)*red_1)/7;
-+ }
-+ }
-+ else
-+ {
-+ for( int i = 2; i < 6; ++i )
-+ {
-+ codes[i] = ((6-i)*red_0 + (i-1)*red_1)/5;
-+ }
-+ }
-+
-+ int green_0 = bytes[8];
-+ int green_1 = bytes[9];
-+
-+ codes[0 + 8] = green_0;
-+ codes[1 + 8] = green_1;
-+ codes[6 + 8] = 0.0f;
-+ codes[7 + 8] = 1.0f;
-+ // generate the midpoints
-+ if(green_0 > green_1)
-+ {
-+ for( int i = 2; i < 8; ++i )
-+ {
-+ codes[i + 8] = ((8-i)*green_0 + (i-1)*green_1)/7;
-+ }
-+ }
-+ else
-+ {
-+ for( int i = 2; i < 6; ++i )
-+ {
-+ codes[i + 8] = ((6-i)*green_0 + (i-1)*green_1)/5;
-+ }
-+ }
-+
-+ u8 indices[32];
-+ for( int i = 0; i < 4; ++i )
-+ {
-+ u8 packed = bytes[2 + i];
-+ u8* red_ind = indices + 4*i;
-+
-+ red_ind[0] = packed & 0x3;
-+ red_ind[1] = ( packed >> 2 ) & 0x3;
-+ red_ind[2] = ( packed >> 4 ) & 0x3;
-+ red_ind[3] = ( packed >> 6 ) & 0x3;
-+
-+ packed = bytes[8 + i];
-+ u8* green_ind = indices + 4*i + 16;
-+ green_ind[0] = packed & 0x3;
-+ green_ind[1] = ( packed >> 2 ) & 0x3;
-+ green_ind[2] = ( packed >> 4 ) & 0x3;
-+ green_ind[3] = ( packed >> 6 ) & 0x3;
-+ }
-+
-+ // store out the colours
-+ for( int i = 0; i < 16; ++i )
-+ {
-+ rgba[4*i] = codes[indices[i]];
-+ rgba[4*i +1] = codes[indices[i + 16] + 8];
-+ rgba[4*i +2] = 0;
-+ rgba[4*i +3] = 255;
-+ }
-+}
-+// -- GODOT end --
-+
-+
- } // namespace squish
-diff --git a/thirdparty/squish/colourblock.h b/thirdparty/squish/colourblock.h
-index fee2cd7c5..3cb9b7e3b 100644
---- a/thirdparty/squish/colourblock.h
-+++ b/thirdparty/squish/colourblock.h
-@@ -35,6 +35,9 @@ void WriteColourBlock3( Vec3::Arg start, Vec3::Arg end, u8 const* indices, void*
- void WriteColourBlock4( Vec3::Arg start, Vec3::Arg end, u8 const* indices, void* block );
-
- void DecompressColour( u8* rgba, void const* block, bool isDxt1 );
-+// -- GODOT start --
-+void DecompressColourBc5( u8* rgba, void const* block );
-+// -- GODOT end --
-
- } // namespace squish
-
-diff --git a/thirdparty/squish/squish.cpp b/thirdparty/squish/squish.cpp
-index 1d22a64ad..fd11a147d 100644
---- a/thirdparty/squish/squish.cpp
-+++ b/thirdparty/squish/squish.cpp
-@@ -135,7 +135,13 @@ void Decompress( u8* rgba, void const* block, int flags )
- colourBlock = reinterpret_cast< u8 const* >( block ) + 8;
-
- // decompress colour
-- DecompressColour( rgba, colourBlock, ( flags & kDxt1 ) != 0 );
-+ // -- GODOT start --
-+ //DecompressColour( rgba, colourBlock, ( flags & kDxt1 ) != 0 );
-+ if(( flags & ( kBc5 ) ) != 0)
-+ DecompressColourBc5( rgba, colourBlock);
-+ else
-+ DecompressColour( rgba, colourBlock, ( flags & kDxt1 ) != 0 );
-+ // -- GODOT end --
-
- // decompress alpha separately if necessary
- if( ( flags & kDxt3 ) != 0 )
---
-2.13.6
-
diff --git a/thirdparty/squish/colourblock.cpp b/thirdparty/squish/colourblock.cpp
index 3de46382c0..3d87adaa77 100644
--- a/thirdparty/squish/colourblock.cpp
+++ b/thirdparty/squish/colourblock.cpp
@@ -24,6 +24,9 @@
-------------------------------------------------------------------------- */
#include "colourblock.h"
+// -- Godot start --
+#include "alpha.h"
+// -- Godot end --
namespace squish {
@@ -214,83 +217,17 @@ void DecompressColour( u8* rgba, void const* block, bool isDxt1 )
// -- Godot start --
void DecompressColourBc5( u8* rgba, void const* block)
{
- // get the block bytes
- u8 const* bytes = reinterpret_cast< u8 const* >( block );
-
- // unpack the endpoints
- u8 codes[16];
- int red_0 = bytes[0];
- int red_1 = bytes[1];
-
- codes[0] = red_0;
- codes[1] = red_1;
- codes[6] = 0.0f;
- codes[7] = 1.0f;
- // generate the midpoints
- if(red_0 > red_1)
- {
- for( int i = 2; i < 8; ++i )
- {
- codes[i] = ((8-i)*red_0 + (i-1)*red_1)/7;
- }
- }
- else
- {
- for( int i = 2; i < 6; ++i )
- {
- codes[i] = ((6-i)*red_0 + (i-1)*red_1)/5;
- }
- }
-
- int green_0 = bytes[8];
- int green_1 = bytes[9];
-
- codes[0 + 8] = green_0;
- codes[1 + 8] = green_1;
- codes[6 + 8] = 0.0f;
- codes[7 + 8] = 1.0f;
- // generate the midpoints
- if(green_0 > green_1)
- {
- for( int i = 2; i < 8; ++i )
- {
- codes[i + 8] = ((8-i)*green_0 + (i-1)*green_1)/7;
- }
- }
- else
- {
- for( int i = 2; i < 6; ++i )
- {
- codes[i + 8] = ((6-i)*green_0 + (i-1)*green_1)/5;
- }
- }
-
- u8 indices[32];
- for( int i = 0; i < 4; ++i )
- {
- u8 packed = bytes[2 + i];
- u8* red_ind = indices + 4*i;
-
- red_ind[0] = packed & 0x3;
- red_ind[1] = ( packed >> 2 ) & 0x3;
- red_ind[2] = ( packed >> 4 ) & 0x3;
- red_ind[3] = ( packed >> 6 ) & 0x3;
-
- packed = bytes[8 + i];
- u8* green_ind = indices + 4*i + 16;
- green_ind[0] = packed & 0x3;
- green_ind[1] = ( packed >> 2 ) & 0x3;
- green_ind[2] = ( packed >> 4 ) & 0x3;
- green_ind[3] = ( packed >> 6 ) & 0x3;
+ void const* rblock = block;
+ void const* gblock = reinterpret_cast< u8 const* >( block ) + 8;
+ DecompressAlphaDxt5(rgba,rblock);
+ for ( int i = 0; i < 16; ++i ) {
+ rgba[i*4] = rgba[i*4 + 3];
}
-
- // store out the colours
- for( int i = 0; i < 16; ++i )
- {
- rgba[4*i] = codes[indices[i]];
- rgba[4*i +1] = codes[indices[i + 16] + 8];
- rgba[4*i +2] = 0;
- rgba[4*i +3] = 255;
+ DecompressAlphaDxt5(rgba,gblock);
+ for ( int i = 0; i < 16; ++i ) {
+ rgba[i*4+1] = rgba[i*4 + 3];
+ rgba[i*4 + 2] = 0;
+ rgba[i*4 + 3] = 255;
}
}
// -- GODOT end --
diff --git a/thirdparty/squish/config.h b/thirdparty/squish/config.h
index 92edefe966..05f8d72598 100644
--- a/thirdparty/squish/config.h
+++ b/thirdparty/squish/config.h
@@ -32,6 +32,26 @@
#endif
// Set to 1 or 2 when building squish to use SSE or SSE2 instructions.
+// -- GODOT start --
+#ifdef _MSC_VER
+ #if defined(_M_IX86_FP)
+ #if _M_IX86_FP >= 2
+ #define SQUISH_USE_SSE 2
+ #elif _M_IX86_FP >= 1
+ #define SQUISH_USE_SSE 1
+ #endif
+ #elif defined(_M_X64)
+ #define SQUISH_USE_SSE 2
+ #endif
+#else
+ #if defined(__SSE2__)
+ #define SQUISH_USE_SSE 2
+ #elif defined(__SSE__)
+ #define SQUISH_USE_SSE 1
+ #endif
+#endif
+// -- GODOT end --
+
#ifndef SQUISH_USE_SSE
#define SQUISH_USE_SSE 0
#endif
diff --git a/thirdparty/squish/godot-changes.patch b/thirdparty/squish/godot-changes.patch
new file mode 100644
index 0000000000..ef7bafb4b4
--- /dev/null
+++ b/thirdparty/squish/godot-changes.patch
@@ -0,0 +1,102 @@
+diff --git a/thirdparty/squish/colourblock.cpp b/thirdparty/squish/colourblock.cpp
+index af8b98036..3d87adaa7 100644
+--- a/thirdparty/squish/colourblock.cpp
++++ b/thirdparty/squish/colourblock.cpp
+@@ -24,6 +24,9 @@
+ -------------------------------------------------------------------------- */
+
+ #include "colourblock.h"
++// -- Godot start --
++#include "alpha.h"
++// -- Godot end --
+
+ namespace squish {
+
+@@ -211,4 +214,23 @@ void DecompressColour( u8* rgba, void const* block, bool isDxt1 )
+ }
+ }
+
++// -- Godot start --
++void DecompressColourBc5( u8* rgba, void const* block)
++{
++ void const* rblock = block;
++ void const* gblock = reinterpret_cast< u8 const* >( block ) + 8;
++ DecompressAlphaDxt5(rgba,rblock);
++ for ( int i = 0; i < 16; ++i ) {
++ rgba[i*4] = rgba[i*4 + 3];
++ }
++ DecompressAlphaDxt5(rgba,gblock);
++ for ( int i = 0; i < 16; ++i ) {
++ rgba[i*4+1] = rgba[i*4 + 3];
++ rgba[i*4 + 2] = 0;
++ rgba[i*4 + 3] = 255;
++ }
++}
++// -- GODOT end --
++
++
+ } // namespace squish
+diff --git a/thirdparty/squish/colourblock.h b/thirdparty/squish/colourblock.h
+index fee2cd7c5..3cb9b7e3b 100644
+--- a/thirdparty/squish/colourblock.h
++++ b/thirdparty/squish/colourblock.h
+@@ -35,6 +35,9 @@ void WriteColourBlock3( Vec3::Arg start, Vec3::Arg end, u8 const* indices, void*
+ void WriteColourBlock4( Vec3::Arg start, Vec3::Arg end, u8 const* indices, void* block );
+
+ void DecompressColour( u8* rgba, void const* block, bool isDxt1 );
++// -- GODOT start --
++void DecompressColourBc5( u8* rgba, void const* block );
++// -- GODOT end --
+
+ } // namespace squish
+
+diff --git a/thirdparty/squish/config.h b/thirdparty/squish/config.h
+index 92edefe96..05f8d7259 100644
+--- a/thirdparty/squish/config.h
++++ b/thirdparty/squish/config.h
+@@ -32,6 +32,26 @@
+ #endif
+
+ // Set to 1 or 2 when building squish to use SSE or SSE2 instructions.
++// -- GODOT start --
++#ifdef _MSC_VER
++ #if defined(_M_IX86_FP)
++ #if _M_IX86_FP >= 2
++ #define SQUISH_USE_SSE 2
++ #elif _M_IX86_FP >= 1
++ #define SQUISH_USE_SSE 1
++ #endif
++ #elif defined(_M_X64)
++ #define SQUISH_USE_SSE 2
++ #endif
++#else
++ #if defined(__SSE2__)
++ #define SQUISH_USE_SSE 2
++ #elif defined(__SSE__)
++ #define SQUISH_USE_SSE 1
++ #endif
++#endif
++// -- GODOT end --
++
+ #ifndef SQUISH_USE_SSE
+ #define SQUISH_USE_SSE 0
+ #endif
+diff --git a/thirdparty/squish/squish.cpp b/thirdparty/squish/squish.cpp
+index 1d22a64ad..fd11a147d 100644
+--- a/thirdparty/squish/squish.cpp
++++ b/thirdparty/squish/squish.cpp
+@@ -135,7 +135,13 @@ void Decompress( u8* rgba, void const* block, int flags )
+ colourBlock = reinterpret_cast< u8 const* >( block ) + 8;
+
+ // decompress colour
+- DecompressColour( rgba, colourBlock, ( flags & kDxt1 ) != 0 );
++ // -- GODOT start --
++ //DecompressColour( rgba, colourBlock, ( flags & kDxt1 ) != 0 );
++ if(( flags & ( kBc5 ) ) != 0)
++ DecompressColourBc5( rgba, colourBlock);
++ else
++ DecompressColour( rgba, colourBlock, ( flags & kDxt1 ) != 0 );
++ // -- GODOT end --
+
+ // decompress alpha separately if necessary
+ if( ( flags & kDxt3 ) != 0 )
diff --git a/thirdparty/thekla_atlas/nvcore/nvcore.h b/thirdparty/thekla_atlas/nvcore/nvcore.h
index a3deb66be2..5ef69668d9 100644
--- a/thirdparty/thekla_atlas/nvcore/nvcore.h
+++ b/thirdparty/thekla_atlas/nvcore/nvcore.h
@@ -44,6 +44,9 @@
#elif defined POSH_OS_FREEBSD
# define NV_OS_FREEBSD 1
# define NV_OS_UNIX 1
+#elif defined POSH_OS_HAIKU
+# define NV_OS_HAIKU 1
+# define NV_OS_UNIX 1
#elif defined POSH_OS_OPENBSD
# define NV_OS_OPENBSD 1
# define NV_OS_UNIX 1
@@ -341,7 +344,7 @@ template <typename T, size_t N> char (&ArraySizeHelper(T (&array)[N]))[N];
#elif NV_CC_GNUC
# if NV_OS_LINUX
# include "DefsGnucLinux.h"
-# elif NV_OS_DARWIN || NV_OS_FREEBSD || NV_OS_OPENBSD
+# elif NV_OS_DARWIN || NV_OS_FREEBSD || NV_OS_OPENBSD || NV_OS_HAIKU
# include "DefsGnucDarwin.h"
# elif NV_OS_ORBIS
# include "DefsOrbis.h"
diff --git a/thirdparty/thekla_atlas/nvmath/nvmath.h b/thirdparty/thekla_atlas/nvmath/nvmath.h
index f2b69426e1..a697f9293d 100644
--- a/thirdparty/thekla_atlas/nvmath/nvmath.h
+++ b/thirdparty/thekla_atlas/nvmath/nvmath.h
@@ -181,10 +181,8 @@ namespace nv
{
#if NV_OS_WIN32 || NV_OS_XBOX || NV_OS_DURANGO
return _finite(f) != 0;
-#elif NV_OS_DARWIN || NV_OS_FREEBSD || NV_OS_OPENBSD || NV_OS_ORBIS
+#elif NV_OS_DARWIN || NV_OS_FREEBSD || NV_OS_OPENBSD || NV_OS_ORBIS || NV_OS_LINUX
return isfinite(f);
-#elif NV_OS_LINUX
- return finitef(f);
#else
# error "isFinite not supported"
#endif
@@ -196,10 +194,8 @@ namespace nv
{
#if NV_OS_WIN32 || NV_OS_XBOX || NV_OS_DURANGO
return _isnan(f) != 0;
-#elif NV_OS_DARWIN || NV_OS_FREEBSD || NV_OS_OPENBSD || NV_OS_ORBIS
+#elif NV_OS_DARWIN || NV_OS_FREEBSD || NV_OS_OPENBSD || NV_OS_ORBIS || NV_OS_LINUX
return isnan(f);
-#elif NV_OS_LINUX
- return isnanf(f);
#else
# error "isNan not supported"
#endif
diff --git a/thirdparty/thekla_atlas/poshlib/posh.h b/thirdparty/thekla_atlas/poshlib/posh.h
index 3038297b39..72acd20ce0 100644
--- a/thirdparty/thekla_atlas/poshlib/posh.h
+++ b/thirdparty/thekla_atlas/poshlib/posh.h
@@ -298,6 +298,11 @@ Metrowerks:
# define POSH_OS_STRING "Linux"
#endif
+#if defined __HAIKU__
+# define POSH_OS_HAIKU 1
+# define POSH_OS_STRING "Haiku"
+#endif
+
#if defined __FreeBSD__
# define POSH_OS_FREEBSD 1
# define POSH_OS_STRING "FreeBSD"
diff --git a/thirdparty/tinyexr/tinyexr.h b/thirdparty/tinyexr/tinyexr.h
index 107c22ffb3..b3a7ee00c2 100644
--- a/thirdparty/tinyexr/tinyexr.h
+++ b/thirdparty/tinyexr/tinyexr.h
@@ -1,5 +1,5 @@
/*
-Copyright (c) 2014 - 2017, Syoyo Fujita
+Copyright (c) 2014 - 2018, Syoyo Fujita and many contributors.
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -115,6 +115,9 @@ extern "C" {
#define TINYEXR_ERROR_CANT_OPEN_FILE (-6)
#define TINYEXR_ERROR_UNSUPPORTED_FORMAT (-7)
#define TINYEXR_ERROR_INVALID_HEADER (-8)
+#define TINYEXR_ERROR_UNSUPPORTED_FEATURE (-9)
+#define TINYEXR_ERROR_CANT_WRITE_FILE (-10)
+#define TINYEXR_ERROR_SERIALZATION_FAILED (-11)
// @note { OpenEXR file format: http://www.openexr.com/openexrfilelayout.pdf }
@@ -123,7 +126,8 @@ extern "C" {
#define TINYEXR_PIXELTYPE_HALF (1)
#define TINYEXR_PIXELTYPE_FLOAT (2)
-#define TINYEXR_MAX_ATTRIBUTES (128)
+#define TINYEXR_MAX_HEADER_ATTRIBUTES (1024)
+#define TINYEXR_MAX_CUSTOM_ATTRIBUTES (128)
#define TINYEXR_COMPRESSIONTYPE_NONE (0)
#define TINYEXR_COMPRESSIONTYPE_RLE (1)
@@ -205,7 +209,8 @@ typedef struct _EXRHeader {
// Custom attributes(exludes required attributes(e.g. `channels`,
// `compression`, etc)
int num_custom_attributes;
- EXRAttribute custom_attributes[TINYEXR_MAX_ATTRIBUTES];
+ EXRAttribute *custom_attributes; // array of EXRAttribute. size =
+ // `num_custom_attributes`.
EXRChannelInfo *channels; // [num_channels]
@@ -276,9 +281,12 @@ extern int LoadEXR(float **out_rgba, int *width, int *height,
// Save image as fp16(HALF) format when `save_as_fp16` is positive non-zero
// value.
// Save image as fp32(FLOAT) format when `save_as_fp16` is 0.
+// Use ZIP compression by default.
+// Returns negative value and may set error string in `err` when there's an
+// error
extern int SaveEXR(const float *data, const int width, const int height,
const int components, const int save_as_fp16,
- const char *filename);
+ const char *filename, const char **err);
// Initialize EXRHeader struct
extern void InitEXRHeader(EXRHeader *exr_header);
@@ -292,6 +300,9 @@ extern int FreeEXRHeader(EXRHeader *exr_header);
// Free's internal data of EXRImage struct
extern int FreeEXRImage(EXRImage *exr_image);
+// Free's error message
+extern void FreeEXRErrorMessage(const char *msg);
+
// Parse EXR version header of a file.
extern int ParseEXRVersionFromFile(EXRVersion *version, const char *filename);
@@ -300,10 +311,14 @@ extern int ParseEXRVersionFromMemory(EXRVersion *version,
const unsigned char *memory, size_t size);
// Parse single-part OpenEXR header from a file and initialize `EXRHeader`.
+// When there was an error message, Application must free `err` with
+// FreeEXRErrorMessage()
extern int ParseEXRHeaderFromFile(EXRHeader *header, const EXRVersion *version,
const char *filename, const char **err);
// Parse single-part OpenEXR header from a memory and initialize `EXRHeader`.
+// When there was an error message, Application must free `err` with
+// FreeEXRErrorMessage()
extern int ParseEXRHeaderFromMemory(EXRHeader *header,
const EXRVersion *version,
const unsigned char *memory, size_t size,
@@ -311,6 +326,8 @@ extern int ParseEXRHeaderFromMemory(EXRHeader *header,
// Parse multi-part OpenEXR headers from a file and initialize `EXRHeader*`
// array.
+// When there was an error message, Application must free `err` with
+// FreeEXRErrorMessage()
extern int ParseEXRMultipartHeaderFromFile(EXRHeader ***headers,
int *num_headers,
const EXRVersion *version,
@@ -319,6 +336,8 @@ extern int ParseEXRMultipartHeaderFromFile(EXRHeader ***headers,
// Parse multi-part OpenEXR headers from a memory and initialize `EXRHeader*`
// array
+// When there was an error message, Application must free `err` with
+// FreeEXRErrorMessage()
extern int ParseEXRMultipartHeaderFromMemory(EXRHeader ***headers,
int *num_headers,
const EXRVersion *version,
@@ -330,6 +349,8 @@ extern int ParseEXRMultipartHeaderFromMemory(EXRHeader ***headers,
// Application can free EXRImage using `FreeEXRImage`
// Returns negative value and may set error string in `err` when there's an
// error
+// When there was an error message, Application must free `err` with
+// FreeEXRErrorMessage()
extern int LoadEXRImageFromFile(EXRImage *image, const EXRHeader *header,
const char *filename, const char **err);
@@ -339,6 +360,8 @@ extern int LoadEXRImageFromFile(EXRImage *image, const EXRHeader *header,
// Application can free EXRImage using `FreeEXRImage`
// Returns negative value and may set error string in `err` when there's an
// error
+// When there was an error message, Application must free `err` with
+// FreeEXRErrorMessage()
extern int LoadEXRImageFromMemory(EXRImage *image, const EXRHeader *header,
const unsigned char *memory,
const size_t size, const char **err);
@@ -349,6 +372,8 @@ extern int LoadEXRImageFromMemory(EXRImage *image, const EXRHeader *header,
// Application can free EXRImage using `FreeEXRImage`
// Returns negative value and may set error string in `err` when there's an
// error
+// When there was an error message, Application must free `err` with
+// FreeEXRErrorMessage()
extern int LoadEXRMultipartImageFromFile(EXRImage *images,
const EXRHeader **headers,
unsigned int num_parts,
@@ -361,6 +386,8 @@ extern int LoadEXRMultipartImageFromFile(EXRImage *images,
// Application can free EXRImage using `FreeEXRImage`
// Returns negative value and may set error string in `err` when there's an
// error
+// When there was an error message, Application must free `err` with
+// FreeEXRErrorMessage()
extern int LoadEXRMultipartImageFromMemory(EXRImage *images,
const EXRHeader **headers,
unsigned int num_parts,
@@ -370,15 +397,19 @@ extern int LoadEXRMultipartImageFromMemory(EXRImage *images,
// Saves multi-channel, single-frame OpenEXR image to a file.
// Returns negative value and may set error string in `err` when there's an
// error
+// When there was an error message, Application must free `err` with
+// FreeEXRErrorMessage()
extern int SaveEXRImageToFile(const EXRImage *image,
const EXRHeader *exr_header, const char *filename,
const char **err);
// Saves multi-channel, single-frame OpenEXR image to a memory.
// Image is compressed using EXRImage.compression value.
-// Return the number of bytes if succes.
-// Returns negative value and may set error string in `err` when there's an
-// error
+// Return the number of bytes if success.
+// Return zero and will set error string in `err` when there's an
+// error.
+// When there was an error message, Application must free `err` with
+// FreeEXRErrorMessage()
extern size_t SaveEXRImageToMemory(const EXRImage *image,
const EXRHeader *exr_header,
unsigned char **memory, const char **err);
@@ -387,6 +418,8 @@ extern size_t SaveEXRImageToMemory(const EXRImage *image,
// Application must free memory of variables in DeepImage(image, offset_table)
// Returns negative value and may set error string in `err` when there's an
// error
+// When there was an error message, Application must free `err` with
+// FreeEXRErrorMessage()
extern int LoadDeepEXR(DeepImage *out_image, const char *filename,
const char **err);
@@ -409,6 +442,8 @@ extern int LoadDeepEXR(DeepImage *out_image, const char *filename,
// RGB(A) channels.
// Returns negative value and may set error string in `err` when there's an
// error
+// When there was an error message, Application must free `err` with
+// FreeEXRErrorMessage()
extern int LoadEXRFromMemory(float **out_rgba, int *width, int *height,
const unsigned char *memory, size_t size,
const char **err);
@@ -428,8 +463,10 @@ extern int LoadEXRFromMemory(float **out_rgba, int *width, int *height,
#include <cstdio>
#include <cstdlib>
#include <cstring>
+#include <iostream>
#include <sstream>
+#include <limits>
#include <string>
#include <vector>
@@ -486,15 +523,29 @@ namespace miniz {
#pragma clang diagnostic ignored "-Wc++11-extensions"
#pragma clang diagnostic ignored "-Wconversion"
#pragma clang diagnostic ignored "-Wunused-function"
+#pragma clang diagnostic ignored "-Wc++98-compat-pedantic"
+#pragma clang diagnostic ignored "-Wundef"
+
#if __has_warning("-Wcomma")
#pragma clang diagnostic ignored "-Wcomma"
#endif
+
#if __has_warning("-Wmacro-redefined")
#pragma clang diagnostic ignored "-Wmacro-redefined"
#endif
+
#if __has_warning("-Wcast-qual")
#pragma clang diagnostic ignored "-Wcast-qual"
#endif
+
+#if __has_warning("-Wzero-as-null-pointer-constant")
+#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"
+#endif
+
+#if __has_warning("-Wtautological-constant-compare")
+#pragma clang diagnostic ignored "-Wtautological-constant-compare"
+#endif
+
#endif
/* miniz.c v1.15 - public domain deflate/inflate, zlib-subset, ZIP
@@ -2900,9 +2951,8 @@ void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len,
tinfl_status status = tinfl_decompress(
&decomp, (const mz_uint8 *)pSrc_buf + src_buf_ofs, &src_buf_size,
(mz_uint8 *)pBuf, pBuf ? (mz_uint8 *)pBuf + *pOut_len : NULL,
- &dst_buf_size,
- (flags & ~TINFL_FLAG_HAS_MORE_INPUT) |
- TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF);
+ &dst_buf_size, (flags & ~TINFL_FLAG_HAS_MORE_INPUT) |
+ TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF);
if ((status < 0) || (status == TINFL_STATUS_NEEDS_MORE_INPUT)) {
MZ_FREE(pBuf);
*pOut_len = 0;
@@ -3549,10 +3599,9 @@ static int tdefl_flush_block(tdefl_compressor *d, int flush) {
mz_uint saved_bit_buf, saved_bits_in;
mz_uint8 *pSaved_output_buf;
mz_bool comp_block_succeeded = MZ_FALSE;
- int n,
- use_raw_block =
- ((d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS) != 0) &&
- (d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size;
+ int n, use_raw_block =
+ ((d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS) != 0) &&
+ (d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size;
mz_uint8 *pOutput_buf_start =
((d->m_pPut_buf_func == NULL) &&
((*d->m_pOut_buf_size - d->m_out_buf_ofs) >= TDEFL_OUT_BUF_SIZE))
@@ -3582,9 +3631,8 @@ static int tdefl_flush_block(tdefl_compressor *d, int flush) {
if (!use_raw_block)
comp_block_succeeded =
- tdefl_compress_block(d,
- (d->m_flags & TDEFL_FORCE_ALL_STATIC_BLOCKS) ||
- (d->m_total_lz_bytes < 48));
+ tdefl_compress_block(d, (d->m_flags & TDEFL_FORCE_ALL_STATIC_BLOCKS) ||
+ (d->m_total_lz_bytes < 48));
// If the block gets expanded, forget the current contents of the output
// buffer and send a raw block instead.
@@ -4388,9 +4436,8 @@ mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits,
// C and C99, so no big deal)
#pragma warning(disable : 4244) // 'initializing': conversion from '__int64' to
// 'int', possible loss of data
-#pragma warning( \
- disable : 4267) // 'argument': conversion from '__int64' to 'int',
- // possible loss of data
+#pragma warning(disable : 4267) // 'argument': conversion from '__int64' to
+ // 'int', possible loss of data
#pragma warning(disable : 4996) // 'strdup': The POSIX name for this item is
// deprecated. Instead, use the ISO C and C++
// conformant name: _strdup.
@@ -5229,10 +5276,9 @@ mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index,
n = MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS);
n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE - 1);
pStat->m_comment_size = n;
- memcpy(pStat->m_comment,
- p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE +
- MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) +
- MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS),
+ memcpy(pStat->m_comment, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE +
+ MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) +
+ MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS),
n);
pStat->m_comment[n] = '\0';
@@ -6894,7 +6940,7 @@ void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename,
#ifdef _MSC_VER
#pragma warning(pop)
#endif
-}
+} // namespace miniz
#else
// Reuse MINIZ_LITTE_ENDIAN macro
@@ -6919,8 +6965,26 @@ void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename,
// return bint.c[0] == 1;
//}
+static void SetErrorMessage(const std::string &msg, const char **err) {
+ if (err) {
+#ifdef _WIN32
+ (*err) = _strdup(msg.c_str());
+#else
+ (*err) = strdup(msg.c_str());
+#endif
+ }
+}
+
static const int kEXRVersionSize = 8;
+static void cpy2(unsigned short *dst_val, const unsigned short *src_val) {
+ unsigned char *dst = reinterpret_cast<unsigned char *>(dst_val);
+ const unsigned char *src = reinterpret_cast<const unsigned char *>(src_val);
+
+ dst[0] = src[0];
+ dst[1] = src[1];
+}
+
static void swap2(unsigned short *val) {
#ifdef MINIZ_LITTLE_ENDIAN
(void)val;
@@ -6934,6 +6998,36 @@ static void swap2(unsigned short *val) {
#endif
}
+static void cpy4(int *dst_val, const int *src_val) {
+ unsigned char *dst = reinterpret_cast<unsigned char *>(dst_val);
+ const unsigned char *src = reinterpret_cast<const unsigned char *>(src_val);
+
+ dst[0] = src[0];
+ dst[1] = src[1];
+ dst[2] = src[2];
+ dst[3] = src[3];
+}
+
+static void cpy4(unsigned int *dst_val, const unsigned int *src_val) {
+ unsigned char *dst = reinterpret_cast<unsigned char *>(dst_val);
+ const unsigned char *src = reinterpret_cast<const unsigned char *>(src_val);
+
+ dst[0] = src[0];
+ dst[1] = src[1];
+ dst[2] = src[2];
+ dst[3] = src[3];
+}
+
+static void cpy4(float *dst_val, const float *src_val) {
+ unsigned char *dst = reinterpret_cast<unsigned char *>(dst_val);
+ const unsigned char *src = reinterpret_cast<const unsigned char *>(src_val);
+
+ dst[0] = src[0];
+ dst[1] = src[1];
+ dst[2] = src[2];
+ dst[3] = src[3];
+}
+
static void swap4(unsigned int *val) {
#ifdef MINIZ_LITTLE_ENDIAN
(void)val;
@@ -6949,6 +7043,22 @@ static void swap4(unsigned int *val) {
#endif
}
+#if 0
+static void cpy8(tinyexr::tinyexr_uint64 *dst_val, const tinyexr::tinyexr_uint64 *src_val) {
+ unsigned char *dst = reinterpret_cast<unsigned char *>(dst_val);
+ const unsigned char *src = reinterpret_cast<const unsigned char *>(src_val);
+
+ dst[0] = src[0];
+ dst[1] = src[1];
+ dst[2] = src[2];
+ dst[3] = src[3];
+ dst[4] = src[4];
+ dst[5] = src[5];
+ dst[6] = src[6];
+ dst[7] = src[7];
+}
+#endif
+
static void swap8(tinyexr::tinyexr_uint64 *val) {
#ifdef MINIZ_LITTLE_ENDIAN
(void)val;
@@ -7084,6 +7194,15 @@ static FP16 float_to_half_full(FP32 f) {
// #define IMF_B44_COMPRESSION 6
// #define IMF_B44A_COMPRESSION 7
+#ifdef __clang__
+#pragma clang diagnostic push
+
+#if __has_warning("-Wzero-as-null-pointer-constant")
+#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"
+#endif
+
+#endif
+
static const char *ReadString(std::string *s, const char *ptr, size_t len) {
// Read untile NULL(\0).
const char *p = ptr;
@@ -7133,7 +7252,21 @@ static bool ReadAttribute(std::string *name, std::string *type,
tinyexr::swap4(reinterpret_cast<unsigned int *>(&data_len));
if (data_len == 0) {
- return false;
+ if ((*type).compare("string") == 0) {
+ // Accept empty string attribute.
+
+ marker += sizeof(uint32_t);
+ size -= sizeof(uint32_t);
+
+ *marker_size = name_len + 1 + type_len + 1 + sizeof(uint32_t);
+
+ data->resize(1);
+ (*data)[0] = '\0';
+
+ return true;
+ } else {
+ return false;
+ }
}
marker += sizeof(uint32_t);
@@ -7236,18 +7369,24 @@ static bool ReadChannelInfo(std::vector<ChannelInfo> &channels,
}
ChannelInfo info;
- tinyexr_int64 data_len = static_cast<tinyexr_int64>(data.size()) - (p - reinterpret_cast<const char *>(data.data()));
+ tinyexr_int64 data_len = static_cast<tinyexr_int64>(data.size()) -
+ (p - reinterpret_cast<const char *>(data.data()));
if (data_len < 0) {
return false;
}
- p = ReadString(
- &info.name, p, size_t(data_len));
+ p = ReadString(&info.name, p, size_t(data_len));
if ((p == NULL) && (info.name.empty())) {
// Buffer overrun. Issue #51.
return false;
}
+ const unsigned char *data_end =
+ reinterpret_cast<const unsigned char *>(p) + 16;
+ if (data_end >= (data.data() + data.size())) {
+ return false;
+ }
+
memcpy(&info.pixel_type, p, sizeof(int));
p += 4;
info.p_linear = static_cast<unsigned char>(p[0]); // uchar
@@ -7468,9 +7607,8 @@ static bool DecompressZip(unsigned char *dst,
// C and C99, so no big deal)
#pragma warning(disable : 4244) // 'initializing': conversion from '__int64' to
// 'int', possible loss of data
-#pragma warning( \
- disable : 4267) // 'argument': conversion from '__int64' to 'int',
- // possible loss of data
+#pragma warning(disable : 4267) // 'argument': conversion from '__int64' to
+ // 'int', possible loss of data
#pragma warning(disable : 4996) // 'strdup': The POSIX name for this item is
// deprecated. Instead, use the ISO C and C++
// conformant name: _strdup.
@@ -7705,6 +7843,7 @@ static void DecompressRle(unsigned char *dst,
#pragma clang diagnostic ignored "-Wsign-conversion"
#pragma clang diagnostic ignored "-Wc++11-extensions"
#pragma clang diagnostic ignored "-Wconversion"
+#pragma clang diagnostic ignored "-Wc++98-compat-pedantic"
#if __has_warning("-Wcast-qual")
#pragma clang diagnostic ignored "-Wcast-qual"
@@ -8187,8 +8326,8 @@ static void hufBuildEncTable(
// for all array entries.
//
- int hlink[HUF_ENCSIZE];
- long long *fHeap[HUF_ENCSIZE];
+ std::vector<int> hlink(HUF_ENCSIZE);
+ std::vector<long long *> fHeap(HUF_ENCSIZE);
*im = 0;
@@ -8247,8 +8386,8 @@ static void hufBuildEncTable(
std::make_heap(&fHeap[0], &fHeap[nf], FHeapCompare());
- long long scode[HUF_ENCSIZE];
- memset(scode, 0, sizeof(long long) * HUF_ENCSIZE);
+ std::vector<long long> scode(HUF_ENCSIZE);
+ memset(scode.data(), 0, sizeof(long long) * HUF_ENCSIZE);
while (nf > 1) {
//
@@ -8320,8 +8459,8 @@ static void hufBuildEncTable(
// code table from scode into frq.
//
- hufCanonicalCodeTable(scode);
- memcpy(frq, scode, sizeof(long long) * HUF_ENCSIZE);
+ hufCanonicalCodeTable(scode.data());
+ memcpy(frq, scode.data(), sizeof(long long) * HUF_ENCSIZE);
}
//
@@ -8657,26 +8796,62 @@ static int hufEncode // return: output size (in bits)
lc += 8; \
}
-#define getCode(po, rlc, c, lc, in, out, oe) \
- { \
- if (po == rlc) { \
- if (lc < 8) getChar(c, lc, in); \
- \
- lc -= 8; \
- \
- unsigned char cs = (c >> lc); \
- \
- if (out + cs > oe) return false; \
- \
- unsigned short s = out[-1]; \
- \
- while (cs-- > 0) *out++ = s; \
- } else if (out < oe) { \
- *out++ = po; \
- } else { \
- return false; \
- } \
+#if 0
+#define getCode(po, rlc, c, lc, in, out, ob, oe) \
+ { \
+ if (po == rlc) { \
+ if (lc < 8) getChar(c, lc, in); \
+ \
+ lc -= 8; \
+ \
+ unsigned char cs = (c >> lc); \
+ \
+ if (out + cs > oe) return false; \
+ \
+ /* TinyEXR issue 78 */ \
+ unsigned short s = out[-1]; \
+ \
+ while (cs-- > 0) *out++ = s; \
+ } else if (out < oe) { \
+ *out++ = po; \
+ } else { \
+ return false; \
+ } \
}
+#else
+static bool getCode(int po, int rlc, long long &c, int &lc, const char *&in,
+ const char *in_end, unsigned short *&out,
+ const unsigned short *ob, const unsigned short *oe) {
+ (void)ob;
+ if (po == rlc) {
+ if (lc < 8) {
+ /* TinyEXR issue 78 */
+ if ((in + 1) >= in_end) {
+ return false;
+ }
+
+ getChar(c, lc, in);
+ }
+
+ lc -= 8;
+
+ unsigned char cs = (c >> lc);
+
+ if (out + cs > oe) return false;
+
+ // Bounds check for safety
+ if ((out - 1) <= ob) return false;
+ unsigned short s = out[-1];
+
+ while (cs-- > 0) *out++ = s;
+ } else if (out < oe) {
+ *out++ = po;
+ } else {
+ return false;
+ }
+ return true;
+}
+#endif
//
// Decode (uncompress) ni bits based on encoding & decoding tables:
@@ -8692,8 +8867,8 @@ static bool hufDecode(const long long *hcode, // i : encoding table
{
long long c = 0;
int lc = 0;
- unsigned short *outb = out;
- unsigned short *oe = out + no;
+ unsigned short *outb = out; // begin
+ unsigned short *oe = out + no; // end
const char *ie = in + (ni + 7) / 8; // input byte size
//
@@ -8716,7 +8891,16 @@ static bool hufDecode(const long long *hcode, // i : encoding table
//
lc -= pl.len;
- getCode(pl.lit, rlc, c, lc, in, out, oe);
+ // std::cout << "lit = " << pl.lit << std::endl;
+ // std::cout << "rlc = " << rlc << std::endl;
+ // std::cout << "c = " << c << std::endl;
+ // std::cout << "lc = " << lc << std::endl;
+ // std::cout << "in = " << in << std::endl;
+ // std::cout << "out = " << out << std::endl;
+ // std::cout << "oe = " << oe << std::endl;
+ if (!getCode(pl.lit, rlc, c, lc, in, ie, out, outb, oe)) {
+ return false;
+ }
} else {
if (!pl.p) {
return false;
@@ -8743,7 +8927,9 @@ static bool hufDecode(const long long *hcode, // i : encoding table
//
lc -= l;
- getCode(pl.p[j], rlc, c, lc, in, out, oe);
+ if (!getCode(pl.p[j], rlc, c, lc, in, ie, out, outb, oe)) {
+ return false;
+ }
break;
}
}
@@ -8770,7 +8956,9 @@ static bool hufDecode(const long long *hcode, // i : encoding table
if (pl.len) {
lc -= pl.len;
- getCode(pl.lit, rlc, c, lc, in, out, oe);
+ if (!getCode(pl.lit, rlc, c, lc, in, ie, out, outb, oe)) {
+ return false;
+ }
} else {
return false;
// invalidCode(); // wrong (long) code
@@ -8785,7 +8973,7 @@ static bool hufDecode(const long long *hcode, // i : encoding table
return true;
}
-static void countFrequencies(long long freq[HUF_ENCSIZE],
+static void countFrequencies(std::vector<long long> &freq,
const unsigned short data[/*n*/], int n) {
for (int i = 0; i < HUF_ENCSIZE; ++i) freq[i] = 0;
@@ -8816,21 +9004,21 @@ static int hufCompress(const unsigned short raw[], int nRaw,
char compressed[]) {
if (nRaw == 0) return 0;
- long long freq[HUF_ENCSIZE];
+ std::vector<long long> freq(HUF_ENCSIZE);
countFrequencies(freq, raw, nRaw);
int im = 0;
int iM = 0;
- hufBuildEncTable(freq, &im, &iM);
+ hufBuildEncTable(freq.data(), &im, &iM);
char *tableStart = compressed + 20;
char *tableEnd = tableStart;
- hufPackEncTable(freq, im, iM, &tableEnd);
+ hufPackEncTable(freq.data(), im, iM, &tableEnd);
int tableLength = tableEnd - tableStart;
char *dataStart = tableEnd;
- int nBits = hufEncode(freq, raw, nRaw, iM, dataStart);
+ int nBits = hufEncode(freq.data(), raw, nRaw, iM, dataStart);
int data_length = (nBits + 7) / 8;
writeUInt(compressed, im);
@@ -8843,9 +9031,9 @@ static int hufCompress(const unsigned short raw[], int nRaw,
}
static bool hufUncompress(const char compressed[], int nCompressed,
- unsigned short raw[], int nRaw) {
+ std::vector<unsigned short> *raw) {
if (nCompressed == 0) {
- if (nRaw != 0) return false;
+ if (raw->size() != 0) return false;
return false;
}
@@ -8886,7 +9074,8 @@ static bool hufUncompress(const char compressed[], int nCompressed,
}
hufBuildDecTable(&freq.at(0), im, iM, &hdec.at(0));
- hufDecode(&freq.at(0), &hdec.at(0), ptr, nBits, iM, nRaw, raw);
+ hufDecode(&freq.at(0), &hdec.at(0), ptr, nBits, iM, raw->size(),
+ raw->data());
}
// catch (...)
//{
@@ -8975,7 +9164,7 @@ static bool CompressPiz(unsigned char *outPtr, unsigned int *outSize,
const unsigned char *inPtr, size_t inSize,
const std::vector<ChannelInfo> &channelInfo,
int data_width, int num_lines) {
- unsigned char bitmap[BITMAP_SIZE];
+ std::vector<unsigned char> bitmap(BITMAP_SIZE);
unsigned short minNonZero;
unsigned short maxNonZero;
@@ -9026,12 +9215,12 @@ static bool CompressPiz(unsigned char *outPtr, unsigned int *outSize,
}
}
- bitmapFromData(&tmpBuffer.at(0), static_cast<int>(tmpBuffer.size()), bitmap,
- minNonZero, maxNonZero);
+ bitmapFromData(&tmpBuffer.at(0), static_cast<int>(tmpBuffer.size()),
+ bitmap.data(), minNonZero, maxNonZero);
- unsigned short lut[USHORT_RANGE];
- unsigned short maxValue = forwardLutFromBitmap(bitmap, lut);
- applyLut(lut, &tmpBuffer.at(0), static_cast<int>(tmpBuffer.size()));
+ std::vector<unsigned short> lut(USHORT_RANGE);
+ unsigned short maxValue = forwardLutFromBitmap(bitmap.data(), lut.data());
+ applyLut(lut.data(), &tmpBuffer.at(0), static_cast<int>(tmpBuffer.size()));
//
// Store range compression info in _outBuffer
@@ -9101,7 +9290,7 @@ static bool DecompressPiz(unsigned char *outPtr, const unsigned char *inPtr,
return true;
}
- unsigned char bitmap[BITMAP_SIZE];
+ std::vector<unsigned char> bitmap(BITMAP_SIZE);
unsigned short minNonZero;
unsigned short maxNonZero;
@@ -9111,11 +9300,13 @@ static bool DecompressPiz(unsigned char *outPtr, const unsigned char *inPtr,
return false;
#endif
- memset(bitmap, 0, BITMAP_SIZE);
+ memset(bitmap.data(), 0, BITMAP_SIZE);
const unsigned char *ptr = inPtr;
- minNonZero = *(reinterpret_cast<const unsigned short *>(ptr));
- maxNonZero = *(reinterpret_cast<const unsigned short *>(ptr + 2));
+ // minNonZero = *(reinterpret_cast<const unsigned short *>(ptr));
+ tinyexr::cpy2(&minNonZero, reinterpret_cast<const unsigned short *>(ptr));
+ // maxNonZero = *(reinterpret_cast<const unsigned short *>(ptr + 2));
+ tinyexr::cpy2(&maxNonZero, reinterpret_cast<const unsigned short *>(ptr + 2));
ptr += 4;
if (maxNonZero >= BITMAP_SIZE) {
@@ -9128,9 +9319,9 @@ static bool DecompressPiz(unsigned char *outPtr, const unsigned char *inPtr,
ptr += maxNonZero - minNonZero + 1;
}
- unsigned short lut[USHORT_RANGE];
- memset(lut, 0, sizeof(unsigned short) * USHORT_RANGE);
- unsigned short maxValue = reverseLutFromBitmap(bitmap, lut);
+ std::vector<unsigned short> lut(USHORT_RANGE);
+ memset(lut.data(), 0, sizeof(unsigned short) * USHORT_RANGE);
+ unsigned short maxValue = reverseLutFromBitmap(bitmap.data(), lut.data());
//
// Huffman decoding
@@ -9138,12 +9329,12 @@ static bool DecompressPiz(unsigned char *outPtr, const unsigned char *inPtr,
int length;
- length = *(reinterpret_cast<const int *>(ptr));
+ // length = *(reinterpret_cast<const int *>(ptr));
+ tinyexr::cpy4(&length, reinterpret_cast<const int *>(ptr));
ptr += sizeof(int);
std::vector<unsigned short> tmpBuffer(tmpBufSize);
- hufUncompress(reinterpret_cast<const char *>(ptr), length, &tmpBuffer.at(0),
- static_cast<int>(tmpBufSize));
+ hufUncompress(reinterpret_cast<const char *>(ptr), length, &tmpBuffer);
//
// Wavelet decoding
@@ -9184,7 +9375,7 @@ static bool DecompressPiz(unsigned char *outPtr, const unsigned char *inPtr,
// Expand the pixel data to their original range
//
- applyLut(lut, &tmpBuffer.at(0), static_cast<int>(tmpBufSize));
+ applyLut(lut.data(), &tmpBuffer.at(0), static_cast<int>(tmpBufSize));
for (int y = 0; y < num_lines; y++) {
for (size_t i = 0; i < channelData.size(); ++i) {
@@ -9409,6 +9600,7 @@ bool CompressZfp(std::vector<unsigned char> *outBuf, unsigned int *outSize,
// -----------------------------------------------------------------
//
+// TODO(syoyo): Refactor function arguments.
static bool DecodePixelData(/* out */ unsigned char **out_images,
const int *requested_pixel_types,
const unsigned char *data_ptr, size_t data_len,
@@ -9421,6 +9613,11 @@ static bool DecodePixelData(/* out */ unsigned char **out_images,
const std::vector<size_t> &channel_offset_list) {
if (compression_type == TINYEXR_COMPRESSIONTYPE_PIZ) { // PIZ
#if TINYEXR_USE_PIZ
+ if ((width == 0) || (num_lines == 0) || (pixel_data_size == 0)) {
+ // Invalid input #90
+ return false;
+ }
+
// Allocate original data size.
std::vector<unsigned char> outBuf(static_cast<size_t>(
static_cast<size_t>(width * num_lines) * pixel_data_size));
@@ -9452,7 +9649,10 @@ static bool DecodePixelData(/* out */ unsigned char **out_images,
for (size_t u = 0; u < static_cast<size_t>(width); u++) {
FP16 hf;
- hf.u = line_ptr[u];
+ // hf.u = line_ptr[u];
+ // use `cpy` to avoid unaligned memory access when compiler's
+ // optimization is on.
+ tinyexr::cpy2(&(hf.u), line_ptr + u);
tinyexr::swap2(reinterpret_cast<unsigned short *>(&hf.u));
@@ -9495,7 +9695,9 @@ static bool DecodePixelData(/* out */ unsigned char **out_images,
&outBuf.at(v * pixel_data_size * static_cast<size_t>(width) +
channel_offset_list[c] * static_cast<size_t>(width)));
for (size_t u = 0; u < static_cast<size_t>(width); u++) {
- unsigned int val = line_ptr[u];
+ unsigned int val;
+ // val = line_ptr[u];
+ tinyexr::cpy4(&val, line_ptr + u);
tinyexr::swap4(&val);
@@ -9521,7 +9723,9 @@ static bool DecodePixelData(/* out */ unsigned char **out_images,
v * pixel_data_size * static_cast<size_t>(x_stride) +
channel_offset_list[c] * static_cast<size_t>(x_stride)));
for (size_t u = 0; u < static_cast<size_t>(width); u++) {
- float val = line_ptr[u];
+ float val;
+ // val = line_ptr[u];
+ tinyexr::cpy4(&val, line_ptr + u);
tinyexr::swap4(reinterpret_cast<unsigned int *>(&val));
@@ -9557,9 +9761,9 @@ static bool DecodePixelData(/* out */ unsigned char **out_images,
unsigned long dstLen = static_cast<unsigned long>(outBuf.size());
assert(dstLen > 0);
- if (!tinyexr::DecompressZip(reinterpret_cast<unsigned char *>(&outBuf.at(0)),
- &dstLen, data_ptr,
- static_cast<unsigned long>(data_len))) {
+ if (!tinyexr::DecompressZip(
+ reinterpret_cast<unsigned char *>(&outBuf.at(0)), &dstLen, data_ptr,
+ static_cast<unsigned long>(data_len))) {
return false;
}
@@ -9583,7 +9787,8 @@ static bool DecodePixelData(/* out */ unsigned char **out_images,
for (size_t u = 0; u < static_cast<size_t>(width); u++) {
tinyexr::FP16 hf;
- hf.u = line_ptr[u];
+ // hf.u = line_ptr[u];
+ tinyexr::cpy2(&(hf.u), line_ptr + u);
tinyexr::swap2(reinterpret_cast<unsigned short *>(&hf.u));
@@ -9626,7 +9831,9 @@ static bool DecodePixelData(/* out */ unsigned char **out_images,
&outBuf.at(v * pixel_data_size * static_cast<size_t>(width) +
channel_offset_list[c] * static_cast<size_t>(width)));
for (size_t u = 0; u < static_cast<size_t>(width); u++) {
- unsigned int val = line_ptr[u];
+ unsigned int val;
+ // val = line_ptr[u];
+ tinyexr::cpy4(&val, line_ptr + u);
tinyexr::swap4(&val);
@@ -9652,7 +9859,9 @@ static bool DecodePixelData(/* out */ unsigned char **out_images,
&outBuf.at(v * pixel_data_size * static_cast<size_t>(width) +
channel_offset_list[c] * static_cast<size_t>(width)));
for (size_t u = 0; u < static_cast<size_t>(width); u++) {
- float val = line_ptr[u];
+ float val;
+ // val = line_ptr[u];
+ tinyexr::cpy4(&val, line_ptr + u);
tinyexr::swap4(reinterpret_cast<unsigned int *>(&val));
@@ -9707,7 +9916,8 @@ static bool DecodePixelData(/* out */ unsigned char **out_images,
for (size_t u = 0; u < static_cast<size_t>(width); u++) {
tinyexr::FP16 hf;
- hf.u = line_ptr[u];
+ // hf.u = line_ptr[u];
+ tinyexr::cpy2(&(hf.u), line_ptr + u);
tinyexr::swap2(reinterpret_cast<unsigned short *>(&hf.u));
@@ -9750,7 +9960,9 @@ static bool DecodePixelData(/* out */ unsigned char **out_images,
&outBuf.at(v * pixel_data_size * static_cast<size_t>(width) +
channel_offset_list[c] * static_cast<size_t>(width)));
for (size_t u = 0; u < static_cast<size_t>(width); u++) {
- unsigned int val = line_ptr[u];
+ unsigned int val;
+ // val = line_ptr[u];
+ tinyexr::cpy4(&val, line_ptr + u);
tinyexr::swap4(&val);
@@ -9776,7 +9988,9 @@ static bool DecodePixelData(/* out */ unsigned char **out_images,
&outBuf.at(v * pixel_data_size * static_cast<size_t>(width) +
channel_offset_list[c] * static_cast<size_t>(width)));
for (size_t u = 0; u < static_cast<size_t>(width); u++) {
- float val = line_ptr[u];
+ float val;
+ // val = line_ptr[u];
+ tinyexr::cpy4(&val, line_ptr + u);
tinyexr::swap4(reinterpret_cast<unsigned int *>(&val));
@@ -9839,7 +10053,8 @@ static bool DecodePixelData(/* out */ unsigned char **out_images,
&outBuf.at(v * pixel_data_size * static_cast<size_t>(width) +
channel_offset_list[c] * static_cast<size_t>(width)));
for (size_t u = 0; u < static_cast<size_t>(width); u++) {
- float val = line_ptr[u];
+ float val;
+ tinyexr::cpy4(&val, line_ptr + u);
tinyexr::swap4(reinterpret_cast<unsigned int *>(&val));
@@ -9871,88 +10086,120 @@ static bool DecodePixelData(/* out */ unsigned char **out_images,
#endif
} else if (compression_type == TINYEXR_COMPRESSIONTYPE_NONE) {
for (size_t c = 0; c < num_channels; c++) {
- if (channels[c].pixel_type == TINYEXR_PIXELTYPE_HALF) {
- const unsigned short *line_ptr =
- reinterpret_cast<const unsigned short *>(
- data_ptr +
- c * static_cast<size_t>(width) * sizeof(unsigned short));
-
- if (requested_pixel_types[c] == TINYEXR_PIXELTYPE_HALF) {
- unsigned short *outLine =
- reinterpret_cast<unsigned short *>(out_images[c]);
- if (line_order == 0) {
- outLine += y * x_stride;
- } else {
- outLine += (height - 1 - y) * x_stride;
- }
+ for (size_t v = 0; v < static_cast<size_t>(num_lines); v++) {
+ if (channels[c].pixel_type == TINYEXR_PIXELTYPE_HALF) {
+ const unsigned short *line_ptr =
+ reinterpret_cast<const unsigned short *>(
+ data_ptr + v * pixel_data_size * size_t(width) +
+ channel_offset_list[c] * static_cast<size_t>(width));
+
+ if (requested_pixel_types[c] == TINYEXR_PIXELTYPE_HALF) {
+ unsigned short *outLine =
+ reinterpret_cast<unsigned short *>(out_images[c]);
+ if (line_order == 0) {
+ outLine += (size_t(y) + v) * size_t(x_stride);
+ } else {
+ outLine +=
+ (size_t(height) - 1 - (size_t(y) + v)) * size_t(x_stride);
+ }
- for (int u = 0; u < width; u++) {
- tinyexr::FP16 hf;
+ for (int u = 0; u < width; u++) {
+ tinyexr::FP16 hf;
- hf.u = line_ptr[u];
+ // hf.u = line_ptr[u];
+ tinyexr::cpy2(&(hf.u), line_ptr + u);
- tinyexr::swap2(reinterpret_cast<unsigned short *>(&hf.u));
+ tinyexr::swap2(reinterpret_cast<unsigned short *>(&hf.u));
- outLine[u] = hf.u;
+ outLine[u] = hf.u;
+ }
+ } else if (requested_pixel_types[c] == TINYEXR_PIXELTYPE_FLOAT) {
+ float *outLine = reinterpret_cast<float *>(out_images[c]);
+ if (line_order == 0) {
+ outLine += (size_t(y) + v) * size_t(x_stride);
+ } else {
+ outLine +=
+ (size_t(height) - 1 - (size_t(y) + v)) * size_t(x_stride);
+ }
+
+ if (reinterpret_cast<const unsigned char *>(line_ptr + width) >
+ (data_ptr + data_len)) {
+ // Insufficient data size
+ return false;
+ }
+
+ for (int u = 0; u < width; u++) {
+ tinyexr::FP16 hf;
+
+ // address may not be aliged. use byte-wise copy for safety.#76
+ // hf.u = line_ptr[u];
+ tinyexr::cpy2(&(hf.u), line_ptr + u);
+
+ tinyexr::swap2(reinterpret_cast<unsigned short *>(&hf.u));
+
+ tinyexr::FP32 f32 = half_to_float(hf);
+
+ outLine[u] = f32.f;
+ }
+ } else {
+ assert(0);
+ return false;
}
- } else if (requested_pixel_types[c] == TINYEXR_PIXELTYPE_FLOAT) {
+ } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_FLOAT) {
+ const float *line_ptr = reinterpret_cast<const float *>(
+ data_ptr + v * pixel_data_size * size_t(width) +
+ channel_offset_list[c] * static_cast<size_t>(width));
+
float *outLine = reinterpret_cast<float *>(out_images[c]);
if (line_order == 0) {
- outLine += y * x_stride;
+ outLine += (size_t(y) + v) * size_t(x_stride);
} else {
- outLine += (height - 1 - y) * x_stride;
+ outLine +=
+ (size_t(height) - 1 - (size_t(y) + v)) * size_t(x_stride);
}
- for (int u = 0; u < width; u++) {
- tinyexr::FP16 hf;
-
- hf.u = line_ptr[u];
-
- tinyexr::swap2(reinterpret_cast<unsigned short *>(&hf.u));
-
- tinyexr::FP32 f32 = half_to_float(hf);
-
- outLine[u] = f32.f;
+ if (reinterpret_cast<const unsigned char *>(line_ptr + width) >
+ (data_ptr + data_len)) {
+ // Insufficient data size
+ return false;
}
- } else {
- assert(0);
- return false;
- }
- } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_FLOAT) {
- const float *line_ptr = reinterpret_cast<const float *>(
- data_ptr + c * static_cast<size_t>(width) * sizeof(float));
- float *outLine = reinterpret_cast<float *>(out_images[c]);
- if (line_order == 0) {
- outLine += y * x_stride;
- } else {
- outLine += (height - 1 - y) * x_stride;
- }
+ for (int u = 0; u < width; u++) {
+ float val;
+ tinyexr::cpy4(&val, line_ptr + u);
- for (int u = 0; u < width; u++) {
- float val = line_ptr[u];
+ tinyexr::swap4(reinterpret_cast<unsigned int *>(&val));
- tinyexr::swap4(reinterpret_cast<unsigned int *>(&val));
+ outLine[u] = val;
+ }
+ } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_UINT) {
+ const unsigned int *line_ptr = reinterpret_cast<const unsigned int *>(
+ data_ptr + v * pixel_data_size * size_t(width) +
+ channel_offset_list[c] * static_cast<size_t>(width));
- outLine[u] = val;
- }
- } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_UINT) {
- const unsigned int *line_ptr = reinterpret_cast<const unsigned int *>(
- data_ptr + c * static_cast<size_t>(width) * sizeof(unsigned int));
+ unsigned int *outLine =
+ reinterpret_cast<unsigned int *>(out_images[c]);
+ if (line_order == 0) {
+ outLine += (size_t(y) + v) * size_t(x_stride);
+ } else {
+ outLine +=
+ (size_t(height) - 1 - (size_t(y) + v)) * size_t(x_stride);
+ }
- unsigned int *outLine = reinterpret_cast<unsigned int *>(out_images[c]);
- if (line_order == 0) {
- outLine += y * x_stride;
- } else {
- outLine += (height - 1 - y) * x_stride;
- }
+ for (int u = 0; u < width; u++) {
+ if (reinterpret_cast<const unsigned char *>(line_ptr + u) >=
+ (data_ptr + data_len)) {
+ // Corrupsed data?
+ return false;
+ }
- for (int u = 0; u < width; u++) {
- unsigned int val = line_ptr[u];
+ unsigned int val;
+ tinyexr::cpy4(&val, line_ptr + u);
- tinyexr::swap4(reinterpret_cast<unsigned int *>(&val));
+ tinyexr::swap4(reinterpret_cast<unsigned int *>(&val));
- outLine[u] = val;
+ outLine[u] = val;
+ }
}
}
}
@@ -9994,7 +10241,7 @@ static void DecodeTiledPixelData(
num_channels, channels, channel_offset_list);
}
-static void ComputeChannelLayout(std::vector<size_t> *channel_offset_list,
+static bool ComputeChannelLayout(std::vector<size_t> *channel_offset_list,
int *pixel_data_size, size_t *channel_offset,
int num_channels,
const EXRChannelInfo *channels) {
@@ -10015,9 +10262,11 @@ static void ComputeChannelLayout(std::vector<size_t> *channel_offset_list,
(*pixel_data_size) += sizeof(unsigned int);
(*channel_offset) += sizeof(unsigned int);
} else {
- assert(0);
+ // ???
+ return false;
}
}
+ return true;
}
static unsigned char **AllocateImage(int num_channels,
@@ -10125,8 +10374,11 @@ static int ParseEXRHeader(HeaderInfo *info, bool *empty_header,
// Read attributes
size_t orig_size = size;
- for (;;) {
+ for (size_t nattr = 0; nattr < TINYEXR_MAX_HEADER_ATTRIBUTES; nattr++) {
if (0 == size) {
+ if (err) {
+ (*err) += "Insufficient data size for attributes.\n";
+ }
return TINYEXR_ERROR_INVALID_DATA;
} else if (marker[0] == '\0') {
size--;
@@ -10139,6 +10391,9 @@ static int ParseEXRHeader(HeaderInfo *info, bool *empty_header,
size_t marker_size;
if (!tinyexr::ReadAttribute(&attr_name, &attr_type, &data, &marker_size,
marker, size)) {
+ if (err) {
+ (*err) += "Failed to read attribute.\n";
+ }
return TINYEXR_ERROR_INVALID_DATA;
}
marker += marker_size;
@@ -10209,14 +10464,14 @@ static int ParseEXRHeader(HeaderInfo *info, bool *empty_header,
if (!ReadChannelInfo(info->channels, data)) {
if (err) {
- (*err) = "Failed to parse channel info.";
+ (*err) += "Failed to parse channel info.\n";
}
return TINYEXR_ERROR_INVALID_DATA;
}
if (info->channels.size() < 1) {
if (err) {
- (*err) = "# of channels is zero.";
+ (*err) += "# of channels is zero.\n";
}
return TINYEXR_ERROR_INVALID_DATA;
}
@@ -10224,9 +10479,7 @@ static int ParseEXRHeader(HeaderInfo *info, bool *empty_header,
has_channels = true;
} else if (attr_name.compare("dataWindow") == 0) {
- if (data.size() < 16) {
- // Corrupsed file(Issue #50).
- } else {
+ if (data.size() >= 16) {
memcpy(&info->data_window[0], &data.at(0), sizeof(int));
memcpy(&info->data_window[1], &data.at(4), sizeof(int));
memcpy(&info->data_window[2], &data.at(8), sizeof(int));
@@ -10238,48 +10491,60 @@ static int ParseEXRHeader(HeaderInfo *info, bool *empty_header,
has_data_window = true;
}
} else if (attr_name.compare("displayWindow") == 0) {
- memcpy(&info->display_window[0], &data.at(0), sizeof(int));
- memcpy(&info->display_window[1], &data.at(4), sizeof(int));
- memcpy(&info->display_window[2], &data.at(8), sizeof(int));
- memcpy(&info->display_window[3], &data.at(12), sizeof(int));
- tinyexr::swap4(
- reinterpret_cast<unsigned int *>(&info->display_window[0]));
- tinyexr::swap4(
- reinterpret_cast<unsigned int *>(&info->display_window[1]));
- tinyexr::swap4(
- reinterpret_cast<unsigned int *>(&info->display_window[2]));
- tinyexr::swap4(
- reinterpret_cast<unsigned int *>(&info->display_window[3]));
-
- has_display_window = true;
+ if (data.size() >= 16) {
+ memcpy(&info->display_window[0], &data.at(0), sizeof(int));
+ memcpy(&info->display_window[1], &data.at(4), sizeof(int));
+ memcpy(&info->display_window[2], &data.at(8), sizeof(int));
+ memcpy(&info->display_window[3], &data.at(12), sizeof(int));
+ tinyexr::swap4(
+ reinterpret_cast<unsigned int *>(&info->display_window[0]));
+ tinyexr::swap4(
+ reinterpret_cast<unsigned int *>(&info->display_window[1]));
+ tinyexr::swap4(
+ reinterpret_cast<unsigned int *>(&info->display_window[2]));
+ tinyexr::swap4(
+ reinterpret_cast<unsigned int *>(&info->display_window[3]));
+
+ has_display_window = true;
+ }
} else if (attr_name.compare("lineOrder") == 0) {
- info->line_order = static_cast<int>(data[0]);
- has_line_order = true;
+ if (data.size() >= 1) {
+ info->line_order = static_cast<int>(data[0]);
+ has_line_order = true;
+ }
} else if (attr_name.compare("pixelAspectRatio") == 0) {
- memcpy(&info->pixel_aspect_ratio, &data.at(0), sizeof(float));
- tinyexr::swap4(
- reinterpret_cast<unsigned int *>(&info->pixel_aspect_ratio));
- has_pixel_aspect_ratio = true;
+ if (data.size() >= sizeof(float)) {
+ memcpy(&info->pixel_aspect_ratio, &data.at(0), sizeof(float));
+ tinyexr::swap4(
+ reinterpret_cast<unsigned int *>(&info->pixel_aspect_ratio));
+ has_pixel_aspect_ratio = true;
+ }
} else if (attr_name.compare("screenWindowCenter") == 0) {
- memcpy(&info->screen_window_center[0], &data.at(0), sizeof(float));
- memcpy(&info->screen_window_center[1], &data.at(4), sizeof(float));
- tinyexr::swap4(
- reinterpret_cast<unsigned int *>(&info->screen_window_center[0]));
- tinyexr::swap4(
- reinterpret_cast<unsigned int *>(&info->screen_window_center[1]));
- has_screen_window_center = true;
+ if (data.size() >= 8) {
+ memcpy(&info->screen_window_center[0], &data.at(0), sizeof(float));
+ memcpy(&info->screen_window_center[1], &data.at(4), sizeof(float));
+ tinyexr::swap4(
+ reinterpret_cast<unsigned int *>(&info->screen_window_center[0]));
+ tinyexr::swap4(
+ reinterpret_cast<unsigned int *>(&info->screen_window_center[1]));
+ has_screen_window_center = true;
+ }
} else if (attr_name.compare("screenWindowWidth") == 0) {
- memcpy(&info->screen_window_width, &data.at(0), sizeof(float));
- tinyexr::swap4(
- reinterpret_cast<unsigned int *>(&info->screen_window_width));
+ if (data.size() >= sizeof(float)) {
+ memcpy(&info->screen_window_width, &data.at(0), sizeof(float));
+ tinyexr::swap4(
+ reinterpret_cast<unsigned int *>(&info->screen_window_width));
- has_screen_window_width = true;
+ has_screen_window_width = true;
+ }
} else if (attr_name.compare("chunkCount") == 0) {
- memcpy(&info->chunk_count, &data.at(0), sizeof(int));
- tinyexr::swap4(reinterpret_cast<unsigned int *>(&info->chunk_count));
+ if (data.size() >= sizeof(int)) {
+ memcpy(&info->chunk_count, &data.at(0), sizeof(int));
+ tinyexr::swap4(reinterpret_cast<unsigned int *>(&info->chunk_count));
+ }
} else {
- // Custom attribute(up to TINYEXR_MAX_ATTRIBUTES)
- if (info->attributes.size() < TINYEXR_MAX_ATTRIBUTES) {
+ // Custom attribute(up to TINYEXR_MAX_CUSTOM_ATTRIBUTES)
+ if (info->attributes.size() < TINYEXR_MAX_CUSTOM_ATTRIBUTES) {
EXRAttribute attrib;
#ifdef _MSC_VER
strncpy_s(attrib.name, attr_name.c_str(), 255);
@@ -10409,15 +10674,30 @@ static void ConvertHeader(EXRHeader *exr_header, const HeaderInfo &info) {
exr_header->requested_pixel_types[c] = info.channels[c].pixel_type;
}
- assert(info.attributes.size() < TINYEXR_MAX_ATTRIBUTES);
exr_header->num_custom_attributes = static_cast<int>(info.attributes.size());
- for (size_t i = 0; i < info.attributes.size(); i++) {
- memcpy(exr_header->custom_attributes[i].name, info.attributes[i].name, 256);
- memcpy(exr_header->custom_attributes[i].type, info.attributes[i].type, 256);
- exr_header->custom_attributes[i].size = info.attributes[i].size;
- // Just copy poiner
- exr_header->custom_attributes[i].value = info.attributes[i].value;
+ if (exr_header->num_custom_attributes > 0) {
+ // TODO(syoyo): Report warning when # of attributes exceeds
+ // `TINYEXR_MAX_CUSTOM_ATTRIBUTES`
+ if (exr_header->num_custom_attributes > TINYEXR_MAX_CUSTOM_ATTRIBUTES) {
+ exr_header->num_custom_attributes = TINYEXR_MAX_CUSTOM_ATTRIBUTES;
+ }
+
+ exr_header->custom_attributes = static_cast<EXRAttribute *>(malloc(
+ sizeof(EXRAttribute) * size_t(exr_header->num_custom_attributes)));
+
+ for (size_t i = 0; i < info.attributes.size(); i++) {
+ memcpy(exr_header->custom_attributes[i].name, info.attributes[i].name,
+ 256);
+ memcpy(exr_header->custom_attributes[i].type, info.attributes[i].type,
+ 256);
+ exr_header->custom_attributes[i].size = info.attributes[i].size;
+ // Just copy poiner
+ exr_header->custom_attributes[i].value = info.attributes[i].value;
+ }
+
+ } else {
+ exr_header->custom_attributes = NULL;
}
exr_header->header_len = info.header_len;
@@ -10425,7 +10705,8 @@ static void ConvertHeader(EXRHeader *exr_header, const HeaderInfo &info) {
static int DecodeChunk(EXRImage *exr_image, const EXRHeader *exr_header,
const std::vector<tinyexr::tinyexr_uint64> &offsets,
- const unsigned char *head, const size_t size) {
+ const unsigned char *head, const size_t size,
+ std::string *err) {
int num_channels = exr_header->num_channels;
int num_scanline_blocks = 1;
@@ -10445,32 +10726,40 @@ static int DecodeChunk(EXRImage *exr_image, const EXRHeader *exr_header,
std::vector<size_t> channel_offset_list;
int pixel_data_size = 0;
size_t channel_offset = 0;
- tinyexr::ComputeChannelLayout(&channel_offset_list, &pixel_data_size,
- &channel_offset, num_channels,
- exr_header->channels);
+ if (!tinyexr::ComputeChannelLayout(&channel_offset_list, &pixel_data_size,
+ &channel_offset, num_channels,
+ exr_header->channels)) {
+ if (err) {
+ (*err) += "Failed to compute channel layout.\n";
+ }
+ return TINYEXR_ERROR_INVALID_DATA;
+ }
- bool invalid_data = false;
+ bool invalid_data = false; // TODO(LTE): Use atomic lock for MT safety.
if (exr_header->tiled) {
size_t num_tiles = offsets.size(); // = # of blocks
exr_image->tiles = static_cast<EXRTile *>(
- malloc(sizeof(EXRTile) * static_cast<size_t>(num_tiles)));
+ calloc(sizeof(EXRTile), static_cast<size_t>(num_tiles)));
for (size_t tile_idx = 0; tile_idx < num_tiles; tile_idx++) {
// Allocate memory for each tile.
exr_image->tiles[tile_idx].images = tinyexr::AllocateImage(
num_channels, exr_header->channels, exr_header->requested_pixel_types,
- data_width, data_height);
+ exr_header->tile_size_x, exr_header->tile_size_y);
// 16 byte: tile coordinates
// 4 byte : data size
// ~ : data(uncompressed or compressed)
if (offsets[tile_idx] + sizeof(int) * 5 > size) {
+ if (err) {
+ (*err) += "Insufficient data size.\n";
+ }
return TINYEXR_ERROR_INVALID_DATA;
}
- size_t data_size = size - (offsets[tile_idx] + sizeof(int) * 5);
+ size_t data_size = size_t(size - (offsets[tile_idx] + sizeof(int) * 5));
const unsigned char *data_ptr =
reinterpret_cast<const unsigned char *>(head + offsets[tile_idx]);
@@ -10482,8 +10771,12 @@ static int DecodeChunk(EXRImage *exr_image, const EXRHeader *exr_header,
tinyexr::swap4(reinterpret_cast<unsigned int *>(&tile_coordinates[3]));
// @todo{ LoD }
- assert(tile_coordinates[2] == 0);
- assert(tile_coordinates[3] == 0);
+ if (tile_coordinates[2] != 0) {
+ return TINYEXR_ERROR_UNSUPPORTED_FEATURE;
+ }
+ if (tile_coordinates[3] != 0) {
+ return TINYEXR_ERROR_UNSUPPORTED_FEATURE;
+ }
int data_len;
memcpy(&data_len, data_ptr + 16,
@@ -10491,6 +10784,9 @@ static int DecodeChunk(EXRImage *exr_image, const EXRHeader *exr_header,
tinyexr::swap4(reinterpret_cast<unsigned int *>(&data_len));
if (data_len < 4 || size_t(data_len) > data_size) {
+ if (err) {
+ (*err) += "Insufficient data length.\n";
+ }
return TINYEXR_ERROR_INVALID_DATA;
}
@@ -10531,56 +10827,56 @@ static int DecodeChunk(EXRImage *exr_image, const EXRHeader *exr_header,
size_t y_idx = static_cast<size_t>(y);
if (offsets[y_idx] + sizeof(int) * 2 > size) {
- return TINYEXR_ERROR_INVALID_DATA;
- }
-
- // 4 byte: scan line
- // 4 byte: data size
- // ~ : pixel data(uncompressed or compressed)
- size_t data_size = size - (offsets[y_idx] + sizeof(int) * 2);
- const unsigned char *data_ptr =
- reinterpret_cast<const unsigned char *>(head + offsets[y_idx]);
-
- int line_no;
- memcpy(&line_no, data_ptr, sizeof(int));
- int data_len;
- memcpy(&data_len, data_ptr + 4, sizeof(int));
- tinyexr::swap4(reinterpret_cast<unsigned int *>(&line_no));
- tinyexr::swap4(reinterpret_cast<unsigned int *>(&data_len));
-
- if (size_t(data_len) > data_size) {
- return TINYEXR_ERROR_INVALID_DATA;
- }
-
- int end_line_no = (std::min)(line_no + num_scanline_blocks,
- (exr_header->data_window[3] + 1));
-
- int num_lines = end_line_no - line_no;
- //assert(num_lines > 0);
-
- if (num_lines <= 0) {
invalid_data = true;
} else {
-
- // Move to data addr: 8 = 4 + 4;
- data_ptr += 8;
-
- // Adjust line_no with data_window.bmin.y
- line_no -= exr_header->data_window[1];
-
- if (line_no < 0) {
+ // 4 byte: scan line
+ // 4 byte: data size
+ // ~ : pixel data(uncompressed or compressed)
+ size_t data_size = size_t(size - (offsets[y_idx] + sizeof(int) * 2));
+ const unsigned char *data_ptr =
+ reinterpret_cast<const unsigned char *>(head + offsets[y_idx]);
+
+ int line_no;
+ memcpy(&line_no, data_ptr, sizeof(int));
+ int data_len;
+ memcpy(&data_len, data_ptr + 4, sizeof(int));
+ tinyexr::swap4(reinterpret_cast<unsigned int *>(&line_no));
+ tinyexr::swap4(reinterpret_cast<unsigned int *>(&data_len));
+
+ if (size_t(data_len) > data_size) {
invalid_data = true;
} else {
- if (!tinyexr::DecodePixelData(
- exr_image->images, exr_header->requested_pixel_types, data_ptr,
- static_cast<size_t>(data_len), exr_header->compression_type,
- exr_header->line_order, data_width, data_height, data_width, y,
- line_no, num_lines, static_cast<size_t>(pixel_data_size),
- static_cast<size_t>(exr_header->num_custom_attributes),
- exr_header->custom_attributes,
- static_cast<size_t>(exr_header->num_channels), exr_header->channels,
- channel_offset_list)) {
+ int end_line_no = (std::min)(line_no + num_scanline_blocks,
+ (exr_header->data_window[3] + 1));
+
+ int num_lines = end_line_no - line_no;
+ // assert(num_lines > 0);
+
+ if (num_lines <= 0) {
invalid_data = true;
+ } else {
+ // Move to data addr: 8 = 4 + 4;
+ data_ptr += 8;
+
+ // Adjust line_no with data_window.bmin.y
+ line_no -= exr_header->data_window[1];
+
+ if (line_no < 0) {
+ invalid_data = true;
+ } else {
+ if (!tinyexr::DecodePixelData(
+ exr_image->images, exr_header->requested_pixel_types,
+ data_ptr, static_cast<size_t>(data_len),
+ exr_header->compression_type, exr_header->line_order,
+ data_width, data_height, data_width, y, line_no,
+ num_lines, static_cast<size_t>(pixel_data_size),
+ static_cast<size_t>(exr_header->num_custom_attributes),
+ exr_header->custom_attributes,
+ static_cast<size_t>(exr_header->num_channels),
+ exr_header->channels, channel_offset_list)) {
+ invalid_data = true;
+ }
+ }
}
}
}
@@ -10648,9 +10944,7 @@ static int DecodeEXRImage(EXRImage *exr_image, const EXRHeader *exr_header,
const char **err) {
if (exr_image == NULL || exr_header == NULL || head == NULL ||
marker == NULL || (size <= tinyexr::kEXRVersionSize)) {
- if (err) {
- (*err) = "Invalid argument.";
- }
+ tinyexr::SetErrorMessage("Invalid argument for DecodeEXRImage().", err);
return TINYEXR_ERROR_INVALID_ARGUMENT;
}
@@ -10663,13 +10957,23 @@ static int DecodeEXRImage(EXRImage *exr_image, const EXRHeader *exr_header,
num_scanline_blocks = 16;
}
- int data_width = exr_header->data_window[2] - exr_header->data_window[0] + 1;
- int data_height = exr_header->data_window[3] - exr_header->data_window[1] + 1;
+ int data_width = exr_header->data_window[2] - exr_header->data_window[0];
+ if (data_width >= std::numeric_limits<int>::max()) {
+ // Issue 63
+ tinyexr::SetErrorMessage("Invalid data window value", err);
+ return TINYEXR_ERROR_INVALID_DATA;
+ }
+ data_width++;
+
+ int data_height = exr_header->data_window[3] - exr_header->data_window[1];
+ if (data_height >= std::numeric_limits<int>::max()) {
+ tinyexr::SetErrorMessage("Invalid data height value", err);
+ return TINYEXR_ERROR_INVALID_DATA;
+ }
+ data_height++;
if ((data_width < 0) || (data_height < 0)) {
- if (err) {
- (*err) = "Invalid data window value.";
- }
+ tinyexr::SetErrorMessage("data window or data height is negative.", err);
return TINYEXR_ERROR_INVALID_DATA;
}
@@ -10708,12 +11012,16 @@ static int DecodeEXRImage(EXRImage *exr_image, const EXRHeader *exr_header,
for (size_t y = 0; y < num_blocks; y++) {
tinyexr::tinyexr_uint64 offset;
+ // Issue #81
+ if ((marker + sizeof(tinyexr_uint64)) >= (head + size)) {
+ tinyexr::SetErrorMessage("Insufficient data size in offset table.", err);
+ return TINYEXR_ERROR_INVALID_DATA;
+ }
+
memcpy(&offset, marker, sizeof(tinyexr::tinyexr_uint64));
tinyexr::swap8(&offset);
if (offset >= size) {
- if (err) {
- (*err) = "Invalid offset value.";
- }
+ tinyexr::SetErrorMessage("Invalid offset value in DecodeEXRImage.", err);
return TINYEXR_ERROR_INVALID_DATA;
}
marker += sizeof(tinyexr::tinyexr_uint64); // = 8
@@ -10736,15 +11044,37 @@ static int DecodeEXRImage(EXRImage *exr_image, const EXRHeader *exr_header,
// OK
break;
} else {
- if (err) {
- (*err) = "Cannot reconstruct lineOffset table.";
- }
+ tinyexr::SetErrorMessage(
+ "Cannot reconstruct lineOffset table in DecodeEXRImage.", err);
return TINYEXR_ERROR_INVALID_DATA;
}
}
}
- return DecodeChunk(exr_image, exr_header, offsets, head, size);
+ {
+ std::string e;
+ int ret = DecodeChunk(exr_image, exr_header, offsets, head, size, &e);
+
+ if (ret != TINYEXR_SUCCESS) {
+ if (!e.empty()) {
+ tinyexr::SetErrorMessage(e, err);
+ }
+
+ // release memory(if exists)
+ if ((exr_header->num_channels > 0) && exr_image && exr_image->images) {
+ for (size_t c = 0; c < size_t(exr_header->num_channels); c++) {
+ if (exr_image->images[c]) {
+ free(exr_image->images[c]);
+ exr_image->images[c] = NULL;
+ }
+ }
+ free(exr_image->images);
+ exr_image->images = NULL;
+ }
+ }
+
+ return ret;
+ }
}
} // namespace tinyexr
@@ -10752,9 +11082,7 @@ static int DecodeEXRImage(EXRImage *exr_image, const EXRHeader *exr_header,
int LoadEXR(float **out_rgba, int *width, int *height, const char *filename,
const char **err) {
if (out_rgba == NULL) {
- if (err) {
- (*err) = "Invalid argument.\n";
- }
+ tinyexr::SetErrorMessage("Invalid argument for LoadEXR()", err);
return TINYEXR_ERROR_INVALID_ARGUMENT;
}
@@ -10767,13 +11095,14 @@ int LoadEXR(float **out_rgba, int *width, int *height, const char *filename,
{
int ret = ParseEXRVersionFromFile(&exr_version, filename);
if (ret != TINYEXR_SUCCESS) {
+ tinyexr::SetErrorMessage("Invalid EXR header.", err);
return ret;
}
if (exr_version.multipart || exr_version.non_image) {
- if (err) {
- (*err) = "Loading multipart or DeepImage is not supported yet.\n";
- }
+ tinyexr::SetErrorMessage(
+ "Loading multipart or DeepImage is not supported in LoadEXR() API",
+ err);
return TINYEXR_ERROR_INVALID_DATA; // @fixme.
}
}
@@ -10781,6 +11110,7 @@ int LoadEXR(float **out_rgba, int *width, int *height, const char *filename,
{
int ret = ParseEXRHeaderFromFile(&exr_header, &exr_version, filename, err);
if (ret != TINYEXR_SUCCESS) {
+ FreeEXRHeader(&exr_header);
return ret;
}
}
@@ -10795,6 +11125,7 @@ int LoadEXR(float **out_rgba, int *width, int *height, const char *filename,
{
int ret = LoadEXRImageFromFile(&exr_image, &exr_header, filename, err);
if (ret != TINYEXR_SUCCESS) {
+ FreeEXRHeader(&exr_header);
return ret;
}
}
@@ -10816,62 +11147,130 @@ int LoadEXR(float **out_rgba, int *width, int *height, const char *filename,
}
}
- if ((idxA == 0) && (idxR == -1) && (idxG == -1) && (idxB == -1)) {
- // Alpha channel only.
+ if (exr_header.num_channels == 1) {
+ // Grayscale channel only.
(*out_rgba) = reinterpret_cast<float *>(
malloc(4 * sizeof(float) * static_cast<size_t>(exr_image.width) *
static_cast<size_t>(exr_image.height)));
- for (int i = 0; i < exr_image.width * exr_image.height; i++) {
- const float val = reinterpret_cast<float **>(exr_image.images)[0][i];
- (*out_rgba)[4 * i + 0] = val;
- (*out_rgba)[4 * i + 1] = val;
- (*out_rgba)[4 * i + 2] = val;
- (*out_rgba)[4 * i + 3] = val;
+
+ if (exr_header.tiled) {
+ // todo.implement this
+
+ for (int it = 0; it < exr_image.num_tiles; it++) {
+ for (int j = 0; j < exr_header.tile_size_y; j++) {
+ for (int i = 0; i < exr_header.tile_size_x; i++) {
+ const int ii =
+ exr_image.tiles[it].offset_x * exr_header.tile_size_x + i;
+ const int jj =
+ exr_image.tiles[it].offset_y * exr_header.tile_size_y + j;
+ const int idx = ii + jj * exr_image.width;
+
+ // out of region check.
+ if (ii >= exr_image.width) {
+ continue;
+ }
+ if (jj >= exr_image.height) {
+ continue;
+ }
+ const int srcIdx = i + j * exr_header.tile_size_x;
+ unsigned char **src = exr_image.tiles[it].images;
+ (*out_rgba)[4 * idx + 0] =
+ reinterpret_cast<float **>(src)[0][srcIdx];
+ (*out_rgba)[4 * idx + 1] =
+ reinterpret_cast<float **>(src)[0][srcIdx];
+ (*out_rgba)[4 * idx + 2] =
+ reinterpret_cast<float **>(src)[0][srcIdx];
+ (*out_rgba)[4 * idx + 3] =
+ reinterpret_cast<float **>(src)[0][srcIdx];
+ }
+ }
+ }
+ } else {
+ for (int i = 0; i < exr_image.width * exr_image.height; i++) {
+ const float val = reinterpret_cast<float **>(exr_image.images)[0][i];
+ (*out_rgba)[4 * i + 0] = val;
+ (*out_rgba)[4 * i + 1] = val;
+ (*out_rgba)[4 * i + 2] = val;
+ (*out_rgba)[4 * i + 3] = val;
+ }
}
} else {
// Assume RGB(A)
if (idxR == -1) {
- if (err) {
- (*err) = "R channel not found\n";
- }
+ tinyexr::SetErrorMessage("R channel not found", err);
// @todo { free exr_image }
+ FreeEXRHeader(&exr_header);
return TINYEXR_ERROR_INVALID_DATA;
}
if (idxG == -1) {
- if (err) {
- (*err) = "G channel not found\n";
- }
+ tinyexr::SetErrorMessage("G channel not found", err);
// @todo { free exr_image }
+ FreeEXRHeader(&exr_header);
return TINYEXR_ERROR_INVALID_DATA;
}
if (idxB == -1) {
- if (err) {
- (*err) = "B channel not found\n";
- }
+ tinyexr::SetErrorMessage("B channel not found", err);
// @todo { free exr_image }
+ FreeEXRHeader(&exr_header);
return TINYEXR_ERROR_INVALID_DATA;
}
(*out_rgba) = reinterpret_cast<float *>(
malloc(4 * sizeof(float) * static_cast<size_t>(exr_image.width) *
static_cast<size_t>(exr_image.height)));
- for (int i = 0; i < exr_image.width * exr_image.height; i++) {
- (*out_rgba)[4 * i + 0] =
- reinterpret_cast<float **>(exr_image.images)[idxR][i];
- (*out_rgba)[4 * i + 1] =
- reinterpret_cast<float **>(exr_image.images)[idxG][i];
- (*out_rgba)[4 * i + 2] =
- reinterpret_cast<float **>(exr_image.images)[idxB][i];
- if (idxA != -1) {
- (*out_rgba)[4 * i + 3] =
- reinterpret_cast<float **>(exr_image.images)[idxA][i];
- } else {
- (*out_rgba)[4 * i + 3] = 1.0;
+ if (exr_header.tiled) {
+ for (int it = 0; it < exr_image.num_tiles; it++) {
+ for (int j = 0; j < exr_header.tile_size_y; j++) {
+ for (int i = 0; i < exr_header.tile_size_x; i++) {
+ const int ii =
+ exr_image.tiles[it].offset_x * exr_header.tile_size_x + i;
+ const int jj =
+ exr_image.tiles[it].offset_y * exr_header.tile_size_y + j;
+ const int idx = ii + jj * exr_image.width;
+
+ // out of region check.
+ if (ii >= exr_image.width) {
+ continue;
+ }
+ if (jj >= exr_image.height) {
+ continue;
+ }
+ const int srcIdx = i + j * exr_header.tile_size_x;
+ unsigned char **src = exr_image.tiles[it].images;
+ (*out_rgba)[4 * idx + 0] =
+ reinterpret_cast<float **>(src)[idxR][srcIdx];
+ (*out_rgba)[4 * idx + 1] =
+ reinterpret_cast<float **>(src)[idxG][srcIdx];
+ (*out_rgba)[4 * idx + 2] =
+ reinterpret_cast<float **>(src)[idxB][srcIdx];
+ if (idxA != -1) {
+ (*out_rgba)[4 * idx + 3] =
+ reinterpret_cast<float **>(src)[idxA][srcIdx];
+ } else {
+ (*out_rgba)[4 * idx + 3] = 1.0;
+ }
+ }
+ }
+ }
+ } else {
+ for (int i = 0; i < exr_image.width * exr_image.height; i++) {
+ (*out_rgba)[4 * i + 0] =
+ reinterpret_cast<float **>(exr_image.images)[idxR][i];
+ (*out_rgba)[4 * i + 1] =
+ reinterpret_cast<float **>(exr_image.images)[idxG][i];
+ (*out_rgba)[4 * i + 2] =
+ reinterpret_cast<float **>(exr_image.images)[idxB][i];
+ if (idxA != -1) {
+ (*out_rgba)[4 * i + 3] =
+ reinterpret_cast<float **>(exr_image.images)[idxA][i];
+ } else {
+ (*out_rgba)[4 * i + 3] = 1.0;
+ }
}
}
}
@@ -10889,15 +11288,17 @@ int ParseEXRHeaderFromMemory(EXRHeader *exr_header, const EXRVersion *version,
const unsigned char *memory, size_t size,
const char **err) {
if (memory == NULL || exr_header == NULL) {
- if (err) {
- (*err) = "Invalid argument.\n";
- }
+ tinyexr::SetErrorMessage(
+ "Invalid argument. `memory` or `exr_header` argument is null in "
+ "ParseEXRHeaderFromMemory()",
+ err);
// Invalid argument
return TINYEXR_ERROR_INVALID_ARGUMENT;
}
if (size < tinyexr::kEXRVersionSize) {
+ tinyexr::SetErrorMessage("Insufficient header/data size.\n", err);
return TINYEXR_ERROR_INVALID_DATA;
}
@@ -10912,11 +11313,7 @@ int ParseEXRHeaderFromMemory(EXRHeader *exr_header, const EXRVersion *version,
if (ret != TINYEXR_SUCCESS) {
if (err && !err_str.empty()) {
-#ifdef _WIN32
- (*err) = _strdup(err_str.c_str()); // May leak
-#else
- (*err) = strdup(err_str.c_str()); // May leak
-#endif
+ tinyexr::SetErrorMessage(err_str, err);
}
}
@@ -10932,9 +11329,7 @@ int LoadEXRFromMemory(float **out_rgba, int *width, int *height,
const unsigned char *memory, size_t size,
const char **err) {
if (out_rgba == NULL || memory == NULL) {
- if (err) {
- (*err) = "Invalid argument.\n";
- }
+ tinyexr::SetErrorMessage("Invalid argument for LoadEXRFromMemory", err);
return TINYEXR_ERROR_INVALID_ARGUMENT;
}
@@ -10946,6 +11341,7 @@ int LoadEXRFromMemory(float **out_rgba, int *width, int *height,
int ret = ParseEXRVersionFromMemory(&exr_version, memory, size);
if (ret != TINYEXR_SUCCESS) {
+ tinyexr::SetErrorMessage("Failed to parse EXR version", err);
return ret;
}
@@ -10985,26 +11381,20 @@ int LoadEXRFromMemory(float **out_rgba, int *width, int *height,
}
if (idxR == -1) {
- if (err) {
- (*err) = "R channel not found\n";
- }
+ tinyexr::SetErrorMessage("R channel not found", err);
// @todo { free exr_image }
return TINYEXR_ERROR_INVALID_DATA;
}
if (idxG == -1) {
- if (err) {
- (*err) = "G channel not found\n";
- }
+ tinyexr::SetErrorMessage("G channel not found", err);
// @todo { free exr_image }
return TINYEXR_ERROR_INVALID_DATA;
}
if (idxB == -1) {
- if (err) {
- (*err) = "B channel not found\n";
- }
+ tinyexr::SetErrorMessage("B channel not found", err);
// @todo { free exr_image }
return TINYEXR_ERROR_INVALID_DATA;
}
@@ -11013,18 +11403,53 @@ int LoadEXRFromMemory(float **out_rgba, int *width, int *height,
malloc(4 * sizeof(float) * static_cast<size_t>(exr_image.width) *
static_cast<size_t>(exr_image.height)));
- for (int i = 0; i < exr_image.width * exr_image.height; i++) {
- (*out_rgba)[4 * i + 0] =
- reinterpret_cast<float **>(exr_image.images)[idxR][i];
- (*out_rgba)[4 * i + 1] =
- reinterpret_cast<float **>(exr_image.images)[idxG][i];
- (*out_rgba)[4 * i + 2] =
- reinterpret_cast<float **>(exr_image.images)[idxB][i];
- if (idxA != -1) {
- (*out_rgba)[4 * i + 3] =
- reinterpret_cast<float **>(exr_image.images)[idxA][i];
- } else {
- (*out_rgba)[4 * i + 3] = 1.0;
+ if (exr_header.tiled) {
+ for (int it = 0; it < exr_image.num_tiles; it++) {
+ for (int j = 0; j < exr_header.tile_size_y; j++)
+ for (int i = 0; i < exr_header.tile_size_x; i++) {
+ const int ii =
+ exr_image.tiles[it].offset_x * exr_header.tile_size_x + i;
+ const int jj =
+ exr_image.tiles[it].offset_y * exr_header.tile_size_y + j;
+ const int idx = ii + jj * exr_image.width;
+
+ // out of region check.
+ if (ii >= exr_image.width) {
+ continue;
+ }
+ if (jj >= exr_image.height) {
+ continue;
+ }
+ const int srcIdx = i + j * exr_header.tile_size_x;
+ unsigned char **src = exr_image.tiles[it].images;
+ (*out_rgba)[4 * idx + 0] =
+ reinterpret_cast<float **>(src)[idxR][srcIdx];
+ (*out_rgba)[4 * idx + 1] =
+ reinterpret_cast<float **>(src)[idxG][srcIdx];
+ (*out_rgba)[4 * idx + 2] =
+ reinterpret_cast<float **>(src)[idxB][srcIdx];
+ if (idxA != -1) {
+ (*out_rgba)[4 * idx + 3] =
+ reinterpret_cast<float **>(src)[idxA][srcIdx];
+ } else {
+ (*out_rgba)[4 * idx + 3] = 1.0;
+ }
+ }
+ }
+ } else {
+ for (int i = 0; i < exr_image.width * exr_image.height; i++) {
+ (*out_rgba)[4 * i + 0] =
+ reinterpret_cast<float **>(exr_image.images)[idxR][i];
+ (*out_rgba)[4 * i + 1] =
+ reinterpret_cast<float **>(exr_image.images)[idxG][i];
+ (*out_rgba)[4 * i + 2] =
+ reinterpret_cast<float **>(exr_image.images)[idxB][i];
+ if (idxA != -1) {
+ (*out_rgba)[4 * i + 3] =
+ reinterpret_cast<float **>(exr_image.images)[idxA][i];
+ } else {
+ (*out_rgba)[4 * i + 3] = 1.0;
+ }
}
}
@@ -11040,9 +11465,7 @@ int LoadEXRFromMemory(float **out_rgba, int *width, int *height,
int LoadEXRImageFromFile(EXRImage *exr_image, const EXRHeader *exr_header,
const char *filename, const char **err) {
if (exr_image == NULL) {
- if (err) {
- (*err) = "Invalid argument.";
- }
+ tinyexr::SetErrorMessage("Invalid argument for LoadEXRImageFromFile", err);
return TINYEXR_ERROR_INVALID_ARGUMENT;
}
@@ -11053,9 +11476,7 @@ int LoadEXRImageFromFile(EXRImage *exr_image, const EXRHeader *exr_header,
FILE *fp = fopen(filename, "rb");
#endif
if (!fp) {
- if (err) {
- (*err) = "Cannot read file.";
- }
+ tinyexr::SetErrorMessage("Cannot read file " + std::string(filename), err);
return TINYEXR_ERROR_CANT_OPEN_FILE;
}
@@ -11065,6 +11486,12 @@ int LoadEXRImageFromFile(EXRImage *exr_image, const EXRHeader *exr_header,
filesize = static_cast<size_t>(ftell(fp));
fseek(fp, 0, SEEK_SET);
+ if (filesize < 16) {
+ tinyexr::SetErrorMessage("File size too short " + std::string(filename),
+ err);
+ return TINYEXR_ERROR_INVALID_FILE;
+ }
+
std::vector<unsigned char> buf(filesize); // @todo { use mmap }
{
size_t ret;
@@ -11083,16 +11510,13 @@ int LoadEXRImageFromMemory(EXRImage *exr_image, const EXRHeader *exr_header,
const char **err) {
if (exr_image == NULL || memory == NULL ||
(size < tinyexr::kEXRVersionSize)) {
- if (err) {
- (*err) = "Invalid argument.";
- }
+ tinyexr::SetErrorMessage("Invalid argument for LoadEXRImageFromMemory",
+ err);
return TINYEXR_ERROR_INVALID_ARGUMENT;
}
if (exr_header->header_len == 0) {
- if (err) {
- (*err) = "EXRHeader is not initialized.";
- }
+ tinyexr::SetErrorMessage("EXRHeader variable is not initialized.", err);
return TINYEXR_ERROR_INVALID_ARGUMENT;
}
@@ -11109,26 +11533,22 @@ size_t SaveEXRImageToMemory(const EXRImage *exr_image,
unsigned char **memory_out, const char **err) {
if (exr_image == NULL || memory_out == NULL ||
exr_header->compression_type < 0) {
- if (err) {
- (*err) = "Invalid argument.";
- }
- return 0; // @fixme
+ tinyexr::SetErrorMessage("Invalid argument for SaveEXRImageToMemory", err);
+ return 0;
}
#if !TINYEXR_USE_PIZ
if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_PIZ) {
- if (err) {
- (*err) = "PIZ compression is not supported in this build.";
- }
+ tinyexr::SetErrorMessage("PIZ compression is not supported in this build",
+ err);
return 0;
}
#endif
#if !TINYEXR_USE_ZFP
if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_ZFP) {
- if (err) {
- (*err) = "ZFP compression is not supported in this build.";
- }
+ tinyexr::SetErrorMessage("ZFP compression is not supported in this build",
+ err);
return 0;
}
#endif
@@ -11136,9 +11556,8 @@ size_t SaveEXRImageToMemory(const EXRImage *exr_image,
#if TINYEXR_USE_ZFP
for (size_t i = 0; i < static_cast<size_t>(exr_header->num_channels); i++) {
if (exr_header->requested_pixel_types[i] != TINYEXR_PIXELTYPE_FLOAT) {
- if (err) {
- (*err) = "Pixel type must be FLOAT for ZFP compression.";
- }
+ tinyexr::SetErrorMessage("Pixel type must be FLOAT for ZFP compression",
+ err);
return 0;
}
}
@@ -11286,8 +11705,6 @@ size_t SaveEXRImageToMemory(const EXRImage *exr_image,
sizeof(
tinyexr::tinyexr_int64); // sizeof(header) + sizeof(offsetTable)
- std::vector<unsigned char> data;
-
std::vector<std::vector<unsigned char> > data_list(
static_cast<size_t>(num_blocks));
std::vector<size_t> channel_offset_list(
@@ -11348,6 +11765,11 @@ size_t SaveEXRImageToMemory(const EXRImage *exr_image,
if (exr_header->pixel_types[c] == TINYEXR_PIXELTYPE_HALF) {
if (exr_header->requested_pixel_types[c] == TINYEXR_PIXELTYPE_FLOAT) {
for (int y = 0; y < h; y++) {
+ // Assume increasing Y
+ float *line_ptr = reinterpret_cast<float *>(&buf.at(
+ static_cast<size_t>(pixel_data_size * y * exr_image->width) +
+ channel_offset_list[c] *
+ static_cast<size_t>(exr_image->width)));
for (int x = 0; x < exr_image->width; x++) {
tinyexr::FP16 h16;
h16.u = reinterpret_cast<unsigned short **>(
@@ -11357,30 +11779,27 @@ size_t SaveEXRImageToMemory(const EXRImage *exr_image,
tinyexr::swap4(reinterpret_cast<unsigned int *>(&f32.f));
- // Assume increasing Y
- float *line_ptr = reinterpret_cast<float *>(&buf.at(
- static_cast<size_t>(pixel_data_size * y * exr_image->width) +
- channel_offset_list[c] *
- static_cast<size_t>(exr_image->width)));
- line_ptr[x] = f32.f;
+ // line_ptr[x] = f32.f;
+ tinyexr::cpy4(line_ptr + x, &(f32.f));
}
}
} else if (exr_header->requested_pixel_types[c] ==
TINYEXR_PIXELTYPE_HALF) {
for (int y = 0; y < h; y++) {
+ // Assume increasing Y
+ unsigned short *line_ptr = reinterpret_cast<unsigned short *>(
+ &buf.at(static_cast<size_t>(pixel_data_size * y *
+ exr_image->width) +
+ channel_offset_list[c] *
+ static_cast<size_t>(exr_image->width)));
for (int x = 0; x < exr_image->width; x++) {
unsigned short val = reinterpret_cast<unsigned short **>(
exr_image->images)[c][(y + start_y) * exr_image->width + x];
tinyexr::swap2(&val);
- // Assume increasing Y
- unsigned short *line_ptr = reinterpret_cast<unsigned short *>(
- &buf.at(static_cast<size_t>(pixel_data_size * y *
- exr_image->width) +
- channel_offset_list[c] *
- static_cast<size_t>(exr_image->width)));
- line_ptr[x] = val;
+ // line_ptr[x] = val;
+ tinyexr::cpy2(line_ptr + x, &val);
}
}
} else {
@@ -11390,6 +11809,12 @@ size_t SaveEXRImageToMemory(const EXRImage *exr_image,
} else if (exr_header->pixel_types[c] == TINYEXR_PIXELTYPE_FLOAT) {
if (exr_header->requested_pixel_types[c] == TINYEXR_PIXELTYPE_HALF) {
for (int y = 0; y < h; y++) {
+ // Assume increasing Y
+ unsigned short *line_ptr = reinterpret_cast<unsigned short *>(
+ &buf.at(static_cast<size_t>(pixel_data_size * y *
+ exr_image->width) +
+ channel_offset_list[c] *
+ static_cast<size_t>(exr_image->width)));
for (int x = 0; x < exr_image->width; x++) {
tinyexr::FP32 f32;
f32.f = reinterpret_cast<float **>(
@@ -11400,30 +11825,26 @@ size_t SaveEXRImageToMemory(const EXRImage *exr_image,
tinyexr::swap2(reinterpret_cast<unsigned short *>(&h16.u));
- // Assume increasing Y
- unsigned short *line_ptr = reinterpret_cast<unsigned short *>(
- &buf.at(static_cast<size_t>(pixel_data_size * y *
- exr_image->width) +
- channel_offset_list[c] *
- static_cast<size_t>(exr_image->width)));
- line_ptr[x] = h16.u;
+ // line_ptr[x] = h16.u;
+ tinyexr::cpy2(line_ptr + x, &(h16.u));
}
}
} else if (exr_header->requested_pixel_types[c] ==
TINYEXR_PIXELTYPE_FLOAT) {
for (int y = 0; y < h; y++) {
+ // Assume increasing Y
+ float *line_ptr = reinterpret_cast<float *>(&buf.at(
+ static_cast<size_t>(pixel_data_size * y * exr_image->width) +
+ channel_offset_list[c] *
+ static_cast<size_t>(exr_image->width)));
for (int x = 0; x < exr_image->width; x++) {
float val = reinterpret_cast<float **>(
exr_image->images)[c][(y + start_y) * exr_image->width + x];
tinyexr::swap4(reinterpret_cast<unsigned int *>(&val));
- // Assume increasing Y
- float *line_ptr = reinterpret_cast<float *>(&buf.at(
- static_cast<size_t>(pixel_data_size * y * exr_image->width) +
- channel_offset_list[c] *
- static_cast<size_t>(exr_image->width)));
- line_ptr[x] = val;
+ // line_ptr[x] = val;
+ tinyexr::cpy4(line_ptr + x, &val);
}
}
} else {
@@ -11431,18 +11852,18 @@ size_t SaveEXRImageToMemory(const EXRImage *exr_image,
}
} else if (exr_header->pixel_types[c] == TINYEXR_PIXELTYPE_UINT) {
for (int y = 0; y < h; y++) {
+ // Assume increasing Y
+ unsigned int *line_ptr = reinterpret_cast<unsigned int *>(&buf.at(
+ static_cast<size_t>(pixel_data_size * y * exr_image->width) +
+ channel_offset_list[c] * static_cast<size_t>(exr_image->width)));
for (int x = 0; x < exr_image->width; x++) {
unsigned int val = reinterpret_cast<unsigned int **>(
exr_image->images)[c][(y + start_y) * exr_image->width + x];
tinyexr::swap4(&val);
- // Assume increasing Y
- unsigned int *line_ptr = reinterpret_cast<unsigned int *>(&buf.at(
- static_cast<size_t>(pixel_data_size * y * exr_image->width) +
- channel_offset_list[c] *
- static_cast<size_t>(exr_image->width)));
- line_ptr[x] = val;
+ // line_ptr[x] = val;
+ tinyexr::cpy4(line_ptr + x, &val);
}
}
}
@@ -11522,9 +11943,9 @@ size_t SaveEXRImageToMemory(const EXRImage *exr_image,
} else if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_PIZ) {
#if TINYEXR_USE_PIZ
unsigned int bufLen =
- 1024 + static_cast<unsigned int>(
- 1.2 * static_cast<unsigned int>(
- buf.size())); // @fixme { compute good bound. }
+ 8192 + static_cast<unsigned int>(
+ 2 * static_cast<unsigned int>(
+ buf.size())); // @fixme { compute good bound. }
std::vector<unsigned char> block(bufLen);
unsigned int outSize = static_cast<unsigned int>(block.size());
@@ -11583,13 +12004,12 @@ size_t SaveEXRImageToMemory(const EXRImage *exr_image,
} // omp parallel
for (size_t i = 0; i < static_cast<size_t>(num_blocks); i++) {
- data.insert(data.end(), data_list[i].begin(), data_list[i].end());
-
offsets[i] = offset;
tinyexr::swap8(reinterpret_cast<tinyexr::tinyexr_uint64 *>(&offsets[i]));
offset += data_list[i].size();
}
+ size_t totalSize = static_cast<size_t>(offset);
{
memory.insert(
memory.end(), reinterpret_cast<unsigned char *>(&offsets.at(0)),
@@ -11597,41 +12017,44 @@ size_t SaveEXRImageToMemory(const EXRImage *exr_image,
sizeof(tinyexr::tinyexr_uint64) * static_cast<size_t>(num_blocks));
}
- { memory.insert(memory.end(), data.begin(), data.end()); }
-
- assert(memory.size() > 0);
+ if ( memory.size() == 0 ) {
+ tinyexr::SetErrorMessage("Output memory size is zero", err);
+ return 0;
+ }
- (*memory_out) = static_cast<unsigned char *>(malloc(memory.size()));
+ (*memory_out) = static_cast<unsigned char *>(malloc(totalSize));
memcpy((*memory_out), &memory.at(0), memory.size());
+ unsigned char *memory_ptr = *memory_out + memory.size();
+
+ for (size_t i = 0; i < static_cast<size_t>(num_blocks); i++) {
+ memcpy(memory_ptr, &data_list[i].at(0), data_list[i].size());
+ memory_ptr += data_list[i].size();
+ }
- return memory.size(); // OK
+ return totalSize; // OK
}
int SaveEXRImageToFile(const EXRImage *exr_image, const EXRHeader *exr_header,
const char *filename, const char **err) {
if (exr_image == NULL || filename == NULL ||
exr_header->compression_type < 0) {
- if (err) {
- (*err) = "Invalid argument.";
- }
+ tinyexr::SetErrorMessage("Invalid argument for SaveEXRImageToFile", err);
return TINYEXR_ERROR_INVALID_ARGUMENT;
}
#if !TINYEXR_USE_PIZ
if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_PIZ) {
- if (err) {
- (*err) = "PIZ compression is not supported in this build.";
- }
- return 0;
+ tinyexr::SetErrorMessage("PIZ compression is not supported in this build",
+ err);
+ return TINYEXR_ERROR_UNSUPPORTED_FEATURE;
}
#endif
#if !TINYEXR_USE_ZFP
if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_ZFP) {
- if (err) {
- (*err) = "ZFP compression is not supported in this build.";
- }
- return 0;
+ tinyexr::SetErrorMessage("ZFP compression is not supported in this build",
+ err);
+ return TINYEXR_ERROR_UNSUPPORTED_FEATURE;
}
#endif
@@ -11642,48 +12065,51 @@ int SaveEXRImageToFile(const EXRImage *exr_image, const EXRHeader *exr_header,
FILE *fp = fopen(filename, "wb");
#endif
if (!fp) {
- if (err) {
- (*err) = "Cannot write a file.";
- }
- return TINYEXR_ERROR_CANT_OPEN_FILE;
+ tinyexr::SetErrorMessage("Cannot write a file", err);
+ return TINYEXR_ERROR_CANT_WRITE_FILE;
}
unsigned char *mem = NULL;
size_t mem_size = SaveEXRImageToMemory(exr_image, exr_header, &mem, err);
+ if (mem_size == 0) {
+ return TINYEXR_ERROR_SERIALZATION_FAILED;
+ }
+ size_t written_size = 0;
if ((mem_size > 0) && mem) {
- fwrite(mem, 1, mem_size, fp);
+ written_size = fwrite(mem, 1, mem_size, fp);
}
free(mem);
fclose(fp);
+ if (written_size != mem_size) {
+ tinyexr::SetErrorMessage("Cannot write a file", err);
+ return TINYEXR_ERROR_CANT_WRITE_FILE;
+ }
+
return TINYEXR_SUCCESS;
}
int LoadDeepEXR(DeepImage *deep_image, const char *filename, const char **err) {
if (deep_image == NULL) {
- if (err) {
- (*err) = "Invalid argument.";
- }
+ tinyexr::SetErrorMessage("Invalid argument for LoadDeepEXR", err);
return TINYEXR_ERROR_INVALID_ARGUMENT;
}
#ifdef _MSC_VER
FILE *fp = NULL;
errno_t errcode = fopen_s(&fp, filename, "rb");
- if ((!errcode) || (!fp)) {
- if (err) {
- (*err) = "Cannot read file.";
- }
+ if ((0 != errcode) || (!fp)) {
+ tinyexr::SetErrorMessage("Cannot read a file " + std::string(filename),
+ err);
return TINYEXR_ERROR_CANT_OPEN_FILE;
}
#else
FILE *fp = fopen(filename, "rb");
if (!fp) {
- if (err) {
- (*err) = "Cannot read file.";
- }
+ tinyexr::SetErrorMessage("Cannot read a file " + std::string(filename),
+ err);
return TINYEXR_ERROR_CANT_OPEN_FILE;
}
#endif
@@ -11696,9 +12122,8 @@ int LoadDeepEXR(DeepImage *deep_image, const char *filename, const char **err) {
if (filesize == 0) {
fclose(fp);
- if (err) {
- (*err) = "File size is zero.";
- }
+ tinyexr::SetErrorMessage("File size is zero : " + std::string(filename),
+ err);
return TINYEXR_ERROR_INVALID_FILE;
}
@@ -11719,9 +12144,7 @@ int LoadDeepEXR(DeepImage *deep_image, const char *filename, const char **err) {
const char header[] = {0x76, 0x2f, 0x31, 0x01};
if (memcmp(marker, header, 4) != 0) {
- if (err) {
- (*err) = "Invalid magic number.";
- }
+ tinyexr::SetErrorMessage("Invalid magic number", err);
return TINYEXR_ERROR_INVALID_MAGIC_NUMBER;
}
marker += 4;
@@ -11732,9 +12155,7 @@ int LoadDeepEXR(DeepImage *deep_image, const char *filename, const char **err) {
// ver 2.0, scanline, deep bit on(0x800)
// must be [2, 0, 0, 0]
if (marker[0] != 2 || marker[1] != 8 || marker[2] != 0 || marker[3] != 0) {
- if (err) {
- (*err) = "Unsupported version or scanline.";
- }
+ tinyexr::SetErrorMessage("Unsupported version or scanline", err);
return TINYEXR_ERROR_UNSUPPORTED_FORMAT;
}
@@ -11775,9 +12196,9 @@ int LoadDeepEXR(DeepImage *deep_image, const char *filename, const char **err) {
if (attr_name.compare("compression") == 0) {
compression_type = data[0];
if (compression_type > TINYEXR_COMPRESSIONTYPE_PIZ) {
- if (err) {
- (*err) = "Unsupported compression type.";
- }
+ std::stringstream ss;
+ ss << "Unsupported compression type : " << compression_type;
+ tinyexr::SetErrorMessage(ss.str(), err);
return TINYEXR_ERROR_UNSUPPORTED_FORMAT;
}
@@ -11794,18 +12215,14 @@ int LoadDeepEXR(DeepImage *deep_image, const char *filename, const char **err) {
// ySampling: int
if (!tinyexr::ReadChannelInfo(channels, data)) {
- if (err) {
- (*err) = "Failed to parse channel info.";
- }
+ tinyexr::SetErrorMessage("Failed to parse channel info", err);
return TINYEXR_ERROR_INVALID_DATA;
}
num_channels = static_cast<int>(channels.size());
if (num_channels < 1) {
- if (err) {
- (*err) = "Invalid channels format.";
- }
+ tinyexr::SetErrorMessage("Invalid channels format", err);
return TINYEXR_ERROR_INVALID_DATA;
}
@@ -11877,9 +12294,7 @@ int LoadDeepEXR(DeepImage *deep_image, const char *filename, const char **err) {
#endif
// OK
} else {
- if (err) {
- (*err) = "Unsupported format.";
- }
+ tinyexr::SetErrorMessage("Unsupported compression format", err);
return TINYEXR_ERROR_UNSUPPORTED_FORMAT;
}
@@ -11936,8 +12351,9 @@ int LoadDeepEXR(DeepImage *deep_image, const char *filename, const char **err) {
unsigned long dstLen =
static_cast<unsigned long>(pixelOffsetTable.size() * sizeof(int));
if (!tinyexr::DecompressZip(
- reinterpret_cast<unsigned char *>(&pixelOffsetTable.at(0)), &dstLen,
- data_ptr + 28, static_cast<unsigned long>(packedOffsetTableSize))) {
+ reinterpret_cast<unsigned char *>(&pixelOffsetTable.at(0)),
+ &dstLen, data_ptr + 28,
+ static_cast<unsigned long>(packedOffsetTableSize))) {
return false;
}
@@ -11955,9 +12371,9 @@ int LoadDeepEXR(DeepImage *deep_image, const char *filename, const char **err) {
unsigned long dstLen = static_cast<unsigned long>(unpackedSampleDataSize);
if (dstLen) {
if (!tinyexr::DecompressZip(
- reinterpret_cast<unsigned char *>(&sample_data.at(0)), &dstLen,
- data_ptr + 28 + packedOffsetTableSize,
- static_cast<unsigned long>(packedSampleDataSize))) {
+ reinterpret_cast<unsigned char *>(&sample_data.at(0)), &dstLen,
+ data_ptr + 28 + packedOffsetTableSize,
+ static_cast<unsigned long>(packedSampleDataSize))) {
return false;
}
assert(dstLen == static_cast<unsigned long>(unpackedSampleDataSize));
@@ -12006,8 +12422,10 @@ int LoadDeepEXR(DeepImage *deep_image, const char *filename, const char **err) {
if (channels[c].pixel_type == 0) { // UINT
for (size_t x = 0; x < static_cast<size_t>(samples_per_line); x++) {
- unsigned int ui = *reinterpret_cast<unsigned int *>(
+ unsigned int ui;
+ unsigned int *src_ptr = reinterpret_cast<unsigned int *>(
&sample_data.at(size_t(data_offset) + x * sizeof(int)));
+ tinyexr::cpy4(&ui, src_ptr);
deep_image->image[c][y][x] = static_cast<float>(ui); // @fixme
}
data_offset +=
@@ -12015,16 +12433,19 @@ int LoadDeepEXR(DeepImage *deep_image, const char *filename, const char **err) {
} else if (channels[c].pixel_type == 1) { // half
for (size_t x = 0; x < static_cast<size_t>(samples_per_line); x++) {
tinyexr::FP16 f16;
- f16.u = *reinterpret_cast<unsigned short *>(
+ const unsigned short *src_ptr = reinterpret_cast<unsigned short *>(
&sample_data.at(size_t(data_offset) + x * sizeof(short)));
+ tinyexr::cpy2(&(f16.u), src_ptr);
tinyexr::FP32 f32 = half_to_float(f16);
deep_image->image[c][y][x] = f32.f;
}
data_offset += sizeof(short) * static_cast<size_t>(samples_per_line);
} else { // float
for (size_t x = 0; x < static_cast<size_t>(samples_per_line); x++) {
- float f = *reinterpret_cast<float *>(
+ float f;
+ const float *src_ptr = reinterpret_cast<float *>(
&sample_data.at(size_t(data_offset) + x * sizeof(float)));
+ tinyexr::cpy4(&f, src_ptr);
deep_image->image[c][y][x] = f;
}
data_offset += sizeof(float) * static_cast<size_t>(samples_per_line);
@@ -12065,6 +12486,13 @@ void InitEXRImage(EXRImage *exr_image) {
exr_image->num_tiles = 0;
}
+void FreeEXRErrorMessage(const char *msg) {
+ if (msg) {
+ free(reinterpret_cast<void *>(const_cast<char *>(msg)));
+ }
+ return;
+}
+
void InitEXRHeader(EXRHeader *exr_header) {
if (exr_header == NULL) {
return;
@@ -12096,6 +12524,10 @@ int FreeEXRHeader(EXRHeader *exr_header) {
}
}
+ if (exr_header->custom_attributes) {
+ free(exr_header->custom_attributes);
+ }
+
return TINYEXR_SUCCESS;
}
@@ -12125,6 +12557,7 @@ int FreeEXRImage(EXRImage *exr_image) {
free(exr_image->tiles[tid].images);
}
}
+ free(exr_image->tiles);
}
return TINYEXR_SUCCESS;
@@ -12133,9 +12566,8 @@ int FreeEXRImage(EXRImage *exr_image) {
int ParseEXRHeaderFromFile(EXRHeader *exr_header, const EXRVersion *exr_version,
const char *filename, const char **err) {
if (exr_header == NULL || exr_version == NULL || filename == NULL) {
- if (err) {
- (*err) = "Invalid argument.";
- }
+ tinyexr::SetErrorMessage("Invalid argument for ParseEXRHeaderFromFile",
+ err);
return TINYEXR_ERROR_INVALID_ARGUMENT;
}
@@ -12146,9 +12578,7 @@ int ParseEXRHeaderFromFile(EXRHeader *exr_header, const EXRVersion *exr_version,
FILE *fp = fopen(filename, "rb");
#endif
if (!fp) {
- if (err) {
- (*err) = "Cannot read file.";
- }
+ tinyexr::SetErrorMessage("Cannot read file " + std::string(filename), err);
return TINYEXR_ERROR_CANT_OPEN_FILE;
}
@@ -12166,9 +12596,8 @@ int ParseEXRHeaderFromFile(EXRHeader *exr_header, const EXRVersion *exr_version,
fclose(fp);
if (ret != filesize) {
- if (err) {
- (*err) = "fread error.";
- }
+ tinyexr::SetErrorMessage("fread() error on " + std::string(filename),
+ err);
return TINYEXR_ERROR_INVALID_FILE;
}
}
@@ -12185,10 +12614,13 @@ int ParseEXRMultipartHeaderFromMemory(EXRHeader ***exr_headers,
if (memory == NULL || exr_headers == NULL || num_headers == NULL ||
exr_version == NULL) {
// Invalid argument
+ tinyexr::SetErrorMessage(
+ "Invalid argument for ParseEXRMultipartHeaderFromMemory", err);
return TINYEXR_ERROR_INVALID_ARGUMENT;
}
if (size < tinyexr::kEXRVersionSize) {
+ tinyexr::SetErrorMessage("Data size too short", err);
return TINYEXR_ERROR_INVALID_DATA;
}
@@ -12207,13 +12639,7 @@ int ParseEXRMultipartHeaderFromMemory(EXRHeader ***exr_headers,
marker, marker_size);
if (ret != TINYEXR_SUCCESS) {
- if (err) {
-#ifdef _WIN32
- (*err) = _strdup(err_str.c_str()); // may leak
-#else
- (*err) = strdup(err_str.c_str()); // may leak
-#endif
- }
+ tinyexr::SetErrorMessage(err_str, err);
return ret;
}
@@ -12224,9 +12650,8 @@ int ParseEXRMultipartHeaderFromMemory(EXRHeader ***exr_headers,
// `chunkCount` must exist in the header.
if (info.chunk_count == 0) {
- if (err) {
- (*err) = "`chunkCount' attribute is not found in the header.";
- }
+ tinyexr::SetErrorMessage(
+ "`chunkCount' attribute is not found in the header.", err);
return TINYEXR_ERROR_INVALID_DATA;
}
@@ -12261,9 +12686,8 @@ int ParseEXRMultipartHeaderFromFile(EXRHeader ***exr_headers, int *num_headers,
const char *filename, const char **err) {
if (exr_headers == NULL || num_headers == NULL || exr_version == NULL ||
filename == NULL) {
- if (err) {
- (*err) = "Invalid argument.";
- }
+ tinyexr::SetErrorMessage(
+ "Invalid argument for ParseEXRMultipartHeaderFromFile()", err);
return TINYEXR_ERROR_INVALID_ARGUMENT;
}
@@ -12274,9 +12698,7 @@ int ParseEXRMultipartHeaderFromFile(EXRHeader ***exr_headers, int *num_headers,
FILE *fp = fopen(filename, "rb");
#endif
if (!fp) {
- if (err) {
- (*err) = "Cannot read file.";
- }
+ tinyexr::SetErrorMessage("Cannot read file " + std::string(filename), err);
return TINYEXR_ERROR_CANT_OPEN_FILE;
}
@@ -12294,9 +12716,7 @@ int ParseEXRMultipartHeaderFromFile(EXRHeader ***exr_headers, int *num_headers,
fclose(fp);
if (ret != filesize) {
- if (err) {
- (*err) = "fread error.";
- }
+ tinyexr::SetErrorMessage("`fread' error. file may be corrupted.", err);
return TINYEXR_ERROR_INVALID_FILE;
}
}
@@ -12405,9 +12825,8 @@ int LoadEXRMultipartImageFromMemory(EXRImage *exr_images,
const size_t size, const char **err) {
if (exr_images == NULL || exr_headers == NULL || num_parts == 0 ||
memory == NULL || (size <= tinyexr::kEXRVersionSize)) {
- if (err) {
- (*err) = "Invalid argument.";
- }
+ tinyexr::SetErrorMessage(
+ "Invalid argument for LoadEXRMultipartImageFromMemory()", err);
return TINYEXR_ERROR_INVALID_ARGUMENT;
}
@@ -12415,9 +12834,7 @@ int LoadEXRMultipartImageFromMemory(EXRImage *exr_images,
size_t total_header_size = 0;
for (unsigned int i = 0; i < num_parts; i++) {
if (exr_headers[i]->header_len == 0) {
- if (err) {
- (*err) = "EXRHeader is not initialized.";
- }
+ tinyexr::SetErrorMessage("EXRHeader variable is not initialized.", err);
return TINYEXR_ERROR_INVALID_ARGUMENT;
}
@@ -12452,9 +12869,8 @@ int LoadEXRMultipartImageFromMemory(EXRImage *exr_images,
tinyexr::swap8(&offset);
if (offset >= size) {
- if (err) {
- (*err) = "Invalid offset size.";
- }
+ tinyexr::SetErrorMessage("Invalid offset size in EXR header chunks.",
+ err);
return TINYEXR_ERROR_INVALID_DATA;
}
@@ -12479,14 +12895,19 @@ int LoadEXRMultipartImageFromMemory(EXRImage *exr_images,
tinyexr::swap4(&part_no);
if (part_no != i) {
- assert(0);
+ tinyexr::SetErrorMessage("Invalid `part number' in EXR header chunks.",
+ err);
return TINYEXR_ERROR_INVALID_DATA;
}
}
+ std::string e;
int ret = tinyexr::DecodeChunk(&exr_images[i], exr_headers[i], offset_table,
- memory, size);
+ memory, size, &e);
if (ret != TINYEXR_SUCCESS) {
+ if (!e.empty()) {
+ tinyexr::SetErrorMessage(e, err);
+ }
return ret;
}
}
@@ -12499,9 +12920,8 @@ int LoadEXRMultipartImageFromFile(EXRImage *exr_images,
unsigned int num_parts, const char *filename,
const char **err) {
if (exr_images == NULL || exr_headers == NULL || num_parts == 0) {
- if (err) {
- (*err) = "Invalid argument.";
- }
+ tinyexr::SetErrorMessage(
+ "Invalid argument for LoadEXRMultipartImageFromFile", err);
return TINYEXR_ERROR_INVALID_ARGUMENT;
}
@@ -12512,9 +12932,7 @@ int LoadEXRMultipartImageFromFile(EXRImage *exr_images,
FILE *fp = fopen(filename, "rb");
#endif
if (!fp) {
- if (err) {
- (*err) = "Cannot read file.";
- }
+ tinyexr::SetErrorMessage("Cannot read file " + std::string(filename), err);
return TINYEXR_ERROR_CANT_OPEN_FILE;
}
@@ -12538,20 +12956,27 @@ int LoadEXRMultipartImageFromFile(EXRImage *exr_images,
}
int SaveEXR(const float *data, int width, int height, int components,
- const int save_as_fp16, const char *outfilename) {
+ const int save_as_fp16, const char *outfilename, const char **err) {
if ((components == 1) || components == 3 || components == 4) {
// OK
} else {
+ std::stringstream ss;
+ ss << "Unsupported component value : " << components << std::endl;
+
+ tinyexr::SetErrorMessage(ss.str(), err);
return TINYEXR_ERROR_INVALID_ARGUMENT;
}
- // Assume at least 16x16 pixels.
- if (width < 16) return TINYEXR_ERROR_INVALID_ARGUMENT;
- if (height < 16) return TINYEXR_ERROR_INVALID_ARGUMENT;
-
EXRHeader header;
InitEXRHeader(&header);
+ if ((width < 16) && (height < 16)) {
+ // No compression for small image.
+ header.compression_type = TINYEXR_COMPRESSIONTYPE_NONE;
+ } else {
+ header.compression_type = TINYEXR_COMPRESSIONTYPE_ZIP;
+ }
+
EXRImage image;
InitEXRImage(&image);
@@ -12657,8 +13082,7 @@ int SaveEXR(const float *data, int width, int height, int components,
}
}
- const char *err;
- int ret = SaveEXRImageToFile(&image, &header, outfilename, &err);
+ int ret = SaveEXRImageToFile(&image, &header, outfilename, err);
if (ret != TINYEXR_SUCCESS) {
return ret;
}
@@ -12670,5 +13094,10 @@ int SaveEXR(const float *data, int width, int height, int components,
return ret;
}
+#ifdef __clang__
+// zero-as-null-ppinter-constant
+#pragma clang diagnostic pop
+#endif
+
#endif // TINYEXR_IMPLEMENTATION_DEIFNED
#endif // TINYEXR_IMPLEMENTATION
diff --git a/thirdparty/xatlas/xatlas.cpp b/thirdparty/xatlas/xatlas.cpp
new file mode 100644
index 0000000000..f6a9ce64dc
--- /dev/null
+++ b/thirdparty/xatlas/xatlas.cpp
@@ -0,0 +1,7384 @@
+// This code is in the public domain -- castanyo@yahoo.es
+#include "xatlas.h"
+#include <assert.h>
+#include <float.h>
+#include <math.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <algorithm>
+#include <cmath>
+#include <memory>
+#include <unordered_map>
+#include <vector>
+
+#undef min
+#undef max
+
+#ifndef xaAssert
+#define xaAssert(exp) \
+ if (!(exp)) { \
+ xaPrint("%s %s %s\n", #exp, __FILE__, __LINE__); \
+ }
+#endif
+#ifndef xaDebugAssert
+#define xaDebugAssert(exp) assert(exp)
+#endif
+#ifndef xaPrint
+#define xaPrint(...) \
+ if (xatlas::internal::s_print) { \
+ xatlas::internal::s_print(__VA_ARGS__); \
+ }
+#endif
+
+#ifdef _MSC_VER
+// Ignore gcc attributes.
+#define __attribute__(X)
+#endif
+
+#ifdef _MSC_VER
+#define restrict
+#define NV_FORCEINLINE __forceinline
+#else
+#define restrict __restrict__
+#define NV_FORCEINLINE __attribute__((always_inline)) inline
+#endif
+
+#define NV_UINT32_MAX 0xffffffff
+#define NV_FLOAT_MAX 3.402823466e+38F
+
+#ifndef PI
+#define PI float(3.1415926535897932384626433833)
+#endif
+
+#define NV_EPSILON (0.0001f)
+#define NV_NORMAL_EPSILON (0.001f)
+
+namespace xatlas {
+namespace internal {
+
+static PrintFunc s_print = NULL;
+
+static int align(int x, int a) {
+ return (x + a - 1) & ~(a - 1);
+}
+
+static bool isAligned(int x, int a) {
+ return (x & (a - 1)) == 0;
+}
+
+/// Return the maximum of the three arguments.
+template <typename T>
+static T max3(const T &a, const T &b, const T &c) {
+ return std::max(a, std::max(b, c));
+}
+
+/// Return the maximum of the three arguments.
+template <typename T>
+static T min3(const T &a, const T &b, const T &c) {
+ return std::min(a, std::min(b, c));
+}
+
+/// Clamp between two values.
+template <typename T>
+static T clamp(const T &x, const T &a, const T &b) {
+ return std::min(std::max(x, a), b);
+}
+
+static float saturate(float f) {
+ return clamp(f, 0.0f, 1.0f);
+}
+
+// Robust floating point comparisons:
+// http://realtimecollisiondetection.net/blog/?p=89
+static bool equal(const float f0, const float f1, const float epsilon = NV_EPSILON) {
+ //return fabs(f0-f1) <= epsilon;
+ return fabs(f0 - f1) <= epsilon * max3(1.0f, fabsf(f0), fabsf(f1));
+}
+
+NV_FORCEINLINE static int ftoi_floor(float val) {
+ return (int)val;
+}
+
+NV_FORCEINLINE static int ftoi_ceil(float val) {
+ return (int)ceilf(val);
+}
+
+NV_FORCEINLINE static int ftoi_round(float f) {
+ return int(floorf(f + 0.5f));
+}
+
+static bool isZero(const float f, const float epsilon = NV_EPSILON) {
+ return fabs(f) <= epsilon;
+}
+
+static float lerp(float f0, float f1, float t) {
+ const float s = 1.0f - t;
+ return f0 * s + f1 * t;
+}
+
+static float square(float f) {
+ return f * f;
+}
+
+static int square(int i) {
+ return i * i;
+}
+
+/** Return the next power of two.
+* @see http://graphics.stanford.edu/~seander/bithacks.html
+* @warning Behaviour for 0 is undefined.
+* @note isPowerOfTwo(x) == true -> nextPowerOfTwo(x) == x
+* @note nextPowerOfTwo(x) = 2 << log2(x-1)
+*/
+static uint32_t nextPowerOfTwo(uint32_t x) {
+ xaDebugAssert(x != 0);
+ // On modern CPUs this is supposed to be as fast as using the bsr instruction.
+ x--;
+ x |= x >> 1;
+ x |= x >> 2;
+ x |= x >> 4;
+ x |= x >> 8;
+ x |= x >> 16;
+ return x + 1;
+}
+
+static uint64_t nextPowerOfTwo(uint64_t x) {
+ xaDebugAssert(x != 0);
+ uint32_t p = 1;
+ while (x > p) {
+ p += p;
+ }
+ return p;
+}
+
+static uint32_t sdbmHash(const void *data_in, uint32_t size, uint32_t h = 5381) {
+ const uint8_t *data = (const uint8_t *)data_in;
+ uint32_t i = 0;
+ while (i < size) {
+ h = (h << 16) + (h << 6) - h + (uint32_t)data[i++];
+ }
+ return h;
+}
+
+// Note that this hash does not handle NaN properly.
+static uint32_t sdbmFloatHash(const float *f, uint32_t count, uint32_t h = 5381) {
+ for (uint32_t i = 0; i < count; i++) {
+ union {
+ float f;
+ uint32_t i;
+ } x = { f[i] };
+ if (x.i == 0x80000000) x.i = 0;
+ h = sdbmHash(&x, 4, h);
+ }
+ return h;
+}
+
+template <typename T>
+static uint32_t hash(const T &t, uint32_t h = 5381) {
+ return sdbmHash(&t, sizeof(T), h);
+}
+
+static uint32_t hash(const float &f, uint32_t h) {
+ return sdbmFloatHash(&f, 1, h);
+}
+
+// Functors for hash table:
+template <typename Key>
+struct Hash {
+ uint32_t operator()(const Key &k) const { return hash(k); }
+};
+
+template <typename Key>
+struct Equal {
+ bool operator()(const Key &k0, const Key &k1) const { return k0 == k1; }
+};
+
+class Vector2 {
+public:
+ typedef Vector2 const &Arg;
+
+ Vector2() {}
+ explicit Vector2(float f) :
+ x(f),
+ y(f) {}
+ Vector2(float x, float y) :
+ x(x),
+ y(y) {}
+ Vector2(Vector2::Arg v) :
+ x(v.x),
+ y(v.y) {}
+
+ const Vector2 &operator=(Vector2::Arg v) {
+ x = v.x;
+ y = v.y;
+ return *this;
+ }
+ const float *ptr() const { return &x; }
+
+ void set(float _x, float _y) {
+ x = _x;
+ y = _y;
+ }
+
+ Vector2 operator-() const {
+ return Vector2(-x, -y);
+ }
+
+ void operator+=(Vector2::Arg v) {
+ x += v.x;
+ y += v.y;
+ }
+
+ void operator-=(Vector2::Arg v) {
+ x -= v.x;
+ y -= v.y;
+ }
+
+ void operator*=(float s) {
+ x *= s;
+ y *= s;
+ }
+
+ void operator*=(Vector2::Arg v) {
+ x *= v.x;
+ y *= v.y;
+ }
+
+ friend bool operator==(Vector2::Arg a, Vector2::Arg b) {
+ return a.x == b.x && a.y == b.y;
+ }
+
+ friend bool operator!=(Vector2::Arg a, Vector2::Arg b) {
+ return a.x != b.x || a.y != b.y;
+ }
+
+ union {
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable : 4201)
+#endif
+ struct
+ {
+ float x, y;
+ };
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+ float component[2];
+ };
+};
+
+Vector2 operator+(Vector2::Arg a, Vector2::Arg b) {
+ return Vector2(a.x + b.x, a.y + b.y);
+}
+
+Vector2 operator-(Vector2::Arg a, Vector2::Arg b) {
+ return Vector2(a.x - b.x, a.y - b.y);
+}
+
+Vector2 operator*(Vector2::Arg v, float s) {
+ return Vector2(v.x * s, v.y * s);
+}
+
+Vector2 operator*(Vector2::Arg v1, Vector2::Arg v2) {
+ return Vector2(v1.x * v2.x, v1.y * v2.y);
+}
+
+Vector2 operator/(Vector2::Arg v, float s) {
+ return Vector2(v.x / s, v.y / s);
+}
+
+Vector2 lerp(Vector2::Arg v1, Vector2::Arg v2, float t) {
+ const float s = 1.0f - t;
+ return Vector2(v1.x * s + t * v2.x, v1.y * s + t * v2.y);
+}
+
+float dot(Vector2::Arg a, Vector2::Arg b) {
+ return a.x * b.x + a.y * b.y;
+}
+
+float lengthSquared(Vector2::Arg v) {
+ return v.x * v.x + v.y * v.y;
+}
+
+float length(Vector2::Arg v) {
+ return sqrtf(lengthSquared(v));
+}
+
+float distance(Vector2::Arg a, Vector2::Arg b) {
+ return length(a - b);
+}
+
+bool isNormalized(Vector2::Arg v, float epsilon = NV_NORMAL_EPSILON) {
+ return equal(length(v), 1, epsilon);
+}
+
+Vector2 normalize(Vector2::Arg v, float epsilon = NV_EPSILON) {
+ float l = length(v);
+ xaDebugAssert(!isZero(l, epsilon));
+#ifdef NDEBUG
+ epsilon = 0; // silence unused parameter warning
+#endif
+ Vector2 n = v * (1.0f / l);
+ xaDebugAssert(isNormalized(n));
+ return n;
+}
+
+Vector2 normalizeSafe(Vector2::Arg v, Vector2::Arg fallback, float epsilon = NV_EPSILON) {
+ float l = length(v);
+ if (isZero(l, epsilon)) {
+ return fallback;
+ }
+ return v * (1.0f / l);
+}
+
+bool equal(Vector2::Arg v1, Vector2::Arg v2, float epsilon = NV_EPSILON) {
+ return equal(v1.x, v2.x, epsilon) && equal(v1.y, v2.y, epsilon);
+}
+
+Vector2 max(Vector2::Arg a, Vector2::Arg b) {
+ return Vector2(std::max(a.x, b.x), std::max(a.y, b.y));
+}
+
+bool isFinite(Vector2::Arg v) {
+ return std::isfinite(v.x) && std::isfinite(v.y);
+}
+
+// Note, this is the area scaled by 2!
+float triangleArea(Vector2::Arg v0, Vector2::Arg v1) {
+ return (v0.x * v1.y - v0.y * v1.x); // * 0.5f;
+}
+float triangleArea(Vector2::Arg a, Vector2::Arg b, Vector2::Arg c) {
+ // IC: While it may be appealing to use the following expression:
+ //return (c.x * a.y + a.x * b.y + b.x * c.y - b.x * a.y - c.x * b.y - a.x * c.y); // * 0.5f;
+ // That's actually a terrible idea. Small triangles far from the origin can end up producing fairly large floating point
+ // numbers and the results becomes very unstable and dependent on the order of the factors.
+ // Instead, it's preferable to subtract the vertices first, and multiply the resulting small values together. The result
+ // in this case is always much more accurate (as long as the triangle is small) and less dependent of the location of
+ // the triangle.
+ //return ((a.x - c.x) * (b.y - c.y) - (a.y - c.y) * (b.x - c.x)); // * 0.5f;
+ return triangleArea(a - c, b - c);
+}
+
+float triangleArea2(Vector2::Arg v1, Vector2::Arg v2, Vector2::Arg v3) {
+ return 0.5f * (v3.x * v1.y + v1.x * v2.y + v2.x * v3.y - v2.x * v1.y - v3.x * v2.y - v1.x * v3.y);
+}
+
+static uint32_t hash(const Vector2 &v, uint32_t h) {
+ return sdbmFloatHash(v.component, 2, h);
+}
+
+class Vector3 {
+public:
+ typedef Vector3 const &Arg;
+
+ Vector3() {}
+ explicit Vector3(float f) :
+ x(f),
+ y(f),
+ z(f) {}
+ Vector3(float x, float y, float z) :
+ x(x),
+ y(y),
+ z(z) {}
+ Vector3(Vector2::Arg v, float z) :
+ x(v.x),
+ y(v.y),
+ z(z) {}
+ Vector3(Vector3::Arg v) :
+ x(v.x),
+ y(v.y),
+ z(v.z) {}
+
+ const Vector3 &operator=(Vector3::Arg v) {
+ x = v.x;
+ y = v.y;
+ z = v.z;
+ return *this;
+ }
+
+ Vector2 xy() const {
+ return Vector2(x, y);
+ }
+
+ const float *ptr() const { return &x; }
+
+ void set(float _x, float _y, float _z) {
+ x = _x;
+ y = _y;
+ z = _z;
+ }
+
+ Vector3 operator-() const {
+ return Vector3(-x, -y, -z);
+ }
+
+ void operator+=(Vector3::Arg v) {
+ x += v.x;
+ y += v.y;
+ z += v.z;
+ }
+
+ void operator-=(Vector3::Arg v) {
+ x -= v.x;
+ y -= v.y;
+ z -= v.z;
+ }
+
+ void operator*=(float s) {
+ x *= s;
+ y *= s;
+ z *= s;
+ }
+
+ void operator/=(float s) {
+ float is = 1.0f / s;
+ x *= is;
+ y *= is;
+ z *= is;
+ }
+
+ void operator*=(Vector3::Arg v) {
+ x *= v.x;
+ y *= v.y;
+ z *= v.z;
+ }
+
+ void operator/=(Vector3::Arg v) {
+ x /= v.x;
+ y /= v.y;
+ z /= v.z;
+ }
+
+ friend bool operator==(Vector3::Arg a, Vector3::Arg b) {
+ return a.x == b.x && a.y == b.y && a.z == b.z;
+ }
+
+ friend bool operator!=(Vector3::Arg a, Vector3::Arg b) {
+ return a.x != b.x || a.y != b.y || a.z != b.z;
+ }
+
+ union {
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable : 4201)
+#endif
+ struct
+ {
+ float x, y, z;
+ };
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+ float component[3];
+ };
+};
+
+Vector3 add(Vector3::Arg a, Vector3::Arg b) {
+ return Vector3(a.x + b.x, a.y + b.y, a.z + b.z);
+}
+Vector3 add(Vector3::Arg a, float b) {
+ return Vector3(a.x + b, a.y + b, a.z + b);
+}
+Vector3 operator+(Vector3::Arg a, Vector3::Arg b) {
+ return add(a, b);
+}
+Vector3 operator+(Vector3::Arg a, float b) {
+ return add(a, b);
+}
+
+Vector3 sub(Vector3::Arg a, Vector3::Arg b) {
+ return Vector3(a.x - b.x, a.y - b.y, a.z - b.z);
+}
+
+Vector3 sub(Vector3::Arg a, float b) {
+ return Vector3(a.x - b, a.y - b, a.z - b);
+}
+
+Vector3 operator-(Vector3::Arg a, Vector3::Arg b) {
+ return sub(a, b);
+}
+
+Vector3 operator-(Vector3::Arg a, float b) {
+ return sub(a, b);
+}
+
+Vector3 cross(Vector3::Arg a, Vector3::Arg b) {
+ return Vector3(a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x);
+}
+
+Vector3 operator*(Vector3::Arg v, float s) {
+ return Vector3(v.x * s, v.y * s, v.z * s);
+}
+
+Vector3 operator*(float s, Vector3::Arg v) {
+ return Vector3(v.x * s, v.y * s, v.z * s);
+}
+
+Vector3 operator*(Vector3::Arg v, Vector3::Arg s) {
+ return Vector3(v.x * s.x, v.y * s.y, v.z * s.z);
+}
+
+Vector3 operator/(Vector3::Arg v, float s) {
+ return v * (1.0f / s);
+}
+
+Vector3 lerp(Vector3::Arg v1, Vector3::Arg v2, float t) {
+ const float s = 1.0f - t;
+ return Vector3(v1.x * s + t * v2.x, v1.y * s + t * v2.y, v1.z * s + t * v2.z);
+}
+
+float dot(Vector3::Arg a, Vector3::Arg b) {
+ return a.x * b.x + a.y * b.y + a.z * b.z;
+}
+
+float lengthSquared(Vector3::Arg v) {
+ return v.x * v.x + v.y * v.y + v.z * v.z;
+}
+
+float length(Vector3::Arg v) {
+ return sqrtf(lengthSquared(v));
+}
+
+float distance(Vector3::Arg a, Vector3::Arg b) {
+ return length(a - b);
+}
+
+float distanceSquared(Vector3::Arg a, Vector3::Arg b) {
+ return lengthSquared(a - b);
+}
+
+bool isNormalized(Vector3::Arg v, float epsilon = NV_NORMAL_EPSILON) {
+ return equal(length(v), 1, epsilon);
+}
+
+Vector3 normalize(Vector3::Arg v, float epsilon = NV_EPSILON) {
+ float l = length(v);
+ xaDebugAssert(!isZero(l, epsilon));
+#ifdef NDEBUG
+ epsilon = 0; // silence unused parameter warning
+#endif
+ Vector3 n = v * (1.0f / l);
+ xaDebugAssert(isNormalized(n));
+ return n;
+}
+
+Vector3 normalizeSafe(Vector3::Arg v, Vector3::Arg fallback, float epsilon = NV_EPSILON) {
+ float l = length(v);
+ if (isZero(l, epsilon)) {
+ return fallback;
+ }
+ return v * (1.0f / l);
+}
+
+bool equal(Vector3::Arg v1, Vector3::Arg v2, float epsilon = NV_EPSILON) {
+ return equal(v1.x, v2.x, epsilon) && equal(v1.y, v2.y, epsilon) && equal(v1.z, v2.z, epsilon);
+}
+
+Vector3 min(Vector3::Arg a, Vector3::Arg b) {
+ return Vector3(std::min(a.x, b.x), std::min(a.y, b.y), std::min(a.z, b.z));
+}
+
+Vector3 max(Vector3::Arg a, Vector3::Arg b) {
+ return Vector3(std::max(a.x, b.x), std::max(a.y, b.y), std::max(a.z, b.z));
+}
+
+Vector3 clamp(Vector3::Arg v, float min, float max) {
+ return Vector3(clamp(v.x, min, max), clamp(v.y, min, max), clamp(v.z, min, max));
+}
+
+Vector3 saturate(Vector3::Arg v) {
+ return Vector3(saturate(v.x), saturate(v.y), saturate(v.z));
+}
+
+Vector3 floor(Vector3::Arg v) {
+ return Vector3(floorf(v.x), floorf(v.y), floorf(v.z));
+}
+
+bool isFinite(Vector3::Arg v) {
+ return std::isfinite(v.x) && std::isfinite(v.y) && std::isfinite(v.z);
+}
+
+static uint32_t hash(const Vector3 &v, uint32_t h) {
+ return sdbmFloatHash(v.component, 3, h);
+}
+
+/// Basis class to compute tangent space basis, ortogonalizations and to
+/// transform vectors from one space to another.
+class Basis {
+public:
+ /// Create a null basis.
+ Basis() :
+ tangent(0, 0, 0),
+ bitangent(0, 0, 0),
+ normal(0, 0, 0) {}
+
+ void buildFrameForDirection(Vector3::Arg d, float angle = 0) {
+ xaAssert(isNormalized(d));
+ normal = d;
+ // Choose minimum axis.
+ if (fabsf(normal.x) < fabsf(normal.y) && fabsf(normal.x) < fabsf(normal.z)) {
+ tangent = Vector3(1, 0, 0);
+ } else if (fabsf(normal.y) < fabsf(normal.z)) {
+ tangent = Vector3(0, 1, 0);
+ } else {
+ tangent = Vector3(0, 0, 1);
+ }
+ // Ortogonalize
+ tangent -= normal * dot(normal, tangent);
+ tangent = normalize(tangent);
+ bitangent = cross(normal, tangent);
+ // Rotate frame around normal according to angle.
+ if (angle != 0.0f) {
+ float c = cosf(angle);
+ float s = sinf(angle);
+ Vector3 tmp = c * tangent - s * bitangent;
+ bitangent = s * tangent + c * bitangent;
+ tangent = tmp;
+ }
+ }
+
+ Vector3 tangent;
+ Vector3 bitangent;
+ Vector3 normal;
+};
+
+// Simple bit array.
+class BitArray {
+public:
+ BitArray() :
+ m_size(0) {}
+ BitArray(uint32_t sz) {
+ resize(sz);
+ }
+
+ uint32_t size() const {
+ return m_size;
+ }
+
+ void clear() {
+ resize(0);
+ }
+
+ void resize(uint32_t new_size) {
+ m_size = new_size;
+ m_wordArray.resize((m_size + 31) >> 5);
+ }
+
+ /// Get bit.
+ bool bitAt(uint32_t b) const {
+ xaDebugAssert(b < m_size);
+ return (m_wordArray[b >> 5] & (1 << (b & 31))) != 0;
+ }
+
+ // Set a bit.
+ void setBitAt(uint32_t idx) {
+ xaDebugAssert(idx < m_size);
+ m_wordArray[idx >> 5] |= (1 << (idx & 31));
+ }
+
+ // Toggle a bit.
+ void toggleBitAt(uint32_t idx) {
+ xaDebugAssert(idx < m_size);
+ m_wordArray[idx >> 5] ^= (1 << (idx & 31));
+ }
+
+ // Set a bit to the given value. @@ Rename modifyBitAt?
+ void setBitAt(uint32_t idx, bool b) {
+ xaDebugAssert(idx < m_size);
+ m_wordArray[idx >> 5] = setBits(m_wordArray[idx >> 5], 1 << (idx & 31), b);
+ xaDebugAssert(bitAt(idx) == b);
+ }
+
+ // Clear all the bits.
+ void clearAll() {
+ memset(m_wordArray.data(), 0, m_wordArray.size() * sizeof(uint32_t));
+ }
+
+ // Set all the bits.
+ void setAll() {
+ memset(m_wordArray.data(), 0xFF, m_wordArray.size() * sizeof(uint32_t));
+ }
+
+private:
+ // See "Conditionally set or clear bits without branching" at http://graphics.stanford.edu/~seander/bithacks.html
+ uint32_t setBits(uint32_t w, uint32_t m, bool b) {
+ return (w & ~m) | (-int(b) & m);
+ }
+
+ // Number of bits stored.
+ uint32_t m_size;
+
+ // Array of bits.
+ std::vector<uint32_t> m_wordArray;
+};
+
+/// Bit map. This should probably be called BitImage.
+class BitMap {
+public:
+ BitMap() :
+ m_width(0),
+ m_height(0) {}
+ BitMap(uint32_t w, uint32_t h) :
+ m_width(w),
+ m_height(h),
+ m_bitArray(w * h) {}
+
+ uint32_t width() const {
+ return m_width;
+ }
+ uint32_t height() const {
+ return m_height;
+ }
+
+ void resize(uint32_t w, uint32_t h, bool initValue) {
+ BitArray tmp(w * h);
+ if (initValue)
+ tmp.setAll();
+ else
+ tmp.clearAll();
+ // @@ Copying one bit at a time. This could be much faster.
+ for (uint32_t y = 0; y < m_height; y++) {
+ for (uint32_t x = 0; x < m_width; x++) {
+ //tmp.setBitAt(y*w + x, bitAt(x, y));
+ if (bitAt(x, y) != initValue) tmp.toggleBitAt(y * w + x);
+ }
+ }
+ std::swap(m_bitArray, tmp);
+ m_width = w;
+ m_height = h;
+ }
+
+ bool bitAt(uint32_t x, uint32_t y) const {
+ xaDebugAssert(x < m_width && y < m_height);
+ return m_bitArray.bitAt(y * m_width + x);
+ }
+
+ void setBitAt(uint32_t x, uint32_t y) {
+ xaDebugAssert(x < m_width && y < m_height);
+ m_bitArray.setBitAt(y * m_width + x);
+ }
+
+ void clearAll() {
+ m_bitArray.clearAll();
+ }
+
+private:
+ uint32_t m_width;
+ uint32_t m_height;
+ BitArray m_bitArray;
+};
+
+// Axis Aligned Bounding Box.
+class Box {
+public:
+ Box() {}
+ Box(const Box &b) :
+ minCorner(b.minCorner),
+ maxCorner(b.maxCorner) {}
+ Box(const Vector3 &mins, const Vector3 &maxs) :
+ minCorner(mins),
+ maxCorner(maxs) {}
+
+ operator const float *() const {
+ return reinterpret_cast<const float *>(this);
+ }
+
+ // Clear the bounds.
+ void clearBounds() {
+ minCorner.set(FLT_MAX, FLT_MAX, FLT_MAX);
+ maxCorner.set(-FLT_MAX, -FLT_MAX, -FLT_MAX);
+ }
+
+ // Return extents of the box.
+ Vector3 extents() const {
+ return (maxCorner - minCorner) * 0.5f;
+ }
+
+ // Add a point to this box.
+ void addPointToBounds(const Vector3 &p) {
+ minCorner = min(minCorner, p);
+ maxCorner = max(maxCorner, p);
+ }
+
+ // Get the volume of the box.
+ float volume() const {
+ Vector3 d = extents();
+ return 8.0f * (d.x * d.y * d.z);
+ }
+
+ Vector3 minCorner;
+ Vector3 maxCorner;
+};
+
+class Fit {
+public:
+ static Vector3 computeCentroid(int n, const Vector3 *__restrict points) {
+ Vector3 centroid(0.0f);
+ for (int i = 0; i < n; i++) {
+ centroid += points[i];
+ }
+ centroid /= float(n);
+ return centroid;
+ }
+
+ static Vector3 computeCovariance(int n, const Vector3 *__restrict points, float *__restrict covariance) {
+ // compute the centroid
+ Vector3 centroid = computeCentroid(n, points);
+ // compute covariance matrix
+ for (int i = 0; i < 6; i++) {
+ covariance[i] = 0.0f;
+ }
+ for (int i = 0; i < n; i++) {
+ Vector3 v = points[i] - centroid;
+ covariance[0] += v.x * v.x;
+ covariance[1] += v.x * v.y;
+ covariance[2] += v.x * v.z;
+ covariance[3] += v.y * v.y;
+ covariance[4] += v.y * v.z;
+ covariance[5] += v.z * v.z;
+ }
+ return centroid;
+ }
+
+ static bool isPlanar(int n, const Vector3 *points, float epsilon = NV_EPSILON) {
+ // compute the centroid and covariance
+ float matrix[6];
+ computeCovariance(n, points, matrix);
+ float eigenValues[3];
+ Vector3 eigenVectors[3];
+ if (!eigenSolveSymmetric3(matrix, eigenValues, eigenVectors)) {
+ return false;
+ }
+ return eigenValues[2] < epsilon;
+ }
+
+ // Tridiagonal solver from Charles Bloom.
+ // Householder transforms followed by QL decomposition.
+ // Seems to be based on the code from Numerical Recipes in C.
+ static bool eigenSolveSymmetric3(const float matrix[6], float eigenValues[3], Vector3 eigenVectors[3]) {
+ xaDebugAssert(matrix != NULL && eigenValues != NULL && eigenVectors != NULL);
+ float subd[3];
+ float diag[3];
+ float work[3][3];
+ work[0][0] = matrix[0];
+ work[0][1] = work[1][0] = matrix[1];
+ work[0][2] = work[2][0] = matrix[2];
+ work[1][1] = matrix[3];
+ work[1][2] = work[2][1] = matrix[4];
+ work[2][2] = matrix[5];
+ EigenSolver3_Tridiagonal(work, diag, subd);
+ if (!EigenSolver3_QLAlgorithm(work, diag, subd)) {
+ for (int i = 0; i < 3; i++) {
+ eigenValues[i] = 0;
+ eigenVectors[i] = Vector3(0);
+ }
+ return false;
+ }
+ for (int i = 0; i < 3; i++) {
+ eigenValues[i] = (float)diag[i];
+ }
+ // eigenvectors are the columns; make them the rows :
+ for (int i = 0; i < 3; i++) {
+ for (int j = 0; j < 3; j++) {
+ eigenVectors[j].component[i] = (float)work[i][j];
+ }
+ }
+ // shuffle to sort by singular value :
+ if (eigenValues[2] > eigenValues[0] && eigenValues[2] > eigenValues[1]) {
+ std::swap(eigenValues[0], eigenValues[2]);
+ std::swap(eigenVectors[0], eigenVectors[2]);
+ }
+ if (eigenValues[1] > eigenValues[0]) {
+ std::swap(eigenValues[0], eigenValues[1]);
+ std::swap(eigenVectors[0], eigenVectors[1]);
+ }
+ if (eigenValues[2] > eigenValues[1]) {
+ std::swap(eigenValues[1], eigenValues[2]);
+ std::swap(eigenVectors[1], eigenVectors[2]);
+ }
+ xaDebugAssert(eigenValues[0] >= eigenValues[1] && eigenValues[0] >= eigenValues[2]);
+ xaDebugAssert(eigenValues[1] >= eigenValues[2]);
+ return true;
+ }
+
+private:
+ static void EigenSolver3_Tridiagonal(float mat[3][3], float *diag, float *subd) {
+ // Householder reduction T = Q^t M Q
+ // Input:
+ // mat, symmetric 3x3 matrix M
+ // Output:
+ // mat, orthogonal matrix Q
+ // diag, diagonal entries of T
+ // subd, subdiagonal entries of T (T is symmetric)
+ const float epsilon = 1e-08f;
+ float a = mat[0][0];
+ float b = mat[0][1];
+ float c = mat[0][2];
+ float d = mat[1][1];
+ float e = mat[1][2];
+ float f = mat[2][2];
+ diag[0] = a;
+ subd[2] = 0.f;
+ if (fabsf(c) >= epsilon) {
+ const float ell = sqrtf(b * b + c * c);
+ b /= ell;
+ c /= ell;
+ const float q = 2 * b * e + c * (f - d);
+ diag[1] = d + c * q;
+ diag[2] = f - c * q;
+ subd[0] = ell;
+ subd[1] = e - b * q;
+ mat[0][0] = 1;
+ mat[0][1] = 0;
+ mat[0][2] = 0;
+ mat[1][0] = 0;
+ mat[1][1] = b;
+ mat[1][2] = c;
+ mat[2][0] = 0;
+ mat[2][1] = c;
+ mat[2][2] = -b;
+ } else {
+ diag[1] = d;
+ diag[2] = f;
+ subd[0] = b;
+ subd[1] = e;
+ mat[0][0] = 1;
+ mat[0][1] = 0;
+ mat[0][2] = 0;
+ mat[1][0] = 0;
+ mat[1][1] = 1;
+ mat[1][2] = 0;
+ mat[2][0] = 0;
+ mat[2][1] = 0;
+ mat[2][2] = 1;
+ }
+ }
+
+ static bool EigenSolver3_QLAlgorithm(float mat[3][3], float *diag, float *subd) {
+ // QL iteration with implicit shifting to reduce matrix from tridiagonal
+ // to diagonal
+ const int maxiter = 32;
+ for (int ell = 0; ell < 3; ell++) {
+ int iter;
+ for (iter = 0; iter < maxiter; iter++) {
+ int m;
+ for (m = ell; m <= 1; m++) {
+ float dd = fabsf(diag[m]) + fabsf(diag[m + 1]);
+ if (fabsf(subd[m]) + dd == dd)
+ break;
+ }
+ if (m == ell)
+ break;
+ float g = (diag[ell + 1] - diag[ell]) / (2 * subd[ell]);
+ float r = sqrtf(g * g + 1);
+ if (g < 0)
+ g = diag[m] - diag[ell] + subd[ell] / (g - r);
+ else
+ g = diag[m] - diag[ell] + subd[ell] / (g + r);
+ float s = 1, c = 1, p = 0;
+ for (int i = m - 1; i >= ell; i--) {
+ float f = s * subd[i], b = c * subd[i];
+ if (fabsf(f) >= fabsf(g)) {
+ c = g / f;
+ r = sqrtf(c * c + 1);
+ subd[i + 1] = f * r;
+ c *= (s = 1 / r);
+ } else {
+ s = f / g;
+ r = sqrtf(s * s + 1);
+ subd[i + 1] = g * r;
+ s *= (c = 1 / r);
+ }
+ g = diag[i + 1] - p;
+ r = (diag[i] - g) * s + 2 * b * c;
+ p = s * r;
+ diag[i + 1] = g + p;
+ g = c * r - b;
+ for (int k = 0; k < 3; k++) {
+ f = mat[k][i + 1];
+ mat[k][i + 1] = s * mat[k][i] + c * f;
+ mat[k][i] = c * mat[k][i] - s * f;
+ }
+ }
+ diag[ell] -= p;
+ subd[ell] = g;
+ subd[m] = 0;
+ }
+ if (iter == maxiter)
+ // should not get here under normal circumstances
+ return false;
+ }
+ return true;
+ }
+};
+
+/// Fixed size vector class.
+class FullVector {
+public:
+ FullVector(uint32_t dim) { m_array.resize(dim); }
+ FullVector(const FullVector &v) :
+ m_array(v.m_array) {}
+
+ const FullVector &operator=(const FullVector &v) {
+ xaAssert(dimension() == v.dimension());
+ m_array = v.m_array;
+ return *this;
+ }
+
+ uint32_t dimension() const { return m_array.size(); }
+ const float &operator[](uint32_t index) const { return m_array[index]; }
+ float &operator[](uint32_t index) { return m_array[index]; }
+
+ void fill(float f) {
+ const uint32_t dim = dimension();
+ for (uint32_t i = 0; i < dim; i++) {
+ m_array[i] = f;
+ }
+ }
+
+ void operator+=(const FullVector &v) {
+ xaDebugAssert(dimension() == v.dimension());
+ const uint32_t dim = dimension();
+ for (uint32_t i = 0; i < dim; i++) {
+ m_array[i] += v.m_array[i];
+ }
+ }
+
+ void operator-=(const FullVector &v) {
+ xaDebugAssert(dimension() == v.dimension());
+ const uint32_t dim = dimension();
+ for (uint32_t i = 0; i < dim; i++) {
+ m_array[i] -= v.m_array[i];
+ }
+ }
+
+ void operator*=(const FullVector &v) {
+ xaDebugAssert(dimension() == v.dimension());
+ const uint32_t dim = dimension();
+ for (uint32_t i = 0; i < dim; i++) {
+ m_array[i] *= v.m_array[i];
+ }
+ }
+
+ void operator+=(float f) {
+ const uint32_t dim = dimension();
+ for (uint32_t i = 0; i < dim; i++) {
+ m_array[i] += f;
+ }
+ }
+
+ void operator-=(float f) {
+ const uint32_t dim = dimension();
+ for (uint32_t i = 0; i < dim; i++) {
+ m_array[i] -= f;
+ }
+ }
+
+ void operator*=(float f) {
+ const uint32_t dim = dimension();
+ for (uint32_t i = 0; i < dim; i++) {
+ m_array[i] *= f;
+ }
+ }
+
+private:
+ std::vector<float> m_array;
+};
+
+namespace halfedge {
+class Face;
+class Vertex;
+
+class Edge {
+public:
+ uint32_t id;
+ Edge *next;
+ Edge *prev; // This is not strictly half-edge, but makes algorithms easier and faster.
+ Edge *pair;
+ Vertex *vertex;
+ Face *face;
+
+ // Default constructor.
+ Edge(uint32_t id) :
+ id(id),
+ next(NULL),
+ prev(NULL),
+ pair(NULL),
+ vertex(NULL),
+ face(NULL) {}
+
+ // Vertex queries.
+ const Vertex *from() const {
+ return vertex;
+ }
+
+ Vertex *from() {
+ return vertex;
+ }
+
+ const Vertex *to() const {
+ return pair->vertex; // This used to be 'next->vertex', but that changed often when the connectivity of the mesh changes.
+ }
+
+ Vertex *to() {
+ return pair->vertex;
+ }
+
+ // Edge queries.
+ void setNext(Edge *e) {
+ next = e;
+ if (e != NULL) e->prev = this;
+ }
+ void setPrev(Edge *e) {
+ prev = e;
+ if (e != NULL) e->next = this;
+ }
+
+ // @@ It would be more simple to only check m_pair == NULL
+ // Face queries.
+ bool isBoundary() const {
+ return !(face && pair->face);
+ }
+
+ // @@ This is not exactly accurate, we should compare the texture coordinates...
+ bool isSeam() const {
+ return vertex != pair->next->vertex || next->vertex != pair->vertex;
+ }
+
+ bool isNormalSeam() const;
+ bool isTextureSeam() const;
+
+ bool isValid() const {
+ // null face is OK.
+ if (next == NULL || prev == NULL || pair == NULL || vertex == NULL) return false;
+ if (next->prev != this) return false;
+ if (prev->next != this) return false;
+ if (pair->pair != this) return false;
+ return true;
+ }
+
+ float length() const;
+
+ // Return angle between this edge and the previous one.
+ float angle() const;
+};
+
+class Vertex {
+public:
+ uint32_t id;
+ uint32_t original_id;
+ Edge *edge;
+ Vertex *next;
+ Vertex *prev;
+ Vector3 pos;
+ Vector3 nor;
+ Vector2 tex;
+
+ Vertex(uint32_t id) :
+ id(id),
+ original_id(id),
+ edge(NULL),
+ pos(0.0f),
+ nor(0.0f),
+ tex(0.0f) {
+ next = this;
+ prev = this;
+ }
+
+ // Set first edge of all colocals.
+ void setEdge(Edge *e) {
+ for (VertexIterator it(colocals()); !it.isDone(); it.advance()) {
+ it.current()->edge = e;
+ }
+ }
+
+ // Update position of all colocals.
+ void setPos(const Vector3 &p) {
+ for (VertexIterator it(colocals()); !it.isDone(); it.advance()) {
+ it.current()->pos = p;
+ }
+ }
+
+ bool isFirstColocal() const {
+ return firstColocal() == this;
+ }
+
+ const Vertex *firstColocal() const {
+ uint32_t firstId = id;
+ const Vertex *vertex = this;
+ for (ConstVertexIterator it(colocals()); !it.isDone(); it.advance()) {
+ if (it.current()->id < firstId) {
+ firstId = vertex->id;
+ vertex = it.current();
+ }
+ }
+ return vertex;
+ }
+
+ Vertex *firstColocal() {
+ Vertex *vertex = this;
+ uint32_t firstId = id;
+ for (VertexIterator it(colocals()); !it.isDone(); it.advance()) {
+ if (it.current()->id < firstId) {
+ firstId = vertex->id;
+ vertex = it.current();
+ }
+ }
+ return vertex;
+ }
+
+ bool isColocal(const Vertex *v) const {
+ if (this == v) return true;
+ if (pos != v->pos) return false;
+ for (ConstVertexIterator it(colocals()); !it.isDone(); it.advance()) {
+ if (v == it.current()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ void linkColocal(Vertex *v) {
+ next->prev = v;
+ v->next = next;
+ next = v;
+ v->prev = this;
+ }
+ void unlinkColocal() {
+ next->prev = prev;
+ prev->next = next;
+ next = this;
+ prev = this;
+ }
+
+ // @@ Note: This only works if linkBoundary has been called.
+ bool isBoundary() const {
+ return (edge && !edge->face);
+ }
+
+ // Iterator that visits the edges around this vertex in counterclockwise order.
+ class EdgeIterator //: public Iterator<Edge *>
+ {
+ public:
+ EdgeIterator(Edge *e) :
+ m_end(NULL),
+ m_current(e) {}
+
+ virtual void advance() {
+ if (m_end == NULL) m_end = m_current;
+ m_current = m_current->pair->next;
+ //m_current = m_current->prev->pair;
+ }
+
+ virtual bool isDone() const {
+ return m_end == m_current;
+ }
+ virtual Edge *current() const {
+ return m_current;
+ }
+ Vertex *vertex() const {
+ return m_current->vertex;
+ }
+
+ private:
+ Edge *m_end;
+ Edge *m_current;
+ };
+
+ EdgeIterator edges() {
+ return EdgeIterator(edge);
+ }
+ EdgeIterator edges(Edge *e) {
+ return EdgeIterator(e);
+ }
+
+ // Iterator that visits the edges around this vertex in counterclockwise order.
+ class ConstEdgeIterator //: public Iterator<Edge *>
+ {
+ public:
+ ConstEdgeIterator(const Edge *e) :
+ m_end(NULL),
+ m_current(e) {}
+ ConstEdgeIterator(EdgeIterator it) :
+ m_end(NULL),
+ m_current(it.current()) {}
+
+ virtual void advance() {
+ if (m_end == NULL) m_end = m_current;
+ m_current = m_current->pair->next;
+ //m_current = m_current->prev->pair;
+ }
+
+ virtual bool isDone() const {
+ return m_end == m_current;
+ }
+ virtual const Edge *current() const {
+ return m_current;
+ }
+ const Vertex *vertex() const {
+ return m_current->to();
+ }
+
+ private:
+ const Edge *m_end;
+ const Edge *m_current;
+ };
+
+ ConstEdgeIterator edges() const {
+ return ConstEdgeIterator(edge);
+ }
+ ConstEdgeIterator edges(const Edge *e) const {
+ return ConstEdgeIterator(e);
+ }
+
+ // Iterator that visits all the colocal vertices.
+ class VertexIterator //: public Iterator<Edge *>
+ {
+ public:
+ VertexIterator(Vertex *v) :
+ m_end(NULL),
+ m_current(v) {}
+
+ virtual void advance() {
+ if (m_end == NULL) m_end = m_current;
+ m_current = m_current->next;
+ }
+
+ virtual bool isDone() const {
+ return m_end == m_current;
+ }
+ virtual Vertex *current() const {
+ return m_current;
+ }
+
+ private:
+ Vertex *m_end;
+ Vertex *m_current;
+ };
+
+ VertexIterator colocals() {
+ return VertexIterator(this);
+ }
+
+ // Iterator that visits all the colocal vertices.
+ class ConstVertexIterator //: public Iterator<Edge *>
+ {
+ public:
+ ConstVertexIterator(const Vertex *v) :
+ m_end(NULL),
+ m_current(v) {}
+
+ virtual void advance() {
+ if (m_end == NULL) m_end = m_current;
+ m_current = m_current->next;
+ }
+
+ virtual bool isDone() const {
+ return m_end == m_current;
+ }
+ virtual const Vertex *current() const {
+ return m_current;
+ }
+
+ private:
+ const Vertex *m_end;
+ const Vertex *m_current;
+ };
+
+ ConstVertexIterator colocals() const {
+ return ConstVertexIterator(this);
+ }
+};
+
+bool Edge::isNormalSeam() const {
+ return (vertex->nor != pair->next->vertex->nor || next->vertex->nor != pair->vertex->nor);
+}
+
+bool Edge::isTextureSeam() const {
+ return (vertex->tex != pair->next->vertex->tex || next->vertex->tex != pair->vertex->tex);
+}
+
+float Edge::length() const {
+ return internal::length(to()->pos - from()->pos);
+}
+
+float Edge::angle() const {
+ Vector3 p = vertex->pos;
+ Vector3 a = prev->vertex->pos;
+ Vector3 b = next->vertex->pos;
+ Vector3 v0 = a - p;
+ Vector3 v1 = b - p;
+ return acosf(dot(v0, v1) / (internal::length(v0) * internal::length(v1)));
+}
+
+class Face {
+public:
+ uint32_t id;
+ uint16_t group;
+ uint16_t material;
+ Edge *edge;
+
+ Face(uint32_t id) :
+ id(id),
+ group(uint16_t(~0)),
+ material(uint16_t(~0)),
+ edge(NULL) {}
+
+ float area() const {
+ float area = 0;
+ const Vector3 &v0 = edge->from()->pos;
+ for (ConstEdgeIterator it(edges(edge->next)); it.current() != edge->prev; it.advance()) {
+ const Edge *e = it.current();
+ const Vector3 &v1 = e->vertex->pos;
+ const Vector3 &v2 = e->next->vertex->pos;
+ area += length(cross(v1 - v0, v2 - v0));
+ }
+ return area * 0.5f;
+ }
+
+ float parametricArea() const {
+ float area = 0;
+ const Vector2 &v0 = edge->from()->tex;
+ for (ConstEdgeIterator it(edges(edge->next)); it.current() != edge->prev; it.advance()) {
+ const Edge *e = it.current();
+ const Vector2 &v1 = e->vertex->tex;
+ const Vector2 &v2 = e->next->vertex->tex;
+ area += triangleArea(v0, v1, v2);
+ }
+ return area * 0.5f;
+ }
+
+ Vector3 normal() const {
+ Vector3 n(0);
+ const Vertex *vertex0 = NULL;
+ for (ConstEdgeIterator it(edges()); !it.isDone(); it.advance()) {
+ const Edge *e = it.current();
+ xaAssert(e != NULL);
+ if (vertex0 == NULL) {
+ vertex0 = e->vertex;
+ } else if (e->next->vertex != vertex0) {
+ const halfedge::Vertex *vertex1 = e->from();
+ const halfedge::Vertex *vertex2 = e->to();
+ const Vector3 &p0 = vertex0->pos;
+ const Vector3 &p1 = vertex1->pos;
+ const Vector3 &p2 = vertex2->pos;
+ Vector3 v10 = p1 - p0;
+ Vector3 v20 = p2 - p0;
+ n += cross(v10, v20);
+ }
+ }
+ return normalizeSafe(n, Vector3(0, 0, 1), 0.0f);
+ }
+
+ Vector3 centroid() const {
+ Vector3 sum(0.0f);
+ uint32_t count = 0;
+ for (ConstEdgeIterator it(edges()); !it.isDone(); it.advance()) {
+ const Edge *e = it.current();
+ sum += e->from()->pos;
+ count++;
+ }
+ return sum / float(count);
+ }
+
+ // Unnormalized face normal assuming it's a triangle.
+ Vector3 triangleNormal() const {
+ Vector3 p0 = edge->vertex->pos;
+ Vector3 p1 = edge->next->vertex->pos;
+ Vector3 p2 = edge->next->next->vertex->pos;
+ Vector3 e0 = p2 - p0;
+ Vector3 e1 = p1 - p0;
+ return normalizeSafe(cross(e0, e1), Vector3(0), 0.0f);
+ }
+
+ Vector3 triangleNormalAreaScaled() const {
+ Vector3 p0 = edge->vertex->pos;
+ Vector3 p1 = edge->next->vertex->pos;
+ Vector3 p2 = edge->next->next->vertex->pos;
+ Vector3 e0 = p2 - p0;
+ Vector3 e1 = p1 - p0;
+ return cross(e0, e1);
+ }
+
+ // Average of the edge midpoints weighted by the edge length.
+ // I want a point inside the triangle, but closer to the cirumcenter.
+ Vector3 triangleCenter() const {
+ Vector3 p0 = edge->vertex->pos;
+ Vector3 p1 = edge->next->vertex->pos;
+ Vector3 p2 = edge->next->next->vertex->pos;
+ float l0 = length(p1 - p0);
+ float l1 = length(p2 - p1);
+ float l2 = length(p0 - p2);
+ Vector3 m0 = (p0 + p1) * l0 / (l0 + l1 + l2);
+ Vector3 m1 = (p1 + p2) * l1 / (l0 + l1 + l2);
+ Vector3 m2 = (p2 + p0) * l2 / (l0 + l1 + l2);
+ return m0 + m1 + m2;
+ }
+
+ bool isValid() const {
+ uint32_t count = 0;
+ for (ConstEdgeIterator it(edges()); !it.isDone(); it.advance()) {
+ const Edge *e = it.current();
+ if (e->face != this) return false;
+ if (!e->isValid()) return false;
+ if (!e->pair->isValid()) return false;
+ count++;
+ }
+ if (count < 3) return false;
+ return true;
+ }
+
+ bool contains(const Edge *e) const {
+ for (ConstEdgeIterator it(edges()); !it.isDone(); it.advance()) {
+ if (it.current() == e) return true;
+ }
+ return false;
+ }
+
+ uint32_t edgeCount() const {
+ uint32_t count = 0;
+ for (ConstEdgeIterator it(edges()); !it.isDone(); it.advance()) {
+ ++count;
+ }
+ return count;
+ }
+
+ // The iterator that visits the edges of this face in clockwise order.
+ class EdgeIterator //: public Iterator<Edge *>
+ {
+ public:
+ EdgeIterator(Edge *e) :
+ m_end(NULL),
+ m_current(e) {}
+
+ virtual void advance() {
+ if (m_end == NULL) m_end = m_current;
+ m_current = m_current->next;
+ }
+
+ virtual bool isDone() const {
+ return m_end == m_current;
+ }
+ virtual Edge *current() const {
+ return m_current;
+ }
+ Vertex *vertex() const {
+ return m_current->vertex;
+ }
+
+ private:
+ Edge *m_end;
+ Edge *m_current;
+ };
+
+ EdgeIterator edges() {
+ return EdgeIterator(edge);
+ }
+ EdgeIterator edges(Edge *e) {
+ xaDebugAssert(contains(e));
+ return EdgeIterator(e);
+ }
+
+ // The iterator that visits the edges of this face in clockwise order.
+ class ConstEdgeIterator //: public Iterator<const Edge *>
+ {
+ public:
+ ConstEdgeIterator(const Edge *e) :
+ m_end(NULL),
+ m_current(e) {}
+ ConstEdgeIterator(const EdgeIterator &it) :
+ m_end(NULL),
+ m_current(it.current()) {}
+
+ virtual void advance() {
+ if (m_end == NULL) m_end = m_current;
+ m_current = m_current->next;
+ }
+
+ virtual bool isDone() const {
+ return m_end == m_current;
+ }
+ virtual const Edge *current() const {
+ return m_current;
+ }
+ const Vertex *vertex() const {
+ return m_current->vertex;
+ }
+
+ private:
+ const Edge *m_end;
+ const Edge *m_current;
+ };
+
+ ConstEdgeIterator edges() const {
+ return ConstEdgeIterator(edge);
+ }
+ ConstEdgeIterator edges(const Edge *e) const {
+ xaDebugAssert(contains(e));
+ return ConstEdgeIterator(e);
+ }
+};
+
+/// Simple half edge mesh designed for dynamic mesh manipulation.
+class Mesh {
+public:
+ Mesh() :
+ m_colocalVertexCount(0) {}
+
+ Mesh(const Mesh *mesh) {
+ // Copy mesh vertices.
+ const uint32_t vertexCount = mesh->vertexCount();
+ m_vertexArray.resize(vertexCount);
+ for (uint32_t v = 0; v < vertexCount; v++) {
+ const Vertex *vertex = mesh->vertexAt(v);
+ xaDebugAssert(vertex->id == v);
+ m_vertexArray[v] = new Vertex(v);
+ m_vertexArray[v]->pos = vertex->pos;
+ m_vertexArray[v]->nor = vertex->nor;
+ m_vertexArray[v]->tex = vertex->tex;
+ }
+ m_colocalVertexCount = vertexCount;
+ // Copy mesh faces.
+ const uint32_t faceCount = mesh->faceCount();
+ std::vector<uint32_t> indexArray;
+ indexArray.reserve(3);
+ for (uint32_t f = 0; f < faceCount; f++) {
+ const Face *face = mesh->faceAt(f);
+ for (Face::ConstEdgeIterator it(face->edges()); !it.isDone(); it.advance()) {
+ const Vertex *vertex = it.current()->from();
+ indexArray.push_back(vertex->id);
+ }
+ addFace(indexArray);
+ indexArray.clear();
+ }
+ }
+
+ ~Mesh() {
+ clear();
+ }
+
+ void clear() {
+ for (size_t i = 0; i < m_vertexArray.size(); i++)
+ delete m_vertexArray[i];
+ m_vertexArray.clear();
+ for (auto it = m_edgeMap.begin(); it != m_edgeMap.end(); it++)
+ delete it->second;
+ m_edgeArray.clear();
+ m_edgeMap.clear();
+ for (size_t i = 0; i < m_faceArray.size(); i++)
+ delete m_faceArray[i];
+ m_faceArray.clear();
+ }
+
+ Vertex *addVertex(const Vector3 &pos) {
+ xaDebugAssert(isFinite(pos));
+ Vertex *v = new Vertex(m_vertexArray.size());
+ v->pos = pos;
+ m_vertexArray.push_back(v);
+ return v;
+ }
+
+ /// Link colocal vertices based on geometric location only.
+ void linkColocals() {
+ xaPrint("--- Linking colocals:\n");
+ const uint32_t vertexCount = this->vertexCount();
+ std::unordered_map<Vector3, Vertex *, Hash<Vector3>, Equal<Vector3> > vertexMap;
+ vertexMap.reserve(vertexCount);
+ for (uint32_t v = 0; v < vertexCount; v++) {
+ Vertex *vertex = vertexAt(v);
+ Vertex *colocal = vertexMap[vertex->pos];
+ if (colocal) {
+ colocal->linkColocal(vertex);
+ } else {
+ vertexMap[vertex->pos] = vertex;
+ }
+ }
+ m_colocalVertexCount = vertexMap.size();
+ xaPrint("--- %d vertex positions.\n", m_colocalVertexCount);
+ // @@ Remove duplicated vertices? or just leave them as colocals?
+ }
+
+ void linkColocalsWithCanonicalMap(const std::vector<uint32_t> &canonicalMap) {
+ xaPrint("--- Linking colocals:\n");
+ uint32_t vertexMapSize = 0;
+ for (uint32_t i = 0; i < canonicalMap.size(); i++) {
+ vertexMapSize = std::max(vertexMapSize, canonicalMap[i] + 1);
+ }
+ std::vector<Vertex *> vertexMap;
+ vertexMap.resize(vertexMapSize, NULL);
+ m_colocalVertexCount = 0;
+ const uint32_t vertexCount = this->vertexCount();
+ for (uint32_t v = 0; v < vertexCount; v++) {
+ Vertex *vertex = vertexAt(v);
+ Vertex *colocal = vertexMap[canonicalMap[v]];
+ if (colocal != NULL) {
+ xaDebugAssert(vertex->pos == colocal->pos);
+ colocal->linkColocal(vertex);
+ } else {
+ vertexMap[canonicalMap[v]] = vertex;
+ m_colocalVertexCount++;
+ }
+ }
+ xaPrint("--- %d vertex positions.\n", m_colocalVertexCount);
+ }
+
+ Face *addFace() {
+ Face *f = new Face(m_faceArray.size());
+ m_faceArray.push_back(f);
+ return f;
+ }
+
+ Face *addFace(uint32_t v0, uint32_t v1, uint32_t v2) {
+ uint32_t indexArray[3];
+ indexArray[0] = v0;
+ indexArray[1] = v1;
+ indexArray[2] = v2;
+ return addFace(indexArray, 3, 0, 3);
+ }
+
+ Face *addUniqueFace(uint32_t v0, uint32_t v1, uint32_t v2) {
+
+ int base_vertex = m_vertexArray.size();
+
+ uint32_t ids[3] = { v0, v1, v2 };
+
+ Vector3 base[3] = {
+ m_vertexArray[v0]->pos,
+ m_vertexArray[v1]->pos,
+ m_vertexArray[v2]->pos,
+ };
+
+ //make sure its not a degenerate
+ bool degenerate = distanceSquared(base[0], base[1]) < NV_EPSILON || distanceSquared(base[0], base[2]) < NV_EPSILON || distanceSquared(base[1], base[2]) < NV_EPSILON;
+ xaDebugAssert(!degenerate);
+
+ float min_x = 0;
+
+ for (int i = 0; i < 3; i++) {
+ if (i == 0 || m_vertexArray[v0]->pos.x < min_x) {
+ min_x = m_vertexArray[v0]->pos.x;
+ }
+ }
+
+ float max_x = 0;
+
+ for (int j = 0; j < m_vertexArray.size(); j++) {
+ if (j == 0 || m_vertexArray[j]->pos.x > max_x) { //vertex already exists
+ max_x = m_vertexArray[j]->pos.x;
+ }
+ }
+
+ //separate from everything else, in x axis
+ for (int i = 0; i < 3; i++) {
+
+ base[i].x -= min_x;
+ base[i].x += max_x + 10.0;
+ }
+
+ for (int i = 0; i < 3; i++) {
+ Vertex *v = new Vertex(m_vertexArray.size());
+ v->pos = base[i];
+ v->nor = m_vertexArray[ids[i]]->nor,
+ v->tex = m_vertexArray[ids[i]]->tex,
+
+ v->original_id = ids[i];
+ m_vertexArray.push_back(v);
+ }
+
+ uint32_t indexArray[3];
+ indexArray[0] = base_vertex + 0;
+ indexArray[1] = base_vertex + 1;
+ indexArray[2] = base_vertex + 2;
+ return addFace(indexArray, 3, 0, 3);
+ }
+
+ Face *addFace(uint32_t v0, uint32_t v1, uint32_t v2, uint32_t v3) {
+ uint32_t indexArray[4];
+ indexArray[0] = v0;
+ indexArray[1] = v1;
+ indexArray[2] = v2;
+ indexArray[3] = v3;
+ return addFace(indexArray, 4, 0, 4);
+ }
+
+ Face *addFace(const std::vector<uint32_t> &indexArray) {
+ return addFace(indexArray, 0, indexArray.size());
+ }
+
+ Face *addFace(const std::vector<uint32_t> &indexArray, uint32_t first, uint32_t num) {
+ return addFace(indexArray.data(), (uint32_t)indexArray.size(), first, num);
+ }
+
+ Face *addFace(const uint32_t *indexArray, uint32_t indexCount, uint32_t first, uint32_t num) {
+ xaDebugAssert(first < indexCount);
+ xaDebugAssert(num <= indexCount - first);
+ xaDebugAssert(num > 2);
+ if (!canAddFace(indexArray, first, num)) {
+ return NULL;
+ }
+ Face *f = new Face(m_faceArray.size());
+ Edge *firstEdge = NULL;
+ Edge *last = NULL;
+ Edge *current = NULL;
+ for (uint32_t i = 0; i < num - 1; i++) {
+ current = addEdge(indexArray[first + i], indexArray[first + i + 1]);
+ xaAssert(current != NULL && current->face == NULL);
+ current->face = f;
+ if (last != NULL)
+ last->setNext(current);
+ else
+ firstEdge = current;
+ last = current;
+ }
+ current = addEdge(indexArray[first + num - 1], indexArray[first]);
+ xaAssert(current != NULL && current->face == NULL);
+ current->face = f;
+ last->setNext(current);
+ current->setNext(firstEdge);
+ f->edge = firstEdge;
+ m_faceArray.push_back(f);
+ return f;
+ }
+
+ // These functions disconnect the given element from the mesh and delete it.
+
+ // @@ We must always disconnect edge pairs simultaneously.
+ void disconnect(Edge *edge) {
+ xaDebugAssert(edge != NULL);
+ // Remove from edge list.
+ if ((edge->id & 1) == 0) {
+ xaDebugAssert(m_edgeArray[edge->id / 2] == edge);
+ m_edgeArray[edge->id / 2] = NULL;
+ }
+ // Remove edge from map. @@ Store map key inside edge?
+ xaDebugAssert(edge->from() != NULL && edge->to() != NULL);
+ size_t removed = m_edgeMap.erase(Key(edge->from()->id, edge->to()->id));
+ xaDebugAssert(removed == 1);
+#ifdef NDEBUG
+ removed = 0; // silence unused parameter warning
+#endif
+ // Disconnect from vertex.
+ if (edge->vertex != NULL) {
+ if (edge->vertex->edge == edge) {
+ if (edge->prev && edge->prev->pair) {
+ edge->vertex->edge = edge->prev->pair;
+ } else if (edge->pair && edge->pair->next) {
+ edge->vertex->edge = edge->pair->next;
+ } else {
+ edge->vertex->edge = NULL;
+ // @@ Remove disconnected vertex?
+ }
+ }
+ }
+ // Disconnect from face.
+ if (edge->face != NULL) {
+ if (edge->face->edge == edge) {
+ if (edge->next != NULL && edge->next != edge) {
+ edge->face->edge = edge->next;
+ } else if (edge->prev != NULL && edge->prev != edge) {
+ edge->face->edge = edge->prev;
+ } else {
+ edge->face->edge = NULL;
+ // @@ Remove disconnected face?
+ }
+ }
+ }
+ // Disconnect from previous.
+ if (edge->prev) {
+ if (edge->prev->next == edge) {
+ edge->prev->setNext(NULL);
+ }
+ //edge->setPrev(NULL);
+ }
+ // Disconnect from next.
+ if (edge->next) {
+ if (edge->next->prev == edge) {
+ edge->next->setPrev(NULL);
+ }
+ //edge->setNext(NULL);
+ }
+ }
+
+ void remove(Edge *edge) {
+ xaDebugAssert(edge != NULL);
+ disconnect(edge);
+ delete edge;
+ }
+
+ void remove(Vertex *vertex) {
+ xaDebugAssert(vertex != NULL);
+ // Remove from vertex list.
+ m_vertexArray[vertex->id] = NULL;
+ // Disconnect from colocals.
+ vertex->unlinkColocal();
+ // Disconnect from edges.
+ if (vertex->edge != NULL) {
+ // @@ Removing a connected vertex is asking for trouble...
+ if (vertex->edge->vertex == vertex) {
+ // @@ Connect edge to a colocal?
+ vertex->edge->vertex = NULL;
+ }
+ vertex->setEdge(NULL);
+ }
+ delete vertex;
+ }
+
+ void remove(Face *face) {
+ xaDebugAssert(face != NULL);
+ // Remove from face list.
+ m_faceArray[face->id] = NULL;
+ // Disconnect from edges.
+ if (face->edge != NULL) {
+ xaDebugAssert(face->edge->face == face);
+ face->edge->face = NULL;
+ face->edge = NULL;
+ }
+ delete face;
+ }
+
+ // Triangulate in place.
+ void triangulate() {
+ bool all_triangles = true;
+ const uint32_t faceCount = m_faceArray.size();
+ for (uint32_t f = 0; f < faceCount; f++) {
+ Face *face = m_faceArray[f];
+ if (face->edgeCount() != 3) {
+ all_triangles = false;
+ break;
+ }
+ }
+ if (all_triangles) {
+ return;
+ }
+ // Do not touch vertices, but rebuild edges and faces.
+ std::vector<Edge *> edgeArray;
+ std::vector<Face *> faceArray;
+ std::swap(edgeArray, m_edgeArray);
+ std::swap(faceArray, m_faceArray);
+ m_edgeMap.clear();
+ for (uint32_t f = 0; f < faceCount; f++) {
+ Face *face = faceArray[f];
+ // Trivial fan-like triangulation.
+ const uint32_t v0 = face->edge->vertex->id;
+ uint32_t v2, v1 = (uint32_t)-1;
+ for (Face::EdgeIterator it(face->edges()); !it.isDone(); it.advance()) {
+ Edge *edge = it.current();
+ v2 = edge->to()->id;
+ if (v2 == v0) break;
+ if (v1 != -1) addFace(v0, v1, v2);
+ v1 = v2;
+ }
+ }
+ xaDebugAssert(m_faceArray.size() > faceCount); // triangle count > face count
+ linkBoundary();
+ for (size_t i = 0; i < edgeArray.size(); i++)
+ delete edgeArray[i];
+ for (size_t i = 0; i < faceArray.size(); i++)
+ delete faceArray[i];
+ }
+
+ /// Link boundary edges once the mesh has been created.
+ void linkBoundary() {
+ xaPrint("--- Linking boundaries:\n");
+ int num = 0;
+ // Create boundary edges.
+ uint32_t edgeCount = this->edgeCount();
+ for (uint32_t e = 0; e < edgeCount; e++) {
+ Edge *edge = edgeAt(e);
+ if (edge != NULL && edge->pair == NULL) {
+ Edge *pair = new Edge(edge->id + 1);
+ uint32_t i = edge->from()->id;
+ uint32_t j = edge->next->from()->id;
+ Key key(j, i);
+ xaAssert(m_edgeMap.find(key) == m_edgeMap.end());
+ pair->vertex = m_vertexArray[j];
+ m_edgeMap[key] = pair;
+ edge->pair = pair;
+ pair->pair = edge;
+ num++;
+ }
+ }
+ // Link boundary edges.
+ for (uint32_t e = 0; e < edgeCount; e++) {
+ Edge *edge = edgeAt(e);
+ if (edge != NULL && edge->pair->face == NULL) {
+ linkBoundaryEdge(edge->pair);
+ }
+ }
+ xaPrint("--- %d boundary edges.\n", num);
+ }
+
+ /*
+ Fixing T-junctions.
+
+ - Find T-junctions. Find vertices that are on an edge.
+ - This test is approximate.
+ - Insert edges on a spatial index to speedup queries.
+ - Consider only open edges, that is edges that have no pairs.
+ - Consider only vertices on boundaries.
+ - Close T-junction.
+ - Split edge.
+
+ */
+ bool splitBoundaryEdges() // Returns true if any split was made.
+ {
+ std::vector<Vertex *> boundaryVertices;
+ for (uint32_t i = 0; i < m_vertexArray.size(); i++) {
+ Vertex *v = m_vertexArray[i];
+ if (v->isBoundary()) {
+ boundaryVertices.push_back(v);
+ }
+ }
+ xaPrint("Fixing T-junctions:\n");
+ int splitCount = 0;
+ for (uint32_t v = 0; v < boundaryVertices.size(); v++) {
+ Vertex *vertex = boundaryVertices[v];
+ Vector3 x0 = vertex->pos;
+ // Find edges that this vertex overlaps with.
+ for (uint32_t e = 0; e < m_edgeArray.size(); e++) {
+ Edge *edge = m_edgeArray[e];
+ if (edge != NULL && edge->isBoundary()) {
+ if (edge->from() == vertex || edge->to() == vertex) {
+ continue;
+ }
+ Vector3 x1 = edge->from()->pos;
+ Vector3 x2 = edge->to()->pos;
+ Vector3 v01 = x0 - x1;
+ Vector3 v21 = x2 - x1;
+ float l = length(v21);
+ float d = length(cross(v01, v21)) / l;
+ if (isZero(d)) {
+ float t = dot(v01, v21) / (l * l);
+ if (t > 0.0f + NV_EPSILON && t < 1.0f - NV_EPSILON) {
+ xaDebugAssert(equal(lerp(x1, x2, t), x0));
+ Vertex *splitVertex = splitBoundaryEdge(edge, t, x0);
+ vertex->linkColocal(splitVertex); // @@ Should we do this here?
+ splitCount++;
+ }
+ }
+ }
+ }
+ }
+ xaPrint(" - %d edges split.\n", splitCount);
+ xaDebugAssert(isValid());
+ return splitCount != 0;
+ }
+
+ // Vertices
+ uint32_t vertexCount() const {
+ return m_vertexArray.size();
+ }
+ const Vertex *vertexAt(int i) const {
+ return m_vertexArray[i];
+ }
+ Vertex *vertexAt(int i) {
+ return m_vertexArray[i];
+ }
+
+ uint32_t colocalVertexCount() const {
+ return m_colocalVertexCount;
+ }
+
+ // Faces
+ uint32_t faceCount() const {
+ return m_faceArray.size();
+ }
+ const Face *faceAt(int i) const {
+ return m_faceArray[i];
+ }
+ Face *faceAt(int i) {
+ return m_faceArray[i];
+ }
+
+ // Edges
+ uint32_t edgeCount() const {
+ return m_edgeArray.size();
+ }
+ const Edge *edgeAt(int i) const {
+ return m_edgeArray[i];
+ }
+ Edge *edgeAt(int i) {
+ return m_edgeArray[i];
+ }
+
+ class ConstVertexIterator;
+
+ class VertexIterator {
+ friend class ConstVertexIterator;
+
+ public:
+ VertexIterator(Mesh *mesh) :
+ m_mesh(mesh),
+ m_current(0) {}
+
+ virtual void advance() {
+ m_current++;
+ }
+ virtual bool isDone() const {
+ return m_current == m_mesh->vertexCount();
+ }
+ virtual Vertex *current() const {
+ return m_mesh->vertexAt(m_current);
+ }
+
+ private:
+ halfedge::Mesh *m_mesh;
+ uint32_t m_current;
+ };
+ VertexIterator vertices() {
+ return VertexIterator(this);
+ }
+
+ class ConstVertexIterator {
+ public:
+ ConstVertexIterator(const Mesh *mesh) :
+ m_mesh(mesh),
+ m_current(0) {}
+ ConstVertexIterator(class VertexIterator &it) :
+ m_mesh(it.m_mesh),
+ m_current(it.m_current) {}
+
+ virtual void advance() {
+ m_current++;
+ }
+ virtual bool isDone() const {
+ return m_current == m_mesh->vertexCount();
+ }
+ virtual const Vertex *current() const {
+ return m_mesh->vertexAt(m_current);
+ }
+
+ private:
+ const halfedge::Mesh *m_mesh;
+ uint32_t m_current;
+ };
+ ConstVertexIterator vertices() const {
+ return ConstVertexIterator(this);
+ }
+
+ class ConstFaceIterator;
+
+ class FaceIterator {
+ friend class ConstFaceIterator;
+
+ public:
+ FaceIterator(Mesh *mesh) :
+ m_mesh(mesh),
+ m_current(0) {}
+
+ virtual void advance() {
+ m_current++;
+ }
+ virtual bool isDone() const {
+ return m_current == m_mesh->faceCount();
+ }
+ virtual Face *current() const {
+ return m_mesh->faceAt(m_current);
+ }
+
+ private:
+ halfedge::Mesh *m_mesh;
+ uint32_t m_current;
+ };
+ FaceIterator faces() {
+ return FaceIterator(this);
+ }
+
+ class ConstFaceIterator {
+ public:
+ ConstFaceIterator(const Mesh *mesh) :
+ m_mesh(mesh),
+ m_current(0) {}
+ ConstFaceIterator(const FaceIterator &it) :
+ m_mesh(it.m_mesh),
+ m_current(it.m_current) {}
+
+ virtual void advance() {
+ m_current++;
+ }
+ virtual bool isDone() const {
+ return m_current == m_mesh->faceCount();
+ }
+ virtual const Face *current() const {
+ return m_mesh->faceAt(m_current);
+ }
+
+ private:
+ const halfedge::Mesh *m_mesh;
+ uint32_t m_current;
+ };
+ ConstFaceIterator faces() const {
+ return ConstFaceIterator(this);
+ }
+
+ class ConstEdgeIterator;
+
+ class EdgeIterator {
+ friend class ConstEdgeIterator;
+
+ public:
+ EdgeIterator(Mesh *mesh) :
+ m_mesh(mesh),
+ m_current(0) {}
+
+ virtual void advance() {
+ m_current++;
+ }
+ virtual bool isDone() const {
+ return m_current == m_mesh->edgeCount();
+ }
+ virtual Edge *current() const {
+ return m_mesh->edgeAt(m_current);
+ }
+
+ private:
+ halfedge::Mesh *m_mesh;
+ uint32_t m_current;
+ };
+ EdgeIterator edges() {
+ return EdgeIterator(this);
+ }
+
+ class ConstEdgeIterator {
+ public:
+ ConstEdgeIterator(const Mesh *mesh) :
+ m_mesh(mesh),
+ m_current(0) {}
+ ConstEdgeIterator(const EdgeIterator &it) :
+ m_mesh(it.m_mesh),
+ m_current(it.m_current) {}
+
+ virtual void advance() {
+ m_current++;
+ }
+ virtual bool isDone() const {
+ return m_current == m_mesh->edgeCount();
+ }
+ virtual const Edge *current() const {
+ return m_mesh->edgeAt(m_current);
+ }
+
+ private:
+ const halfedge::Mesh *m_mesh;
+ uint32_t m_current;
+ };
+ ConstEdgeIterator edges() const {
+ return ConstEdgeIterator(this);
+ }
+
+ // @@ Add half-edge iterator.
+
+ bool isValid() const {
+ // Make sure all edges are valid.
+ const uint32_t edgeCount = m_edgeArray.size();
+ for (uint32_t e = 0; e < edgeCount; e++) {
+ Edge *edge = m_edgeArray[e];
+ if (edge != NULL) {
+ if (edge->id != 2 * e) {
+ return false;
+ }
+ if (!edge->isValid()) {
+ return false;
+ }
+ if (edge->pair->id != 2 * e + 1) {
+ return false;
+ }
+ if (!edge->pair->isValid()) {
+ return false;
+ }
+ }
+ }
+ // @@ Make sure all faces are valid.
+ // @@ Make sure all vertices are valid.
+ return true;
+ }
+
+ // Error status:
+
+ struct ErrorCode {
+ enum Enum {
+ AlreadyAddedEdge,
+ DegenerateColocalEdge,
+ DegenerateEdge,
+ DuplicateEdge
+ };
+ };
+
+ mutable ErrorCode::Enum errorCode;
+ mutable uint32_t errorIndex0;
+ mutable uint32_t errorIndex1;
+
+private:
+ // Return true if the face can be added to the manifold mesh.
+ bool canAddFace(const std::vector<uint32_t> &indexArray, uint32_t first, uint32_t num) const {
+ return canAddFace(indexArray.data(), first, num);
+ }
+
+ bool canAddFace(const uint32_t *indexArray, uint32_t first, uint32_t num) const {
+ for (uint32_t j = num - 1, i = 0; i < num; j = i++) {
+ if (!canAddEdge(indexArray[first + j], indexArray[first + i])) {
+ errorIndex0 = indexArray[first + j];
+ errorIndex1 = indexArray[first + i];
+ return false;
+ }
+ }
+ // We also have to make sure the face does not have any duplicate edge!
+ for (uint32_t i = 0; i < num; i++) {
+ int i0 = indexArray[first + i + 0];
+ int i1 = indexArray[first + (i + 1) % num];
+ for (uint32_t j = i + 1; j < num; j++) {
+ int j0 = indexArray[first + j + 0];
+ int j1 = indexArray[first + (j + 1) % num];
+ if (i0 == j0 && i1 == j1) {
+ errorCode = ErrorCode::DuplicateEdge;
+ errorIndex0 = i0;
+ errorIndex1 = i1;
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ // Return true if the edge doesn't exist or doesn't have any adjacent face.
+ bool canAddEdge(uint32_t i, uint32_t j) const {
+ if (i == j) {
+ // Skip degenerate edges.
+ errorCode = ErrorCode::DegenerateEdge;
+ return false;
+ }
+ // Same check, but taking into account colocal vertices.
+ const Vertex *v0 = vertexAt(i);
+ const Vertex *v1 = vertexAt(j);
+ for (Vertex::ConstVertexIterator it(v0->colocals()); !it.isDone(); it.advance()) {
+ if (it.current() == v1) {
+ // Skip degenerate edges.
+ errorCode = ErrorCode::DegenerateColocalEdge;
+ return false;
+ }
+ }
+ // Make sure edge has not been added yet.
+ Edge *edge = findEdge(i, j);
+ // We ignore edges that don't have an adjacent face yet, since this face could become the edge's face.
+ if (!(edge == NULL || edge->face == NULL)) {
+ errorCode = ErrorCode::AlreadyAddedEdge;
+ return false;
+ }
+ return true;
+ }
+
+ Edge *addEdge(uint32_t i, uint32_t j) {
+ xaAssert(i != j);
+ Edge *edge = findEdge(i, j);
+ if (edge != NULL) {
+ // Edge may already exist, but its face must not be set.
+ xaDebugAssert(edge->face == NULL);
+ // Nothing else to do!
+ } else {
+ // Add new edge.
+ // Lookup pair.
+ Edge *pair = findEdge(j, i);
+ if (pair != NULL) {
+ // Create edge with same id.
+ edge = new Edge(pair->id + 1);
+ // Link edge pairs.
+ edge->pair = pair;
+ pair->pair = edge;
+ // @@ I'm not sure this is necessary!
+ pair->vertex->setEdge(pair);
+ } else {
+ // Create edge.
+ edge = new Edge(2 * m_edgeArray.size());
+ // Add only unpaired edges.
+ m_edgeArray.push_back(edge);
+ }
+ edge->vertex = m_vertexArray[i];
+ m_edgeMap[Key(i, j)] = edge;
+ }
+ // Face and Next are set by addFace.
+ return edge;
+ }
+
+ /// Find edge, test all colocals.
+ Edge *findEdge(uint32_t i, uint32_t j) const {
+ Edge *edge = NULL;
+ const Vertex *v0 = vertexAt(i);
+ const Vertex *v1 = vertexAt(j);
+ // Test all colocal pairs.
+ for (Vertex::ConstVertexIterator it0(v0->colocals()); !it0.isDone(); it0.advance()) {
+ for (Vertex::ConstVertexIterator it1(v1->colocals()); !it1.isDone(); it1.advance()) {
+ Key key(it0.current()->id, it1.current()->id);
+ if (edge == NULL) {
+ auto edgeIt = m_edgeMap.find(key);
+ if (edgeIt != m_edgeMap.end())
+ edge = (*edgeIt).second;
+#if !defined(_DEBUG)
+ if (edge != NULL) return edge;
+#endif
+ } else {
+ // Make sure that only one edge is found.
+ xaDebugAssert(m_edgeMap.find(key) == m_edgeMap.end());
+ }
+ }
+ }
+ return edge;
+ }
+
+ /// Link this boundary edge.
+ void linkBoundaryEdge(Edge *edge) {
+ xaAssert(edge->face == NULL);
+ // Make sure next pointer has not been set. @@ We want to be able to relink boundary edges after mesh changes.
+ Edge *next = edge;
+ while (next->pair->face != NULL) {
+ // Get pair prev
+ Edge *e = next->pair->next;
+ while (e->next != next->pair) {
+ e = e->next;
+ }
+ next = e;
+ }
+ edge->setNext(next->pair);
+ // Adjust vertex edge, so that it's the boundary edge. (required for isBoundary())
+ if (edge->vertex->edge != edge) {
+ // Multiple boundaries in the same edge.
+ edge->vertex->edge = edge;
+ }
+ }
+
+ Vertex *splitBoundaryEdge(Edge *edge, float t, const Vector3 &pos) {
+ /*
+ We want to go from this configuration:
+
+ + +
+ | ^
+ edge |<->| pair
+ v |
+ + +
+
+ To this one:
+
+ + +
+ | ^
+ e0 |<->| p0
+ v |
+ vertex + +
+ | ^
+ e1 |<->| p1
+ v |
+ + +
+
+ */
+ Edge *pair = edge->pair;
+ // Make sure boundaries are linked.
+ xaDebugAssert(pair != NULL);
+ // Make sure edge is a boundary edge.
+ xaDebugAssert(pair->face == NULL);
+ // Add new vertex.
+ Vertex *vertex = addVertex(pos);
+ vertex->nor = lerp(edge->from()->nor, edge->to()->nor, t);
+ vertex->tex = lerp(edge->from()->tex, edge->to()->tex, t);
+ disconnect(edge);
+ disconnect(pair);
+ // Add edges.
+ Edge *e0 = addEdge(edge->from()->id, vertex->id);
+ Edge *p0 = addEdge(vertex->id, pair->to()->id);
+ Edge *e1 = addEdge(vertex->id, edge->to()->id);
+ Edge *p1 = addEdge(pair->from()->id, vertex->id);
+ // Link edges.
+ e0->setNext(e1);
+ p1->setNext(p0);
+ e0->setPrev(edge->prev);
+ e1->setNext(edge->next);
+ p1->setPrev(pair->prev);
+ p0->setNext(pair->next);
+ xaDebugAssert(e0->next == e1);
+ xaDebugAssert(e1->prev == e0);
+ xaDebugAssert(p1->next == p0);
+ xaDebugAssert(p0->prev == p1);
+ xaDebugAssert(p0->pair == e0);
+ xaDebugAssert(e0->pair == p0);
+ xaDebugAssert(p1->pair == e1);
+ xaDebugAssert(e1->pair == p1);
+ // Link faces.
+ e0->face = edge->face;
+ e1->face = edge->face;
+ // Link vertices.
+ edge->from()->setEdge(e0);
+ vertex->setEdge(e1);
+ delete edge;
+ delete pair;
+ return vertex;
+ }
+
+private:
+ std::vector<Vertex *> m_vertexArray;
+ std::vector<Edge *> m_edgeArray;
+ std::vector<Face *> m_faceArray;
+
+ struct Key {
+ Key() {}
+ Key(const Key &k) :
+ p0(k.p0),
+ p1(k.p1) {}
+ Key(uint32_t v0, uint32_t v1) :
+ p0(v0),
+ p1(v1) {}
+ void operator=(const Key &k) {
+ p0 = k.p0;
+ p1 = k.p1;
+ }
+ bool operator==(const Key &k) const {
+ return p0 == k.p0 && p1 == k.p1;
+ }
+
+ uint32_t p0;
+ uint32_t p1;
+ };
+
+ friend struct Hash<Mesh::Key>;
+ std::unordered_map<Key, Edge *, Hash<Key>, Equal<Key> > m_edgeMap;
+ uint32_t m_colocalVertexCount;
+};
+
+class MeshTopology {
+public:
+ MeshTopology(const Mesh *mesh) {
+ buildTopologyInfo(mesh);
+ }
+
+ /// Determine if the mesh is connected.
+ bool isConnected() const {
+ return m_connectedCount == 1;
+ }
+
+ /// Determine if the mesh is closed. (Each edge is shared by two faces)
+ bool isClosed() const {
+ return m_boundaryCount == 0;
+ }
+
+ /// Return true if the mesh has the topology of a disk.
+ bool isDisk() const {
+ return isConnected() && m_boundaryCount == 1 /* && m_eulerNumber == 1*/;
+ }
+
+private:
+ void buildTopologyInfo(const Mesh *mesh) {
+ const uint32_t vertexCount = mesh->colocalVertexCount();
+ const uint32_t faceCount = mesh->faceCount();
+ const uint32_t edgeCount = mesh->edgeCount();
+ xaPrint("--- Building mesh topology:\n");
+ std::vector<uint32_t> stack(faceCount);
+ BitArray bitFlags(faceCount);
+ bitFlags.clearAll();
+ // Compute connectivity.
+ xaPrint("--- Computing connectivity.\n");
+ m_connectedCount = 0;
+ for (uint32_t f = 0; f < faceCount; f++) {
+ if (bitFlags.bitAt(f) == false) {
+ m_connectedCount++;
+ stack.push_back(f);
+ while (!stack.empty()) {
+ const uint32_t top = stack.back();
+ xaAssert(top != uint32_t(~0));
+ stack.pop_back();
+ if (bitFlags.bitAt(top) == false) {
+ bitFlags.setBitAt(top);
+ const Face *face = mesh->faceAt(top);
+ const Edge *firstEdge = face->edge;
+ const Edge *edge = firstEdge;
+ do {
+ const Face *neighborFace = edge->pair->face;
+ if (neighborFace != NULL) {
+ stack.push_back(neighborFace->id);
+ }
+ edge = edge->next;
+ } while (edge != firstEdge);
+ }
+ }
+ }
+ }
+ xaAssert(stack.empty());
+ xaPrint("--- %d connected components.\n", m_connectedCount);
+ // Count boundary loops.
+ xaPrint("--- Counting boundary loops.\n");
+ m_boundaryCount = 0;
+ bitFlags.resize(edgeCount);
+ bitFlags.clearAll();
+ // Don't forget to link the boundary otherwise this won't work.
+ for (uint32_t e = 0; e < edgeCount; e++) {
+ const Edge *startEdge = mesh->edgeAt(e);
+ if (startEdge != NULL && startEdge->isBoundary() && bitFlags.bitAt(e) == false) {
+ xaDebugAssert(startEdge->face != NULL);
+ xaDebugAssert(startEdge->pair->face == NULL);
+ startEdge = startEdge->pair;
+ m_boundaryCount++;
+ const Edge *edge = startEdge;
+ do {
+ bitFlags.setBitAt(edge->id / 2);
+ edge = edge->next;
+ } while (startEdge != edge);
+ }
+ }
+ xaPrint("--- %d boundary loops found.\n", m_boundaryCount);
+ // Compute euler number.
+ m_eulerNumber = vertexCount - edgeCount + faceCount;
+ xaPrint("--- Euler number: %d.\n", m_eulerNumber);
+ // Compute genus. (only valid on closed connected surfaces)
+ m_genus = -1;
+ if (isClosed() && isConnected()) {
+ m_genus = (2 - m_eulerNumber) / 2;
+ xaPrint("--- Genus: %d.\n", m_genus);
+ }
+ }
+
+private:
+ ///< Number of boundary loops.
+ int m_boundaryCount;
+
+ ///< Number of connected components.
+ int m_connectedCount;
+
+ ///< Euler number.
+ int m_eulerNumber;
+
+ /// Mesh genus.
+ int m_genus;
+};
+
+float computeSurfaceArea(const halfedge::Mesh *mesh) {
+ float area = 0;
+ for (halfedge::Mesh::ConstFaceIterator it(mesh->faces()); !it.isDone(); it.advance()) {
+ const halfedge::Face *face = it.current();
+ area += face->area();
+ }
+ xaDebugAssert(area >= 0);
+ return area;
+}
+
+float computeParametricArea(const halfedge::Mesh *mesh) {
+ float area = 0;
+ for (halfedge::Mesh::ConstFaceIterator it(mesh->faces()); !it.isDone(); it.advance()) {
+ const halfedge::Face *face = it.current();
+ area += face->parametricArea();
+ }
+ return area;
+}
+
+uint32_t countMeshTriangles(const Mesh *mesh) {
+ const uint32_t faceCount = mesh->faceCount();
+ uint32_t triangleCount = 0;
+ for (uint32_t f = 0; f < faceCount; f++) {
+ const Face *face = mesh->faceAt(f);
+ uint32_t edgeCount = face->edgeCount();
+ xaDebugAssert(edgeCount > 2);
+ triangleCount += edgeCount - 2;
+ }
+ return triangleCount;
+}
+
+Mesh *unifyVertices(const Mesh *inputMesh) {
+ Mesh *mesh = new Mesh;
+ // Only add the first colocal.
+ const uint32_t vertexCount = inputMesh->vertexCount();
+ for (uint32_t v = 0; v < vertexCount; v++) {
+ const Vertex *vertex = inputMesh->vertexAt(v);
+ if (vertex->isFirstColocal()) {
+ mesh->addVertex(vertex->pos);
+ }
+ }
+ std::vector<uint32_t> indexArray;
+ // Add new faces pointing to first colocals.
+ uint32_t faceCount = inputMesh->faceCount();
+ for (uint32_t f = 0; f < faceCount; f++) {
+ const Face *face = inputMesh->faceAt(f);
+ indexArray.clear();
+ for (Face::ConstEdgeIterator it(face->edges()); !it.isDone(); it.advance()) {
+ const Edge *edge = it.current();
+ const Vertex *vertex = edge->vertex->firstColocal();
+ indexArray.push_back(vertex->id);
+ }
+ mesh->addFace(indexArray);
+ }
+ mesh->linkBoundary();
+ return mesh;
+}
+
+static bool pointInTriangle(const Vector2 &p, const Vector2 &a, const Vector2 &b, const Vector2 &c) {
+ return triangleArea(a, b, p) >= 0.00001f &&
+ triangleArea(b, c, p) >= 0.00001f &&
+ triangleArea(c, a, p) >= 0.00001f;
+}
+
+// This is doing a simple ear-clipping algorithm that skips invalid triangles. Ideally, we should
+// also sort the ears by angle, start with the ones that have the smallest angle and proceed in order.
+Mesh *triangulate(const Mesh *inputMesh) {
+ Mesh *mesh = new Mesh;
+ // Add all vertices.
+ const uint32_t vertexCount = inputMesh->vertexCount();
+ for (uint32_t v = 0; v < vertexCount; v++) {
+ const Vertex *vertex = inputMesh->vertexAt(v);
+ mesh->addVertex(vertex->pos);
+ }
+ std::vector<int> polygonVertices;
+ std::vector<float> polygonAngles;
+ std::vector<Vector2> polygonPoints;
+ const uint32_t faceCount = inputMesh->faceCount();
+ for (uint32_t f = 0; f < faceCount; f++) {
+ const Face *face = inputMesh->faceAt(f);
+ xaDebugAssert(face != NULL);
+ const uint32_t edgeCount = face->edgeCount();
+ xaDebugAssert(edgeCount >= 3);
+ polygonVertices.clear();
+ polygonVertices.reserve(edgeCount);
+ if (edgeCount == 3) {
+ // Simple case for triangles.
+ for (Face::ConstEdgeIterator it(face->edges()); !it.isDone(); it.advance()) {
+ const Edge *edge = it.current();
+ const Vertex *vertex = edge->vertex;
+ polygonVertices.push_back(vertex->id);
+ }
+ int v0 = polygonVertices[0];
+ int v1 = polygonVertices[1];
+ int v2 = polygonVertices[2];
+ mesh->addFace(v0, v1, v2);
+ } else {
+ // Build 2D polygon projecting vertices onto normal plane.
+ // Faces are not necesarily planar, this is for example the case, when the face comes from filling a hole. In such cases
+ // it's much better to use the best fit plane.
+ const Vector3 fn = face->normal();
+ Basis basis;
+ basis.buildFrameForDirection(fn);
+ polygonPoints.clear();
+ polygonPoints.reserve(edgeCount);
+ polygonAngles.clear();
+ polygonAngles.reserve(edgeCount);
+ for (Face::ConstEdgeIterator it(face->edges()); !it.isDone(); it.advance()) {
+ const Edge *edge = it.current();
+ const Vertex *vertex = edge->vertex;
+ polygonVertices.push_back(vertex->id);
+ Vector2 p;
+ p.x = dot(basis.tangent, vertex->pos);
+ p.y = dot(basis.bitangent, vertex->pos);
+ polygonPoints.push_back(p);
+ }
+ polygonAngles.resize(edgeCount);
+ while (polygonVertices.size() > 2) {
+ uint32_t size = polygonVertices.size();
+ // Update polygon angles. @@ Update only those that have changed.
+ float minAngle = 2 * PI;
+ uint32_t bestEar = 0; // Use first one if none of them is valid.
+ bool bestIsValid = false;
+ for (uint32_t i = 0; i < size; i++) {
+ uint32_t i0 = i;
+ uint32_t i1 = (i + 1) % size; // Use Sean's polygon interation trick.
+ uint32_t i2 = (i + 2) % size;
+ Vector2 p0 = polygonPoints[i0];
+ Vector2 p1 = polygonPoints[i1];
+ Vector2 p2 = polygonPoints[i2];
+
+ bool degenerate = distance(p0, p1) < NV_EPSILON || distance(p0, p2) < NV_EPSILON || distance(p1, p2) < NV_EPSILON;
+ if (degenerate) {
+ continue;
+ }
+
+ float d = clamp(dot(p0 - p1, p2 - p1) / (length(p0 - p1) * length(p2 - p1)), -1.0f, 1.0f);
+ float angle = acosf(d);
+ float area = triangleArea(p0, p1, p2);
+ if (area < 0.0f) angle = 2.0f * PI - angle;
+ polygonAngles[i1] = angle;
+ if (angle < minAngle || !bestIsValid) {
+ // Make sure this is a valid ear, if not, skip this point.
+ bool valid = true;
+ for (uint32_t j = 0; j < size; j++) {
+ if (j == i0 || j == i1 || j == i2) continue;
+ Vector2 p = polygonPoints[j];
+ if (pointInTriangle(p, p0, p1, p2)) {
+ valid = false;
+ break;
+ }
+ }
+ if (valid || !bestIsValid) {
+ minAngle = angle;
+ bestEar = i1;
+ bestIsValid = valid;
+ }
+ }
+ }
+ if (!bestIsValid)
+ break;
+
+ xaDebugAssert(minAngle <= 2 * PI);
+ // Clip best ear:
+ uint32_t i0 = (bestEar + size - 1) % size;
+ uint32_t i1 = (bestEar + 0) % size;
+ uint32_t i2 = (bestEar + 1) % size;
+ int v0 = polygonVertices[i0];
+ int v1 = polygonVertices[i1];
+ int v2 = polygonVertices[i2];
+ mesh->addFace(v0, v1, v2);
+ polygonVertices.erase(polygonVertices.begin() + i1);
+ polygonPoints.erase(polygonPoints.begin() + i1);
+ polygonAngles.erase(polygonAngles.begin() + i1);
+ }
+ }
+ }
+ mesh->linkBoundary();
+ return mesh;
+}
+
+} // namespace halfedge
+
+/// Mersenne twister random number generator.
+class MTRand {
+public:
+ enum time_e { Time };
+ enum { N = 624 }; // length of state vector
+ enum { M = 397 };
+
+ /// Constructor that uses the current time as the seed.
+ MTRand(time_e) {
+ seed((uint32_t)time(NULL));
+ }
+
+ /// Constructor that uses the given seed.
+ MTRand(uint32_t s = 0) {
+ seed(s);
+ }
+
+ /// Provide a new seed.
+ void seed(uint32_t s) {
+ initialize(s);
+ reload();
+ }
+
+ /// Get a random number between 0 - 65536.
+ uint32_t get() {
+ // Pull a 32-bit integer from the generator state
+ // Every other access function simply transforms the numbers extracted here
+ if (left == 0) {
+ reload();
+ }
+ left--;
+ uint32_t s1;
+ s1 = *next++;
+ s1 ^= (s1 >> 11);
+ s1 ^= (s1 << 7) & 0x9d2c5680U;
+ s1 ^= (s1 << 15) & 0xefc60000U;
+ return (s1 ^ (s1 >> 18));
+ };
+
+ /// Get a random number on [0, max] interval.
+ uint32_t getRange(uint32_t max) {
+ if (max == 0) return 0;
+ if (max == NV_UINT32_MAX) return get();
+ const uint32_t np2 = nextPowerOfTwo(max + 1); // @@ This fails if max == NV_UINT32_MAX
+ const uint32_t mask = np2 - 1;
+ uint32_t n;
+ do {
+ n = get() & mask;
+ } while (n > max);
+ return n;
+ }
+
+private:
+ void initialize(uint32_t seed) {
+ // Initialize generator state with seed
+ // See Knuth TAOCP Vol 2, 3rd Ed, p.106 for multiplier.
+ // In previous versions, most significant bits (MSBs) of the seed affect
+ // only MSBs of the state array. Modified 9 Jan 2002 by Makoto Matsumoto.
+ uint32_t *s = state;
+ uint32_t *r = state;
+ int i = 1;
+ *s++ = seed & 0xffffffffUL;
+ for (; i < N; ++i) {
+ *s++ = (1812433253UL * (*r ^ (*r >> 30)) + i) & 0xffffffffUL;
+ r++;
+ }
+ }
+
+ void reload() {
+ // Generate N new values in state
+ // Made clearer and faster by Matthew Bellew (matthew.bellew@home.com)
+ uint32_t *p = state;
+ int i;
+ for (i = N - M; i--; ++p)
+ *p = twist(p[M], p[0], p[1]);
+ for (i = M; --i; ++p)
+ *p = twist(p[M - N], p[0], p[1]);
+ *p = twist(p[M - N], p[0], state[0]);
+ left = N, next = state;
+ }
+
+ uint32_t hiBit(uint32_t u) const {
+ return u & 0x80000000U;
+ }
+ uint32_t loBit(uint32_t u) const {
+ return u & 0x00000001U;
+ }
+ uint32_t loBits(uint32_t u) const {
+ return u & 0x7fffffffU;
+ }
+ uint32_t mixBits(uint32_t u, uint32_t v) const {
+ return hiBit(u) | loBits(v);
+ }
+ uint32_t twist(uint32_t m, uint32_t s0, uint32_t s1) const {
+ return m ^ (mixBits(s0, s1) >> 1) ^ ((~loBit(s1) + 1) & 0x9908b0dfU);
+ }
+
+ uint32_t state[N]; // internal state
+ uint32_t *next; // next value to get from state
+ int left; // number of values left before reload needed
+};
+
+namespace morton {
+// Code from ryg:
+// http://fgiesen.wordpress.com/2009/12/13/decoding-morton-codes/
+
+// Inverse of part1By1 - "delete" all odd-indexed bits
+uint32_t compact1By1(uint32_t x) {
+ x &= 0x55555555; // x = -f-e -d-c -b-a -9-8 -7-6 -5-4 -3-2 -1-0
+ x = (x ^ (x >> 1)) & 0x33333333; // x = --fe --dc --ba --98 --76 --54 --32 --10
+ x = (x ^ (x >> 2)) & 0x0f0f0f0f; // x = ---- fedc ---- ba98 ---- 7654 ---- 3210
+ x = (x ^ (x >> 4)) & 0x00ff00ff; // x = ---- ---- fedc ba98 ---- ---- 7654 3210
+ x = (x ^ (x >> 8)) & 0x0000ffff; // x = ---- ---- ---- ---- fedc ba98 7654 3210
+ return x;
+}
+
+// Inverse of part1By2 - "delete" all bits not at positions divisible by 3
+uint32_t compact1By2(uint32_t x) {
+ x &= 0x09249249; // x = ---- 9--8 --7- -6-- 5--4 --3- -2-- 1--0
+ x = (x ^ (x >> 2)) & 0x030c30c3; // x = ---- --98 ---- 76-- --54 ---- 32-- --10
+ x = (x ^ (x >> 4)) & 0x0300f00f; // x = ---- --98 ---- ---- 7654 ---- ---- 3210
+ x = (x ^ (x >> 8)) & 0xff0000ff; // x = ---- --98 ---- ---- ---- ---- 7654 3210
+ x = (x ^ (x >> 16)) & 0x000003ff; // x = ---- ---- ---- ---- ---- --98 7654 3210
+ return x;
+}
+
+uint32_t decodeMorton2X(uint32_t code) {
+ return compact1By1(code >> 0);
+}
+
+uint32_t decodeMorton2Y(uint32_t code) {
+ return compact1By1(code >> 1);
+}
+
+uint32_t decodeMorton3X(uint32_t code) {
+ return compact1By2(code >> 0);
+}
+
+uint32_t decodeMorton3Y(uint32_t code) {
+ return compact1By2(code >> 1);
+}
+
+uint32_t decodeMorton3Z(uint32_t code) {
+ return compact1By2(code >> 2);
+}
+} // namespace morton
+
+// A simple, dynamic proximity grid based on Jon's code.
+// Instead of storing pointers here I store indices.
+struct ProximityGrid {
+ void init(const Box &box, uint32_t count) {
+ cellArray.clear();
+ // Determine grid size.
+ float cellWidth;
+ Vector3 diagonal = box.extents() * 2.f;
+ float volume = box.volume();
+ if (equal(volume, 0)) {
+ // Degenerate box, treat like a quad.
+ Vector2 quad;
+ if (diagonal.x < diagonal.y && diagonal.x < diagonal.z) {
+ quad.x = diagonal.y;
+ quad.y = diagonal.z;
+ } else if (diagonal.y < diagonal.x && diagonal.y < diagonal.z) {
+ quad.x = diagonal.x;
+ quad.y = diagonal.z;
+ } else {
+ quad.x = diagonal.x;
+ quad.y = diagonal.y;
+ }
+ float cellArea = quad.x * quad.y / count;
+ cellWidth = sqrtf(cellArea); // pow(cellArea, 1.0f / 2.0f);
+ } else {
+ // Ideally we want one cell per point.
+ float cellVolume = volume / count;
+ cellWidth = powf(cellVolume, 1.0f / 3.0f);
+ }
+ xaDebugAssert(cellWidth != 0);
+ sx = std::max(1, ftoi_ceil(diagonal.x / cellWidth));
+ sy = std::max(1, ftoi_ceil(diagonal.y / cellWidth));
+ sz = std::max(1, ftoi_ceil(diagonal.z / cellWidth));
+ invCellSize.x = float(sx) / diagonal.x;
+ invCellSize.y = float(sy) / diagonal.y;
+ invCellSize.z = float(sz) / diagonal.z;
+ cellArray.resize(sx * sy * sz);
+ corner = box.minCorner; // @@ Align grid better?
+ }
+
+ int index_x(float x) const {
+ return clamp(ftoi_floor((x - corner.x) * invCellSize.x), 0, sx - 1);
+ }
+
+ int index_y(float y) const {
+ return clamp(ftoi_floor((y - corner.y) * invCellSize.y), 0, sy - 1);
+ }
+
+ int index_z(float z) const {
+ return clamp(ftoi_floor((z - corner.z) * invCellSize.z), 0, sz - 1);
+ }
+
+ int index(int x, int y, int z) const {
+ xaDebugAssert(x >= 0 && x < sx);
+ xaDebugAssert(y >= 0 && y < sy);
+ xaDebugAssert(z >= 0 && z < sz);
+ int idx = (z * sy + y) * sx + x;
+ xaDebugAssert(idx >= 0 && uint32_t(idx) < cellArray.size());
+ return idx;
+ }
+
+ uint32_t mortonCount() const {
+ uint64_t s = uint64_t(max3(sx, sy, sz));
+ s = nextPowerOfTwo(s);
+ if (s > 1024) {
+ return uint32_t(s * s * min3(sx, sy, sz));
+ }
+ return uint32_t(s * s * s);
+ }
+
+ int mortonIndex(uint32_t code) const {
+ uint32_t x, y, z;
+ uint32_t s = uint32_t(max3(sx, sy, sz));
+ if (s > 1024) {
+ // Use layered two-dimensional morton order.
+ s = nextPowerOfTwo(s);
+ uint32_t layer = code / (s * s);
+ code = code % (s * s);
+ uint32_t layer_count = uint32_t(min3(sx, sy, sz));
+ if (sx == (int)layer_count) {
+ x = layer;
+ y = morton::decodeMorton2X(code);
+ z = morton::decodeMorton2Y(code);
+ } else if (sy == (int)layer_count) {
+ x = morton::decodeMorton2Y(code);
+ y = layer;
+ z = morton::decodeMorton2X(code);
+ } else { /*if (sz == layer_count)*/
+ x = morton::decodeMorton2X(code);
+ y = morton::decodeMorton2Y(code);
+ z = layer;
+ }
+ } else {
+ x = morton::decodeMorton3X(code);
+ y = morton::decodeMorton3Y(code);
+ z = morton::decodeMorton3Z(code);
+ }
+ if (x >= uint32_t(sx) || y >= uint32_t(sy) || z >= uint32_t(sz)) {
+ return -1;
+ }
+ return index(x, y, z);
+ }
+
+ void add(const Vector3 &pos, uint32_t key) {
+ int x = index_x(pos.x);
+ int y = index_y(pos.y);
+ int z = index_z(pos.z);
+ uint32_t idx = index(x, y, z);
+ cellArray[idx].indexArray.push_back(key);
+ }
+
+ // Gather all points inside the given sphere.
+ // Radius is assumed to be small, so we don't bother culling the cells.
+ void gather(const Vector3 &position, float radius, std::vector<uint32_t> &indexArray) {
+ int x0 = index_x(position.x - radius);
+ int x1 = index_x(position.x + radius);
+ int y0 = index_y(position.y - radius);
+ int y1 = index_y(position.y + radius);
+ int z0 = index_z(position.z - radius);
+ int z1 = index_z(position.z + radius);
+ for (int z = z0; z <= z1; z++) {
+ for (int y = y0; y <= y1; y++) {
+ for (int x = x0; x <= x1; x++) {
+ int idx = index(x, y, z);
+ indexArray.insert(indexArray.begin(), cellArray[idx].indexArray.begin(), cellArray[idx].indexArray.end());
+ }
+ }
+ }
+ }
+
+ struct Cell {
+ std::vector<uint32_t> indexArray;
+ };
+
+ std::vector<Cell> cellArray;
+
+ Vector3 corner;
+ Vector3 invCellSize;
+ int sx, sy, sz;
+};
+
+// Based on Pierre Terdiman's and Michael Herf's source code.
+// http://www.codercorner.com/RadixSortRevisited.htm
+// http://www.stereopsis.com/radix.html
+class RadixSort {
+public:
+ RadixSort() :
+ m_size(0),
+ m_ranks(NULL),
+ m_ranks2(NULL),
+ m_validRanks(false) {}
+ ~RadixSort() {
+ // Release everything
+ free(m_ranks2);
+ free(m_ranks);
+ }
+
+ RadixSort &sort(const float *input, uint32_t count) {
+ if (input == NULL || count == 0) return *this;
+ // Resize lists if needed
+ if (count != m_size) {
+ if (count > m_size) {
+ m_ranks2 = (uint32_t *)realloc(m_ranks2, sizeof(uint32_t) * count);
+ m_ranks = (uint32_t *)realloc(m_ranks, sizeof(uint32_t) * count);
+ }
+ m_size = count;
+ m_validRanks = false;
+ }
+ if (count < 32) {
+ insertionSort(input, count);
+ } else {
+ // @@ Avoid touching the input multiple times.
+ for (uint32_t i = 0; i < count; i++) {
+ FloatFlip((uint32_t &)input[i]);
+ }
+ radixSort<uint32_t>((const uint32_t *)input, count);
+ for (uint32_t i = 0; i < count; i++) {
+ IFloatFlip((uint32_t &)input[i]);
+ }
+ }
+ return *this;
+ }
+
+ RadixSort &sort(const std::vector<float> &input) {
+ return sort(input.data(), input.size());
+ }
+
+ // Access to results. m_ranks is a list of indices in sorted order, i.e. in the order you may further process your data
+ const uint32_t *ranks() const {
+ xaDebugAssert(m_validRanks);
+ return m_ranks;
+ }
+ uint32_t *ranks() {
+ xaDebugAssert(m_validRanks);
+ return m_ranks;
+ }
+
+private:
+ uint32_t m_size;
+ uint32_t *m_ranks;
+ uint32_t *m_ranks2;
+ bool m_validRanks;
+
+ void FloatFlip(uint32_t &f) {
+ int32_t mask = (int32_t(f) >> 31) | 0x80000000; // Warren Hunt, Manchor Ko.
+ f ^= mask;
+ }
+
+ void IFloatFlip(uint32_t &f) {
+ uint32_t mask = ((f >> 31) - 1) | 0x80000000; // Michael Herf.
+ f ^= mask;
+ }
+
+ template <typename T>
+ void createHistograms(const T *buffer, uint32_t count, uint32_t *histogram) {
+ const uint32_t bucketCount = sizeof(T); // (8 * sizeof(T)) / log2(radix)
+ // Init bucket pointers.
+ uint32_t *h[bucketCount];
+ for (uint32_t i = 0; i < bucketCount; i++) {
+ h[i] = histogram + 256 * i;
+ }
+ // Clear histograms.
+ memset(histogram, 0, 256 * bucketCount * sizeof(uint32_t));
+ // @@ Add support for signed integers.
+ // Build histograms.
+ const uint8_t *p = (const uint8_t *)buffer; // @@ Does this break aliasing rules?
+ const uint8_t *pe = p + count * sizeof(T);
+ while (p != pe) {
+ h[0][*p++]++, h[1][*p++]++, h[2][*p++]++, h[3][*p++]++;
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable : 4127)
+#endif
+ if (bucketCount == 8) h[4][*p++]++, h[5][*p++]++, h[6][*p++]++, h[7][*p++]++;
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+ }
+ }
+
+ template <typename T>
+ void insertionSort(const T *input, uint32_t count) {
+ if (!m_validRanks) {
+ m_ranks[0] = 0;
+ for (uint32_t i = 1; i != count; ++i) {
+ int rank = m_ranks[i] = i;
+ uint32_t j = i;
+ while (j != 0 && input[rank] < input[m_ranks[j - 1]]) {
+ m_ranks[j] = m_ranks[j - 1];
+ --j;
+ }
+ if (i != j) {
+ m_ranks[j] = rank;
+ }
+ }
+ m_validRanks = true;
+ } else {
+ for (uint32_t i = 1; i != count; ++i) {
+ int rank = m_ranks[i];
+ uint32_t j = i;
+ while (j != 0 && input[rank] < input[m_ranks[j - 1]]) {
+ m_ranks[j] = m_ranks[j - 1];
+ --j;
+ }
+ if (i != j) {
+ m_ranks[j] = rank;
+ }
+ }
+ }
+ }
+
+ template <typename T>
+ void radixSort(const T *input, uint32_t count) {
+ const uint32_t P = sizeof(T); // pass count
+ // Allocate histograms & offsets on the stack
+ uint32_t histogram[256 * P];
+ uint32_t *link[256];
+ createHistograms(input, count, histogram);
+ // Radix sort, j is the pass number (0=LSB, P=MSB)
+ for (uint32_t j = 0; j < P; j++) {
+ // Pointer to this bucket.
+ const uint32_t *h = &histogram[j * 256];
+ const uint8_t *inputBytes = (const uint8_t *)input; // @@ Is this aliasing legal?
+ inputBytes += j;
+ if (h[inputBytes[0]] == count) {
+ // Skip this pass, all values are the same.
+ continue;
+ }
+ // Create offsets
+ link[0] = m_ranks2;
+ for (uint32_t i = 1; i < 256; i++)
+ link[i] = link[i - 1] + h[i - 1];
+ // Perform Radix Sort
+ if (!m_validRanks) {
+ for (uint32_t i = 0; i < count; i++) {
+ *link[inputBytes[i * P]]++ = i;
+ }
+ m_validRanks = true;
+ } else {
+ for (uint32_t i = 0; i < count; i++) {
+ const uint32_t idx = m_ranks[i];
+ *link[inputBytes[idx * P]]++ = idx;
+ }
+ }
+ // Swap pointers for next pass. Valid indices - the most recent ones - are in m_ranks after the swap.
+ std::swap(m_ranks, m_ranks2);
+ }
+ // All values were equal, generate linear ranks.
+ if (!m_validRanks) {
+ for (uint32_t i = 0; i < count; i++) {
+ m_ranks[i] = i;
+ }
+ m_validRanks = true;
+ }
+ }
+};
+
+namespace raster {
+class ClippedTriangle {
+public:
+ ClippedTriangle(Vector2::Arg a, Vector2::Arg b, Vector2::Arg c) {
+ m_numVertices = 3;
+ m_activeVertexBuffer = 0;
+ m_verticesA[0] = a;
+ m_verticesA[1] = b;
+ m_verticesA[2] = c;
+ m_vertexBuffers[0] = m_verticesA;
+ m_vertexBuffers[1] = m_verticesB;
+ }
+
+ uint32_t vertexCount() {
+ return m_numVertices;
+ }
+
+ const Vector2 *vertices() {
+ return m_vertexBuffers[m_activeVertexBuffer];
+ }
+
+ void clipHorizontalPlane(float offset, float clipdirection) {
+ Vector2 *v = m_vertexBuffers[m_activeVertexBuffer];
+ m_activeVertexBuffer ^= 1;
+ Vector2 *v2 = m_vertexBuffers[m_activeVertexBuffer];
+ v[m_numVertices] = v[0];
+ float dy2, dy1 = offset - v[0].y;
+ int dy2in, dy1in = clipdirection * dy1 >= 0;
+ uint32_t p = 0;
+ for (uint32_t k = 0; k < m_numVertices; k++) {
+ dy2 = offset - v[k + 1].y;
+ dy2in = clipdirection * dy2 >= 0;
+ if (dy1in) v2[p++] = v[k];
+ if (dy1in + dy2in == 1) { // not both in/out
+ float dx = v[k + 1].x - v[k].x;
+ float dy = v[k + 1].y - v[k].y;
+ v2[p++] = Vector2(v[k].x + dy1 * (dx / dy), offset);
+ }
+ dy1 = dy2;
+ dy1in = dy2in;
+ }
+ m_numVertices = p;
+ //for (uint32_t k=0; k<m_numVertices; k++) printf("(%f, %f)\n", v2[k].x, v2[k].y); printf("\n");
+ }
+
+ void clipVerticalPlane(float offset, float clipdirection) {
+ Vector2 *v = m_vertexBuffers[m_activeVertexBuffer];
+ m_activeVertexBuffer ^= 1;
+ Vector2 *v2 = m_vertexBuffers[m_activeVertexBuffer];
+ v[m_numVertices] = v[0];
+ float dx2, dx1 = offset - v[0].x;
+ int dx2in, dx1in = clipdirection * dx1 >= 0;
+ uint32_t p = 0;
+ for (uint32_t k = 0; k < m_numVertices; k++) {
+ dx2 = offset - v[k + 1].x;
+ dx2in = clipdirection * dx2 >= 0;
+ if (dx1in) v2[p++] = v[k];
+ if (dx1in + dx2in == 1) { // not both in/out
+ float dx = v[k + 1].x - v[k].x;
+ float dy = v[k + 1].y - v[k].y;
+ v2[p++] = Vector2(offset, v[k].y + dx1 * (dy / dx));
+ }
+ dx1 = dx2;
+ dx1in = dx2in;
+ }
+ m_numVertices = p;
+ }
+
+ void computeAreaCentroid() {
+ Vector2 *v = m_vertexBuffers[m_activeVertexBuffer];
+ v[m_numVertices] = v[0];
+ m_area = 0;
+ float centroidx = 0, centroidy = 0;
+ for (uint32_t k = 0; k < m_numVertices; k++) {
+ // http://local.wasp.uwa.edu.au/~pbourke/geometry/polyarea/
+ float f = v[k].x * v[k + 1].y - v[k + 1].x * v[k].y;
+ m_area += f;
+ centroidx += f * (v[k].x + v[k + 1].x);
+ centroidy += f * (v[k].y + v[k + 1].y);
+ }
+ m_area = 0.5f * fabsf(m_area);
+ if (m_area == 0) {
+ m_centroid = Vector2(0.0f);
+ } else {
+ m_centroid = Vector2(centroidx / (6 * m_area), centroidy / (6 * m_area));
+ }
+ }
+
+ void clipAABox(float x0, float y0, float x1, float y1) {
+ clipVerticalPlane(x0, -1);
+ clipHorizontalPlane(y0, -1);
+ clipVerticalPlane(x1, 1);
+ clipHorizontalPlane(y1, 1);
+ computeAreaCentroid();
+ }
+
+ Vector2 centroid() {
+ return m_centroid;
+ }
+
+ float area() {
+ return m_area;
+ }
+
+private:
+ Vector2 m_verticesA[7 + 1];
+ Vector2 m_verticesB[7 + 1];
+ Vector2 *m_vertexBuffers[2];
+ uint32_t m_numVertices;
+ uint32_t m_activeVertexBuffer;
+ float m_area;
+ Vector2 m_centroid;
+};
+
+/// A callback to sample the environment. Return false to terminate rasterization.
+typedef bool (*SamplingCallback)(void *param, int x, int y, Vector3::Arg bar, Vector3::Arg dx, Vector3::Arg dy, float coverage);
+
+/// A triangle for rasterization.
+struct Triangle {
+ Triangle(Vector2::Arg v0, Vector2::Arg v1, Vector2::Arg v2, Vector3::Arg t0, Vector3::Arg t1, Vector3::Arg t2) {
+ // Init vertices.
+ this->v1 = v0;
+ this->v2 = v2;
+ this->v3 = v1;
+ // Set barycentric coordinates.
+ this->t1 = t0;
+ this->t2 = t2;
+ this->t3 = t1;
+ // make sure every triangle is front facing.
+ flipBackface();
+ // Compute deltas.
+ valid = computeDeltas();
+ computeUnitInwardNormals();
+ }
+
+ /// Compute texture space deltas.
+ /// This method takes two edge vectors that form a basis, determines the
+ /// coordinates of the canonic vectors in that basis, and computes the
+ /// texture gradient that corresponds to those vectors.
+ bool computeDeltas() {
+ Vector2 e0 = v3 - v1;
+ Vector2 e1 = v2 - v1;
+ Vector3 de0 = t3 - t1;
+ Vector3 de1 = t2 - t1;
+ float denom = 1.0f / (e0.y * e1.x - e1.y * e0.x);
+ if (!std::isfinite(denom)) {
+ return false;
+ }
+ float lambda1 = -e1.y * denom;
+ float lambda2 = e0.y * denom;
+ float lambda3 = e1.x * denom;
+ float lambda4 = -e0.x * denom;
+ dx = de0 * lambda1 + de1 * lambda2;
+ dy = de0 * lambda3 + de1 * lambda4;
+ return true;
+ }
+
+ bool draw(const Vector2 &extents, bool enableScissors, SamplingCallback cb, void *param) {
+ // 28.4 fixed-point coordinates
+ const int Y1 = ftoi_round(16.0f * v1.y);
+ const int Y2 = ftoi_round(16.0f * v2.y);
+ const int Y3 = ftoi_round(16.0f * v3.y);
+ const int X1 = ftoi_round(16.0f * v1.x);
+ const int X2 = ftoi_round(16.0f * v2.x);
+ const int X3 = ftoi_round(16.0f * v3.x);
+ // Deltas
+ const int DX12 = X1 - X2;
+ const int DX23 = X2 - X3;
+ const int DX31 = X3 - X1;
+ const int DY12 = Y1 - Y2;
+ const int DY23 = Y2 - Y3;
+ const int DY31 = Y3 - Y1;
+ // Fixed-point deltas
+ const int FDX12 = DX12 << 4;
+ const int FDX23 = DX23 << 4;
+ const int FDX31 = DX31 << 4;
+ const int FDY12 = DY12 << 4;
+ const int FDY23 = DY23 << 4;
+ const int FDY31 = DY31 << 4;
+ int minx, miny, maxx, maxy;
+ if (enableScissors) {
+ int frustumX0 = 0 << 4;
+ int frustumY0 = 0 << 4;
+ int frustumX1 = (int)extents.x << 4;
+ int frustumY1 = (int)extents.y << 4;
+ // Bounding rectangle
+ minx = (std::max(min3(X1, X2, X3), frustumX0) + 0xF) >> 4;
+ miny = (std::max(min3(Y1, Y2, Y3), frustumY0) + 0xF) >> 4;
+ maxx = (std::min(max3(X1, X2, X3), frustumX1) + 0xF) >> 4;
+ maxy = (std::min(max3(Y1, Y2, Y3), frustumY1) + 0xF) >> 4;
+ } else {
+ // Bounding rectangle
+ minx = (min3(X1, X2, X3) + 0xF) >> 4;
+ miny = (min3(Y1, Y2, Y3) + 0xF) >> 4;
+ maxx = (max3(X1, X2, X3) + 0xF) >> 4;
+ maxy = (max3(Y1, Y2, Y3) + 0xF) >> 4;
+ }
+ // Block size, standard 8x8 (must be power of two)
+ const int q = 8;
+ // @@ This won't work when minx,miny are negative. This code path is not used. Leaving as is for now.
+ xaAssert(minx >= 0);
+ xaAssert(miny >= 0);
+ // Start in corner of 8x8 block
+ minx &= ~(q - 1);
+ miny &= ~(q - 1);
+ // Half-edge constants
+ int C1 = DY12 * X1 - DX12 * Y1;
+ int C2 = DY23 * X2 - DX23 * Y2;
+ int C3 = DY31 * X3 - DX31 * Y3;
+ // Correct for fill convention
+ if (DY12 < 0 || (DY12 == 0 && DX12 > 0)) C1++;
+ if (DY23 < 0 || (DY23 == 0 && DX23 > 0)) C2++;
+ if (DY31 < 0 || (DY31 == 0 && DX31 > 0)) C3++;
+ // Loop through blocks
+ for (int y = miny; y < maxy; y += q) {
+ for (int x = minx; x < maxx; x += q) {
+ // Corners of block
+ int x0 = x << 4;
+ int x1 = (x + q - 1) << 4;
+ int y0 = y << 4;
+ int y1 = (y + q - 1) << 4;
+ // Evaluate half-space functions
+ bool a00 = C1 + DX12 * y0 - DY12 * x0 > 0;
+ bool a10 = C1 + DX12 * y0 - DY12 * x1 > 0;
+ bool a01 = C1 + DX12 * y1 - DY12 * x0 > 0;
+ bool a11 = C1 + DX12 * y1 - DY12 * x1 > 0;
+ int a = (a00 << 0) | (a10 << 1) | (a01 << 2) | (a11 << 3);
+ bool b00 = C2 + DX23 * y0 - DY23 * x0 > 0;
+ bool b10 = C2 + DX23 * y0 - DY23 * x1 > 0;
+ bool b01 = C2 + DX23 * y1 - DY23 * x0 > 0;
+ bool b11 = C2 + DX23 * y1 - DY23 * x1 > 0;
+ int b = (b00 << 0) | (b10 << 1) | (b01 << 2) | (b11 << 3);
+ bool c00 = C3 + DX31 * y0 - DY31 * x0 > 0;
+ bool c10 = C3 + DX31 * y0 - DY31 * x1 > 0;
+ bool c01 = C3 + DX31 * y1 - DY31 * x0 > 0;
+ bool c11 = C3 + DX31 * y1 - DY31 * x1 > 0;
+ int c = (c00 << 0) | (c10 << 1) | (c01 << 2) | (c11 << 3);
+ // Skip block when outside an edge
+ if (a == 0x0 || b == 0x0 || c == 0x0) continue;
+ // Accept whole block when totally covered
+ if (a == 0xF && b == 0xF && c == 0xF) {
+ Vector3 texRow = t1 + dy * (y0 - v1.y) + dx * (x0 - v1.x);
+ for (int iy = y; iy < y + q; iy++) {
+ Vector3 tex = texRow;
+ for (int ix = x; ix < x + q; ix++) {
+ //Vector3 tex = t1 + dx * (ix - v1.x) + dy * (iy - v1.y);
+ if (!cb(param, ix, iy, tex, dx, dy, 1.0)) {
+ // early out.
+ return false;
+ }
+ tex += dx;
+ }
+ texRow += dy;
+ }
+ } else { // Partially covered block
+ int CY1 = C1 + DX12 * y0 - DY12 * x0;
+ int CY2 = C2 + DX23 * y0 - DY23 * x0;
+ int CY3 = C3 + DX31 * y0 - DY31 * x0;
+ Vector3 texRow = t1 + dy * (y0 - v1.y) + dx * (x0 - v1.x);
+ for (int iy = y; iy < y + q; iy++) {
+ int CX1 = CY1;
+ int CX2 = CY2;
+ int CX3 = CY3;
+ Vector3 tex = texRow;
+ for (int ix = x; ix < x + q; ix++) {
+ if (CX1 > 0 && CX2 > 0 && CX3 > 0) {
+ if (!cb(param, ix, iy, tex, dx, dy, 1.0)) {
+ // early out.
+ return false;
+ }
+ }
+ CX1 -= FDY12;
+ CX2 -= FDY23;
+ CX3 -= FDY31;
+ tex += dx;
+ }
+ CY1 += FDX12;
+ CY2 += FDX23;
+ CY3 += FDX31;
+ texRow += dy;
+ }
+ }
+ }
+ }
+ return true;
+ }
+
+ // extents has to be multiple of BK_SIZE!!
+ bool drawAA(const Vector2 &extents, bool enableScissors, SamplingCallback cb, void *param) {
+ const float PX_INSIDE = 1.0f / sqrt(2.0f);
+ const float PX_OUTSIDE = -1.0f / sqrt(2.0f);
+ const float BK_SIZE = 8;
+ const float BK_INSIDE = sqrt(BK_SIZE * BK_SIZE / 2.0f);
+ const float BK_OUTSIDE = -sqrt(BK_SIZE * BK_SIZE / 2.0f);
+
+ float minx, miny, maxx, maxy;
+ if (enableScissors) {
+ // Bounding rectangle
+ minx = floorf(std::max(min3(v1.x, v2.x, v3.x), 0.0f));
+ miny = floorf(std::max(min3(v1.y, v2.y, v3.y), 0.0f));
+ maxx = ceilf(std::min(max3(v1.x, v2.x, v3.x), extents.x - 1.0f));
+ maxy = ceilf(std::min(max3(v1.y, v2.y, v3.y), extents.y - 1.0f));
+ } else {
+ // Bounding rectangle
+ minx = floorf(min3(v1.x, v2.x, v3.x));
+ miny = floorf(min3(v1.y, v2.y, v3.y));
+ maxx = ceilf(max3(v1.x, v2.x, v3.x));
+ maxy = ceilf(max3(v1.y, v2.y, v3.y));
+ }
+ // There's no reason to align the blocks to the viewport, instead we align them to the origin of the triangle bounds.
+ minx = floorf(minx);
+ miny = floorf(miny);
+ //minx = (float)(((int)minx) & (~((int)BK_SIZE - 1))); // align to blocksize (we don't need to worry about blocks partially out of viewport)
+ //miny = (float)(((int)miny) & (~((int)BK_SIZE - 1)));
+ minx += 0.5;
+ miny += 0.5; // sampling at texel centers!
+ maxx += 0.5;
+ maxy += 0.5;
+ // Half-edge constants
+ float C1 = n1.x * (-v1.x) + n1.y * (-v1.y);
+ float C2 = n2.x * (-v2.x) + n2.y * (-v2.y);
+ float C3 = n3.x * (-v3.x) + n3.y * (-v3.y);
+ // Loop through blocks
+ for (float y0 = miny; y0 <= maxy; y0 += BK_SIZE) {
+ for (float x0 = minx; x0 <= maxx; x0 += BK_SIZE) {
+ // Corners of block
+ float xc = (x0 + (BK_SIZE - 1) / 2.0f);
+ float yc = (y0 + (BK_SIZE - 1) / 2.0f);
+ // Evaluate half-space functions
+ float aC = C1 + n1.x * xc + n1.y * yc;
+ float bC = C2 + n2.x * xc + n2.y * yc;
+ float cC = C3 + n3.x * xc + n3.y * yc;
+ // Skip block when outside an edge
+ if ((aC <= BK_OUTSIDE) || (bC <= BK_OUTSIDE) || (cC <= BK_OUTSIDE)) continue;
+ // Accept whole block when totally covered
+ if ((aC >= BK_INSIDE) && (bC >= BK_INSIDE) && (cC >= BK_INSIDE)) {
+ Vector3 texRow = t1 + dy * (y0 - v1.y) + dx * (x0 - v1.x);
+ for (float y = y0; y < y0 + BK_SIZE; y++) {
+ Vector3 tex = texRow;
+ for (float x = x0; x < x0 + BK_SIZE; x++) {
+ if (!cb(param, (int)x, (int)y, tex, dx, dy, 1.0f)) {
+ return false;
+ }
+ tex += dx;
+ }
+ texRow += dy;
+ }
+ } else { // Partially covered block
+ float CY1 = C1 + n1.x * x0 + n1.y * y0;
+ float CY2 = C2 + n2.x * x0 + n2.y * y0;
+ float CY3 = C3 + n3.x * x0 + n3.y * y0;
+ Vector3 texRow = t1 + dy * (y0 - v1.y) + dx * (x0 - v1.x);
+ for (float y = y0; y < y0 + BK_SIZE; y++) { // @@ This is not clipping to scissor rectangle correctly.
+ float CX1 = CY1;
+ float CX2 = CY2;
+ float CX3 = CY3;
+ Vector3 tex = texRow;
+ for (float x = x0; x < x0 + BK_SIZE; x++) { // @@ This is not clipping to scissor rectangle correctly.
+ if (CX1 >= PX_INSIDE && CX2 >= PX_INSIDE && CX3 >= PX_INSIDE) {
+ // pixel completely covered
+ Vector3 tex2 = t1 + dx * (x - v1.x) + dy * (y - v1.y);
+ if (!cb(param, (int)x, (int)y, tex2, dx, dy, 1.0f)) {
+ return false;
+ }
+ } else if ((CX1 >= PX_OUTSIDE) && (CX2 >= PX_OUTSIDE) && (CX3 >= PX_OUTSIDE)) {
+ // triangle partially covers pixel. do clipping.
+ ClippedTriangle ct(v1 - Vector2(x, y), v2 - Vector2(x, y), v3 - Vector2(x, y));
+ ct.clipAABox(-0.5, -0.5, 0.5, 0.5);
+ Vector2 centroid = ct.centroid();
+ float area = ct.area();
+ if (area > 0.0f) {
+ Vector3 texCent = tex - dx * centroid.x - dy * centroid.y;
+ //xaAssert(texCent.x >= -0.1f && texCent.x <= 1.1f); // @@ Centroid is not very exact...
+ //xaAssert(texCent.y >= -0.1f && texCent.y <= 1.1f);
+ //xaAssert(texCent.z >= -0.1f && texCent.z <= 1.1f);
+ //Vector3 texCent2 = t1 + dx * (x - v1.x) + dy * (y - v1.y);
+ if (!cb(param, (int)x, (int)y, texCent, dx, dy, area)) {
+ return false;
+ }
+ }
+ }
+ CX1 += n1.x;
+ CX2 += n2.x;
+ CX3 += n3.x;
+ tex += dx;
+ }
+ CY1 += n1.y;
+ CY2 += n2.y;
+ CY3 += n3.y;
+ texRow += dy;
+ }
+ }
+ }
+ }
+ return true;
+ }
+
+ void flipBackface() {
+ // check if triangle is backfacing, if so, swap two vertices
+ if (((v3.x - v1.x) * (v2.y - v1.y) - (v3.y - v1.y) * (v2.x - v1.x)) < 0) {
+ Vector2 hv = v1;
+ v1 = v2;
+ v2 = hv; // swap pos
+ Vector3 ht = t1;
+ t1 = t2;
+ t2 = ht; // swap tex
+ }
+ }
+
+ // compute unit inward normals for each edge.
+ void computeUnitInwardNormals() {
+ n1 = v1 - v2;
+ n1 = Vector2(-n1.y, n1.x);
+ n1 = n1 * (1.0f / sqrtf(n1.x * n1.x + n1.y * n1.y));
+ n2 = v2 - v3;
+ n2 = Vector2(-n2.y, n2.x);
+ n2 = n2 * (1.0f / sqrtf(n2.x * n2.x + n2.y * n2.y));
+ n3 = v3 - v1;
+ n3 = Vector2(-n3.y, n3.x);
+ n3 = n3 * (1.0f / sqrtf(n3.x * n3.x + n3.y * n3.y));
+ }
+
+ // Vertices.
+ Vector2 v1, v2, v3;
+ Vector2 n1, n2, n3; // unit inward normals
+ Vector3 t1, t2, t3;
+
+ // Deltas.
+ Vector3 dx, dy;
+
+ float sign;
+ bool valid;
+};
+
+enum Mode {
+ Mode_Nearest,
+ Mode_Antialiased
+};
+
+// Process the given triangle. Returns false if rasterization was interrupted by the callback.
+static bool drawTriangle(Mode mode, Vector2::Arg extents, bool enableScissors, const Vector2 v[3], SamplingCallback cb, void *param) {
+ Triangle tri(v[0], v[1], v[2], Vector3(1, 0, 0), Vector3(0, 1, 0), Vector3(0, 0, 1));
+ // @@ It would be nice to have a conservative drawing mode that enlarges the triangle extents by one texel and is able to handle degenerate triangles.
+ // @@ Maybe the simplest thing to do would be raster triangle edges.
+ if (tri.valid) {
+ if (mode == Mode_Antialiased) {
+ return tri.drawAA(extents, enableScissors, cb, param);
+ }
+ if (mode == Mode_Nearest) {
+ return tri.draw(extents, enableScissors, cb, param);
+ }
+ }
+ return true;
+}
+
+// Process the given quad. Returns false if rasterization was interrupted by the callback.
+static bool drawQuad(Mode mode, Vector2::Arg extents, bool enableScissors, const Vector2 v[4], SamplingCallback cb, void *param) {
+ bool sign0 = triangleArea2(v[0], v[1], v[2]) > 0.0f;
+ bool sign1 = triangleArea2(v[0], v[2], v[3]) > 0.0f;
+ // Divide the quad into two non overlapping triangles.
+ if (sign0 == sign1) {
+ Triangle tri0(v[0], v[1], v[2], Vector3(0, 0, 0), Vector3(1, 0, 0), Vector3(1, 1, 0));
+ Triangle tri1(v[0], v[2], v[3], Vector3(0, 0, 0), Vector3(1, 1, 0), Vector3(0, 1, 0));
+ if (tri0.valid && tri1.valid) {
+ if (mode == Mode_Antialiased) {
+ return tri0.drawAA(extents, enableScissors, cb, param) && tri1.drawAA(extents, enableScissors, cb, param);
+ } else {
+ return tri0.draw(extents, enableScissors, cb, param) && tri1.draw(extents, enableScissors, cb, param);
+ }
+ }
+ } else {
+ Triangle tri0(v[0], v[1], v[3], Vector3(0, 0, 0), Vector3(1, 0, 0), Vector3(0, 1, 0));
+ Triangle tri1(v[1], v[2], v[3], Vector3(1, 0, 0), Vector3(1, 1, 0), Vector3(0, 1, 0));
+ if (tri0.valid && tri1.valid) {
+ if (mode == Mode_Antialiased) {
+ return tri0.drawAA(extents, enableScissors, cb, param) && tri1.drawAA(extents, enableScissors, cb, param);
+ } else {
+ return tri0.draw(extents, enableScissors, cb, param) && tri1.draw(extents, enableScissors, cb, param);
+ }
+ }
+ }
+ return true;
+}
+} // namespace raster
+
+// Full and sparse vector and matrix classes. BLAS subset.
+// Pseudo-BLAS interface.
+namespace sparse {
+enum Transpose {
+ NoTransposed = 0,
+ Transposed = 1
+};
+
+/**
+* Sparse matrix class. The matrix is assumed to be sparse and to have
+* very few non-zero elements, for this reason it's stored in indexed
+* format. To multiply column vectors efficiently, the matrix stores
+* the elements in indexed-column order, there is a list of indexed
+* elements for each row of the matrix. As with the FullVector the
+* dimension of the matrix is constant.
+**/
+class Matrix {
+public:
+ // An element of the sparse array.
+ struct Coefficient {
+ uint32_t x; // column
+ float v; // value
+ };
+
+ Matrix(uint32_t d) :
+ m_width(d) { m_array.resize(d); }
+ Matrix(uint32_t w, uint32_t h) :
+ m_width(w) { m_array.resize(h); }
+ Matrix(const Matrix &m) :
+ m_width(m.m_width) { m_array = m.m_array; }
+
+ const Matrix &operator=(const Matrix &m) {
+ xaAssert(width() == m.width());
+ xaAssert(height() == m.height());
+ m_array = m.m_array;
+ return *this;
+ }
+
+ uint32_t width() const { return m_width; }
+ uint32_t height() const { return m_array.size(); }
+ bool isSquare() const { return width() == height(); }
+
+ // x is column, y is row
+ float getCoefficient(uint32_t x, uint32_t y) const {
+ xaDebugAssert(x < width());
+ xaDebugAssert(y < height());
+ const uint32_t count = m_array[y].size();
+ for (uint32_t i = 0; i < count; i++) {
+ if (m_array[y][i].x == x) return m_array[y][i].v;
+ }
+ return 0.0f;
+ }
+
+ void setCoefficient(uint32_t x, uint32_t y, float f) {
+ xaDebugAssert(x < width());
+ xaDebugAssert(y < height());
+ const uint32_t count = m_array[y].size();
+ for (uint32_t i = 0; i < count; i++) {
+ if (m_array[y][i].x == x) {
+ m_array[y][i].v = f;
+ return;
+ }
+ }
+ if (f != 0.0f) {
+ Coefficient c = { x, f };
+ m_array[y].push_back(c);
+ }
+ }
+
+ float dotRow(uint32_t y, const FullVector &v) const {
+ xaDebugAssert(y < height());
+ const uint32_t count = m_array[y].size();
+ float sum = 0;
+ for (uint32_t i = 0; i < count; i++) {
+ sum += m_array[y][i].v * v[m_array[y][i].x];
+ }
+ return sum;
+ }
+
+ void madRow(uint32_t y, float alpha, FullVector &v) const {
+ xaDebugAssert(y < height());
+ const uint32_t count = m_array[y].size();
+ for (uint32_t i = 0; i < count; i++) {
+ v[m_array[y][i].x] += alpha * m_array[y][i].v;
+ }
+ }
+
+ void clearRow(uint32_t y) {
+ xaDebugAssert(y < height());
+ m_array[y].clear();
+ }
+
+ void scaleRow(uint32_t y, float f) {
+ xaDebugAssert(y < height());
+ const uint32_t count = m_array[y].size();
+ for (uint32_t i = 0; i < count; i++) {
+ m_array[y][i].v *= f;
+ }
+ }
+
+ const std::vector<Coefficient> &getRow(uint32_t y) const { return m_array[y]; }
+
+private:
+ /// Number of columns.
+ const uint32_t m_width;
+
+ /// Array of matrix elements.
+ std::vector<std::vector<Coefficient> > m_array;
+};
+
+// y = a * x + y
+static void saxpy(float a, const FullVector &x, FullVector &y) {
+ xaDebugAssert(x.dimension() == y.dimension());
+ const uint32_t dim = x.dimension();
+ for (uint32_t i = 0; i < dim; i++) {
+ y[i] += a * x[i];
+ }
+}
+
+static void copy(const FullVector &x, FullVector &y) {
+ xaDebugAssert(x.dimension() == y.dimension());
+ const uint32_t dim = x.dimension();
+ for (uint32_t i = 0; i < dim; i++) {
+ y[i] = x[i];
+ }
+}
+
+static void scal(float a, FullVector &x) {
+ const uint32_t dim = x.dimension();
+ for (uint32_t i = 0; i < dim; i++) {
+ x[i] *= a;
+ }
+}
+
+static float dot(const FullVector &x, const FullVector &y) {
+ xaDebugAssert(x.dimension() == y.dimension());
+ const uint32_t dim = x.dimension();
+ float sum = 0;
+ for (uint32_t i = 0; i < dim; i++) {
+ sum += x[i] * y[i];
+ }
+ return sum;
+}
+
+static void mult(Transpose TM, const Matrix &M, const FullVector &x, FullVector &y) {
+ const uint32_t w = M.width();
+ const uint32_t h = M.height();
+ if (TM == Transposed) {
+ xaDebugAssert(h == x.dimension());
+ xaDebugAssert(w == y.dimension());
+ y.fill(0.0f);
+ for (uint32_t i = 0; i < h; i++) {
+ M.madRow(i, x[i], y);
+ }
+ } else {
+ xaDebugAssert(w == x.dimension());
+ xaDebugAssert(h == y.dimension());
+ for (uint32_t i = 0; i < h; i++) {
+ y[i] = M.dotRow(i, x);
+ }
+ }
+}
+
+// y = M * x
+static void mult(const Matrix &M, const FullVector &x, FullVector &y) {
+ mult(NoTransposed, M, x, y);
+}
+
+static void sgemv(float alpha, Transpose TA, const Matrix &A, const FullVector &x, float beta, FullVector &y) {
+ const uint32_t w = A.width();
+ const uint32_t h = A.height();
+ if (TA == Transposed) {
+ xaDebugAssert(h == x.dimension());
+ xaDebugAssert(w == y.dimension());
+ for (uint32_t i = 0; i < h; i++) {
+ A.madRow(i, alpha * x[i], y);
+ }
+ } else {
+ xaDebugAssert(w == x.dimension());
+ xaDebugAssert(h == y.dimension());
+ for (uint32_t i = 0; i < h; i++) {
+ y[i] = alpha * A.dotRow(i, x) + beta * y[i];
+ }
+ }
+}
+
+// y = alpha*A*x + beta*y
+static void sgemv(float alpha, const Matrix &A, const FullVector &x, float beta, FullVector &y) {
+ sgemv(alpha, NoTransposed, A, x, beta, y);
+}
+
+// dot y-row of A by x-column of B
+static float dotRowColumn(int y, const Matrix &A, int x, const Matrix &B) {
+ const std::vector<Matrix::Coefficient> &row = A.getRow(y);
+ const uint32_t count = row.size();
+ float sum = 0.0f;
+ for (uint32_t i = 0; i < count; i++) {
+ const Matrix::Coefficient &c = row[i];
+ sum += c.v * B.getCoefficient(x, c.x);
+ }
+ return sum;
+}
+
+// dot y-row of A by x-row of B
+static float dotRowRow(int y, const Matrix &A, int x, const Matrix &B) {
+ const std::vector<Matrix::Coefficient> &row = A.getRow(y);
+ const uint32_t count = row.size();
+ float sum = 0.0f;
+ for (uint32_t i = 0; i < count; i++) {
+ const Matrix::Coefficient &c = row[i];
+ sum += c.v * B.getCoefficient(c.x, x);
+ }
+ return sum;
+}
+
+// dot y-column of A by x-column of B
+static float dotColumnColumn(int y, const Matrix &A, int x, const Matrix &B) {
+ xaDebugAssert(A.height() == B.height());
+ const uint32_t h = A.height();
+ float sum = 0.0f;
+ for (uint32_t i = 0; i < h; i++) {
+ sum += A.getCoefficient(y, i) * B.getCoefficient(x, i);
+ }
+ return sum;
+}
+
+static void transpose(const Matrix &A, Matrix &B) {
+ xaDebugAssert(A.width() == B.height());
+ xaDebugAssert(B.width() == A.height());
+ const uint32_t w = A.width();
+ for (uint32_t x = 0; x < w; x++) {
+ B.clearRow(x);
+ }
+ const uint32_t h = A.height();
+ for (uint32_t y = 0; y < h; y++) {
+ const std::vector<Matrix::Coefficient> &row = A.getRow(y);
+ const uint32_t count = row.size();
+ for (uint32_t i = 0; i < count; i++) {
+ const Matrix::Coefficient &c = row[i];
+ xaDebugAssert(c.x < w);
+ B.setCoefficient(y, c.x, c.v);
+ }
+ }
+}
+
+static void sgemm(float alpha, Transpose TA, const Matrix &A, Transpose TB, const Matrix &B, float beta, Matrix &C) {
+ const uint32_t w = C.width();
+ const uint32_t h = C.height();
+ uint32_t aw = (TA == NoTransposed) ? A.width() : A.height();
+ uint32_t ah = (TA == NoTransposed) ? A.height() : A.width();
+ uint32_t bw = (TB == NoTransposed) ? B.width() : B.height();
+ uint32_t bh = (TB == NoTransposed) ? B.height() : B.width();
+ xaDebugAssert(aw == bh);
+ xaDebugAssert(bw == ah);
+ xaDebugAssert(w == bw);
+ xaDebugAssert(h == ah);
+#ifdef NDEBUG
+ aw = ah = bw = bh = 0; // silence unused parameter warning
+#endif
+ for (uint32_t y = 0; y < h; y++) {
+ for (uint32_t x = 0; x < w; x++) {
+ float c = beta * C.getCoefficient(x, y);
+ if (TA == NoTransposed && TB == NoTransposed) {
+ // dot y-row of A by x-column of B.
+ c += alpha * dotRowColumn(y, A, x, B);
+ } else if (TA == Transposed && TB == Transposed) {
+ // dot y-column of A by x-row of B.
+ c += alpha * dotRowColumn(x, B, y, A);
+ } else if (TA == Transposed && TB == NoTransposed) {
+ // dot y-column of A by x-column of B.
+ c += alpha * dotColumnColumn(y, A, x, B);
+ } else if (TA == NoTransposed && TB == Transposed) {
+ // dot y-row of A by x-row of B.
+ c += alpha * dotRowRow(y, A, x, B);
+ }
+ C.setCoefficient(x, y, c);
+ }
+ }
+}
+
+static void mult(Transpose TA, const Matrix &A, Transpose TB, const Matrix &B, Matrix &C) {
+ sgemm(1.0f, TA, A, TB, B, 0.0f, C);
+}
+
+// C = A * B
+static void mult(const Matrix &A, const Matrix &B, Matrix &C) {
+ mult(NoTransposed, A, NoTransposed, B, C);
+}
+
+} // namespace sparse
+
+class JacobiPreconditioner {
+public:
+ JacobiPreconditioner(const sparse::Matrix &M, bool symmetric) :
+ m_inverseDiagonal(M.width()) {
+ xaAssert(M.isSquare());
+ for (uint32_t x = 0; x < M.width(); x++) {
+ float elem = M.getCoefficient(x, x);
+ //xaDebugAssert( elem != 0.0f ); // This can be zero in the presence of zero area triangles.
+ if (symmetric) {
+ m_inverseDiagonal[x] = (elem != 0) ? 1.0f / sqrtf(fabsf(elem)) : 1.0f;
+ } else {
+ m_inverseDiagonal[x] = (elem != 0) ? 1.0f / elem : 1.0f;
+ }
+ }
+ }
+
+ void apply(const FullVector &x, FullVector &y) const {
+ xaDebugAssert(x.dimension() == m_inverseDiagonal.dimension());
+ xaDebugAssert(y.dimension() == m_inverseDiagonal.dimension());
+ // @@ Wrap vector component-wise product into a separate function.
+ const uint32_t D = x.dimension();
+ for (uint32_t i = 0; i < D; i++) {
+ y[i] = m_inverseDiagonal[i] * x[i];
+ }
+ }
+
+private:
+ FullVector m_inverseDiagonal;
+};
+
+// Linear solvers.
+class Solver {
+public:
+ // Solve the symmetric system: At·A·x = At·b
+ static bool LeastSquaresSolver(const sparse::Matrix &A, const FullVector &b, FullVector &x, float epsilon = 1e-5f) {
+ xaDebugAssert(A.width() == x.dimension());
+ xaDebugAssert(A.height() == b.dimension());
+ xaDebugAssert(A.height() >= A.width()); // @@ If height == width we could solve it directly...
+ const uint32_t D = A.width();
+ sparse::Matrix At(A.height(), A.width());
+ sparse::transpose(A, At);
+ FullVector Atb(D);
+ sparse::mult(At, b, Atb);
+ sparse::Matrix AtA(D);
+ sparse::mult(At, A, AtA);
+ return SymmetricSolver(AtA, Atb, x, epsilon);
+ }
+
+ // See section 10.4.3 in: Mesh Parameterization: Theory and Practice, Siggraph Course Notes, August 2007
+ static bool LeastSquaresSolver(const sparse::Matrix &A, const FullVector &b, FullVector &x, const uint32_t *lockedParameters, uint32_t lockedCount, float epsilon = 1e-5f) {
+ xaDebugAssert(A.width() == x.dimension());
+ xaDebugAssert(A.height() == b.dimension());
+ xaDebugAssert(A.height() >= A.width() - lockedCount);
+ // @@ This is not the most efficient way of building a system with reduced degrees of freedom. It would be faster to do it on the fly.
+ const uint32_t D = A.width() - lockedCount;
+ xaDebugAssert(D > 0);
+ // Compute: b - Al * xl
+ FullVector b_Alxl(b);
+ for (uint32_t y = 0; y < A.height(); y++) {
+ const uint32_t count = A.getRow(y).size();
+ for (uint32_t e = 0; e < count; e++) {
+ uint32_t column = A.getRow(y)[e].x;
+ bool isFree = true;
+ for (uint32_t i = 0; i < lockedCount; i++) {
+ isFree &= (lockedParameters[i] != column);
+ }
+ if (!isFree) {
+ b_Alxl[y] -= x[column] * A.getRow(y)[e].v;
+ }
+ }
+ }
+ // Remove locked columns from A.
+ sparse::Matrix Af(D, A.height());
+ for (uint32_t y = 0; y < A.height(); y++) {
+ const uint32_t count = A.getRow(y).size();
+ for (uint32_t e = 0; e < count; e++) {
+ uint32_t column = A.getRow(y)[e].x;
+ uint32_t ix = column;
+ bool isFree = true;
+ for (uint32_t i = 0; i < lockedCount; i++) {
+ isFree &= (lockedParameters[i] != column);
+ if (column > lockedParameters[i]) ix--; // shift columns
+ }
+ if (isFree) {
+ Af.setCoefficient(ix, y, A.getRow(y)[e].v);
+ }
+ }
+ }
+ // Remove elements from x
+ FullVector xf(D);
+ for (uint32_t i = 0, j = 0; i < A.width(); i++) {
+ bool isFree = true;
+ for (uint32_t l = 0; l < lockedCount; l++) {
+ isFree &= (lockedParameters[l] != i);
+ }
+ if (isFree) {
+ xf[j++] = x[i];
+ }
+ }
+ // Solve reduced system.
+ bool result = LeastSquaresSolver(Af, b_Alxl, xf, epsilon);
+ // Copy results back to x.
+ for (uint32_t i = 0, j = 0; i < A.width(); i++) {
+ bool isFree = true;
+ for (uint32_t l = 0; l < lockedCount; l++) {
+ isFree &= (lockedParameters[l] != i);
+ }
+ if (isFree) {
+ x[i] = xf[j++];
+ }
+ }
+ return result;
+ }
+
+private:
+ /**
+ * Compute the solution of the sparse linear system Ab=x using the Conjugate
+ * Gradient method.
+ *
+ * Solving sparse linear systems:
+ * (1) A·x = b
+ *
+ * The conjugate gradient algorithm solves (1) only in the case that A is
+ * symmetric and positive definite. It is based on the idea of minimizing the
+ * function
+ *
+ * (2) f(x) = 1/2·x·A·x - b·x
+ *
+ * This function is minimized when its gradient
+ *
+ * (3) df = A·x - b
+ *
+ * is zero, which is equivalent to (1). The minimization is carried out by
+ * generating a succession of search directions p.k and improved minimizers x.k.
+ * At each stage a quantity alfa.k is found that minimizes f(x.k + alfa.k·p.k),
+ * and x.k+1 is set equal to the new point x.k + alfa.k·p.k. The p.k and x.k are
+ * built up in such a way that x.k+1 is also the minimizer of f over the whole
+ * vector space of directions already taken, {p.1, p.2, . . . , p.k}. After N
+ * iterations you arrive at the minimizer over the entire vector space, i.e., the
+ * solution to (1).
+ *
+ * For a really good explanation of the method see:
+ *
+ * "An Introduction to the Conjugate Gradient Method Without the Agonizing Pain",
+ * Jonhathan Richard Shewchuk.
+ *
+ **/
+ static bool ConjugateGradientSolver(const sparse::Matrix &A, const FullVector &b, FullVector &x, float epsilon) {
+ xaDebugAssert(A.isSquare());
+ xaDebugAssert(A.width() == b.dimension());
+ xaDebugAssert(A.width() == x.dimension());
+ int i = 0;
+ const int D = A.width();
+ const int i_max = 4 * D; // Convergence should be linear, but in some cases, it's not.
+ FullVector r(D); // residual
+ FullVector p(D); // search direction
+ FullVector q(D); //
+ float delta_0;
+ float delta_old;
+ float delta_new;
+ float alpha;
+ float beta;
+ // r = b - A·x;
+ sparse::copy(b, r);
+ sparse::sgemv(-1, A, x, 1, r);
+ // p = r;
+ sparse::copy(r, p);
+ delta_new = sparse::dot(r, r);
+ delta_0 = delta_new;
+ while (i < i_max && delta_new > epsilon * epsilon * delta_0) {
+ i++;
+ // q = A·p
+ mult(A, p, q);
+ // alpha = delta_new / p·q
+ alpha = delta_new / sparse::dot(p, q);
+ // x = alfa·p + x
+ sparse::saxpy(alpha, p, x);
+ if ((i & 31) == 0) { // recompute r after 32 steps
+ // r = b - A·x
+ sparse::copy(b, r);
+ sparse::sgemv(-1, A, x, 1, r);
+ } else {
+ // r = r - alpha·q
+ sparse::saxpy(-alpha, q, r);
+ }
+ delta_old = delta_new;
+ delta_new = sparse::dot(r, r);
+ beta = delta_new / delta_old;
+ // p = beta·p + r
+ sparse::scal(beta, p);
+ sparse::saxpy(1, r, p);
+ }
+ return delta_new <= epsilon * epsilon * delta_0;
+ }
+
+ // Conjugate gradient with preconditioner.
+ static bool ConjugateGradientSolver(const JacobiPreconditioner &preconditioner, const sparse::Matrix &A, const FullVector &b, FullVector &x, float epsilon) {
+ xaDebugAssert(A.isSquare());
+ xaDebugAssert(A.width() == b.dimension());
+ xaDebugAssert(A.width() == x.dimension());
+ int i = 0;
+ const int D = A.width();
+ const int i_max = 4 * D; // Convergence should be linear, but in some cases, it's not.
+ FullVector r(D); // residual
+ FullVector p(D); // search direction
+ FullVector q(D); //
+ FullVector s(D); // preconditioned
+ float delta_0;
+ float delta_old;
+ float delta_new;
+ float alpha;
+ float beta;
+ // r = b - A·x
+ sparse::copy(b, r);
+ sparse::sgemv(-1, A, x, 1, r);
+ // p = M^-1 · r
+ preconditioner.apply(r, p);
+ delta_new = sparse::dot(r, p);
+ delta_0 = delta_new;
+ while (i < i_max && delta_new > epsilon * epsilon * delta_0) {
+ i++;
+ // q = A·p
+ mult(A, p, q);
+ // alpha = delta_new / p·q
+ alpha = delta_new / sparse::dot(p, q);
+ // x = alfa·p + x
+ sparse::saxpy(alpha, p, x);
+ if ((i & 31) == 0) { // recompute r after 32 steps
+ // r = b - A·x
+ sparse::copy(b, r);
+ sparse::sgemv(-1, A, x, 1, r);
+ } else {
+ // r = r - alfa·q
+ sparse::saxpy(-alpha, q, r);
+ }
+ // s = M^-1 · r
+ preconditioner.apply(r, s);
+ delta_old = delta_new;
+ delta_new = sparse::dot(r, s);
+ beta = delta_new / delta_old;
+ // p = s + beta·p
+ sparse::scal(beta, p);
+ sparse::saxpy(1, s, p);
+ }
+ return delta_new <= epsilon * epsilon * delta_0;
+ }
+
+ static bool SymmetricSolver(const sparse::Matrix &A, const FullVector &b, FullVector &x, float epsilon = 1e-5f) {
+ xaDebugAssert(A.height() == A.width());
+ xaDebugAssert(A.height() == b.dimension());
+ xaDebugAssert(b.dimension() == x.dimension());
+ JacobiPreconditioner jacobi(A, true);
+ return ConjugateGradientSolver(jacobi, A, b, x, epsilon);
+ }
+};
+
+namespace param {
+class Atlas;
+class Chart;
+
+// Fast sweep in 3 directions
+static bool findApproximateDiameterVertices(halfedge::Mesh *mesh, halfedge::Vertex **a, halfedge::Vertex **b) {
+ xaDebugAssert(mesh != NULL);
+ xaDebugAssert(a != NULL);
+ xaDebugAssert(b != NULL);
+ const uint32_t vertexCount = mesh->vertexCount();
+ halfedge::Vertex *minVertex[3];
+ halfedge::Vertex *maxVertex[3];
+ minVertex[0] = minVertex[1] = minVertex[2] = NULL;
+ maxVertex[0] = maxVertex[1] = maxVertex[2] = NULL;
+ for (uint32_t v = 1; v < vertexCount; v++) {
+ halfedge::Vertex *vertex = mesh->vertexAt(v);
+ xaDebugAssert(vertex != NULL);
+ if (vertex->isBoundary()) {
+ minVertex[0] = minVertex[1] = minVertex[2] = vertex;
+ maxVertex[0] = maxVertex[1] = maxVertex[2] = vertex;
+ break;
+ }
+ }
+ if (minVertex[0] == NULL) {
+ // Input mesh has not boundaries.
+ return false;
+ }
+ for (uint32_t v = 1; v < vertexCount; v++) {
+ halfedge::Vertex *vertex = mesh->vertexAt(v);
+ xaDebugAssert(vertex != NULL);
+ if (!vertex->isBoundary()) {
+ // Skip interior vertices.
+ continue;
+ }
+ if (vertex->pos.x < minVertex[0]->pos.x)
+ minVertex[0] = vertex;
+ else if (vertex->pos.x > maxVertex[0]->pos.x)
+ maxVertex[0] = vertex;
+ if (vertex->pos.y < minVertex[1]->pos.y)
+ minVertex[1] = vertex;
+ else if (vertex->pos.y > maxVertex[1]->pos.y)
+ maxVertex[1] = vertex;
+ if (vertex->pos.z < minVertex[2]->pos.z)
+ minVertex[2] = vertex;
+ else if (vertex->pos.z > maxVertex[2]->pos.z)
+ maxVertex[2] = vertex;
+ }
+ float lengths[3];
+ for (int i = 0; i < 3; i++) {
+ lengths[i] = length(minVertex[i]->pos - maxVertex[i]->pos);
+ }
+ if (lengths[0] > lengths[1] && lengths[0] > lengths[2]) {
+ *a = minVertex[0];
+ *b = maxVertex[0];
+ } else if (lengths[1] > lengths[2]) {
+ *a = minVertex[1];
+ *b = maxVertex[1];
+ } else {
+ *a = minVertex[2];
+ *b = maxVertex[2];
+ }
+ return true;
+}
+
+// Conformal relations from Brecht Van Lommel (based on ABF):
+
+static float vec_angle_cos(Vector3::Arg v1, Vector3::Arg v2, Vector3::Arg v3) {
+ Vector3 d1 = v1 - v2;
+ Vector3 d2 = v3 - v2;
+ return clamp(dot(d1, d2) / (length(d1) * length(d2)), -1.0f, 1.0f);
+}
+
+static float vec_angle(Vector3::Arg v1, Vector3::Arg v2, Vector3::Arg v3) {
+ float dot = vec_angle_cos(v1, v2, v3);
+ return acosf(dot);
+}
+
+static void triangle_angles(Vector3::Arg v1, Vector3::Arg v2, Vector3::Arg v3, float *a1, float *a2, float *a3) {
+ *a1 = vec_angle(v3, v1, v2);
+ *a2 = vec_angle(v1, v2, v3);
+ *a3 = PI - *a2 - *a1;
+}
+
+static void setup_abf_relations(sparse::Matrix &A, int row, const halfedge::Vertex *v0, const halfedge::Vertex *v1, const halfedge::Vertex *v2) {
+ int id0 = v0->id;
+ int id1 = v1->id;
+ int id2 = v2->id;
+ Vector3 p0 = v0->pos;
+ Vector3 p1 = v1->pos;
+ Vector3 p2 = v2->pos;
+ // @@ IC: Wouldn't it be more accurate to return cos and compute 1-cos^2?
+ // It does indeed seem to be a little bit more robust.
+ // @@ Need to revisit this more carefully!
+ float a0, a1, a2;
+ triangle_angles(p0, p1, p2, &a0, &a1, &a2);
+ float s0 = sinf(a0);
+ float s1 = sinf(a1);
+ float s2 = sinf(a2);
+ if (s1 > s0 && s1 > s2) {
+ std::swap(s1, s2);
+ std::swap(s0, s1);
+ std::swap(a1, a2);
+ std::swap(a0, a1);
+ std::swap(id1, id2);
+ std::swap(id0, id1);
+ } else if (s0 > s1 && s0 > s2) {
+ std::swap(s0, s2);
+ std::swap(s0, s1);
+ std::swap(a0, a2);
+ std::swap(a0, a1);
+ std::swap(id0, id2);
+ std::swap(id0, id1);
+ }
+ float c0 = cosf(a0);
+ float ratio = (s2 == 0.0f) ? 1.0f : s1 / s2;
+ float cosine = c0 * ratio;
+ float sine = s0 * ratio;
+ // Note : 2*id + 0 --> u
+ // 2*id + 1 --> v
+ int u0_id = 2 * id0 + 0;
+ int v0_id = 2 * id0 + 1;
+ int u1_id = 2 * id1 + 0;
+ int v1_id = 2 * id1 + 1;
+ int u2_id = 2 * id2 + 0;
+ int v2_id = 2 * id2 + 1;
+ // Real part
+ A.setCoefficient(u0_id, 2 * row + 0, cosine - 1.0f);
+ A.setCoefficient(v0_id, 2 * row + 0, -sine);
+ A.setCoefficient(u1_id, 2 * row + 0, -cosine);
+ A.setCoefficient(v1_id, 2 * row + 0, sine);
+ A.setCoefficient(u2_id, 2 * row + 0, 1);
+ // Imaginary part
+ A.setCoefficient(u0_id, 2 * row + 1, sine);
+ A.setCoefficient(v0_id, 2 * row + 1, cosine - 1.0f);
+ A.setCoefficient(u1_id, 2 * row + 1, -sine);
+ A.setCoefficient(v1_id, 2 * row + 1, -cosine);
+ A.setCoefficient(v2_id, 2 * row + 1, 1);
+}
+
+bool computeLeastSquaresConformalMap(halfedge::Mesh *mesh) {
+ xaDebugAssert(mesh != NULL);
+ // For this to work properly, mesh should not have colocals that have the same
+ // attributes, unless you want the vertices to actually have different texcoords.
+ const uint32_t vertexCount = mesh->vertexCount();
+ const uint32_t D = 2 * vertexCount;
+ const uint32_t N = 2 * halfedge::countMeshTriangles(mesh);
+ // N is the number of equations (one per triangle)
+ // D is the number of variables (one per vertex; there are 2 pinned vertices).
+ if (N < D - 4) {
+ return false;
+ }
+ sparse::Matrix A(D, N);
+ FullVector b(N);
+ FullVector x(D);
+ // Fill b:
+ b.fill(0.0f);
+ // Fill x:
+ halfedge::Vertex *v0;
+ halfedge::Vertex *v1;
+ if (!findApproximateDiameterVertices(mesh, &v0, &v1)) {
+ // Mesh has no boundaries.
+ return false;
+ }
+ if (v0->tex == v1->tex) {
+ // LSCM expects an existing parameterization.
+ return false;
+ }
+ for (uint32_t v = 0; v < vertexCount; v++) {
+ halfedge::Vertex *vertex = mesh->vertexAt(v);
+ xaDebugAssert(vertex != NULL);
+ // Initial solution.
+ x[2 * v + 0] = vertex->tex.x;
+ x[2 * v + 1] = vertex->tex.y;
+ }
+ // Fill A:
+ const uint32_t faceCount = mesh->faceCount();
+ for (uint32_t f = 0, t = 0; f < faceCount; f++) {
+ const halfedge::Face *face = mesh->faceAt(f);
+ xaDebugAssert(face != NULL);
+ xaDebugAssert(face->edgeCount() == 3);
+ const halfedge::Vertex *vertex0 = NULL;
+ for (halfedge::Face::ConstEdgeIterator it(face->edges()); !it.isDone(); it.advance()) {
+ const halfedge::Edge *edge = it.current();
+ xaAssert(edge != NULL);
+ if (vertex0 == NULL) {
+ vertex0 = edge->vertex;
+ } else if (edge->next->vertex != vertex0) {
+ const halfedge::Vertex *vertex1 = edge->from();
+ const halfedge::Vertex *vertex2 = edge->to();
+ setup_abf_relations(A, t, vertex0, vertex1, vertex2);
+ //setup_conformal_map_relations(A, t, vertex0, vertex1, vertex2);
+ t++;
+ }
+ }
+ }
+ const uint32_t lockedParameters[] = {
+ 2 * v0->id + 0,
+ 2 * v0->id + 1,
+ 2 * v1->id + 0,
+ 2 * v1->id + 1
+ };
+ // Solve
+ Solver::LeastSquaresSolver(A, b, x, lockedParameters, 4, 0.000001f);
+ // Map x back to texcoords:
+ for (uint32_t v = 0; v < vertexCount; v++) {
+ halfedge::Vertex *vertex = mesh->vertexAt(v);
+ xaDebugAssert(vertex != NULL);
+ vertex->tex = Vector2(x[2 * v + 0], x[2 * v + 1]);
+ }
+ return true;
+}
+
+bool computeOrthogonalProjectionMap(halfedge::Mesh *mesh) {
+ Vector3 axis[2];
+ uint32_t vertexCount = mesh->vertexCount();
+ std::vector<Vector3> points(vertexCount);
+ points.resize(vertexCount);
+ for (uint32_t i = 0; i < vertexCount; i++) {
+ points[i] = mesh->vertexAt(i)->pos;
+ }
+ // Avoid redundant computations.
+ float matrix[6];
+ Fit::computeCovariance(vertexCount, points.data(), matrix);
+ if (matrix[0] == 0 && matrix[3] == 0 && matrix[5] == 0) {
+ return false;
+ }
+ float eigenValues[3];
+ Vector3 eigenVectors[3];
+ if (!Fit::eigenSolveSymmetric3(matrix, eigenValues, eigenVectors)) {
+ return false;
+ }
+ axis[0] = normalize(eigenVectors[0]);
+ axis[1] = normalize(eigenVectors[1]);
+ // Project vertices to plane.
+ for (halfedge::Mesh::VertexIterator it(mesh->vertices()); !it.isDone(); it.advance()) {
+ halfedge::Vertex *vertex = it.current();
+ vertex->tex.x = dot(axis[0], vertex->pos);
+ vertex->tex.y = dot(axis[1], vertex->pos);
+ }
+ return true;
+}
+
+void computeSingleFaceMap(halfedge::Mesh *mesh) {
+ xaDebugAssert(mesh != NULL);
+ xaDebugAssert(mesh->faceCount() == 1);
+ halfedge::Face *face = mesh->faceAt(0);
+ xaAssert(face != NULL);
+ Vector3 p0 = face->edge->from()->pos;
+ Vector3 p1 = face->edge->to()->pos;
+ Vector3 X = normalizeSafe(p1 - p0, Vector3(0.0f), 0.0f);
+ Vector3 Z = face->normal();
+ Vector3 Y = normalizeSafe(cross(Z, X), Vector3(0.0f), 0.0f);
+ uint32_t i = 0;
+ for (halfedge::Face::EdgeIterator it(face->edges()); !it.isDone(); it.advance(), i++) {
+ halfedge::Vertex *vertex = it.vertex();
+ xaAssert(vertex != NULL);
+ if (i == 0) {
+ vertex->tex = Vector2(0);
+ } else {
+ Vector3 pn = vertex->pos;
+ float xn = dot((pn - p0), X);
+ float yn = dot((pn - p0), Y);
+ vertex->tex = Vector2(xn, yn);
+ }
+ }
+}
+
+// Dummy implementation of a priority queue using sort at insertion.
+// - Insertion is o(n)
+// - Smallest element goes at the end, so that popping it is o(1).
+// - Resorting is n*log(n)
+// @@ Number of elements in the queue is usually small, and we'd have to rebalance often. I'm not sure it's worth implementing a heap.
+// @@ Searcing at removal would remove the need for sorting when priorities change.
+struct PriorityQueue {
+ PriorityQueue(uint32_t size = UINT_MAX) :
+ maxSize(size) {}
+
+ void push(float priority, uint32_t face) {
+ uint32_t i = 0;
+ const uint32_t count = pairs.size();
+ for (; i < count; i++) {
+ if (pairs[i].priority > priority) break;
+ }
+ Pair p = { priority, face };
+ pairs.insert(pairs.begin() + i, p);
+ if (pairs.size() > maxSize) {
+ pairs.erase(pairs.begin());
+ }
+ }
+
+ // push face out of order, to be sorted later.
+ void push(uint32_t face) {
+ Pair p = { 0.0f, face };
+ pairs.push_back(p);
+ }
+
+ uint32_t pop() {
+ uint32_t f = pairs.back().face;
+ pairs.pop_back();
+ return f;
+ }
+
+ void sort() {
+ //sort(pairs); // @@ My intro sort appears to be much slower than it should!
+ std::sort(pairs.begin(), pairs.end());
+ }
+
+ void clear() {
+ pairs.clear();
+ }
+
+ uint32_t count() const {
+ return pairs.size();
+ }
+
+ float firstPriority() const {
+ return pairs.back().priority;
+ }
+
+ const uint32_t maxSize;
+
+ struct Pair {
+ bool operator<(const Pair &p) const {
+ return priority > p.priority; // !! Sort in inverse priority order!
+ }
+
+ float priority;
+ uint32_t face;
+ };
+
+ std::vector<Pair> pairs;
+};
+
+struct ChartBuildData {
+ ChartBuildData(int p_id) :
+ id(p_id) {
+ planeNormal = Vector3(0);
+ centroid = Vector3(0);
+ coneAxis = Vector3(0);
+ coneAngle = 0;
+ area = 0;
+ boundaryLength = 0;
+ normalSum = Vector3(0);
+ centroidSum = Vector3(0);
+ }
+
+ int id;
+
+ // Proxy info:
+ Vector3 planeNormal;
+ Vector3 centroid;
+ Vector3 coneAxis;
+ float coneAngle;
+
+ float area;
+ float boundaryLength;
+ Vector3 normalSum;
+ Vector3 centroidSum;
+
+ std::vector<uint32_t> seeds; // @@ These could be a pointers to the halfedge faces directly.
+ std::vector<uint32_t> faces;
+ PriorityQueue candidates;
+};
+
+struct AtlasBuilder {
+ AtlasBuilder(const halfedge::Mesh *m) :
+ mesh(m),
+ facesLeft(m->faceCount()) {
+ const uint32_t faceCount = m->faceCount();
+ faceChartArray.resize(faceCount, -1);
+ faceCandidateArray.resize(faceCount, (uint32_t)-1);
+ // @@ Floyd for the whole mesh is too slow. We could compute floyd progressively per patch as the patch grows. We need a better solution to compute most central faces.
+ //computeShortestPaths();
+ // Precompute edge lengths and face areas.
+ uint32_t edgeCount = m->edgeCount();
+ edgeLengths.resize(edgeCount);
+ for (uint32_t i = 0; i < edgeCount; i++) {
+ uint32_t id = m->edgeAt(i)->id;
+ xaDebugAssert(id / 2 == i);
+#ifdef NDEBUG
+ id = 0; // silence unused parameter warning
+#endif
+ edgeLengths[i] = m->edgeAt(i)->length();
+ }
+ faceAreas.resize(faceCount);
+ for (uint32_t i = 0; i < faceCount; i++) {
+ faceAreas[i] = m->faceAt(i)->area();
+ }
+ }
+
+ ~AtlasBuilder() {
+ const uint32_t chartCount = chartArray.size();
+ for (uint32_t i = 0; i < chartCount; i++) {
+ delete chartArray[i];
+ }
+ }
+
+ void markUnchartedFaces(const std::vector<uint32_t> &unchartedFaces) {
+ const uint32_t unchartedFaceCount = unchartedFaces.size();
+ for (uint32_t i = 0; i < unchartedFaceCount; i++) {
+ uint32_t f = unchartedFaces[i];
+ faceChartArray[f] = -2;
+ //faceCandidateArray[f] = -2; // @@ ?
+ removeCandidate(f);
+ }
+ xaDebugAssert(facesLeft >= unchartedFaceCount);
+ facesLeft -= unchartedFaceCount;
+ }
+
+ void computeShortestPaths() {
+ const uint32_t faceCount = mesh->faceCount();
+ shortestPaths.resize(faceCount * faceCount, FLT_MAX);
+ // Fill edges:
+ for (uint32_t i = 0; i < faceCount; i++) {
+ shortestPaths[i * faceCount + i] = 0.0f;
+ const halfedge::Face *face_i = mesh->faceAt(i);
+ Vector3 centroid_i = face_i->centroid();
+ for (halfedge::Face::ConstEdgeIterator it(face_i->edges()); !it.isDone(); it.advance()) {
+ const halfedge::Edge *edge = it.current();
+ if (!edge->isBoundary()) {
+ const halfedge::Face *face_j = edge->pair->face;
+ uint32_t j = face_j->id;
+ Vector3 centroid_j = face_j->centroid();
+ shortestPaths[i * faceCount + j] = shortestPaths[j * faceCount + i] = length(centroid_i - centroid_j);
+ }
+ }
+ }
+ // Use Floyd-Warshall algorithm to compute all paths:
+ for (uint32_t k = 0; k < faceCount; k++) {
+ for (uint32_t i = 0; i < faceCount; i++) {
+ for (uint32_t j = 0; j < faceCount; j++) {
+ shortestPaths[i * faceCount + j] = std::min(shortestPaths[i * faceCount + j], shortestPaths[i * faceCount + k] + shortestPaths[k * faceCount + j]);
+ }
+ }
+ }
+ }
+
+ void placeSeeds(float threshold, uint32_t maxSeedCount) {
+ // Instead of using a predefiened number of seeds:
+ // - Add seeds one by one, growing chart until a certain treshold.
+ // - Undo charts and restart growing process.
+ // @@ How can we give preference to faces far from sharp features as in the LSCM paper?
+ // - those points can be found using a simple flood filling algorithm.
+ // - how do we weight the probabilities?
+ for (uint32_t i = 0; i < maxSeedCount; i++) {
+ if (facesLeft == 0) {
+ // No faces left, stop creating seeds.
+ break;
+ }
+ createRandomChart(threshold);
+ }
+ }
+
+ void createRandomChart(float threshold) {
+ ChartBuildData *chart = new ChartBuildData(chartArray.size());
+ chartArray.push_back(chart);
+ // Pick random face that is not used by any chart yet.
+ uint32_t randomFaceIdx = rand.getRange(facesLeft - 1);
+ uint32_t i = 0;
+ for (uint32_t f = 0; f != randomFaceIdx; f++, i++) {
+ while (faceChartArray[i] != -1)
+ i++;
+ }
+ while (faceChartArray[i] != -1)
+ i++;
+ chart->seeds.push_back(i);
+ addFaceToChart(chart, i, true);
+ // Grow the chart as much as possible within the given threshold.
+ growChart(chart, threshold * 0.5f, facesLeft);
+ //growCharts(threshold - threshold * 0.75f / chartCount(), facesLeft);
+ }
+
+ void addFaceToChart(ChartBuildData *chart, uint32_t f, bool recomputeProxy = false) {
+ // Add face to chart.
+ chart->faces.push_back(f);
+ xaDebugAssert(faceChartArray[f] == -1);
+ faceChartArray[f] = chart->id;
+ facesLeft--;
+ // Update area and boundary length.
+ chart->area = evaluateChartArea(chart, f);
+ chart->boundaryLength = evaluateBoundaryLength(chart, f);
+ chart->normalSum = evaluateChartNormalSum(chart, f);
+ chart->centroidSum = evaluateChartCentroidSum(chart, f);
+ if (recomputeProxy) {
+ // Update proxy and candidate's priorities.
+ updateProxy(chart);
+ }
+ // Update candidates.
+ removeCandidate(f);
+ updateCandidates(chart, f);
+ updatePriorities(chart);
+ }
+
+ // Returns true if any of the charts can grow more.
+ bool growCharts(float threshold, uint32_t faceCount) {
+ // Using one global list.
+ faceCount = std::min(faceCount, facesLeft);
+ for (uint32_t i = 0; i < faceCount; i++) {
+ const Candidate &candidate = getBestCandidate();
+ if (candidate.metric > threshold) {
+ return false; // Can't grow more.
+ }
+ addFaceToChart(candidate.chart, candidate.face);
+ }
+ return facesLeft != 0; // Can continue growing.
+ }
+
+ bool growChart(ChartBuildData *chart, float threshold, uint32_t faceCount) {
+ // Try to add faceCount faces within threshold to chart.
+ for (uint32_t i = 0; i < faceCount;) {
+ if (chart->candidates.count() == 0 || chart->candidates.firstPriority() > threshold) {
+ return false;
+ }
+ uint32_t f = chart->candidates.pop();
+ if (faceChartArray[f] == -1) {
+ addFaceToChart(chart, f);
+ i++;
+ }
+ }
+ if (chart->candidates.count() == 0 || chart->candidates.firstPriority() > threshold) {
+ return false;
+ }
+ return true;
+ }
+
+ void resetCharts() {
+ const uint32_t faceCount = mesh->faceCount();
+ for (uint32_t i = 0; i < faceCount; i++) {
+ faceChartArray[i] = -1;
+ faceCandidateArray[i] = (uint32_t)-1;
+ }
+ facesLeft = faceCount;
+ candidateArray.clear();
+ const uint32_t chartCount = chartArray.size();
+ for (uint32_t i = 0; i < chartCount; i++) {
+ ChartBuildData *chart = chartArray[i];
+ const uint32_t seed = chart->seeds.back();
+ chart->area = 0.0f;
+ chart->boundaryLength = 0.0f;
+ chart->normalSum = Vector3(0);
+ chart->centroidSum = Vector3(0);
+ chart->faces.clear();
+ chart->candidates.clear();
+ addFaceToChart(chart, seed);
+ }
+ }
+
+ void updateCandidates(ChartBuildData *chart, uint32_t f) {
+ const halfedge::Face *face = mesh->faceAt(f);
+ // Traverse neighboring faces, add the ones that do not belong to any chart yet.
+ for (halfedge::Face::ConstEdgeIterator it(face->edges()); !it.isDone(); it.advance()) {
+ const halfedge::Edge *edge = it.current()->pair;
+ if (!edge->isBoundary()) {
+ uint32_t faceId = edge->face->id;
+ if (faceChartArray[faceId] == -1) {
+ chart->candidates.push(faceId);
+ }
+ }
+ }
+ }
+
+ void updateProxies() {
+ const uint32_t chartCount = chartArray.size();
+ for (uint32_t i = 0; i < chartCount; i++) {
+ updateProxy(chartArray[i]);
+ }
+ }
+
+ void updateProxy(ChartBuildData *chart) {
+ //#pragma message(NV_FILE_LINE "TODO: Use best fit plane instead of average normal.")
+ chart->planeNormal = normalizeSafe(chart->normalSum, Vector3(0), 0.0f);
+ chart->centroid = chart->centroidSum / float(chart->faces.size());
+ }
+
+ bool relocateSeeds() {
+ bool anySeedChanged = false;
+ const uint32_t chartCount = chartArray.size();
+ for (uint32_t i = 0; i < chartCount; i++) {
+ if (relocateSeed(chartArray[i])) {
+ anySeedChanged = true;
+ }
+ }
+ return anySeedChanged;
+ }
+
+ bool relocateSeed(ChartBuildData *chart) {
+ Vector3 centroid = computeChartCentroid(chart);
+ const uint32_t N = 10; // @@ Hardcoded to 10?
+ PriorityQueue bestTriangles(N);
+ // Find the first N triangles that fit the proxy best.
+ const uint32_t faceCount = chart->faces.size();
+ for (uint32_t i = 0; i < faceCount; i++) {
+ float priority = evaluateProxyFitMetric(chart, chart->faces[i]);
+ bestTriangles.push(priority, chart->faces[i]);
+ }
+ // Of those, choose the most central triangle.
+ uint32_t mostCentral;
+ float maxDistance = -1;
+ const uint32_t bestCount = bestTriangles.count();
+ for (uint32_t i = 0; i < bestCount; i++) {
+ const halfedge::Face *face = mesh->faceAt(bestTriangles.pairs[i].face);
+ Vector3 faceCentroid = face->triangleCenter();
+ float distance = length(centroid - faceCentroid);
+ if (distance > maxDistance) {
+ maxDistance = distance;
+ mostCentral = bestTriangles.pairs[i].face;
+ }
+ }
+ xaDebugAssert(maxDistance >= 0);
+ // In order to prevent k-means cyles we record all the previously chosen seeds.
+ uint32_t index = std::find(chart->seeds.begin(), chart->seeds.end(), mostCentral) - chart->seeds.begin();
+ if (index < chart->seeds.size()) {
+ // Move new seed to the end of the seed array.
+ uint32_t last = chart->seeds.size() - 1;
+ std::swap(chart->seeds[index], chart->seeds[last]);
+ return false;
+ } else {
+ // Append new seed.
+ chart->seeds.push_back(mostCentral);
+ return true;
+ }
+ }
+
+ void updatePriorities(ChartBuildData *chart) {
+ // Re-evaluate candidate priorities.
+ uint32_t candidateCount = chart->candidates.count();
+ for (uint32_t i = 0; i < candidateCount; i++) {
+ chart->candidates.pairs[i].priority = evaluatePriority(chart, chart->candidates.pairs[i].face);
+ if (faceChartArray[chart->candidates.pairs[i].face] == -1) {
+ updateCandidate(chart, chart->candidates.pairs[i].face, chart->candidates.pairs[i].priority);
+ }
+ }
+ // Sort candidates.
+ chart->candidates.sort();
+ }
+
+ // Evaluate combined metric.
+ float evaluatePriority(ChartBuildData *chart, uint32_t face) {
+ // Estimate boundary length and area:
+ float newBoundaryLength = evaluateBoundaryLength(chart, face);
+ float newChartArea = evaluateChartArea(chart, face);
+ float F = evaluateProxyFitMetric(chart, face);
+ float C = evaluateRoundnessMetric(chart, face, newBoundaryLength, newChartArea);
+ float P = evaluateStraightnessMetric(chart, face);
+ // Penalize faces that cross seams, reward faces that close seams or reach boundaries.
+ float N = evaluateNormalSeamMetric(chart, face);
+ float T = evaluateTextureSeamMetric(chart, face);
+ //float R = evaluateCompletenessMetric(chart, face);
+ //float D = evaluateDihedralAngleMetric(chart, face);
+ // @@ Add a metric based on local dihedral angle.
+ // @@ Tweaking the normal and texture seam metrics.
+ // - Cause more impedance. Never cross 90 degree edges.
+ // -
+ float cost = float(
+ options.proxyFitMetricWeight * F +
+ options.roundnessMetricWeight * C +
+ options.straightnessMetricWeight * P +
+ options.normalSeamMetricWeight * N +
+ options.textureSeamMetricWeight * T);
+ // Enforce limits strictly:
+ if (newChartArea > options.maxChartArea) cost = FLT_MAX;
+ if (newBoundaryLength > options.maxBoundaryLength) cost = FLT_MAX;
+ // Make sure normal seams are fully respected:
+ if (options.normalSeamMetricWeight >= 1000 && N != 0) cost = FLT_MAX;
+ xaAssert(std::isfinite(cost));
+ return cost;
+ }
+
+ // Returns a value in [0-1].
+ float evaluateProxyFitMetric(ChartBuildData *chart, uint32_t f) {
+ const halfedge::Face *face = mesh->faceAt(f);
+ Vector3 faceNormal = face->triangleNormal();
+ // Use plane fitting metric for now:
+ return 1 - dot(faceNormal, chart->planeNormal); // @@ normal deviations should be weighted by face area
+ }
+
+ float evaluateRoundnessMetric(ChartBuildData *chart, uint32_t /*face*/, float newBoundaryLength, float newChartArea) {
+ float roundness = square(chart->boundaryLength) / chart->area;
+ float newRoundness = square(newBoundaryLength) / newChartArea;
+ if (newRoundness > roundness) {
+ return square(newBoundaryLength) / (newChartArea * 4 * PI);
+ } else {
+ // Offer no impedance to faces that improve roundness.
+ return 0;
+ }
+ }
+
+ float evaluateStraightnessMetric(ChartBuildData *chart, uint32_t f) {
+ float l_out = 0.0f;
+ float l_in = 0.0f;
+ const halfedge::Face *face = mesh->faceAt(f);
+ for (halfedge::Face::ConstEdgeIterator it(face->edges()); !it.isDone(); it.advance()) {
+ const halfedge::Edge *edge = it.current();
+ float l = edgeLengths[edge->id / 2];
+ if (edge->isBoundary()) {
+ l_out += l;
+ } else {
+ uint32_t neighborFaceId = edge->pair->face->id;
+ if (faceChartArray[neighborFaceId] != chart->id) {
+ l_out += l;
+ } else {
+ l_in += l;
+ }
+ }
+ }
+ xaDebugAssert(l_in != 0.0f); // Candidate face must be adjacent to chart. @@ This is not true if the input mesh has zero-length edges.
+ float ratio = (l_out - l_in) / (l_out + l_in);
+ return std::min(ratio, 0.0f); // Only use the straightness metric to close gaps.
+ }
+
+ float evaluateNormalSeamMetric(ChartBuildData *chart, uint32_t f) {
+ float seamFactor = 0.0f;
+ float totalLength = 0.0f;
+ const halfedge::Face *face = mesh->faceAt(f);
+ for (halfedge::Face::ConstEdgeIterator it(face->edges()); !it.isDone(); it.advance()) {
+ const halfedge::Edge *edge = it.current();
+ if (edge->isBoundary()) {
+ continue;
+ }
+ const uint32_t neighborFaceId = edge->pair->face->id;
+ if (faceChartArray[neighborFaceId] != chart->id) {
+ continue;
+ }
+ //float l = edge->length();
+ float l = edgeLengths[edge->id / 2];
+ totalLength += l;
+ if (!edge->isSeam()) {
+ continue;
+ }
+ // Make sure it's a normal seam.
+ if (edge->isNormalSeam()) {
+ float d0 = clamp(dot(edge->vertex->nor, edge->pair->next->vertex->nor), 0.0f, 1.0f);
+ float d1 = clamp(dot(edge->next->vertex->nor, edge->pair->vertex->nor), 0.0f, 1.0f);
+ l *= 1 - (d0 + d1) * 0.5f;
+ seamFactor += l;
+ }
+ }
+ if (seamFactor == 0) return 0.0f;
+ return seamFactor / totalLength;
+ }
+
+ float evaluateTextureSeamMetric(ChartBuildData *chart, uint32_t f) {
+ float seamLength = 0.0f;
+ float totalLength = 0.0f;
+ const halfedge::Face *face = mesh->faceAt(f);
+ for (halfedge::Face::ConstEdgeIterator it(face->edges()); !it.isDone(); it.advance()) {
+ const halfedge::Edge *edge = it.current();
+ if (edge->isBoundary()) {
+ continue;
+ }
+ const uint32_t neighborFaceId = edge->pair->face->id;
+ if (faceChartArray[neighborFaceId] != chart->id) {
+ continue;
+ }
+ //float l = edge->length();
+ float l = edgeLengths[edge->id / 2];
+ totalLength += l;
+ if (!edge->isSeam()) {
+ continue;
+ }
+ // Make sure it's a texture seam.
+ if (edge->isTextureSeam()) {
+ seamLength += l;
+ }
+ }
+ if (seamLength == 0.0f) {
+ return 0.0f; // Avoid division by zero.
+ }
+ return seamLength / totalLength;
+ }
+
+ float evaluateChartArea(ChartBuildData *chart, uint32_t f) {
+ const halfedge::Face *face = mesh->faceAt(f);
+ return chart->area + faceAreas[face->id];
+ }
+
+ float evaluateBoundaryLength(ChartBuildData *chart, uint32_t f) {
+ float boundaryLength = chart->boundaryLength;
+ // Add new edges, subtract edges shared with the chart.
+ const halfedge::Face *face = mesh->faceAt(f);
+ for (halfedge::Face::ConstEdgeIterator it(face->edges()); !it.isDone(); it.advance()) {
+ const halfedge::Edge *edge = it.current();
+ //float edgeLength = edge->length();
+ float edgeLength = edgeLengths[edge->id / 2];
+ if (edge->isBoundary()) {
+ boundaryLength += edgeLength;
+ } else {
+ uint32_t neighborFaceId = edge->pair->face->id;
+ if (faceChartArray[neighborFaceId] != chart->id) {
+ boundaryLength += edgeLength;
+ } else {
+ boundaryLength -= edgeLength;
+ }
+ }
+ }
+ return std::max(0.0f, boundaryLength); // @@ Hack!
+ }
+
+ Vector3 evaluateChartNormalSum(ChartBuildData *chart, uint32_t f) {
+ const halfedge::Face *face = mesh->faceAt(f);
+ return chart->normalSum + face->triangleNormalAreaScaled();
+ }
+
+ Vector3 evaluateChartCentroidSum(ChartBuildData *chart, uint32_t f) {
+ const halfedge::Face *face = mesh->faceAt(f);
+ return chart->centroidSum + face->centroid();
+ }
+
+ Vector3 computeChartCentroid(const ChartBuildData *chart) {
+ Vector3 centroid(0);
+ const uint32_t faceCount = chart->faces.size();
+ for (uint32_t i = 0; i < faceCount; i++) {
+ const halfedge::Face *face = mesh->faceAt(chart->faces[i]);
+ centroid += face->triangleCenter();
+ }
+ return centroid / float(faceCount);
+ }
+
+ void fillHoles(float threshold) {
+ while (facesLeft > 0)
+ createRandomChart(threshold);
+ }
+
+ void mergeCharts() {
+ std::vector<float> sharedBoundaryLengths;
+ const uint32_t chartCount = chartArray.size();
+ for (int c = chartCount - 1; c >= 0; c--) {
+ sharedBoundaryLengths.clear();
+ sharedBoundaryLengths.resize(chartCount, 0.0f);
+ ChartBuildData *chart = chartArray[c];
+ float externalBoundary = 0.0f;
+ const uint32_t faceCount = chart->faces.size();
+ for (uint32_t i = 0; i < faceCount; i++) {
+ uint32_t f = chart->faces[i];
+ const halfedge::Face *face = mesh->faceAt(f);
+ for (halfedge::Face::ConstEdgeIterator it(face->edges()); !it.isDone(); it.advance()) {
+ const halfedge::Edge *edge = it.current();
+ //float l = edge->length();
+ float l = edgeLengths[edge->id / 2];
+ if (edge->isBoundary()) {
+ externalBoundary += l;
+ } else {
+ uint32_t neighborFace = edge->pair->face->id;
+ uint32_t neighborChart = faceChartArray[neighborFace];
+ if (neighborChart != (uint32_t)c) {
+ if ((edge->isSeam() && (edge->isNormalSeam() || edge->isTextureSeam())) || neighborChart == -2) {
+ externalBoundary += l;
+ } else {
+ sharedBoundaryLengths[neighborChart] += l;
+ }
+ }
+ }
+ }
+ }
+ for (int cc = chartCount - 1; cc >= 0; cc--) {
+ if (cc == c)
+ continue;
+ ChartBuildData *chart2 = chartArray[cc];
+ if (chart2 == NULL)
+ continue;
+ if (sharedBoundaryLengths[cc] > 0.8 * std::max(0.0f, chart->boundaryLength - externalBoundary)) {
+ // Try to avoid degenerate configurations.
+ if (chart2->boundaryLength > sharedBoundaryLengths[cc]) {
+ if (dot(chart2->planeNormal, chart->planeNormal) > -0.25) {
+ mergeChart(chart2, chart, sharedBoundaryLengths[cc]);
+ delete chart;
+ chartArray[c] = NULL;
+ break;
+ }
+ }
+ }
+ if (sharedBoundaryLengths[cc] > 0.20 * std::max(0.0f, chart->boundaryLength - externalBoundary)) {
+ // Compare proxies.
+ if (dot(chart2->planeNormal, chart->planeNormal) > 0) {
+ mergeChart(chart2, chart, sharedBoundaryLengths[cc]);
+ delete chart;
+ chartArray[c] = NULL;
+ break;
+ }
+ }
+ }
+ }
+ // Remove deleted charts.
+ for (int c = 0; c < int32_t(chartArray.size()); /*do not increment if removed*/) {
+ if (chartArray[c] == NULL) {
+ chartArray.erase(chartArray.begin() + c);
+ // Update faceChartArray.
+ const uint32_t faceCount = faceChartArray.size();
+ for (uint32_t i = 0; i < faceCount; i++) {
+ xaDebugAssert(faceChartArray[i] != -1);
+ xaDebugAssert(faceChartArray[i] != c);
+ xaDebugAssert(faceChartArray[i] <= int32_t(chartArray.size()));
+ if (faceChartArray[i] > c) {
+ faceChartArray[i]--;
+ }
+ }
+ } else {
+ chartArray[c]->id = c;
+ c++;
+ }
+ }
+ }
+
+ // @@ Cleanup.
+ struct Candidate {
+ uint32_t face;
+ ChartBuildData *chart;
+ float metric;
+ };
+
+ // @@ Get N best candidates in one pass.
+ const Candidate &getBestCandidate() const {
+ uint32_t best = 0;
+ float bestCandidateMetric = FLT_MAX;
+ const uint32_t candidateCount = candidateArray.size();
+ xaAssert(candidateCount > 0);
+ for (uint32_t i = 0; i < candidateCount; i++) {
+ const Candidate &candidate = candidateArray[i];
+ if (candidate.metric < bestCandidateMetric) {
+ bestCandidateMetric = candidate.metric;
+ best = i;
+ }
+ }
+ return candidateArray[best];
+ }
+
+ void removeCandidate(uint32_t f) {
+ int c = faceCandidateArray[f];
+ if (c != -1) {
+ faceCandidateArray[f] = (uint32_t)-1;
+ if (c == int(candidateArray.size() - 1)) {
+ candidateArray.pop_back();
+ } else {
+ // Replace with last.
+ candidateArray[c] = candidateArray[candidateArray.size() - 1];
+ candidateArray.pop_back();
+ faceCandidateArray[candidateArray[c].face] = c;
+ }
+ }
+ }
+
+ void updateCandidate(ChartBuildData *chart, uint32_t f, float metric) {
+ if (faceCandidateArray[f] == -1) {
+ const uint32_t index = candidateArray.size();
+ faceCandidateArray[f] = index;
+ candidateArray.resize(index + 1);
+ candidateArray[index].face = f;
+ candidateArray[index].chart = chart;
+ candidateArray[index].metric = metric;
+ } else {
+ int c = faceCandidateArray[f];
+ xaDebugAssert(c != -1);
+ Candidate &candidate = candidateArray[c];
+ xaDebugAssert(candidate.face == f);
+ if (metric < candidate.metric || chart == candidate.chart) {
+ candidate.metric = metric;
+ candidate.chart = chart;
+ }
+ }
+ }
+
+ void mergeChart(ChartBuildData *owner, ChartBuildData *chart, float sharedBoundaryLength) {
+ const uint32_t faceCount = chart->faces.size();
+ for (uint32_t i = 0; i < faceCount; i++) {
+ uint32_t f = chart->faces[i];
+ xaDebugAssert(faceChartArray[f] == chart->id);
+ faceChartArray[f] = owner->id;
+ owner->faces.push_back(f);
+ }
+ // Update adjacencies?
+ owner->area += chart->area;
+ owner->boundaryLength += chart->boundaryLength - sharedBoundaryLength;
+ owner->normalSum += chart->normalSum;
+ owner->centroidSum += chart->centroidSum;
+ updateProxy(owner);
+ }
+
+ uint32_t chartCount() const { return chartArray.size(); }
+ const std::vector<uint32_t> &chartFaces(uint32_t i) const { return chartArray[i]->faces; }
+
+ const halfedge::Mesh *mesh;
+ uint32_t facesLeft;
+ std::vector<int> faceChartArray;
+ std::vector<ChartBuildData *> chartArray;
+ std::vector<float> shortestPaths;
+ std::vector<float> edgeLengths;
+ std::vector<float> faceAreas;
+ std::vector<Candidate> candidateArray; //
+ std::vector<uint32_t> faceCandidateArray; // Map face index to candidate index.
+ MTRand rand;
+ CharterOptions options;
+};
+
+/// A chart is a connected set of faces with a certain topology (usually a disk).
+class Chart {
+public:
+ Chart() :
+ m_isDisk(false),
+ m_isVertexMapped(false) {}
+
+ void build(const halfedge::Mesh *originalMesh, const std::vector<uint32_t> &faceArray) {
+ // Copy face indices.
+ m_faceArray = faceArray;
+ const uint32_t meshVertexCount = originalMesh->vertexCount();
+ m_chartMesh.reset(new halfedge::Mesh());
+ m_unifiedMesh.reset(new halfedge::Mesh());
+ std::vector<uint32_t> chartMeshIndices(meshVertexCount, (uint32_t)~0);
+ std::vector<uint32_t> unifiedMeshIndices(meshVertexCount, (uint32_t)~0);
+ // Add vertices.
+ const uint32_t faceCount = faceArray.size();
+ for (uint32_t f = 0; f < faceCount; f++) {
+ const halfedge::Face *face = originalMesh->faceAt(faceArray[f]);
+ xaDebugAssert(face != NULL);
+ for (halfedge::Face::ConstEdgeIterator it(face->edges()); !it.isDone(); it.advance()) {
+ const halfedge::Vertex *vertex = it.current()->vertex;
+ const halfedge::Vertex *unifiedVertex = vertex->firstColocal();
+ if (unifiedMeshIndices[unifiedVertex->id] == ~0) {
+ unifiedMeshIndices[unifiedVertex->id] = m_unifiedMesh->vertexCount();
+ xaDebugAssert(vertex->pos == unifiedVertex->pos);
+ m_unifiedMesh->addVertex(vertex->pos);
+ }
+ if (chartMeshIndices[vertex->id] == ~0) {
+ chartMeshIndices[vertex->id] = m_chartMesh->vertexCount();
+ m_chartToOriginalMap.push_back(vertex->original_id);
+ m_chartToUnifiedMap.push_back(unifiedMeshIndices[unifiedVertex->id]);
+ halfedge::Vertex *v = m_chartMesh->addVertex(vertex->pos);
+ v->nor = vertex->nor;
+ v->tex = vertex->tex;
+ }
+ }
+ }
+ // This is ignoring the canonical map:
+ // - Is it really necessary to link colocals?
+ m_chartMesh->linkColocals();
+ //m_unifiedMesh->linkColocals(); // Not strictly necessary, no colocals in the unified mesh. # Wrong.
+ // This check is not valid anymore, if the original mesh vertices were linked with a canonical map, then it might have
+ // some colocal vertices that were unlinked. So, the unified mesh might have some duplicate vertices, because firstColocal()
+ // is not guaranteed to return the same vertex for two colocal vertices.
+ //xaAssert(m_chartMesh->colocalVertexCount() == m_unifiedMesh->vertexCount());
+ // Is that OK? What happens in meshes were that happens? Does anything break? Apparently not...
+ std::vector<uint32_t> faceIndices;
+ faceIndices.reserve(7);
+ // Add faces.
+ for (uint32_t f = 0; f < faceCount; f++) {
+ const halfedge::Face *face = originalMesh->faceAt(faceArray[f]);
+ xaDebugAssert(face != NULL);
+ faceIndices.clear();
+ for (halfedge::Face::ConstEdgeIterator it(face->edges()); !it.isDone(); it.advance()) {
+ const halfedge::Vertex *vertex = it.current()->vertex;
+ xaDebugAssert(vertex != NULL);
+ faceIndices.push_back(chartMeshIndices[vertex->id]);
+ }
+ m_chartMesh->addFace(faceIndices);
+ faceIndices.clear();
+ for (halfedge::Face::ConstEdgeIterator it(face->edges()); !it.isDone(); it.advance()) {
+ const halfedge::Vertex *vertex = it.current()->vertex;
+ xaDebugAssert(vertex != NULL);
+ vertex = vertex->firstColocal();
+ faceIndices.push_back(unifiedMeshIndices[vertex->id]);
+ }
+ m_unifiedMesh->addFace(faceIndices);
+ }
+ m_chartMesh->linkBoundary();
+ m_unifiedMesh->linkBoundary();
+ //exportMesh(m_unifiedMesh.ptr(), "debug_input.obj");
+ if (m_unifiedMesh->splitBoundaryEdges()) {
+ m_unifiedMesh.reset(halfedge::unifyVertices(m_unifiedMesh.get()));
+ }
+ //exportMesh(m_unifiedMesh.ptr(), "debug_split.obj");
+ // Closing the holes is not always the best solution and does not fix all the problems.
+ // We need to do some analysis of the holes and the genus to:
+ // - Find cuts that reduce genus.
+ // - Find cuts to connect holes.
+ // - Use minimal spanning trees or seamster.
+ if (!closeHoles()) {
+ /*static int pieceCount = 0;
+ StringBuilder fileName;
+ fileName.format("debug_hole_%d.obj", pieceCount++);
+ exportMesh(m_unifiedMesh.ptr(), fileName.str());*/
+ }
+ m_unifiedMesh.reset(halfedge::triangulate(m_unifiedMesh.get()));
+ //exportMesh(m_unifiedMesh.ptr(), "debug_triangulated.obj");
+ // Analyze chart topology.
+ halfedge::MeshTopology topology(m_unifiedMesh.get());
+ m_isDisk = topology.isDisk();
+ }
+
+ void buildVertexMap(const halfedge::Mesh *originalMesh, const std::vector<uint32_t> &unchartedMaterialArray) {
+ xaAssert(m_chartMesh.get() == NULL && m_unifiedMesh.get() == NULL);
+ m_isVertexMapped = true;
+ // Build face indices.
+ m_faceArray.clear();
+ const uint32_t meshFaceCount = originalMesh->faceCount();
+ for (uint32_t f = 0; f < meshFaceCount; f++) {
+ const halfedge::Face *face = originalMesh->faceAt(f);
+ if (std::find(unchartedMaterialArray.begin(), unchartedMaterialArray.end(), face->material) != unchartedMaterialArray.end()) {
+ m_faceArray.push_back(f);
+ }
+ }
+ const uint32_t faceCount = m_faceArray.size();
+ if (faceCount == 0) {
+ return;
+ }
+ // @@ The chartMesh construction is basically the same as with regular charts, don't duplicate!
+ const uint32_t meshVertexCount = originalMesh->vertexCount();
+ m_chartMesh.reset(new halfedge::Mesh());
+ std::vector<uint32_t> chartMeshIndices(meshVertexCount, (uint32_t)~0);
+ // Vertex map mesh only has disconnected vertices.
+ for (uint32_t f = 0; f < faceCount; f++) {
+ const halfedge::Face *face = originalMesh->faceAt(m_faceArray[f]);
+ xaDebugAssert(face != NULL);
+ for (halfedge::Face::ConstEdgeIterator it(face->edges()); !it.isDone(); it.advance()) {
+ const halfedge::Vertex *vertex = it.current()->vertex;
+ if (chartMeshIndices[vertex->id] == ~0) {
+ chartMeshIndices[vertex->id] = m_chartMesh->vertexCount();
+ m_chartToOriginalMap.push_back(vertex->original_id);
+ halfedge::Vertex *v = m_chartMesh->addVertex(vertex->pos);
+ v->nor = vertex->nor;
+ v->tex = vertex->tex; // @@ Not necessary.
+ }
+ }
+ }
+ // @@ Link colocals using the original mesh canonical map? Build canonical map on the fly? Do we need to link colocals at all for this?
+ //m_chartMesh->linkColocals();
+ std::vector<uint32_t> faceIndices;
+ faceIndices.reserve(7);
+ // Add faces.
+ for (uint32_t f = 0; f < faceCount; f++) {
+ const halfedge::Face *face = originalMesh->faceAt(m_faceArray[f]);
+ xaDebugAssert(face != NULL);
+ faceIndices.clear();
+ for (halfedge::Face::ConstEdgeIterator it(face->edges()); !it.isDone(); it.advance()) {
+ const halfedge::Vertex *vertex = it.current()->vertex;
+ xaDebugAssert(vertex != NULL);
+ xaDebugAssert(chartMeshIndices[vertex->id] != ~0);
+ faceIndices.push_back(chartMeshIndices[vertex->id]);
+ }
+ halfedge::Face *new_face = m_chartMesh->addFace(faceIndices);
+ xaDebugAssert(new_face != NULL);
+#ifdef NDEBUG
+ new_face = NULL; // silence unused parameter warning
+#endif
+ }
+ m_chartMesh->linkBoundary();
+ const uint32_t chartVertexCount = m_chartMesh->vertexCount();
+ Box bounds;
+ bounds.clearBounds();
+ for (uint32_t i = 0; i < chartVertexCount; i++) {
+ halfedge::Vertex *vertex = m_chartMesh->vertexAt(i);
+ bounds.addPointToBounds(vertex->pos);
+ }
+ ProximityGrid grid;
+ grid.init(bounds, chartVertexCount);
+ for (uint32_t i = 0; i < chartVertexCount; i++) {
+ halfedge::Vertex *vertex = m_chartMesh->vertexAt(i);
+ grid.add(vertex->pos, i);
+ }
+ uint32_t texelCount = 0;
+ const float positionThreshold = 0.01f;
+ const float normalThreshold = 0.01f;
+ uint32_t verticesVisited = 0;
+ uint32_t cellsVisited = 0;
+ std::vector<int> vertexIndexArray(chartVertexCount, -1); // Init all indices to -1.
+ // Traverse vertices in morton order. @@ It may be more interesting to sort them based on orientation.
+ const uint32_t cellCodeCount = grid.mortonCount();
+ for (uint32_t cellCode = 0; cellCode < cellCodeCount; cellCode++) {
+ int cell = grid.mortonIndex(cellCode);
+ if (cell < 0) continue;
+ cellsVisited++;
+ const std::vector<uint32_t> &indexArray = grid.cellArray[cell].indexArray;
+ for (uint32_t i = 0; i < indexArray.size(); i++) {
+ uint32_t idx = indexArray[i];
+ halfedge::Vertex *vertex = m_chartMesh->vertexAt(idx);
+ xaDebugAssert(vertexIndexArray[idx] == -1);
+ std::vector<uint32_t> neighbors;
+ grid.gather(vertex->pos, positionThreshold, /*ref*/ neighbors);
+ // Compare against all nearby vertices, cluster greedily.
+ for (uint32_t j = 0; j < neighbors.size(); j++) {
+ uint32_t otherIdx = neighbors[j];
+ if (vertexIndexArray[otherIdx] != -1) {
+ halfedge::Vertex *otherVertex = m_chartMesh->vertexAt(otherIdx);
+ if (distance(vertex->pos, otherVertex->pos) < positionThreshold &&
+ distance(vertex->nor, otherVertex->nor) < normalThreshold) {
+ vertexIndexArray[idx] = vertexIndexArray[otherIdx];
+ break;
+ }
+ }
+ }
+ // If index not assigned, assign new one.
+ if (vertexIndexArray[idx] == -1) {
+ vertexIndexArray[idx] = texelCount++;
+ }
+ verticesVisited++;
+ }
+ }
+ xaDebugAssert(cellsVisited == grid.cellArray.size());
+ xaDebugAssert(verticesVisited == chartVertexCount);
+ vertexMapWidth = ftoi_ceil(sqrtf(float(texelCount)));
+ vertexMapWidth = (vertexMapWidth + 3) & ~3; // Width aligned to 4.
+ vertexMapHeight = vertexMapWidth == 0 ? 0 : (texelCount + vertexMapWidth - 1) / vertexMapWidth;
+ //vertexMapHeight = (vertexMapHeight + 3) & ~3; // Height aligned to 4.
+ xaDebugAssert(vertexMapWidth >= vertexMapHeight);
+ xaPrint("Reduced vertex count from %d to %d.\n", chartVertexCount, texelCount);
+ // Lay down the clustered vertices in morton order.
+ std::vector<uint32_t> texelCodes(texelCount);
+ // For each texel, assign one morton code.
+ uint32_t texelCode = 0;
+ for (uint32_t i = 0; i < texelCount; i++) {
+ uint32_t x, y;
+ do {
+ x = morton::decodeMorton2X(texelCode);
+ y = morton::decodeMorton2Y(texelCode);
+ texelCode++;
+ } while (x >= uint32_t(vertexMapWidth) || y >= uint32_t(vertexMapHeight));
+ texelCodes[i] = texelCode - 1;
+ }
+ for (uint32_t i = 0; i < chartVertexCount; i++) {
+ halfedge::Vertex *vertex = m_chartMesh->vertexAt(i);
+ int idx = vertexIndexArray[i];
+ if (idx != -1) {
+ uint32_t tc = texelCodes[idx];
+ uint32_t x = morton::decodeMorton2X(tc);
+ uint32_t y = morton::decodeMorton2Y(tc);
+ vertex->tex.x = float(x);
+ vertex->tex.y = float(y);
+ }
+ }
+ }
+
+ bool closeHoles() {
+ xaDebugAssert(!m_isVertexMapped);
+ std::vector<halfedge::Edge *> boundaryEdges;
+ getBoundaryEdges(m_unifiedMesh.get(), boundaryEdges);
+ uint32_t boundaryCount = boundaryEdges.size();
+ if (boundaryCount <= 1) {
+ // Nothing to close.
+ return true;
+ }
+ // Compute lengths and areas.
+ std::vector<float> boundaryLengths;
+ for (uint32_t i = 0; i < boundaryCount; i++) {
+ const halfedge::Edge *startEdge = boundaryEdges[i];
+ xaAssert(startEdge->face == NULL);
+ //float boundaryEdgeCount = 0;
+ float boundaryLength = 0.0f;
+ //Vector3 boundaryCentroid(zero);
+ const halfedge::Edge *edge = startEdge;
+ do {
+ Vector3 t0 = edge->from()->pos;
+ Vector3 t1 = edge->to()->pos;
+ //boundaryEdgeCount++;
+ boundaryLength += length(t1 - t0);
+ //boundaryCentroid += edge->vertex()->pos;
+ edge = edge->next;
+ } while (edge != startEdge);
+ boundaryLengths.push_back(boundaryLength);
+ //boundaryCentroids.append(boundaryCentroid / boundaryEdgeCount);
+ }
+ // Find disk boundary.
+ uint32_t diskBoundary = 0;
+ float maxLength = boundaryLengths[0];
+ for (uint32_t i = 1; i < boundaryCount; i++) {
+ if (boundaryLengths[i] > maxLength) {
+ maxLength = boundaryLengths[i];
+ diskBoundary = i;
+ }
+ }
+ // Close holes.
+ for (uint32_t i = 0; i < boundaryCount; i++) {
+ if (diskBoundary == i) {
+ // Skip disk boundary.
+ continue;
+ }
+ halfedge::Edge *startEdge = boundaryEdges[i];
+ xaDebugAssert(startEdge != NULL);
+ xaDebugAssert(startEdge->face == NULL);
+ std::vector<halfedge::Vertex *> vertexLoop;
+ std::vector<halfedge::Edge *> edgeLoop;
+ halfedge::Edge *edge = startEdge;
+ do {
+ halfedge::Vertex *vertex = edge->next->vertex; // edge->to()
+ uint32_t j;
+ for (j = 0; j < vertexLoop.size(); j++) {
+ if (vertex->isColocal(vertexLoop[j])) {
+ break;
+ }
+ }
+ bool isCrossing = (j != vertexLoop.size());
+ if (isCrossing) {
+ halfedge::Edge *prev = edgeLoop[j]; // Previous edge before the loop.
+ halfedge::Edge *next = edge->next; // Next edge after the loop.
+ xaDebugAssert(prev->to()->isColocal(next->from()));
+ // Close loop.
+ edgeLoop.push_back(edge);
+ closeLoop(j + 1, edgeLoop);
+ // Link boundary loop.
+ prev->setNext(next);
+ vertex->setEdge(next);
+ // Start over again.
+ vertexLoop.clear();
+ edgeLoop.clear();
+ edge = startEdge;
+ vertex = edge->to();
+ }
+ vertexLoop.push_back(vertex);
+ edgeLoop.push_back(edge);
+ edge = edge->next;
+ } while (edge != startEdge);
+ closeLoop(0, edgeLoop);
+ }
+ getBoundaryEdges(m_unifiedMesh.get(), boundaryEdges);
+ boundaryCount = boundaryEdges.size();
+ xaDebugAssert(boundaryCount == 1);
+ return boundaryCount == 1;
+ }
+
+ bool isDisk() const {
+ return m_isDisk;
+ }
+ bool isVertexMapped() const {
+ return m_isVertexMapped;
+ }
+
+ uint32_t vertexCount() const {
+ return m_chartMesh->vertexCount();
+ }
+ uint32_t colocalVertexCount() const {
+ return m_unifiedMesh->vertexCount();
+ }
+
+ uint32_t faceCount() const {
+ return m_faceArray.size();
+ }
+ uint32_t faceAt(uint32_t i) const {
+ return m_faceArray[i];
+ }
+
+ const halfedge::Mesh *chartMesh() const {
+ return m_chartMesh.get();
+ }
+ halfedge::Mesh *chartMesh() {
+ return m_chartMesh.get();
+ }
+ const halfedge::Mesh *unifiedMesh() const {
+ return m_unifiedMesh.get();
+ }
+ halfedge::Mesh *unifiedMesh() {
+ return m_unifiedMesh.get();
+ }
+
+ //uint32_t vertexIndex(uint32_t i) const { return m_vertexIndexArray[i]; }
+
+ uint32_t mapChartVertexToOriginalVertex(uint32_t i) const {
+ return m_chartToOriginalMap[i];
+ }
+ uint32_t mapChartVertexToUnifiedVertex(uint32_t i) const {
+ return m_chartToUnifiedMap[i];
+ }
+
+ const std::vector<uint32_t> &faceArray() const {
+ return m_faceArray;
+ }
+
+ // Transfer parameterization from unified mesh to chart mesh.
+ void transferParameterization() {
+ xaDebugAssert(!m_isVertexMapped);
+ uint32_t vertexCount = m_chartMesh->vertexCount();
+ for (uint32_t v = 0; v < vertexCount; v++) {
+ halfedge::Vertex *vertex = m_chartMesh->vertexAt(v);
+ halfedge::Vertex *unifiedVertex = m_unifiedMesh->vertexAt(mapChartVertexToUnifiedVertex(v));
+ vertex->tex = unifiedVertex->tex;
+ }
+ }
+
+ float computeSurfaceArea() const {
+ return halfedge::computeSurfaceArea(m_chartMesh.get()) * scale;
+ }
+
+ float computeParametricArea() const {
+ // This only makes sense in parameterized meshes.
+ xaDebugAssert(m_isDisk);
+ xaDebugAssert(!m_isVertexMapped);
+ return halfedge::computeParametricArea(m_chartMesh.get());
+ }
+
+ Vector2 computeParametricBounds() const {
+ // This only makes sense in parameterized meshes.
+ xaDebugAssert(m_isDisk);
+ xaDebugAssert(!m_isVertexMapped);
+ Box bounds;
+ bounds.clearBounds();
+ uint32_t vertexCount = m_chartMesh->vertexCount();
+ for (uint32_t v = 0; v < vertexCount; v++) {
+ halfedge::Vertex *vertex = m_chartMesh->vertexAt(v);
+ bounds.addPointToBounds(Vector3(vertex->tex, 0));
+ }
+ return bounds.extents().xy();
+ }
+
+ float scale = 1.0f;
+ uint32_t vertexMapWidth;
+ uint32_t vertexMapHeight;
+ bool blockAligned = true;
+
+private:
+ bool closeLoop(uint32_t start, const std::vector<halfedge::Edge *> &loop) {
+ const uint32_t vertexCount = loop.size() - start;
+ xaDebugAssert(vertexCount >= 3);
+ if (vertexCount < 3) return false;
+ xaDebugAssert(loop[start]->vertex->isColocal(loop[start + vertexCount - 1]->to()));
+ // If the hole is planar, then we add a single face that will be properly triangulated later.
+ // If the hole is not planar, we add a triangle fan with a vertex at the hole centroid.
+ // This is still a bit of a hack. There surely are better hole filling algorithms out there.
+ std::vector<Vector3> points(vertexCount);
+ for (uint32_t i = 0; i < vertexCount; i++) {
+ points[i] = loop[start + i]->vertex->pos;
+ }
+ bool isPlanar = Fit::isPlanar(vertexCount, points.data());
+ if (isPlanar) {
+ // Add face and connect edges.
+ halfedge::Face *face = m_unifiedMesh->addFace();
+ for (uint32_t i = 0; i < vertexCount; i++) {
+ halfedge::Edge *edge = loop[start + i];
+ edge->face = face;
+ edge->setNext(loop[start + (i + 1) % vertexCount]);
+ }
+ face->edge = loop[start];
+ xaDebugAssert(face->isValid());
+ } else {
+ // If the polygon is not planar, we just cross our fingers, and hope this will work:
+ // Compute boundary centroid:
+ Vector3 centroidPos(0);
+ for (uint32_t i = 0; i < vertexCount; i++) {
+ centroidPos += points[i];
+ }
+ centroidPos *= (1.0f / vertexCount);
+ halfedge::Vertex *centroid = m_unifiedMesh->addVertex(centroidPos);
+ // Add one pair of edges for each boundary vertex.
+ for (uint32_t j = vertexCount - 1, i = 0; i < vertexCount; j = i++) {
+ halfedge::Face *face = m_unifiedMesh->addFace(centroid->id, loop[start + j]->vertex->id, loop[start + i]->vertex->id);
+ xaDebugAssert(face != NULL);
+#ifdef NDEBUG
+ face = NULL; // silence unused parameter warning
+#endif
+ }
+ }
+ return true;
+ }
+
+ static void getBoundaryEdges(halfedge::Mesh *mesh, std::vector<halfedge::Edge *> &boundaryEdges) {
+ xaDebugAssert(mesh != NULL);
+ const uint32_t edgeCount = mesh->edgeCount();
+ BitArray bitFlags(edgeCount);
+ bitFlags.clearAll();
+ boundaryEdges.clear();
+ // Search for boundary edges. Mark all the edges that belong to the same boundary.
+ for (uint32_t e = 0; e < edgeCount; e++) {
+ halfedge::Edge *startEdge = mesh->edgeAt(e);
+ if (startEdge != NULL && startEdge->isBoundary() && bitFlags.bitAt(e) == false) {
+ xaDebugAssert(startEdge->face != NULL);
+ xaDebugAssert(startEdge->pair->face == NULL);
+ startEdge = startEdge->pair;
+ const halfedge::Edge *edge = startEdge;
+ do {
+ xaDebugAssert(edge->face == NULL);
+ xaDebugAssert(bitFlags.bitAt(edge->id / 2) == false);
+ bitFlags.setBitAt(edge->id / 2);
+ edge = edge->next;
+ } while (startEdge != edge);
+ boundaryEdges.push_back(startEdge);
+ }
+ }
+ }
+
+ // Chart mesh.
+ std::auto_ptr<halfedge::Mesh> m_chartMesh;
+
+ std::auto_ptr<halfedge::Mesh> m_unifiedMesh;
+ bool m_isDisk;
+ bool m_isVertexMapped;
+
+ // List of faces of the original mesh that belong to this chart.
+ std::vector<uint32_t> m_faceArray;
+
+ // Map vertices of the chart mesh to vertices of the original mesh.
+ std::vector<uint32_t> m_chartToOriginalMap;
+
+ std::vector<uint32_t> m_chartToUnifiedMap;
+};
+
+// Estimate quality of existing parameterization.
+class ParameterizationQuality {
+public:
+ ParameterizationQuality() {
+ m_totalTriangleCount = 0;
+ m_flippedTriangleCount = 0;
+ m_zeroAreaTriangleCount = 0;
+ m_parametricArea = 0.0f;
+ m_geometricArea = 0.0f;
+ m_stretchMetric = 0.0f;
+ m_maxStretchMetric = 0.0f;
+ m_conformalMetric = 0.0f;
+ m_authalicMetric = 0.0f;
+ }
+
+ ParameterizationQuality(const halfedge::Mesh *mesh) {
+ xaDebugAssert(mesh != NULL);
+ m_totalTriangleCount = 0;
+ m_flippedTriangleCount = 0;
+ m_zeroAreaTriangleCount = 0;
+ m_parametricArea = 0.0f;
+ m_geometricArea = 0.0f;
+ m_stretchMetric = 0.0f;
+ m_maxStretchMetric = 0.0f;
+ m_conformalMetric = 0.0f;
+ m_authalicMetric = 0.0f;
+ const uint32_t faceCount = mesh->faceCount();
+ for (uint32_t f = 0; f < faceCount; f++) {
+ const halfedge::Face *face = mesh->faceAt(f);
+ const halfedge::Vertex *vertex0 = NULL;
+ Vector3 p[3];
+ Vector2 t[3];
+ for (halfedge::Face::ConstEdgeIterator it(face->edges()); !it.isDone(); it.advance()) {
+ const halfedge::Edge *edge = it.current();
+ if (vertex0 == NULL) {
+ vertex0 = edge->vertex;
+ p[0] = vertex0->pos;
+ t[0] = vertex0->tex;
+ } else if (edge->to() != vertex0) {
+ p[1] = edge->from()->pos;
+ p[2] = edge->to()->pos;
+ t[1] = edge->from()->tex;
+ t[2] = edge->to()->tex;
+ processTriangle(p, t);
+ }
+ }
+ }
+ if (m_flippedTriangleCount + m_zeroAreaTriangleCount == faceCount) {
+ // If all triangles are flipped, then none is.
+ m_flippedTriangleCount = 0;
+ }
+ xaDebugAssert(std::isfinite(m_parametricArea) && m_parametricArea >= 0);
+ xaDebugAssert(std::isfinite(m_geometricArea) && m_geometricArea >= 0);
+ xaDebugAssert(std::isfinite(m_stretchMetric));
+ xaDebugAssert(std::isfinite(m_maxStretchMetric));
+ xaDebugAssert(std::isfinite(m_conformalMetric));
+ xaDebugAssert(std::isfinite(m_authalicMetric));
+ }
+
+ bool isValid() const {
+ return m_flippedTriangleCount == 0; // @@ Does not test for self-overlaps.
+ }
+
+ float rmsStretchMetric() const {
+ if (m_geometricArea == 0) return 0.0f;
+ float normFactor = sqrtf(m_parametricArea / m_geometricArea);
+ return sqrtf(m_stretchMetric / m_geometricArea) * normFactor;
+ }
+
+ float maxStretchMetric() const {
+ if (m_geometricArea == 0) return 0.0f;
+ float normFactor = sqrtf(m_parametricArea / m_geometricArea);
+ return m_maxStretchMetric * normFactor;
+ }
+
+ float rmsConformalMetric() const {
+ if (m_geometricArea == 0) return 0.0f;
+ return sqrtf(m_conformalMetric / m_geometricArea);
+ }
+
+ float maxAuthalicMetric() const {
+ if (m_geometricArea == 0) return 0.0f;
+ return sqrtf(m_authalicMetric / m_geometricArea);
+ }
+
+ void operator+=(const ParameterizationQuality &pq) {
+ m_totalTriangleCount += pq.m_totalTriangleCount;
+ m_flippedTriangleCount += pq.m_flippedTriangleCount;
+ m_zeroAreaTriangleCount += pq.m_zeroAreaTriangleCount;
+ m_parametricArea += pq.m_parametricArea;
+ m_geometricArea += pq.m_geometricArea;
+ m_stretchMetric += pq.m_stretchMetric;
+ m_maxStretchMetric = std::max(m_maxStretchMetric, pq.m_maxStretchMetric);
+ m_conformalMetric += pq.m_conformalMetric;
+ m_authalicMetric += pq.m_authalicMetric;
+ }
+
+private:
+ void processTriangle(Vector3 q[3], Vector2 p[3]) {
+ m_totalTriangleCount++;
+ // Evaluate texture stretch metric. See:
+ // - "Texture Mapping Progressive Meshes", Sander, Snyder, Gortler & Hoppe
+ // - "Mesh Parameterization: Theory and Practice", Siggraph'07 Course Notes, Hormann, Levy & Sheffer.
+ float t1 = p[0].x;
+ float s1 = p[0].y;
+ float t2 = p[1].x;
+ float s2 = p[1].y;
+ float t3 = p[2].x;
+ float s3 = p[2].y;
+ float geometricArea = length(cross(q[1] - q[0], q[2] - q[0])) / 2;
+ float parametricArea = ((s2 - s1) * (t3 - t1) - (s3 - s1) * (t2 - t1)) / 2;
+ if (isZero(parametricArea)) {
+ m_zeroAreaTriangleCount++;
+ return;
+ }
+ Vector3 Ss = (q[0] * (t2 - t3) + q[1] * (t3 - t1) + q[2] * (t1 - t2)) / (2 * parametricArea);
+ Vector3 St = (q[0] * (s3 - s2) + q[1] * (s1 - s3) + q[2] * (s2 - s1)) / (2 * parametricArea);
+ float a = dot(Ss, Ss); // E
+ float b = dot(Ss, St); // F
+ float c = dot(St, St); // G
+ // Compute eigen-values of the first fundamental form:
+ float sigma1 = sqrtf(0.5f * std::max(0.0f, a + c - sqrtf(square(a - c) + 4 * square(b)))); // gamma uppercase, min eigenvalue.
+ float sigma2 = sqrtf(0.5f * std::max(0.0f, a + c + sqrtf(square(a - c) + 4 * square(b)))); // gamma lowercase, max eigenvalue.
+ xaAssert(sigma2 >= sigma1);
+ // isometric: sigma1 = sigma2 = 1
+ // conformal: sigma1 / sigma2 = 1
+ // authalic: sigma1 * sigma2 = 1
+ float rmsStretch = sqrtf((a + c) * 0.5f);
+ float rmsStretch2 = sqrtf((square(sigma1) + square(sigma2)) * 0.5f);
+ xaDebugAssert(equal(rmsStretch, rmsStretch2, 0.01f));
+#ifdef NDEBUG
+ rmsStretch2 = 0; // silence unused parameter warning
+#endif
+ if (parametricArea < 0.0f) {
+ // Count flipped triangles.
+ m_flippedTriangleCount++;
+ parametricArea = fabsf(parametricArea);
+ }
+ m_stretchMetric += square(rmsStretch) * geometricArea;
+ m_maxStretchMetric = std::max(m_maxStretchMetric, sigma2);
+ if (!isZero(sigma1, 0.000001f)) {
+ // sigma1 is zero when geometricArea is zero.
+ m_conformalMetric += (sigma2 / sigma1) * geometricArea;
+ }
+ m_authalicMetric += (sigma1 * sigma2) * geometricArea;
+ // Accumulate total areas.
+ m_geometricArea += geometricArea;
+ m_parametricArea += parametricArea;
+ //triangleConformalEnergy(q, p);
+ }
+
+ uint32_t m_totalTriangleCount;
+ uint32_t m_flippedTriangleCount;
+ uint32_t m_zeroAreaTriangleCount;
+ float m_parametricArea;
+ float m_geometricArea;
+ float m_stretchMetric;
+ float m_maxStretchMetric;
+ float m_conformalMetric;
+ float m_authalicMetric;
+};
+
+// Set of charts corresponding to a single mesh.
+class MeshCharts {
+public:
+ MeshCharts(const halfedge::Mesh *mesh) :
+ m_mesh(mesh) {}
+
+ ~MeshCharts() {
+ for (size_t i = 0; i < m_chartArray.size(); i++)
+ delete m_chartArray[i];
+ }
+
+ uint32_t chartCount() const {
+ return m_chartArray.size();
+ }
+ uint32_t vertexCount() const {
+ return m_totalVertexCount;
+ }
+
+ const Chart *chartAt(uint32_t i) const {
+ return m_chartArray[i];
+ }
+ Chart *chartAt(uint32_t i) {
+ return m_chartArray[i];
+ }
+
+ // Extract the charts of the input mesh.
+ void extractCharts() {
+ const uint32_t faceCount = m_mesh->faceCount();
+ int first = 0;
+ std::vector<uint32_t> queue;
+ queue.reserve(faceCount);
+ BitArray bitFlags(faceCount);
+ bitFlags.clearAll();
+ for (uint32_t f = 0; f < faceCount; f++) {
+ if (bitFlags.bitAt(f) == false) {
+ // Start new patch. Reset queue.
+ first = 0;
+ queue.clear();
+ queue.push_back(f);
+ bitFlags.setBitAt(f);
+ while (first != (int)queue.size()) {
+ const halfedge::Face *face = m_mesh->faceAt(queue[first]);
+ // Visit face neighbors of queue[first]
+ for (halfedge::Face::ConstEdgeIterator it(face->edges()); !it.isDone(); it.advance()) {
+ const halfedge::Edge *edge = it.current();
+ xaDebugAssert(edge->pair != NULL);
+ if (!edge->isBoundary() && /*!edge->isSeam()*/
+ //!(edge->from()->tex() != edge->pair()->to()->tex() || edge->to()->tex() != edge->pair()->from()->tex()))
+ !(edge->from() != edge->pair->to() || edge->to() != edge->pair->from())) { // Preserve existing seams (not just texture seams).
+ const halfedge::Face *neighborFace = edge->pair->face;
+ xaDebugAssert(neighborFace != NULL);
+ if (bitFlags.bitAt(neighborFace->id) == false) {
+ queue.push_back(neighborFace->id);
+ bitFlags.setBitAt(neighborFace->id);
+ }
+ }
+ }
+ first++;
+ }
+ Chart *chart = new Chart();
+ chart->build(m_mesh, queue);
+ m_chartArray.push_back(chart);
+ }
+ }
+ }
+
+ /*
+ Compute charts using a simple segmentation algorithm.
+
+ LSCM:
+ - identify sharp features using local dihedral angles.
+ - identify seed faces farthest from sharp features.
+ - grow charts from these seeds.
+
+ MCGIM:
+ - phase 1: chart growth
+ - grow all charts simultaneously using dijkstra search on the dual graph of the mesh.
+ - graph edges are weighted based on planarity metric.
+ - metric uses distance to global chart normal.
+ - terminate when all faces have been assigned.
+ - phase 2: seed computation:
+ - place new seed of the chart at the most interior face.
+ - most interior is evaluated using distance metric only.
+
+ - method repeates the two phases, until the location of the seeds does not change.
+ - cycles are detected by recording all the previous seeds and chartification terminates.
+
+ D-Charts:
+
+ - Uniaxial conic metric:
+ - N_c = axis of the generalized cone that best fits the chart. (cone can a be cylinder or a plane).
+ - omega_c = angle between the face normals and the axis.
+ - Fitting error between chart C and tringle t: F(c,t) = (N_c*n_t - cos(omega_c))^2
+
+ - Compactness metrics:
+ - Roundness:
+ - C(c,t) = pi * D(S_c,t)^2 / A_c
+ - S_c = chart seed.
+ - D(S_c,t) = length of the shortest path inside the chart betwen S_c and t.
+ - A_c = chart area.
+ - Straightness:
+ - P(c,t) = l_out(c,t) / l_in(c,t)
+ - l_out(c,t) = lenght of the edges not shared between C and t.
+ - l_in(c,t) = lenght of the edges shared between C and t.
+
+ - Combined metric:
+ - Cost(c,t) = F(c,t)^alpha + C(c,t)^beta + P(c,t)^gamma
+ - alpha = 1, beta = 0.7, gamma = 0.5
+
+ Our basic approach:
+ - Just one iteration of k-means?
+ - Avoid dijkstra by greedily growing charts until a threshold is met. Increase threshold and repeat until no faces left.
+ - If distortion metric is too high, split chart, add two seeds.
+ - If chart size is low, try removing chart.
+
+ Postprocess:
+ - If topology is not disk:
+ - Fill holes, if new faces fit proxy.
+ - Find best cut, otherwise.
+ - After parameterization:
+ - If boundary self-intersects:
+ - cut chart along the closest two diametral boundary vertices, repeat parametrization.
+ - what if the overlap is on an appendix? How do we find that out and cut appropiately?
+ - emphasize roundness metrics to prevent those cases.
+ - If interior self-overlaps: preserve boundary parameterization and use mean-value map.
+ */
+ void computeCharts(const CharterOptions &options, const std::vector<uint32_t> &unchartedMaterialArray) {
+ Chart *vertexMap = NULL;
+ if (unchartedMaterialArray.size() != 0) {
+ vertexMap = new Chart();
+ vertexMap->buildVertexMap(m_mesh, unchartedMaterialArray);
+ if (vertexMap->faceCount() == 0) {
+ delete vertexMap;
+ vertexMap = NULL;
+ }
+ }
+ AtlasBuilder builder(m_mesh);
+ if (vertexMap != NULL) {
+ // Mark faces that do not need to be charted.
+ builder.markUnchartedFaces(vertexMap->faceArray());
+ m_chartArray.push_back(vertexMap);
+ }
+ if (builder.facesLeft != 0) {
+ // Tweak these values:
+ const float maxThreshold = 2;
+ const uint32_t growFaceCount = 32;
+ const uint32_t maxIterations = 4;
+ builder.options = options;
+ //builder.options.proxyFitMetricWeight *= 0.75; // relax proxy fit weight during initial seed placement.
+ //builder.options.roundnessMetricWeight = 0;
+ //builder.options.straightnessMetricWeight = 0;
+ // This seems a reasonable estimate.
+ uint32_t maxSeedCount = std::max(6U, builder.facesLeft);
+ // Create initial charts greedely.
+ xaPrint("### Placing seeds\n");
+ builder.placeSeeds(maxThreshold, maxSeedCount);
+ xaPrint("### Placed %d seeds (max = %d)\n", builder.chartCount(), maxSeedCount);
+ builder.updateProxies();
+ builder.mergeCharts();
+#if 1
+ xaPrint("### Relocating seeds\n");
+ builder.relocateSeeds();
+ xaPrint("### Reset charts\n");
+ builder.resetCharts();
+ if (vertexMap != NULL) {
+ builder.markUnchartedFaces(vertexMap->faceArray());
+ }
+ builder.options = options;
+ xaPrint("### Growing charts\n");
+ // Restart process growing charts in parallel.
+ uint32_t iteration = 0;
+ while (true) {
+ if (!builder.growCharts(maxThreshold, growFaceCount)) {
+ xaPrint("### Can't grow anymore\n");
+ // If charts cannot grow more: fill holes, merge charts, relocate seeds and start new iteration.
+ xaPrint("### Filling holes\n");
+ builder.fillHoles(maxThreshold);
+ xaPrint("### Using %d charts now\n", builder.chartCount());
+ builder.updateProxies();
+ xaPrint("### Merging charts\n");
+ builder.mergeCharts();
+ xaPrint("### Using %d charts now\n", builder.chartCount());
+ xaPrint("### Reseeding\n");
+ if (!builder.relocateSeeds()) {
+ xaPrint("### Cannot relocate seeds anymore\n");
+ // Done!
+ break;
+ }
+ if (iteration == maxIterations) {
+ xaPrint("### Reached iteration limit\n");
+ break;
+ }
+ iteration++;
+ xaPrint("### Reset charts\n");
+ builder.resetCharts();
+ if (vertexMap != NULL) {
+ builder.markUnchartedFaces(vertexMap->faceArray());
+ }
+ xaPrint("### Growing charts\n");
+ }
+ };
+#endif
+ // Make sure no holes are left!
+ xaDebugAssert(builder.facesLeft == 0);
+ const uint32_t chartCount = builder.chartArray.size();
+ for (uint32_t i = 0; i < chartCount; i++) {
+ Chart *chart = new Chart();
+ m_chartArray.push_back(chart);
+ chart->build(m_mesh, builder.chartFaces(i));
+ }
+ }
+ const uint32_t chartCount = m_chartArray.size();
+ // Build face indices.
+ m_faceChart.resize(m_mesh->faceCount());
+ m_faceIndex.resize(m_mesh->faceCount());
+ for (uint32_t i = 0; i < chartCount; i++) {
+ const Chart *chart = m_chartArray[i];
+ const uint32_t faceCount = chart->faceCount();
+ for (uint32_t f = 0; f < faceCount; f++) {
+ uint32_t idx = chart->faceAt(f);
+ m_faceChart[idx] = i;
+ m_faceIndex[idx] = f;
+ }
+ }
+ // Build an exclusive prefix sum of the chart vertex counts.
+ m_chartVertexCountPrefixSum.resize(chartCount);
+ if (chartCount > 0) {
+ m_chartVertexCountPrefixSum[0] = 0;
+ for (uint32_t i = 1; i < chartCount; i++) {
+ const Chart *chart = m_chartArray[i - 1];
+ m_chartVertexCountPrefixSum[i] = m_chartVertexCountPrefixSum[i - 1] + chart->vertexCount();
+ }
+ m_totalVertexCount = m_chartVertexCountPrefixSum[chartCount - 1] + m_chartArray[chartCount - 1]->vertexCount();
+ } else {
+ m_totalVertexCount = 0;
+ }
+ }
+
+ void parameterizeCharts() {
+ ParameterizationQuality globalParameterizationQuality;
+ // Parameterize the charts.
+ uint32_t diskCount = 0;
+ const uint32_t chartCount = m_chartArray.size();
+ for (uint32_t i = 0; i < chartCount; i++) {
+ Chart *chart = m_chartArray[i];
+
+ bool isValid = false;
+
+ if (chart->isVertexMapped()) {
+ continue;
+ }
+
+ if (chart->isDisk()) {
+ diskCount++;
+ ParameterizationQuality chartParameterizationQuality;
+ if (chart->faceCount() == 1) {
+ computeSingleFaceMap(chart->unifiedMesh());
+ chartParameterizationQuality = ParameterizationQuality(chart->unifiedMesh());
+ } else {
+ computeOrthogonalProjectionMap(chart->unifiedMesh());
+ ParameterizationQuality orthogonalQuality(chart->unifiedMesh());
+ computeLeastSquaresConformalMap(chart->unifiedMesh());
+ ParameterizationQuality lscmQuality(chart->unifiedMesh());
+ chartParameterizationQuality = lscmQuality;
+ }
+ isValid = chartParameterizationQuality.isValid();
+ if (!isValid) {
+ xaPrint("*** Invalid parameterization.\n");
+ }
+ // @@ Check that parameterization quality is above a certain threshold.
+ // @@ Detect boundary self-intersections.
+ globalParameterizationQuality += chartParameterizationQuality;
+ }
+
+ // Transfer parameterization from unified mesh to chart mesh.
+ chart->transferParameterization();
+ }
+ xaPrint(" Parameterized %d/%d charts.\n", diskCount, chartCount);
+ xaPrint(" RMS stretch metric: %f\n", globalParameterizationQuality.rmsStretchMetric());
+ xaPrint(" MAX stretch metric: %f\n", globalParameterizationQuality.maxStretchMetric());
+ xaPrint(" RMS conformal metric: %f\n", globalParameterizationQuality.rmsConformalMetric());
+ xaPrint(" RMS authalic metric: %f\n", globalParameterizationQuality.maxAuthalicMetric());
+ }
+
+ uint32_t faceChartAt(uint32_t i) const {
+ return m_faceChart[i];
+ }
+ uint32_t faceIndexWithinChartAt(uint32_t i) const {
+ return m_faceIndex[i];
+ }
+
+ uint32_t vertexCountBeforeChartAt(uint32_t i) const {
+ return m_chartVertexCountPrefixSum[i];
+ }
+
+private:
+ const halfedge::Mesh *m_mesh;
+
+ std::vector<Chart *> m_chartArray;
+
+ std::vector<uint32_t> m_chartVertexCountPrefixSum;
+ uint32_t m_totalVertexCount;
+
+ std::vector<uint32_t> m_faceChart; // the chart of every face of the input mesh.
+ std::vector<uint32_t> m_faceIndex; // the index within the chart for every face of the input mesh.
+};
+
+/// An atlas is a set of charts.
+class Atlas {
+public:
+ ~Atlas() {
+ for (size_t i = 0; i < m_meshChartsArray.size(); i++)
+ delete m_meshChartsArray[i];
+ }
+
+ uint32_t meshCount() const {
+ return m_meshChartsArray.size();
+ }
+
+ const MeshCharts *meshAt(uint32_t i) const {
+ return m_meshChartsArray[i];
+ }
+
+ MeshCharts *meshAt(uint32_t i) {
+ return m_meshChartsArray[i];
+ }
+
+ uint32_t chartCount() const {
+ uint32_t count = 0;
+ for (uint32_t c = 0; c < m_meshChartsArray.size(); c++) {
+ count += m_meshChartsArray[c]->chartCount();
+ }
+ return count;
+ }
+
+ const Chart *chartAt(uint32_t i) const {
+ for (uint32_t c = 0; c < m_meshChartsArray.size(); c++) {
+ uint32_t count = m_meshChartsArray[c]->chartCount();
+ if (i < count) {
+ return m_meshChartsArray[c]->chartAt(i);
+ }
+ i -= count;
+ }
+ return NULL;
+ }
+
+ Chart *chartAt(uint32_t i) {
+ for (uint32_t c = 0; c < m_meshChartsArray.size(); c++) {
+ uint32_t count = m_meshChartsArray[c]->chartCount();
+ if (i < count) {
+ return m_meshChartsArray[c]->chartAt(i);
+ }
+ i -= count;
+ }
+ return NULL;
+ }
+
+ // Add mesh charts and takes ownership.
+ // Extract the charts and add to this atlas.
+ void addMeshCharts(MeshCharts *meshCharts) {
+ m_meshChartsArray.push_back(meshCharts);
+ }
+
+ void extractCharts(const halfedge::Mesh *mesh) {
+ MeshCharts *meshCharts = new MeshCharts(mesh);
+ meshCharts->extractCharts();
+ addMeshCharts(meshCharts);
+ }
+
+ void computeCharts(const halfedge::Mesh *mesh, const CharterOptions &options, const std::vector<uint32_t> &unchartedMaterialArray) {
+ MeshCharts *meshCharts = new MeshCharts(mesh);
+ meshCharts->computeCharts(options, unchartedMaterialArray);
+ addMeshCharts(meshCharts);
+ }
+
+ void parameterizeCharts() {
+ for (uint32_t i = 0; i < m_meshChartsArray.size(); i++) {
+ m_meshChartsArray[i]->parameterizeCharts();
+ }
+ }
+
+private:
+ std::vector<MeshCharts *> m_meshChartsArray;
+};
+
+struct AtlasPacker {
+ AtlasPacker(Atlas *atlas) :
+ m_atlas(atlas),
+ m_width(0),
+ m_height(0) {
+ // Save the original uvs.
+ m_originalChartUvs.resize(m_atlas->chartCount());
+ for (uint32_t i = 0; i < m_atlas->chartCount(); i++) {
+ const halfedge::Mesh *mesh = atlas->chartAt(i)->chartMesh();
+ m_originalChartUvs[i].resize(mesh->vertexCount());
+ for (uint32_t j = 0; j < mesh->vertexCount(); j++)
+ m_originalChartUvs[i][j] = mesh->vertexAt(j)->tex;
+ }
+ }
+
+ uint32_t getWidth() const { return m_width; }
+ uint32_t getHeight() const { return m_height; }
+
+ // Pack charts in the smallest possible rectangle.
+ void packCharts(const PackerOptions &options) {
+ const uint32_t chartCount = m_atlas->chartCount();
+ if (chartCount == 0) return;
+ float texelsPerUnit = 1;
+ if (options.method == PackMethod::TexelArea)
+ texelsPerUnit = options.texelArea;
+ for (int iteration = 0;; iteration++) {
+ m_rand = MTRand();
+ std::vector<float> chartOrderArray(chartCount);
+ std::vector<Vector2> chartExtents(chartCount);
+ float meshArea = 0;
+ for (uint32_t c = 0; c < chartCount; c++) {
+ Chart *chart = m_atlas->chartAt(c);
+ if (!chart->isVertexMapped() && !chart->isDisk()) {
+ chartOrderArray[c] = 0;
+ // Skip non-disks.
+ continue;
+ }
+ Vector2 extents(0.0f);
+ if (chart->isVertexMapped()) {
+ // Arrange vertices in a rectangle.
+ extents.x = float(chart->vertexMapWidth);
+ extents.y = float(chart->vertexMapHeight);
+ } else {
+ // Compute surface area to sort charts.
+ float chartArea = chart->computeSurfaceArea();
+ meshArea += chartArea;
+ //chartOrderArray[c] = chartArea;
+ // Compute chart scale
+ float parametricArea = fabsf(chart->computeParametricArea()); // @@ There doesn't seem to be anything preventing parametric area to be negative.
+ if (parametricArea < NV_EPSILON) {
+ // When the parametric area is too small we use a rough approximation to prevent divisions by very small numbers.
+ Vector2 bounds = chart->computeParametricBounds();
+ parametricArea = bounds.x * bounds.y;
+ }
+ float scale = (chartArea / parametricArea) * texelsPerUnit;
+ if (parametricArea == 0) { // < NV_EPSILON)
+ scale = 0;
+ }
+ xaAssert(std::isfinite(scale));
+ // Compute bounding box of chart.
+ Vector2 majorAxis, minorAxis, origin, end;
+ computeBoundingBox(chart, &majorAxis, &minorAxis, &origin, &end);
+ xaAssert(isFinite(majorAxis) && isFinite(minorAxis) && isFinite(origin));
+ // Sort charts by perimeter. @@ This is sometimes producing somewhat unexpected results. Is this right?
+ //chartOrderArray[c] = ((end.x - origin.x) + (end.y - origin.y)) * scale;
+ // Translate, rotate and scale vertices. Compute extents.
+ halfedge::Mesh *mesh = chart->chartMesh();
+ const uint32_t vertexCount = mesh->vertexCount();
+ for (uint32_t i = 0; i < vertexCount; i++) {
+ halfedge::Vertex *vertex = mesh->vertexAt(i);
+ //Vector2 t = vertex->tex - origin;
+ Vector2 tmp;
+ tmp.x = dot(vertex->tex, majorAxis);
+ tmp.y = dot(vertex->tex, minorAxis);
+ tmp -= origin;
+ tmp *= scale;
+ if (tmp.x < 0 || tmp.y < 0) {
+ xaPrint("tmp: %f %f\n", tmp.x, tmp.y);
+ xaPrint("scale: %f\n", scale);
+ xaPrint("origin: %f %f\n", origin.x, origin.y);
+ xaPrint("majorAxis: %f %f\n", majorAxis.x, majorAxis.y);
+ xaPrint("minorAxis: %f %f\n", minorAxis.x, minorAxis.y);
+ xaDebugAssert(false);
+ }
+ //xaAssert(tmp.x >= 0 && tmp.y >= 0);
+ vertex->tex = tmp;
+ xaAssert(std::isfinite(vertex->tex.x) && std::isfinite(vertex->tex.y));
+ extents = max(extents, tmp);
+ }
+ xaDebugAssert(extents.x >= 0 && extents.y >= 0);
+ // Limit chart size.
+ if (extents.x > 1024 || extents.y > 1024) {
+ float limit = std::max(extents.x, extents.y);
+ scale = 1024 / (limit + 1);
+ for (uint32_t i = 0; i < vertexCount; i++) {
+ halfedge::Vertex *vertex = mesh->vertexAt(i);
+ vertex->tex *= scale;
+ }
+ extents *= scale;
+ xaDebugAssert(extents.x <= 1024 && extents.y <= 1024);
+ }
+ // Scale the charts to use the entire texel area available. So, if the width is 0.1 we could scale it to 1 without increasing the lightmap usage and making a better
+ // use of it. In many cases this also improves the look of the seams, since vertices on the chart boundaries have more chances of being aligned with the texel centers.
+ float scale_x = 1.0f;
+ float scale_y = 1.0f;
+ float divide_x = 1.0f;
+ float divide_y = 1.0f;
+ if (extents.x > 0) {
+ int cw = ftoi_ceil(extents.x);
+ if (options.blockAlign && chart->blockAligned) {
+ // Align all chart extents to 4x4 blocks, but taking padding into account.
+ if (options.conservative) {
+ cw = align(cw + 2, 4) - 2;
+ } else {
+ cw = align(cw + 1, 4) - 1;
+ }
+ }
+ scale_x = (float(cw) - NV_EPSILON);
+ divide_x = extents.x;
+ extents.x = float(cw);
+ }
+ if (extents.y > 0) {
+ int ch = ftoi_ceil(extents.y);
+ if (options.blockAlign && chart->blockAligned) {
+ // Align all chart extents to 4x4 blocks, but taking padding into account.
+ if (options.conservative) {
+ ch = align(ch + 2, 4) - 2;
+ } else {
+ ch = align(ch + 1, 4) - 1;
+ }
+ }
+ scale_y = (float(ch) - NV_EPSILON);
+ divide_y = extents.y;
+ extents.y = float(ch);
+ }
+ for (uint32_t v = 0; v < vertexCount; v++) {
+ halfedge::Vertex *vertex = mesh->vertexAt(v);
+ vertex->tex.x /= divide_x;
+ vertex->tex.y /= divide_y;
+ vertex->tex.x *= scale_x;
+ vertex->tex.y *= scale_y;
+ xaAssert(std::isfinite(vertex->tex.x) && std::isfinite(vertex->tex.y));
+ }
+ }
+ chartExtents[c] = extents;
+ // Sort charts by perimeter.
+ chartOrderArray[c] = extents.x + extents.y;
+ }
+ // @@ We can try to improve compression of small charts by sorting them by proximity like we do with vertex samples.
+ // @@ How to do that? One idea: compute chart centroid, insert into grid, compute morton index of the cell, sort based on morton index.
+ // @@ We would sort by morton index, first, then quantize the chart sizes, so that all small charts have the same size, and sort by size preserving the morton order.
+ //xaPrint("Sorting charts.\n");
+ // Sort charts by area.
+ m_radix = RadixSort();
+ m_radix.sort(chartOrderArray);
+ const uint32_t *ranks = m_radix.ranks();
+ // First iteration - guess texelsPerUnit.
+ if (options.method != PackMethod::TexelArea && iteration == 0) {
+ // Estimate size of the map based on the mesh surface area and given texel scale.
+ const float texelCount = std::max(1.0f, meshArea * square(texelsPerUnit) / 0.75f); // Assume 75% utilization.
+ texelsPerUnit = sqrt((options.resolution * options.resolution) / texelCount);
+ resetUvs();
+ continue;
+ }
+ // Init bit map.
+ m_bitmap.clearAll();
+ m_bitmap.resize(options.resolution, options.resolution, false);
+ int w = 0;
+ int h = 0;
+ // Add sorted charts to bitmap.
+ for (uint32_t i = 0; i < chartCount; i++) {
+ uint32_t c = ranks[chartCount - i - 1]; // largest chart first
+ Chart *chart = m_atlas->chartAt(c);
+ if (!chart->isVertexMapped() && !chart->isDisk()) continue;
+ //float scale_x = 1;
+ //float scale_y = 1;
+ BitMap chart_bitmap;
+ if (chart->isVertexMapped()) {
+ chart->blockAligned = false;
+ // Init all bits to 1.
+ chart_bitmap.resize(ftoi_ceil(chartExtents[c].x), ftoi_ceil(chartExtents[c].y), /*initValue=*/true);
+ // @@ Another alternative would be to try to map each vertex to a different texel trying to fill all the available unused texels.
+ } else {
+ // @@ Add special cases for dot and line charts. @@ Lightmap rasterizer also needs to handle these special cases.
+ // @@ We could also have a special case for chart quads. If the quad surface <= 4 texels, align vertices with texel centers and do not add padding. May be very useful for foliage.
+ // @@ In general we could reduce the padding of all charts by one texel by using a rasterizer that takes into account the 2-texel footprint of the tent bilinear filter. For example,
+ // if we have a chart that is less than 1 texel wide currently we add one texel to the left and one texel to the right creating a 3-texel-wide bitmap. However, if we know that the
+ // chart is only 1 texel wide we could align it so that it only touches the footprint of two texels:
+ // | | <- Touches texels 0, 1 and 2.
+ // | | <- Only touches texels 0 and 1.
+ // \ \ / \ / /
+ // \ X X /
+ // \ / \ / \ /
+ // V V V
+ // 0 1 2
+ if (options.conservative) {
+ // Init all bits to 0.
+ chart_bitmap.resize(ftoi_ceil(chartExtents[c].x) + 1 + options.padding, ftoi_ceil(chartExtents[c].y) + 1 + options.padding, /*initValue=*/false); // + 2 to add padding on both sides.
+ // Rasterize chart and dilate.
+ drawChartBitmapDilate(chart, &chart_bitmap, options.padding);
+ } else {
+ // Init all bits to 0.
+ chart_bitmap.resize(ftoi_ceil(chartExtents[c].x) + 1, ftoi_ceil(chartExtents[c].y) + 1, /*initValue=*/false); // Add half a texels on each side.
+ // Rasterize chart and dilate.
+ drawChartBitmap(chart, &chart_bitmap, Vector2(1), Vector2(0.5));
+ }
+ }
+ int best_x, best_y;
+ int best_cw, best_ch; // Includes padding now.
+ int best_r;
+ findChartLocation(options.quality, &chart_bitmap, chartExtents[c], w, h, &best_x, &best_y, &best_cw, &best_ch, &best_r, chart->blockAligned);
+ /*if (w < best_x + best_cw || h < best_y + best_ch)
+ {
+ xaPrint("Resize extents to (%d, %d).\n", best_x + best_cw, best_y + best_ch);
+ }*/
+ // Update parametric extents.
+ w = std::max(w, best_x + best_cw);
+ h = std::max(h, best_y + best_ch);
+ w = align(w, 4);
+ h = align(h, 4);
+ // Resize bitmap if necessary.
+ if (uint32_t(w) > m_bitmap.width() || uint32_t(h) > m_bitmap.height()) {
+ //xaPrint("Resize bitmap (%d, %d).\n", nextPowerOfTwo(w), nextPowerOfTwo(h));
+ m_bitmap.resize(nextPowerOfTwo(uint32_t(w)), nextPowerOfTwo(uint32_t(h)), false);
+ }
+ //xaPrint("Add chart at (%d, %d).\n", best_x, best_y);
+ addChart(&chart_bitmap, w, h, best_x, best_y, best_r);
+ //float best_angle = 2 * PI * best_r;
+ // Translate and rotate chart texture coordinates.
+ halfedge::Mesh *mesh = chart->chartMesh();
+ const uint32_t vertexCount = mesh->vertexCount();
+ for (uint32_t v = 0; v < vertexCount; v++) {
+ halfedge::Vertex *vertex = mesh->vertexAt(v);
+ Vector2 t = vertex->tex;
+ if (best_r) std::swap(t.x, t.y);
+ //vertex->tex.x = best_x + t.x * cosf(best_angle) - t.y * sinf(best_angle);
+ //vertex->tex.y = best_y + t.x * sinf(best_angle) + t.y * cosf(best_angle);
+ vertex->tex.x = best_x + t.x + 0.5f;
+ vertex->tex.y = best_y + t.y + 0.5f;
+ xaAssert(vertex->tex.x >= 0 && vertex->tex.y >= 0);
+ xaAssert(std::isfinite(vertex->tex.x) && std::isfinite(vertex->tex.y));
+ }
+ }
+ //w -= padding - 1; // Leave one pixel border!
+ //h -= padding - 1;
+ m_width = std::max(0, w);
+ m_height = std::max(0, h);
+ xaAssert(isAligned(m_width, 4));
+ xaAssert(isAligned(m_height, 4));
+ if (options.method == PackMethod::ExactResolution) {
+ texelsPerUnit *= sqrt((options.resolution * options.resolution) / (float)(m_width * m_height));
+ if (iteration > 1 && m_width <= options.resolution && m_height <= options.resolution) {
+ m_width = m_height = options.resolution;
+ return;
+ }
+ resetUvs();
+ } else {
+ return;
+ }
+ }
+ }
+
+ float computeAtlasUtilization() const {
+ const uint32_t w = m_width;
+ const uint32_t h = m_height;
+ xaDebugAssert(w <= m_bitmap.width());
+ xaDebugAssert(h <= m_bitmap.height());
+ uint32_t count = 0;
+ for (uint32_t y = 0; y < h; y++) {
+ for (uint32_t x = 0; x < w; x++) {
+ count += m_bitmap.bitAt(x, y);
+ }
+ }
+ return float(count) / (w * h);
+ }
+
+private:
+ void resetUvs() {
+ for (uint32_t i = 0; i < m_atlas->chartCount(); i++) {
+ halfedge::Mesh *mesh = m_atlas->chartAt(i)->chartMesh();
+ for (uint32_t j = 0; j < mesh->vertexCount(); j++)
+ mesh->vertexAt(j)->tex = m_originalChartUvs[i][j];
+ }
+ }
+
+ // IC: Brute force is slow, and random may take too much time to converge. We start inserting large charts in a small atlas. Using brute force is lame, because most of the space
+ // is occupied at this point. At the end we have many small charts and a large atlas with sparse holes. Finding those holes randomly is slow. A better approach would be to
+ // start stacking large charts as if they were tetris pieces. Once charts get small try to place them randomly. It may be interesting to try a intermediate strategy, first try
+ // along one axis and then try exhaustively along that axis.
+ void findChartLocation(int quality, const BitMap *bitmap, Vector2::Arg extents, int w, int h, int *best_x, int *best_y, int *best_w, int *best_h, int *best_r, bool blockAligned) {
+ int attempts = 256;
+ if (quality == 1) attempts = 4096;
+ if (quality == 2) attempts = 2048;
+ if (quality == 3) attempts = 1024;
+ if (quality == 4) attempts = 512;
+ if (quality == 0 || w * h < attempts) {
+ findChartLocation_bruteForce(bitmap, extents, w, h, best_x, best_y, best_w, best_h, best_r, blockAligned);
+ } else {
+ findChartLocation_random(bitmap, extents, w, h, best_x, best_y, best_w, best_h, best_r, attempts, blockAligned);
+ }
+ }
+
+ void findChartLocation_bruteForce(const BitMap *bitmap, Vector2::Arg /*extents*/, int w, int h, int *best_x, int *best_y, int *best_w, int *best_h, int *best_r, bool blockAligned) {
+ const int BLOCK_SIZE = 4;
+ int best_metric = INT_MAX;
+ int step_size = blockAligned ? BLOCK_SIZE : 1;
+ // Try two different orientations.
+ for (int r = 0; r < 2; r++) {
+ int cw = bitmap->width();
+ int ch = bitmap->height();
+ if (r & 1) std::swap(cw, ch);
+ for (int y = 0; y <= h + 1; y += step_size) { // + 1 to extend atlas in case atlas full.
+ for (int x = 0; x <= w + 1; x += step_size) { // + 1 not really necessary here.
+ // Early out.
+ int area = std::max(w, x + cw) * std::max(h, y + ch);
+ //int perimeter = max(w, x+cw) + max(h, y+ch);
+ int extents = std::max(std::max(w, x + cw), std::max(h, y + ch));
+ int metric = extents * extents + area;
+ if (metric > best_metric) {
+ continue;
+ }
+ if (metric == best_metric && std::max(x, y) >= std::max(*best_x, *best_y)) {
+ // If metric is the same, pick the one closest to the origin.
+ continue;
+ }
+ if (canAddChart(bitmap, w, h, x, y, r)) {
+ best_metric = metric;
+ *best_x = x;
+ *best_y = y;
+ *best_w = cw;
+ *best_h = ch;
+ *best_r = r;
+ if (area == w * h) {
+ // Chart is completely inside, do not look at any other location.
+ goto done;
+ }
+ }
+ }
+ }
+ }
+ done:
+ xaDebugAssert(best_metric != INT_MAX);
+ }
+
+ void findChartLocation_random(const BitMap *bitmap, Vector2::Arg /*extents*/, int w, int h, int *best_x, int *best_y, int *best_w, int *best_h, int *best_r, int minTrialCount, bool blockAligned) {
+ const int BLOCK_SIZE = 4;
+ int best_metric = INT_MAX;
+ for (int i = 0; i < minTrialCount || best_metric == INT_MAX; i++) {
+ int r = m_rand.getRange(1);
+ int x = m_rand.getRange(w + 1); // + 1 to extend atlas in case atlas full. We may want to use a higher number to increase probability of extending atlas.
+ int y = m_rand.getRange(h + 1); // + 1 to extend atlas in case atlas full.
+ if (blockAligned) {
+ x = align(x, BLOCK_SIZE);
+ y = align(y, BLOCK_SIZE);
+ }
+ int cw = bitmap->width();
+ int ch = bitmap->height();
+ if (r & 1) std::swap(cw, ch);
+ // Early out.
+ int area = std::max(w, x + cw) * std::max(h, y + ch);
+ //int perimeter = max(w, x+cw) + max(h, y+ch);
+ int extents = std::max(std::max(w, x + cw), std::max(h, y + ch));
+ int metric = extents * extents + area;
+ if (metric > best_metric) {
+ continue;
+ }
+ if (metric == best_metric && std::min(x, y) > std::min(*best_x, *best_y)) {
+ // If metric is the same, pick the one closest to the origin.
+ continue;
+ }
+ if (canAddChart(bitmap, w, h, x, y, r)) {
+ best_metric = metric;
+ *best_x = x;
+ *best_y = y;
+ *best_w = cw;
+ *best_h = ch;
+ *best_r = r;
+ if (area == w * h) {
+ // Chart is completely inside, do not look at any other location.
+ break;
+ }
+ }
+ }
+ }
+
+ void drawChartBitmapDilate(const Chart *chart, BitMap *bitmap, int padding) {
+ const int w = bitmap->width();
+ const int h = bitmap->height();
+ const Vector2 extents = Vector2(float(w), float(h));
+ // Rasterize chart faces, check that all bits are not set.
+ const uint32_t faceCount = chart->faceCount();
+ for (uint32_t f = 0; f < faceCount; f++) {
+ const halfedge::Face *face = chart->chartMesh()->faceAt(f);
+ Vector2 vertices[4];
+ uint32_t edgeCount = 0;
+ for (halfedge::Face::ConstEdgeIterator it(face->edges()); !it.isDone(); it.advance()) {
+ if (edgeCount < 4) {
+ vertices[edgeCount] = it.vertex()->tex + Vector2(0.5) + Vector2(float(padding), float(padding));
+ }
+ edgeCount++;
+ }
+ if (edgeCount == 3) {
+ raster::drawTriangle(raster::Mode_Antialiased, extents, true, vertices, AtlasPacker::setBitsCallback, bitmap);
+ } else {
+ raster::drawQuad(raster::Mode_Antialiased, extents, true, vertices, AtlasPacker::setBitsCallback, bitmap);
+ }
+ }
+ // Expand chart by padding pixels. (dilation)
+ BitMap tmp(w, h);
+ for (int i = 0; i < padding; i++) {
+ tmp.clearAll();
+ for (int y = 0; y < h; y++) {
+ for (int x = 0; x < w; x++) {
+ bool b = bitmap->bitAt(x, y);
+ if (!b) {
+ if (x > 0) {
+ b |= bitmap->bitAt(x - 1, y);
+ if (y > 0) b |= bitmap->bitAt(x - 1, y - 1);
+ if (y < h - 1) b |= bitmap->bitAt(x - 1, y + 1);
+ }
+ if (y > 0) b |= bitmap->bitAt(x, y - 1);
+ if (y < h - 1) b |= bitmap->bitAt(x, y + 1);
+ if (x < w - 1) {
+ b |= bitmap->bitAt(x + 1, y);
+ if (y > 0) b |= bitmap->bitAt(x + 1, y - 1);
+ if (y < h - 1) b |= bitmap->bitAt(x + 1, y + 1);
+ }
+ }
+ if (b) tmp.setBitAt(x, y);
+ }
+ }
+ std::swap(tmp, *bitmap);
+ }
+ }
+
+ void drawChartBitmap(const Chart *chart, BitMap *bitmap, const Vector2 &scale, const Vector2 &offset) {
+ const int w = bitmap->width();
+ const int h = bitmap->height();
+ const Vector2 extents = Vector2(float(w), float(h));
+ static const Vector2 pad[4] = {
+ Vector2(-0.5, -0.5),
+ Vector2(0.5, -0.5),
+ Vector2(-0.5, 0.5),
+ Vector2(0.5, 0.5)
+ };
+ // Rasterize 4 times to add proper padding.
+ for (int i = 0; i < 4; i++) {
+ // Rasterize chart faces, check that all bits are not set.
+ const uint32_t faceCount = chart->chartMesh()->faceCount();
+ for (uint32_t f = 0; f < faceCount; f++) {
+ const halfedge::Face *face = chart->chartMesh()->faceAt(f);
+ Vector2 vertices[4];
+ uint32_t edgeCount = 0;
+ for (halfedge::Face::ConstEdgeIterator it(face->edges()); !it.isDone(); it.advance()) {
+ if (edgeCount < 4) {
+ vertices[edgeCount] = it.vertex()->tex * scale + offset + pad[i];
+ xaAssert(ftoi_ceil(vertices[edgeCount].x) >= 0);
+ xaAssert(ftoi_ceil(vertices[edgeCount].y) >= 0);
+ xaAssert(ftoi_ceil(vertices[edgeCount].x) <= w);
+ xaAssert(ftoi_ceil(vertices[edgeCount].y) <= h);
+ }
+ edgeCount++;
+ }
+ if (edgeCount == 3) {
+ raster::drawTriangle(raster::Mode_Antialiased, extents, /*enableScissors=*/true, vertices, AtlasPacker::setBitsCallback, bitmap);
+ } else {
+ raster::drawQuad(raster::Mode_Antialiased, extents, /*enableScissors=*/true, vertices, AtlasPacker::setBitsCallback, bitmap);
+ }
+ }
+ }
+ // Expand chart by padding pixels. (dilation)
+ BitMap tmp(w, h);
+ tmp.clearAll();
+ for (int y = 0; y < h; y++) {
+ for (int x = 0; x < w; x++) {
+ bool b = bitmap->bitAt(x, y);
+ if (!b) {
+ if (x > 0) {
+ b |= bitmap->bitAt(x - 1, y);
+ if (y > 0) b |= bitmap->bitAt(x - 1, y - 1);
+ if (y < h - 1) b |= bitmap->bitAt(x - 1, y + 1);
+ }
+ if (y > 0) b |= bitmap->bitAt(x, y - 1);
+ if (y < h - 1) b |= bitmap->bitAt(x, y + 1);
+ if (x < w - 1) {
+ b |= bitmap->bitAt(x + 1, y);
+ if (y > 0) b |= bitmap->bitAt(x + 1, y - 1);
+ if (y < h - 1) b |= bitmap->bitAt(x + 1, y + 1);
+ }
+ }
+ if (b) tmp.setBitAt(x, y);
+ }
+ }
+ std::swap(tmp, *bitmap);
+ }
+
+ bool canAddChart(const BitMap *bitmap, int atlas_w, int atlas_h, int offset_x, int offset_y, int r) {
+ xaDebugAssert(r == 0 || r == 1);
+ // Check whether the two bitmaps overlap.
+ const int w = bitmap->width();
+ const int h = bitmap->height();
+ if (r == 0) {
+ for (int y = 0; y < h; y++) {
+ int yy = y + offset_y;
+ if (yy >= 0) {
+ for (int x = 0; x < w; x++) {
+ int xx = x + offset_x;
+ if (xx >= 0) {
+ if (bitmap->bitAt(x, y)) {
+ if (xx < atlas_w && yy < atlas_h) {
+ if (m_bitmap.bitAt(xx, yy)) return false;
+ }
+ }
+ }
+ }
+ }
+ }
+ } else if (r == 1) {
+ for (int y = 0; y < h; y++) {
+ int xx = y + offset_x;
+ if (xx >= 0) {
+ for (int x = 0; x < w; x++) {
+ int yy = x + offset_y;
+ if (yy >= 0) {
+ if (bitmap->bitAt(x, y)) {
+ if (xx < atlas_w && yy < atlas_h) {
+ if (m_bitmap.bitAt(xx, yy)) return false;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return true;
+ }
+
+ void addChart(const BitMap *bitmap, int atlas_w, int atlas_h, int offset_x, int offset_y, int r) {
+ xaDebugAssert(r == 0 || r == 1);
+ // Check whether the two bitmaps overlap.
+ const int w = bitmap->width();
+ const int h = bitmap->height();
+ if (r == 0) {
+ for (int y = 0; y < h; y++) {
+ int yy = y + offset_y;
+ if (yy >= 0) {
+ for (int x = 0; x < w; x++) {
+ int xx = x + offset_x;
+ if (xx >= 0) {
+ if (bitmap->bitAt(x, y)) {
+ if (xx < atlas_w && yy < atlas_h) {
+ xaDebugAssert(m_bitmap.bitAt(xx, yy) == false);
+ m_bitmap.setBitAt(xx, yy);
+ }
+ }
+ }
+ }
+ }
+ }
+ } else if (r == 1) {
+ for (int y = 0; y < h; y++) {
+ int xx = y + offset_x;
+ if (xx >= 0) {
+ for (int x = 0; x < w; x++) {
+ int yy = x + offset_y;
+ if (yy >= 0) {
+ if (bitmap->bitAt(x, y)) {
+ if (xx < atlas_w && yy < atlas_h) {
+ xaDebugAssert(m_bitmap.bitAt(xx, yy) == false);
+ m_bitmap.setBitAt(xx, yy);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ static bool setBitsCallback(void *param, int x, int y, Vector3::Arg, Vector3::Arg, Vector3::Arg, float area) {
+ BitMap *bitmap = (BitMap *)param;
+ if (area > 0.0) {
+ bitmap->setBitAt(x, y);
+ }
+ return true;
+ }
+
+ // Compute the convex hull using Graham Scan.
+ static void convexHull(const std::vector<Vector2> &input, std::vector<Vector2> &output, float epsilon) {
+ const uint32_t inputCount = input.size();
+ std::vector<float> coords(inputCount);
+ for (uint32_t i = 0; i < inputCount; i++) {
+ coords[i] = input[i].x;
+ }
+ RadixSort radix;
+ radix.sort(coords);
+ const uint32_t *ranks = radix.ranks();
+ std::vector<Vector2> top;
+ top.reserve(inputCount);
+ std::vector<Vector2> bottom;
+ bottom.reserve(inputCount);
+ Vector2 P = input[ranks[0]];
+ Vector2 Q = input[ranks[inputCount - 1]];
+ float topy = std::max(P.y, Q.y);
+ float boty = std::min(P.y, Q.y);
+ for (uint32_t i = 0; i < inputCount; i++) {
+ Vector2 p = input[ranks[i]];
+ if (p.y >= boty) top.push_back(p);
+ }
+ for (uint32_t i = 0; i < inputCount; i++) {
+ Vector2 p = input[ranks[inputCount - 1 - i]];
+ if (p.y <= topy) bottom.push_back(p);
+ }
+ // Filter top list.
+ output.clear();
+ output.push_back(top[0]);
+ output.push_back(top[1]);
+ for (uint32_t i = 2; i < top.size();) {
+ Vector2 a = output[output.size() - 2];
+ Vector2 b = output[output.size() - 1];
+ Vector2 c = top[i];
+ float area = triangleArea(a, b, c);
+ if (area >= -epsilon) {
+ output.pop_back();
+ }
+ if (area < -epsilon || output.size() == 1) {
+ output.push_back(c);
+ i++;
+ }
+ }
+ uint32_t top_count = output.size();
+ output.push_back(bottom[1]);
+ // Filter bottom list.
+ for (uint32_t i = 2; i < bottom.size();) {
+ Vector2 a = output[output.size() - 2];
+ Vector2 b = output[output.size() - 1];
+ Vector2 c = bottom[i];
+ float area = triangleArea(a, b, c);
+ if (area >= -epsilon) {
+ output.pop_back();
+ }
+ if (area < -epsilon || output.size() == top_count) {
+ output.push_back(c);
+ i++;
+ }
+ }
+ // Remove duplicate element.
+ xaDebugAssert(output.front() == output.back());
+ output.pop_back();
+ }
+
+ // This should compute convex hull and use rotating calipers to find the best box. Currently it uses a brute force method.
+ static void computeBoundingBox(Chart *chart, Vector2 *majorAxis, Vector2 *minorAxis, Vector2 *minCorner, Vector2 *maxCorner) {
+ // Compute list of boundary points.
+ std::vector<Vector2> points;
+ points.reserve(16);
+ halfedge::Mesh *mesh = chart->chartMesh();
+ const uint32_t vertexCount = mesh->vertexCount();
+ for (uint32_t i = 0; i < vertexCount; i++) {
+ halfedge::Vertex *vertex = mesh->vertexAt(i);
+ if (vertex->isBoundary()) {
+ points.push_back(vertex->tex);
+ }
+ }
+ xaDebugAssert(points.size() > 0);
+ std::vector<Vector2> hull;
+ convexHull(points, hull, 0.00001f);
+ // @@ Ideally I should use rotating calipers to find the best box. Using brute force for now.
+ float best_area = FLT_MAX;
+ Vector2 best_min;
+ Vector2 best_max;
+ Vector2 best_axis;
+ const uint32_t hullCount = hull.size();
+ for (uint32_t i = 0, j = hullCount - 1; i < hullCount; j = i, i++) {
+ if (equal(hull[i], hull[j])) {
+ continue;
+ }
+ Vector2 axis = normalize(hull[i] - hull[j], 0.0f);
+ xaDebugAssert(isFinite(axis));
+ // Compute bounding box.
+ Vector2 box_min(FLT_MAX, FLT_MAX);
+ Vector2 box_max(-FLT_MAX, -FLT_MAX);
+ for (uint32_t v = 0; v < hullCount; v++) {
+ Vector2 point = hull[v];
+ float x = dot(axis, point);
+ if (x < box_min.x) box_min.x = x;
+ if (x > box_max.x) box_max.x = x;
+ float y = dot(Vector2(-axis.y, axis.x), point);
+ if (y < box_min.y) box_min.y = y;
+ if (y > box_max.y) box_max.y = y;
+ }
+ // Compute box area.
+ float area = (box_max.x - box_min.x) * (box_max.y - box_min.y);
+ if (area < best_area) {
+ best_area = area;
+ best_min = box_min;
+ best_max = box_max;
+ best_axis = axis;
+ }
+ }
+ // Consider all points, not only boundary points, in case the input chart is malformed.
+ for (uint32_t i = 0; i < vertexCount; i++) {
+ halfedge::Vertex *vertex = mesh->vertexAt(i);
+ Vector2 point = vertex->tex;
+ float x = dot(best_axis, point);
+ if (x < best_min.x) best_min.x = x;
+ if (x > best_max.x) best_max.x = x;
+ float y = dot(Vector2(-best_axis.y, best_axis.x), point);
+ if (y < best_min.y) best_min.y = y;
+ if (y > best_max.y) best_max.y = y;
+ }
+ *majorAxis = best_axis;
+ *minorAxis = Vector2(-best_axis.y, best_axis.x);
+ *minCorner = best_min;
+ *maxCorner = best_max;
+ }
+
+ Atlas *m_atlas;
+ BitMap m_bitmap;
+ RadixSort m_radix;
+ uint32_t m_width;
+ uint32_t m_height;
+ MTRand m_rand;
+ std::vector<std::vector<Vector2> > m_originalChartUvs;
+};
+
+} // namespace param
+} // namespace internal
+
+struct Atlas {
+ internal::param::Atlas atlas;
+ std::vector<internal::halfedge::Mesh *> heMeshes;
+ uint32_t width = 0;
+ uint32_t height = 0;
+ OutputMesh **outputMeshes = NULL;
+};
+
+void SetPrint(PrintFunc print) {
+ internal::s_print = print;
+}
+
+Atlas *Create() {
+ Atlas *atlas = new Atlas();
+ return atlas;
+}
+
+void Destroy(Atlas *atlas) {
+ xaAssert(atlas);
+ for (int i = 0; i < (int)atlas->heMeshes.size(); i++) {
+ delete atlas->heMeshes[i];
+ if (atlas->outputMeshes) {
+ OutputMesh *outputMesh = atlas->outputMeshes[i];
+ for (uint32_t j = 0; j < outputMesh->chartCount; j++)
+ delete[] outputMesh->chartArray[j].indexArray;
+ delete[] outputMesh->chartArray;
+ delete[] outputMesh->vertexArray;
+ delete[] outputMesh->indexArray;
+ delete outputMesh;
+ }
+ }
+ delete[] atlas->outputMeshes;
+ delete atlas;
+}
+
+static internal::Vector3 DecodePosition(const InputMesh &mesh, uint32_t index) {
+ xaAssert(mesh.vertexPositionData);
+ return *((const internal::Vector3 *)&((const uint8_t *)mesh.vertexPositionData)[mesh.vertexPositionStride * index]);
+}
+
+static internal::Vector3 DecodeNormal(const InputMesh &mesh, uint32_t index) {
+ xaAssert(mesh.vertexNormalData);
+ return *((const internal::Vector3 *)&((const uint8_t *)mesh.vertexNormalData)[mesh.vertexNormalStride * index]);
+}
+
+static internal::Vector2 DecodeUv(const InputMesh &mesh, uint32_t index) {
+ xaAssert(mesh.vertexUvData);
+ return *((const internal::Vector2 *)&((const uint8_t *)mesh.vertexUvData)[mesh.vertexUvStride * index]);
+}
+
+static uint32_t DecodeIndex(IndexFormat::Enum format, const void *indexData, uint32_t i) {
+ if (format == IndexFormat::HalfFloat)
+ return (uint32_t)((const uint16_t *)indexData)[i];
+ return ((const uint32_t *)indexData)[i];
+}
+
+static float EdgeLength(internal::Vector3 pos1, internal::Vector3 pos2) {
+ return internal::length(pos2 - pos1);
+}
+
+AddMeshError AddMesh(Atlas *atlas, const InputMesh &mesh, bool useColocalVertices) {
+ xaAssert(atlas);
+ AddMeshError error;
+ error.code = AddMeshErrorCode::Success;
+ error.face = error.index0 = error.index1 = UINT32_MAX;
+ // Expecting triangle faces.
+ if ((mesh.indexCount % 3) != 0) {
+ error.code = AddMeshErrorCode::InvalidIndexCount;
+ return error;
+ }
+ // Check if any index is out of range.
+ for (uint32_t j = 0; j < mesh.indexCount; j++) {
+ const uint32_t index = DecodeIndex(mesh.indexFormat, mesh.indexData, j);
+ if (index < 0 || index >= mesh.vertexCount) {
+ error.code = AddMeshErrorCode::IndexOutOfRange;
+ error.index0 = index;
+ return error;
+ }
+ }
+ // Build half edge mesh.
+ internal::halfedge::Mesh *heMesh = new internal::halfedge::Mesh;
+ std::vector<uint32_t> canonicalMap;
+ canonicalMap.reserve(mesh.vertexCount);
+ for (uint32_t i = 0; i < mesh.vertexCount; i++) {
+ internal::halfedge::Vertex *vertex = heMesh->addVertex(DecodePosition(mesh, i));
+ if (mesh.vertexNormalData)
+ vertex->nor = DecodeNormal(mesh, i);
+ if (mesh.vertexUvData)
+ vertex->tex = DecodeUv(mesh, i);
+ // Link colocals. You probably want to do this more efficiently! Sort by one axis or use a hash or grid.
+ uint32_t firstColocal = i;
+ if (useColocalVertices) {
+ for (uint32_t j = 0; j < i; j++) {
+ if (vertex->pos != DecodePosition(mesh, j))
+ continue;
+#if 0
+ if (mesh.vertexNormalData && vertex->nor != DecodeNormal(mesh, j))
+ continue;
+#endif
+ if (mesh.vertexUvData && vertex->tex != DecodeUv(mesh, j))
+ continue;
+ firstColocal = j;
+ break;
+ }
+ }
+ canonicalMap.push_back(firstColocal);
+ }
+ heMesh->linkColocalsWithCanonicalMap(canonicalMap);
+ for (uint32_t i = 0; i < mesh.indexCount / 3; i++) {
+ uint32_t tri[3];
+ for (int j = 0; j < 3; j++)
+ tri[j] = DecodeIndex(mesh.indexFormat, mesh.indexData, i * 3 + j);
+ // Check for zero length edges.
+ for (int j = 0; j < 3; j++) {
+ const uint32_t edges[6] = { 0, 1, 1, 2, 2, 0 };
+ const uint32_t index1 = tri[edges[j * 2 + 0]];
+ const uint32_t index2 = tri[edges[j * 2 + 1]];
+ const internal::Vector3 pos1 = DecodePosition(mesh, index1);
+ const internal::Vector3 pos2 = DecodePosition(mesh, index2);
+ if (EdgeLength(pos1, pos2) <= 0.0f) {
+ delete heMesh;
+ error.code = AddMeshErrorCode::ZeroLengthEdge;
+ error.face = i;
+ error.index0 = index1;
+ error.index1 = index2;
+ return error;
+ }
+ }
+ // Check for zero area faces.
+ {
+ const internal::Vector3 a = DecodePosition(mesh, tri[0]);
+ const internal::Vector3 b = DecodePosition(mesh, tri[1]);
+ const internal::Vector3 c = DecodePosition(mesh, tri[2]);
+ const float area = internal::length(internal::cross(b - a, c - a)) * 0.5f;
+ if (area <= 0.0f) {
+ delete heMesh;
+ error.code = AddMeshErrorCode::ZeroAreaFace;
+ error.face = i;
+ return error;
+ }
+ }
+ internal::halfedge::Face *face = heMesh->addFace(tri[0], tri[1], tri[2]);
+
+ if (!face && heMesh->errorCode == internal::halfedge::Mesh::ErrorCode::AlreadyAddedEdge) {
+ //there is still hope for this, no reason to not add, at least add as separate
+ face = heMesh->addUniqueFace(tri[0], tri[1], tri[2]);
+ }
+
+ if (!face) {
+ //continue;
+
+ if (heMesh->errorCode == internal::halfedge::Mesh::ErrorCode::AlreadyAddedEdge) {
+ error.code = AddMeshErrorCode::AlreadyAddedEdge;
+ } else if (heMesh->errorCode == internal::halfedge::Mesh::ErrorCode::DegenerateColocalEdge) {
+ error.code = AddMeshErrorCode::DegenerateColocalEdge;
+ } else if (heMesh->errorCode == internal::halfedge::Mesh::ErrorCode::DegenerateEdge) {
+ error.code = AddMeshErrorCode::DegenerateEdge;
+ } else if (heMesh->errorCode == internal::halfedge::Mesh::ErrorCode::DuplicateEdge) {
+ error.code = AddMeshErrorCode::DuplicateEdge;
+ }
+ error.face = i;
+ error.index0 = heMesh->errorIndex0;
+ error.index1 = heMesh->errorIndex1;
+ delete heMesh;
+ return error;
+ }
+ if (mesh.faceMaterialData)
+ face->material = mesh.faceMaterialData[i];
+ }
+ heMesh->linkBoundary();
+ atlas->heMeshes.push_back(heMesh);
+ return error;
+}
+
+void Generate(Atlas *atlas, CharterOptions charterOptions, PackerOptions packerOptions) {
+ xaAssert(atlas);
+ xaAssert(packerOptions.texelArea > 0);
+ // Chart meshes.
+ for (int i = 0; i < (int)atlas->heMeshes.size(); i++) {
+ std::vector<uint32_t> uncharted_materials;
+ atlas->atlas.computeCharts(atlas->heMeshes[i], charterOptions, uncharted_materials);
+ }
+ atlas->atlas.parameterizeCharts();
+ internal::param::AtlasPacker packer(&atlas->atlas);
+ packer.packCharts(packerOptions);
+ //float utilization = return packer.computeAtlasUtilization();
+ atlas->width = packer.getWidth();
+ atlas->height = packer.getHeight();
+ // Build output meshes.
+ atlas->outputMeshes = new OutputMesh *[atlas->heMeshes.size()];
+ for (int i = 0; i < (int)atlas->heMeshes.size(); i++) {
+ const internal::halfedge::Mesh *heMesh = atlas->heMeshes[i];
+ OutputMesh *outputMesh = atlas->outputMeshes[i] = new OutputMesh;
+ const internal::param::MeshCharts *charts = atlas->atlas.meshAt(i);
+ // Vertices.
+ outputMesh->vertexCount = charts->vertexCount();
+ outputMesh->vertexArray = new OutputVertex[outputMesh->vertexCount];
+ for (uint32_t i = 0; i < charts->chartCount(); i++) {
+ const internal::param::Chart *chart = charts->chartAt(i);
+ const uint32_t vertexOffset = charts->vertexCountBeforeChartAt(i);
+ for (uint32_t v = 0; v < chart->vertexCount(); v++) {
+ OutputVertex &output_vertex = outputMesh->vertexArray[vertexOffset + v];
+ output_vertex.xref = chart->mapChartVertexToOriginalVertex(v);
+ internal::Vector2 uv = chart->chartMesh()->vertexAt(v)->tex;
+ output_vertex.uv[0] = uv.x;
+ output_vertex.uv[1] = uv.y;
+ }
+ }
+ // Indices.
+ outputMesh->indexCount = heMesh->faceCount() * 3;
+ outputMesh->indexArray = new uint32_t[outputMesh->indexCount];
+ for (uint32_t f = 0; f < heMesh->faceCount(); f++) {
+ const uint32_t c = charts->faceChartAt(f);
+ const uint32_t i = charts->faceIndexWithinChartAt(f);
+ const uint32_t vertexOffset = charts->vertexCountBeforeChartAt(c);
+ const internal::param::Chart *chart = charts->chartAt(c);
+ xaDebugAssert(i < chart->chartMesh()->faceCount());
+ xaDebugAssert(chart->faceAt(i) == f);
+ const internal::halfedge::Face *face = chart->chartMesh()->faceAt(i);
+ const internal::halfedge::Edge *edge = face->edge;
+ outputMesh->indexArray[3 * f + 0] = vertexOffset + edge->vertex->id;
+ outputMesh->indexArray[3 * f + 1] = vertexOffset + edge->next->vertex->id;
+ outputMesh->indexArray[3 * f + 2] = vertexOffset + edge->next->next->vertex->id;
+ }
+ // Charts.
+ outputMesh->chartCount = charts->chartCount();
+ outputMesh->chartArray = new OutputChart[outputMesh->chartCount];
+ for (uint32_t i = 0; i < charts->chartCount(); i++) {
+ OutputChart *outputChart = &outputMesh->chartArray[i];
+ const internal::param::Chart *chart = charts->chartAt(i);
+ const uint32_t vertexOffset = charts->vertexCountBeforeChartAt(i);
+ const internal::halfedge::Mesh *mesh = chart->chartMesh();
+ outputChart->indexCount = mesh->faceCount() * 3;
+ outputChart->indexArray = new uint32_t[outputChart->indexCount];
+ for (uint32_t j = 0; j < mesh->faceCount(); j++) {
+ const internal::halfedge::Face *face = mesh->faceAt(j);
+ const internal::halfedge::Edge *edge = face->edge;
+ outputChart->indexArray[3 * j + 0] = vertexOffset + edge->vertex->id;
+ outputChart->indexArray[3 * j + 1] = vertexOffset + edge->next->vertex->id;
+ outputChart->indexArray[3 * j + 2] = vertexOffset + edge->next->next->vertex->id;
+ }
+ }
+ }
+}
+
+uint32_t GetWidth(const Atlas *atlas) {
+ xaAssert(atlas);
+ return atlas->width;
+}
+
+uint32_t GetHeight(const Atlas *atlas) {
+ xaAssert(atlas);
+ return atlas->height;
+}
+
+uint32_t GetNumCharts(const Atlas *atlas) {
+ xaAssert(atlas);
+ return atlas->atlas.chartCount();
+}
+
+const OutputMesh *const *GetOutputMeshes(const Atlas *atlas) {
+ xaAssert(atlas);
+ return atlas->outputMeshes;
+}
+
+const char *StringForEnum(AddMeshErrorCode::Enum error) {
+ if (error == AddMeshErrorCode::AlreadyAddedEdge)
+ return "already added edge";
+ if (error == AddMeshErrorCode::DegenerateColocalEdge)
+ return "degenerate colocal edge";
+ if (error == AddMeshErrorCode::DegenerateEdge)
+ return "degenerate edge";
+ if (error == AddMeshErrorCode::DuplicateEdge)
+ return "duplicate edge";
+ if (error == AddMeshErrorCode::IndexOutOfRange)
+ return "index out of range";
+ if (error == AddMeshErrorCode::InvalidIndexCount)
+ return "invalid index count";
+ if (error == AddMeshErrorCode::ZeroAreaFace)
+ return "zero area face";
+ if (error == AddMeshErrorCode::ZeroLengthEdge)
+ return "zero length edge";
+ return "success";
+}
+
+} // namespace xatlas
diff --git a/thirdparty/xatlas/xatlas.h b/thirdparty/xatlas/xatlas.h
new file mode 100644
index 0000000000..4140429fee
--- /dev/null
+++ b/thirdparty/xatlas/xatlas.h
@@ -0,0 +1,160 @@
+// This code is in the public domain -- castanyo@yahoo.es
+#pragma once
+#ifndef XATLAS_H
+#define XATLAS_H
+#include <float.h> // FLT_MAX
+#include <limits.h>
+#include <stdint.h>
+namespace xatlas {
+
+typedef void (*PrintFunc)(const char *, ...);
+
+struct Atlas;
+
+struct CharterOptions {
+ float proxyFitMetricWeight;
+ float roundnessMetricWeight;
+ float straightnessMetricWeight;
+ float normalSeamMetricWeight;
+ float textureSeamMetricWeight;
+ float maxChartArea;
+ float maxBoundaryLength;
+
+ CharterOptions() {
+ // These are the default values we use on The Witness.
+ proxyFitMetricWeight = 2.0f;
+ roundnessMetricWeight = 0.01f;
+ straightnessMetricWeight = 6.0f;
+ normalSeamMetricWeight = 4.0f;
+ textureSeamMetricWeight = 0.5f;
+ /*
+ proxyFitMetricWeight = 1.0f;
+ roundnessMetricWeight = 0.1f;
+ straightnessMetricWeight = 0.25f;
+ normalSeamMetricWeight = 1.0f;
+ textureSeamMetricWeight = 0.1f;
+ */
+ maxChartArea = FLT_MAX;
+ maxBoundaryLength = FLT_MAX;
+ }
+};
+
+struct PackMethod {
+ enum Enum {
+ TexelArea, // texel_area determines resolution
+ ApproximateResolution, // guess texel_area to approximately match desired resolution
+ ExactResolution // run the packer multiple times to exactly match the desired resolution (slow)
+ };
+};
+
+struct PackerOptions {
+ PackMethod::Enum method;
+
+ // 0 - brute force
+ // 1 - 4096 attempts
+ // 2 - 2048
+ // 3 - 1024
+ // 4 - 512
+ // other - 256
+ // Avoid brute force packing, since it can be unusably slow in some situations.
+ int quality;
+
+ float texelArea; // This is not really texel area, but 1 / texel width?
+ uint32_t resolution;
+ bool blockAlign; // Align charts to 4x4 blocks.
+ bool conservative; // Pack charts with extra padding.
+ int padding;
+
+ PackerOptions() {
+ method = PackMethod::ApproximateResolution;
+ quality = 1;
+ texelArea = 8;
+ resolution = 512;
+ blockAlign = false;
+ conservative = false;
+ padding = 0;
+ }
+};
+
+struct AddMeshErrorCode {
+ enum Enum {
+ Success,
+ AlreadyAddedEdge, // index0 and index1 are the edge indices
+ DegenerateColocalEdge, // index0 and index1 are the edge indices
+ DegenerateEdge, // index0 and index1 are the edge indices
+ DuplicateEdge, // index0 and index1 are the edge indices
+ IndexOutOfRange, // index0 is the index
+ InvalidIndexCount, // not evenly divisible by 3 - expecting triangles
+ ZeroAreaFace,
+ ZeroLengthEdge // index0 and index1 are the edge indices
+ };
+};
+
+struct AddMeshError {
+ AddMeshErrorCode::Enum code;
+ uint32_t face;
+ uint32_t index0, index1;
+};
+
+struct IndexFormat {
+ enum Enum {
+ HalfFloat,
+ Float
+ };
+};
+
+struct InputMesh {
+ uint32_t vertexCount;
+ const void *vertexPositionData;
+ uint32_t vertexPositionStride;
+ const void *vertexNormalData; // optional
+ uint32_t vertexNormalStride; // optional
+
+ // optional
+ // The input UVs are provided as a hint to the chart generator.
+ const void *vertexUvData;
+ uint32_t vertexUvStride;
+
+ uint32_t indexCount;
+ const void *indexData;
+ IndexFormat::Enum indexFormat;
+
+ // optional. indexCount / 3 in length.
+ // Charter also uses material boundaries as a hint to cut charts.
+ const uint16_t *faceMaterialData;
+};
+
+struct OutputChart {
+ uint32_t *indexArray;
+ uint32_t indexCount;
+};
+
+struct OutputVertex {
+ float uv[2];
+ uint32_t xref; // Index of input vertex from which this output vertex originated.
+};
+
+struct OutputMesh {
+ OutputChart *chartArray;
+ uint32_t chartCount;
+ uint32_t *indexArray;
+ uint32_t indexCount;
+ OutputVertex *vertexArray;
+ uint32_t vertexCount;
+};
+
+void SetPrint(PrintFunc print);
+Atlas *Create();
+void Destroy(Atlas *atlas);
+// useColocalVertices - generates fewer charts (good), but is more sensitive to bad geometry.
+AddMeshError AddMesh(Atlas *atlas, const InputMesh &mesh, bool useColocalVertices = true);
+void Generate(Atlas *atlas, CharterOptions charterOptions = CharterOptions(), PackerOptions packerOptions = PackerOptions());
+uint32_t GetWidth(const Atlas *atlas);
+uint32_t GetHeight(const Atlas *atlas);
+uint32_t GetNumCharts(const Atlas *atlas);
+const OutputMesh *const *GetOutputMeshes(const Atlas *atlas);
+const char *StringForEnum(AddMeshErrorCode::Enum error);
+
+} // namespace xatlas
+
+#endif // XATLAS_H
diff --git a/thirdparty/zstd/1314.diff b/thirdparty/zstd/1314.diff
new file mode 100644
index 0000000000..c9f4efadbf
--- /dev/null
+++ b/thirdparty/zstd/1314.diff
@@ -0,0 +1,13 @@
+diff --git a/common/cpu.h b/common/cpu.h
+index 88e0ebf44..eeb428ad5 100644
+--- a/common/cpu.h
++++ b/common/cpu.h
+@@ -36,7 +36,7 @@ MEM_STATIC ZSTD_cpuid_t ZSTD_cpuid(void) {
+ U32 f1d = 0;
+ U32 f7b = 0;
+ U32 f7c = 0;
+-#ifdef _MSC_VER
++#if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_IX86))
+ int reg[4];
+ __cpuid((int*)reg, 0);
+ {
diff --git a/thirdparty/zstd/SCsub b/thirdparty/zstd/SCsub
deleted file mode 100644
index 899a18e1cf..0000000000
--- a/thirdparty/zstd/SCsub
+++ /dev/null
@@ -1,29 +0,0 @@
-#!/usr/bin/env python
-
-Import('env')
-
-thirdparty_zstd_dir = "#thirdparty/zstd/"
-thirdparty_zstd_sources = [
- "common/entropy_common.c",
- "common/error_private.c",
- "common/fse_decompress.c",
- "common/pool.c",
- "common/threading.c",
- "common/xxhash.c",
- "common/zstd_common.c",
- "compress/fse_compress.c",
- "compress/huf_compress.c",
- "compress/zstd_compress.c",
- "compress/zstd_double_fast.c",
- "compress/zstd_fast.c",
- "compress/zstd_lazy.c",
- "compress/zstd_ldm.c",
- "compress/zstdmt_compress.c",
- "compress/zstd_opt.c",
- "decompress/huf_decompress.c",
- "decompress/zstd_decompress.c",
-]
-thirdparty_zstd_sources = [thirdparty_zstd_dir + file for file in thirdparty_zstd_sources]
-env.add_source_files(env.core_sources, thirdparty_zstd_sources)
-env.Append(CPPPATH=["#thirdparty/zstd", "#thirdparty/zstd/common"])
-env.Append(CCFLAGS="-DZSTD_STATIC_LINKING_ONLY")
diff --git a/thirdparty/zstd/common/cpu.h b/thirdparty/zstd/common/cpu.h
index 4eb48e39e1..a109520a33 100644
--- a/thirdparty/zstd/common/cpu.h
+++ b/thirdparty/zstd/common/cpu.h
@@ -36,7 +36,7 @@ MEM_STATIC ZSTD_cpuid_t ZSTD_cpuid(void) {
U32 f1d = 0;
U32 f7b = 0;
U32 f7c = 0;
-#ifdef _MSC_VER
+#if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_IX86))
int reg[4];
__cpuid((int*)reg, 0);
{